What is best (or commonly accepted) practice for where to declare COM object variables (scope) and how to handle cleaning them up when using structured error handling?
I just spend a whole load of time learning about Garbage Collection and Reference Counting and dealing with releasing COM objects in .NET.
Working with COM is annoying...
The Dilemma
I realize it's important to release referenced COM objects after finishing with them. I also realize it's also important to anticipate and handle errors.
These two things together seem to be at odds with what keeps getting beaten into my head as best practice: declaring your variables where they are used.
Now, in order to ensure the references are released when done with them, it seems to make the most sense to do this cleanup within the Finally
portion of a Try/Catch block.
However, doing so means that I cannot declare these variables within the Try or Catch portions of the block because they will not be accessible to the Finally portion.
SO....
Where does that leave me with regards to following best practices?
Should I continue to declare variables at the beginning of each routine in order to clean them up using Finally
?
Is there some other method of accessing COM references at the end of a procedure?
Am I just picking pepper out of fly shit with regards to best practices?
Example Code
In Example 1, I've declared all my variables before entering the Try/Catch block. This way I can ensure they get cleaned up, regardless of any errors.
In Example 2, I've declared my variables where they are used, but this causes a problem with potential non-release of COM objects.
Imports System.Runtime.InteropServices
Module COMexamples
Sub Example1()
Dim Com1 As SomeCOM
Dim Com2 As AnotherCOM
Try
Com1 = New SomeCOM
Com1.DoSomeStuff()
Catch ex As Exception
Com2 = New AnotherCOM
Com2.CleanupTheMess()
Finally
If Not Com1 Is Nothing Then
Com1.Close()
Marshal.FinalReleaseComObject(Com1)
End If
If Not Com2 Is Nothing Then
Com2.Quit()
Marshal.FinalReleaseComObject(Com2)
End If
End Try
End Sub
Sub Example2()
Try
Dim Com1 As New SomeCOM
Com1.DoSomeStuff()
'If an exception is thrown, the object won't get released!
Com1.Close()
Marshal.FinalReleaseComObject(Com1)
Catch ex As Exception
Dim Com2 As New AnotherCOM
Com2.CleanupTheMess()
'Another exception here means we miss releasing this COM reference too!
Com2.Quit()
Marshal.FinalReleaseComObject(Com2)
Finally
'This is pretty much useless now as Com1 and Com2 are out of scope here
End Try
End Sub
End Module