ComReference(Of T)
—
A type safe reference to a COM object
Problem
Calling Marshal.ReleaseComObject and Marshal.FinalReleaseComObject can improve
the performance of .NET applications that make heavy use of COM objects.
Unfortunately neither method is called deterministically. Normally you need to
wrap the COM object usage in a Try/Finally block and call Marshal.ReleaseComObject
from the Finally block if you want to deterministically call these methods.
This unfortunately can lead to some code duplication.
Solution
Create an object that implements IDisposable.Dispose allowing one to use the new
Using Statement
available in Visual Basic 2005
Discussion
ComReference(Of T) calls Marshal.FinalReleaseComObject in its implementation of
the IDisposable.Dispose method. Thus ensuring that Marshal.FinalReleaseComObject
will be called deterministically in a manner. Marshal.FinalReleaseComObject ensures
that the COM object is fully released, without needing a loop around calls to Marshal.ReleaseComObject.
ComReference(Of T) uses Generics to offer a type safe Target property that is
the type of the COM reference it contains.
NOTE: The major caveat of using ComReference(Of T) is that you need to use the
ComReference(Of T).Target property to get to the underlying COM object. Nesting a With statement
inside the Using statement can simplify this...
Example
Example 1
Imports Outlook = Microsoft.Office.Interop.Outlook
Using appOutlook As New ComReference(Of Outlook.Application)(New Outlook.Application)
Using ns As New ComReference(Of Outlook.NameSpace)(appOutlook.Target.GetNamespace("MAPI"))
With ns.Target
.Logon()
.Logoff()
End With
End Using
End Using
Source
ComReference(Of T)
Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices
Public Structure ComReference(Of T As Class)
Implements IDisposable
Private ReadOnly m_target As T
Public Sub New(ByVal target As T)
If target Is Nothing Then Throw New ArgumentNullException("target")
If Not Marshal.IsComObject(target) Then Throw New ArgumentException("Expecting a COM object", "target")
If TypeOf target Is IDisposable Then Throw New ArgumentException("Not expecting a Disposable object", "target")
m_target = target
End Sub
Public Sub New(ByVal target As Object)
MyClass.New(DirectCast(target, T))
End Sub
Public ReadOnly Property Target() As T
Get
Return m_target
End Get
End Property
Public Sub Dispose() Implements IDisposable.Dispose
If Marshal.IsComObject(m_target) Then
If Marshal.FinalReleaseComObject(m_target) <> 0 Then
End If
End If
End Sub
End Structure
See Also