I am creating a C# wrapper over the Acrobat SDK (yes, I know there are utilities out there already). I'm importing an Adobe type library that was created in C/C++. Perhaps this is obvious but I'm assuming this is unmanaged code. Are all COM objects in the realm of unmanaged code? I ask because I'd like to implement a Dispose pattern to release all of the COM objects with Marshal.FinalReleaseComObject(comObject).
Lastly, when is a Finalizer appropriate for unmanaged resources? The Microsoft documentation talks about Files, Network Connections and other unmanaged resources. It's a bit confusing for me because the Disposal pattern provided in the Microsoft documentation shows disposing of Unmanaged Resources in the Dispose method.
Would I call the Marshal.FinalReleaseComObject method in a Dispose or Finalizer? Thanks
UPDATE: There's some debate about whether to call ReleaseComObject vs FinalReleaseComObject. I'm under the impression that FinalReleaseComObject is the better option. As it turns out, FinalReleaseComObject calls ReleaseComObject itself in a loop until the reference count for that object is 0.
Therefore, use the ReleaseComObject only if it is absolutely required. If you want to call this method to ensure that a COM component is released at a determined time, consider using the FinalReleaseComObject method instead. FinalReleaseComObject will release the underlying COM component regardless of how many times it has re-entered the CLR. The internal reference count of the RCW is incremented by one every time the COM component re-enters the CLR. Therefore, you could call the ReleaseComObject method in a loop until the value returned is zero. This achieves the same result as the FinalReleaseComObject method.
From reference source:
public static int FinalReleaseComObject (object o)
{
while (ReleaseComObject (o) != 0) ;
return 0;
}
This is the pattern I'm currently using. I'm open to changing it based on the answer given.
protected virtual void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects)
if(document != null)
{
document.Dispose();
}
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
if (this.application != null) {
this.CloseContext();
Marshal.FinalReleaseComObject(this.application);
}
// TODO: set large fields to null
this.disposedValue = true;
}
}
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
~AdobeContext()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: false);
Console.WriteLine("AdobeContext Finalizer run");
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
Console.WriteLine("AdobeContext Dispose run");
}