从今天开始,使用COM对象的正确方法是什么? [英] As of today, what is the right way to work with COM objects?

查看:181
本文介绍了从今天开始,使用COM对象的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个很常见的问题,我决定问这个问题,因为这个问题到今天可能有不同的答案。希望,答案将有助于了解什么是正确的方式使用COM对象。
在个人方面,我对这个问题有不同的意见后感到非常混乱。

This is a very common question and I decided to ask it because this question may have a different answer as of today. Hopefully, the answers will help to understand what is the right way to work with COM objects. Personally, I feel very confuse after getting different opinions on this subject.

过去5年,我曾经使用COM对象,规则非常为我清除:

The last 5 years, I used to work with COM objects and the rules were very clear for me:


  1. 在代码行中使用单个句点。

  2. 不要使用foreach,使用for循环,而是在每次迭代时释放每个项目

  3. 不要调用FInalReleaseComObject,而应使用ReleaseComObject。

  4. 不要使用GC释放COM对象。 GC意图主要用于调试用法。

  5. 按照与创建对象相反的顺序发布对象。

  1. Use a single period in lines of code. Using more than one period create temporary objects behind the scene that cannot be explictly released.
  2. Do not use foreach, use a for loop instead and release each item on each iteration
  3. Do not call FInalReleaseComObject, use ReleaseComObject instead.
  4. Do not use GC for releasing COM objects. GC intent is mainly for debugging usage.
  5. Release objects in reverse order of their creation.

有些人在阅读最后一行之后可能会感到失望,这是我知道如何正确创建/释放Com Object,我希望得到的答案,将使它更清晰和无争议。

Some of you may be frustrated after reading those last lines, this is what I knew about how to properly create/release Com Object, I hope getting answers that will make it clearer and uncontested.

以下是我在这个主题上找到的一些链接。有些人告诉我们需要调用ReleaseComObject,有些不是。

Following, are some links I found on this topic. Some of them telling that it is needed to call ReleaseComObject and some of them not.

  • How to properly release Excel COM objects (Nov. 2013)
  • Proper Way of Releasing COM Objects in .NET (Aug. 2011)
  • Marshal.ReleaseComObject Considered Dangerous (Mar. 2010)
  • ReleaseCOMObject (Apr. 2004)

...在VSTO方案中,您通常不必使用ReleaseCOMObject ...

"... In VSTO scenarios, you typically don’t ever have to use ReleaseCOMObject. ..."




  • MSDN - Marshal.ReleaseComObject方法(当前.NET Framework版本):

    • MSDN - Marshal.ReleaseComObject Method (current .NET Framework version):

    • ...您应该使用此方法释放保存引用的基础COM对象...

      "...You should use this method to free the underlying COM object that holds references..."

      更新:

      此问题标记为过宽。


      1. 当使用COM对象或调用GC是正确的时候,需要使用ReleaseComObject

      2. VSTO方法是否改变了我们使用COM对象的方式?

      3. 我写的上述规则是必需的,错误?是否有其他人?


      推荐答案

      .NET / COM互操作设计得很好,正确。特别地,.NET Garbage Collector正确地跟踪COM引用,并且当没有剩余的运行时引用时,将正确地释放COM对象。通过调用 Marshal.ReleaseComObject(...) Marshal.FinalReleaseComObject(...)是一种危险但常见的反模式。不幸的是,一些不好的建议来自微软。

      The .NET / COM interop is well designed, and works correctly. In particular, the .NET Garbage Collector correctly tracks COM references, and will correctly release COM objects when they have no remaining runtime references. Interfering with the reference counts of COM object by calling Marshal.ReleaseComObject(...) or Marshal.FinalReleaseComObject(...) is a dangerous but common anti-pattern. Unfortunately, some of the bad advice came out of Microsoft.

      您的.NET代码可以正确地与COM交互,而忽略所有5规则。
      如果你确实需要触发从运行时不再引用的COM对象的确定性清理,你可以安全地强制GC(可能等待终结器完成)。否则,你不必在代码中做任何特殊的事情,来处理COM对象。

      Your .NET code can correctly interact with COM while ignoring all 5 of your rules. If you do need to trigger deterministic clean-up of COM objects that are no longer referenced from the runtime, you can safely force a GC (and possibly wait for finalizers to complete). Otherwise, you don't have to do anything special in your code, to deal with COM objects.

      有一个重要的警告,这可能导致对垃圾回收器的作用的混淆。当调试.NET代码时,局部变量人为地将它们的生命延伸到方法的结尾,以便支持在调试器下观察变量。这意味着你可能仍然有一个COM对象的引用(因此GC不会清理)比预期形式只是看代码。这个问题(只在调试器下发生)的一个好的解决方法是将GC调用的范围与GC清除调用分开。

      There is one important caveat, that might have contributed to confusion about role of the garbage collector. When debugging .NET code, local variables artificially have their lifetime extended to the end of the method, in order to support watching the variabled under the debugger. That means you might still have managed references to a COM object (and hence the GC won't clean up) later than expect form just looking at the code. A good workaround for this issue (which only occurs under the debugger) is to split the scope of COM calls from the GC cleanup calls.

      例如,这里有一些与Excel交互的C#代码,并正确清理。您可以粘贴到控制台应用程序(只需添加对Microsoft.Office.Interop.Excel的引用):

      As an example, here is some C# code that interacts with Excel, and cleans up properly. You can paste into a Console application (just add a reference to Microsoft.Office.Interop.Excel):

      using System;
      using System.Runtime.InteropServices;
      using Microsoft.Office.Interop.Excel;
      
      namespace TestCsCom
      {
          class Program
          {
              static void Main(string[] args)
              {
                  // NOTE: Don't call Excel objects in here... 
                  //       Debugger would keep alive until end, preventing GC cleanup
      
                  // Call a separate function that talks to Excel
                  DoTheWork();
      
                  // Now let the GC clean up (repeat, until no more)
                  do
                  {
                      GC.Collect();
                      GC.WaitForPendingFinalizers();
                  }
                  while (Marshal.AreComObjectsAvailableForCleanup());
              }
      
              static void DoTheWork()
              {
                  Application app = new Application();
                  Workbook book = app.Workbooks.Add();
                  Worksheet worksheet = book.Worksheets["Sheet1"];
                  app.Visible = true;
                  for (int i = 1; i <= 10; i++) {
                      worksheet.Cells.Range["A" + i].Value = "Hello";
                  }
                  book.Save();
                  book.Close();
                  app.Quit();
      
                  // NOTE: No calls the Marshal.ReleaseComObject() are ever needed
              }
          }
      }
      

      您将看到Excel进程正确关闭,表示所有COM对象已正确清理。

      You'll see that the Excel process properly shuts down, indicating that all the COM objects were properly cleaned up.

      VSTO不会改变任何这些问题 - 它只是一个.NET库,包装和扩展本地Office COM对象模型。

      VSTO does not change any of these issues - it is just a .NET library that wraps and extends the native Office COM object model.

      这个问题有很多错误的信息和混乱,包括MSDN和StackOverflow上的许多帖子。

      There is a lot of false information and confusion about this issue, including many posts on MSDN and on StackOverflow.

      什么最终说服我仔细查看并找出正确的建议是这篇文章 https://blogs.msdn.microsoft.com/visualstudio/2010/03/01/marshal-releasecomobject-considered-dangerous/ 以及在StackOverflow上的调试器下查找引用的问题

      What finally convinced me to have a closer look and figure out the right advice was this post https://blogs.msdn.microsoft.com/visualstudio/2010/03/01/marshal-releasecomobject-considered-dangerous/ together with finding the issue with references kept alive under the debugger on a StackOverflow answer.

      此一般性指导的一个例外是COM对象模型需要按特定顺序发布接口。这里描述的GC方法不能控制GC释放COM对象的顺序。

      One exception to this general guidance is when the COM object model requires interfaces to be released in a particular order. The GC approach described here does not give you control over the order in which the COM objects are released by the GC.

      我没有任何引用来指示这个会违反投诉人的合约。一般来说,我希望COM层次结构使用内部引用,以确保对序列的任何依赖性得到正确管理。例如。在Excel的情况下,期望Range对象保持对父Worksheet对象的内部引用,使得对象模型的用户不需要显式地保持活着。

      I don't have any reference to indicate whether this would violate the COM contract. In general, I would expect COM hierarchies to use internal references to ensure any dependencies on the sequence are properly managed. E.g. in the case of Excel, one would expect a Range object to keep an internal reference to the parent Worksheet object, so that a user of the object model need not explicitly keep both alive.

      在某些情况下,即使Office应用程序对释放COM对象的顺序也很敏感。一种情况似乎是在使用OLE嵌入时 - 请参阅 https://blogs.msdn.microsoft.com/vsofficedeveloper/2008/04/11/excel-ole -embedding-errors-if-you-have-managed-add-in-sinking-application-events-in-excel-2 /

      There may be cases where even the Office applications are sensitive to the sequence in which COM objects are released. One case seems to be when the OLE embedding is used - see https://blogs.msdn.microsoft.com/vsofficedeveloper/2008/04/11/excel-ole-embedding-errors-if-you-have-managed-add-in-sinking-application-events-in-excel-2/

      将有可能创建一个COM对象模型失败,如果对象按错误的顺序被释放,并且与这样的COM模型的互操作然后将需要一些更多的关心,并且可能需要手动干扰引用。

      So it would be possible to create a COM object model that fails if objects are released in the wrong sequence, and the interop with such a COM model would then require some more care, and might need manual interference with the references.

      但是对于与Office COM对象模型的一般互操作,我同意 VS博客文章调用Marshal.ReleaseComObject - 一个伪装成解决方案的问题。

      But for general interop with the Office COM object models, I agree with the VS blog post calling "Marshal.ReleaseComObject – a problem disguised as a solution".

      这篇关于从今天开始,使用COM对象的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆