在代码中正确释放 COM 对象

Proper release of COM objects in code

我刚刚开始将一些代码从 VBA 迁移到 VB.Net。所以我绝对是 VB.Net 的初学者——但我想把事情做好。也许我的一些问题很愚蠢,但我想那是因为我是初学者。

作为第一个练习,我开发了我的第一段代码(见下文)。现在我想我必须再次释放所有 COM 对象。其中两个在编写代码时已经抛出错误。而其他人则在运行时抛出错误。

但有趣的是:天气我是否释放其余的 COM 对象(通过将 Marshal.Release 的相关未注释行也添加到注释中——然后所有以 [=82 开头的行=] 是注释行)代码的行为在我看来是完全一样的。

谁能告诉我哪里可以see/find区别?

网上说肯定有区别? 但我想我只是不明白(直到现在)。

除此之外,我还有很多问题:

  1. 是否每个“Dim”语句都会创建一个 COM 对象 - 必须稍后发布?
  2. 如果没有,如何检测是否已创建 COM 对象?哪些“Dim”语句创建 COM 对象,哪些不创建?
  3. 在这个例子中:Dim ActiveWindow As Object = Nothing Try ActiveWindow = Me.HostApplication.ActiveWindow() Catch End Try

Marshal.ReleaseComObject(ActiveWindow) 相同 Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())?

  1. 据此:

http://www.codeproject.com/Tips/235230/Proper-Way-of-Releasing-COM-Objects-in-NET

每个"level"像这样分开释放不是更好吗:

Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())
Marshal.ReleaseComObject(Me.HostApplication)
Marshal.ReleaseComObject(Me)
  1. 总体:我是不是想释放太多?还是正确/好的做法?

  2. "GC.Collect()" 和“... = Null”与这一切有什么关系?我根本没用过。我应该更好地使用它吗?为什么? ( "... = Null" 我在这里看到过:

http://www.codeproject.com/Tips/162691/Proper-Way-of-Releasing-COM-Objects-in-NET)

  1. 为什么我会收到“ShapeCount was not declared …”- 如果我尝试执行“Marshal.ReleaseComObject(ShapeCount)”会出错?与“ShRange”相同。我认为这些也是 COM 对象?!?

  2. 我如何注意到何时是再次释放 COM 对象的最佳时机?当我 process/debug 使用 F11 逐步编写我的代码时,我可以确定最佳(最快)的发布点吗?到目前为止,我对何时不再需要 COM 对象并可以释放它没有“感觉”。

非常欢迎任何帮助和解释。

这是我正在谈论的代码:

Imports System.Runtime.InteropServices
Imports System.ComponentModel
Imports System.Windows.Forms
Imports AddinExpress.MSO
Imports PowerPoint = Microsoft.Office.Interop.PowerPoint

'Add-in Express Add-in Module
<GuidAttribute("D75C609E-7632-400F-8A6F-6A6E6E744E75"),
ProgIdAttribute("MyAddin8.AddinModule")> _
Public Class AddinModule
Inherits AddinExpress.MSO.ADXAddinModule

#Region " Add-in Express automatic code "
[…] 
#End Region

Public Shared Shadows ReadOnly Property CurrentInstance() As AddinModule
    Get
        Return CType(AddinExpress.MSO.ADXAddinModule.CurrentInstance, AddinModule)
    End Get
End Property

Public ReadOnly Property PowerPointApp() As PowerPoint._Application
    Get
        Return CType(HostApplication, PowerPoint._Application)
    End Get
End Property

Private Sub AdxRibbonButton2_OnClick(sender As Object, control As IRibbonControl, pressed As Boolean) Handles AdxRibbonButton2.OnClick
    MsgBox(GetInfoString2())
End Sub

Friend Function GetInfoString2() As String
    Dim ActiveWindow As Object = Nothing
    Try
        ActiveWindow = Me.HostApplication.ActiveWindow()
    Catch
    End Try
    Dim Result As String = "No document window found!"
    If Not ActiveWindow Is Nothing Then
        Select Case Me.HostType
            Case ADXOfficeHostApp.ohaPowerPoint
                Dim Selection As PowerPoint.Selection =
                    CType(ActiveWindow, PowerPoint.DocumentWindow).Selection
                Dim WindowViewType As PowerPoint.PpViewType = PowerPoint.PpViewType.ppViewNormal
                Dim SlideRange As PowerPoint.SlideRange = Selection.SlideRange
                Dim SlideCountString = SlideRange.Count.ToString()
                If WindowViewType = 9 And SlideCountString < 2 Then
                    Dim ShRange As PowerPoint.ShapeRange = Nothing
                    Try
                        ShRange = Selection.ShapeRange
                    Catch
                    End Try
                    If Not ShRange Is Nothing Then
                        Dim ShapeCount = ShRange.Count.ToString()
                        Result = "You have " + ShapeCount _
                            + " shapes selected."
                    Else
                        Result = "You have 0 shapes selected."
                    End If
                End If
                'Marshal.ReleaseComObject(ShapeCount)
                'Marshal.ReleaseComObject(ShRange)
                'Marshal.ReleaseComObject(WindowViewType)
                'Marshal.ReleaseComObject(SlideCountString)
                Marshal.ReleaseComObject(SlideRange)
                Marshal.ReleaseComObject(Selection)
            Case Else
                Result = AddinName + " doesn't support " + HostName
        End Select
        'Marshal.ReleaseComObject(Me.HostType)
        'Marshal.ReleaseComObject(Result)
        Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())
        Marshal.ReleaseComObject(Me.HostApplication)
        'Marshal.ReleaseComObject(Me)
    End If
    Return Result
End Function

End Class

FinalReleaseComObject 调用 ReleaseComObject 直到 returns 0,这意味着释放 COM 对象。以相反的顺序调用它们,如 Excel objects(Application, Workbook, Worksheet) 是处理相关 COM 对象的正确方法。

Exception Condition

ArgumentException
o is not a valid COM object.

ArgumentNullException
o is null.

Marshal class 的 ReleaseComObject 方法减少与指定 COM 对象关联的指定运行时可调用包装器 (RCW) 的引用计数,它不会释放对象。它来自 COM 性质。

通常您需要释放从 Office(在您的例子中是 PowerPoint)对象模型返回的每个对象。异常是作为参数传递给事件处理程序的对象。

您可以阅读更多相关内容并在 When to release COM objects in Office add-ins developed in .NET 文章中找到您的多个问题的答案。