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

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

问题描述

这是一个很常见的问题,我决定问这个问题,因为这个问题今天可能有不同的答案。希望这些答案有助于了解使用COM对象的正确方法。
个人来说,我对这个问题有不同的看法感到很困惑。



过去5年来,我曾经使用COM对象,规则非常对我而言:


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

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

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

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

  5. 以与创建相反的顺序释放对象。





以下是我在这个主题上发现的一些链接。其中有些人告诉它需要调用ReleaseComObject,其中一些不是。






...在VSTO场景中,您通常不必使用ReleaseCOMObject ...





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




  • ...您应该使用此方法来释放持有引用的基础COM对象...


    更新:



    此问题已被标记为太广泛。根据要求,我将尝试简化和提出更简单的问题。


    1. 使用COM对象或调用GC是否需要ReleaseComObject是正确的方式?

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

    3. 我写过的上述规则是必需的,哪些是错误?有没有其他的?


    解决方案

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



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



    有一个重要的警告,这可能有助于混淆垃圾收集器的作用。调试.NET代码时,局部变量人为地将其生命延长到方法的末尾,以支持在调试器下观察变量。这意味着您可能仍然有一个COM对象的管理引用(因此GC将不会清理)晚于期望窗体只是看代码。此问题的一个很好的解决方法(仅在调试器下发生)是从GC清理调用中拆分COM调用的范围。



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

      using System; 
    使用System.Runtime.InteropServices;
    使用Microsoft.Office.Interop.Excel;

    命名空间TestCsCom
    {
    类程序
    {
    static void Main(string [] args)
    {
    //注意:不要在这里调用Excel对象...
    //调试器将保持活动直到结束,阻止GC清理

    //调用与Excel $ b $对话的单独函数b DoTheWork();

    //现在让GC清理(重复,直到不再)
    do
    {
    GC.Collect();
    GC.WaitForPendingFinalizers();
    }
    while(Marshal.AreComObjectsAvailableForCleanup());
    }

    static void DoTheWork()
    {
    应用程序app = new Application();
    工作簿book = app.Workbooks.Add();
    工作表工作表= book.Worksheets [Sheet1];
    app.Visible = true; (int i = 1; i< = 10; i ++)

    工作表Cells.Range [A+ i] .Value =Hello;
    }
    book.Save();
    book.Close();
    app.Quit();

    //注意:不需要调用Marshal.ReleaseComObject()
    }
    }
    }
    / pre>

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



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






    有很多关于这个问题的虚假信息和混淆,包括MSDN和StackOverflow上的许多帖子。



    最后让我相信仔细看看,找出正确的建议是这篇文章 https://blogs.msdn.microsoft.com/visualstudio/2010/03/01/marshal-releasecomobject-considered-dangerous/ 以及查找在调试下保存的引用的问题r在StackOverflow答案上。






    此一般指导的一个例外是当COM对象模型需要在一个特定的顺序这里描述的GC方法不能控制COM对象由GC发布的顺序。



    我没有任何参考来指示是否将违反COM合同。一般来说,我希望COM层次结构使用内部引用来确保序列的任何依赖关系得到妥善管理。例如。在Excel的情况下,可以期望一个Range对象保留对Parent Worksheet对象的内部引用,以便对象模型的用户不需要明确地保持两者的存在。



    可能有些情况下,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 /



    所以它可能会创建一个COM对象模型,如果对象以错误的顺序被释放,那么这种COM模型的互操作将需要更多的关心,并且可能需要手动干扰引用。



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


    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.

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

    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.

    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.

    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.

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

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

    UPDATE:

    This question has been marked as too broad. As requested, I will try to simplify and ask simpler questions.

    1. Does ReleaseComObject is required when working with COM Objects or calling GC is the correct way?
    2. Does VSTO approach change the way we used to work with COM Objects?
    3. Which of the above rules I wrote are required and which are wrong? Is there any others?

    解决方案

    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.

    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.

    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.

    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
            }
        }
    }
    

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

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


    There is a lot of false information and confusion about this issue, including many posts on MSDN and on 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.


    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.

    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.

    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/

    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.

    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天全站免登陆