Hello there,
I have some doubts about the best practice for using COM automation,
the Runtime
Callable Wrapper (RCW) and Marshal.Release ComObject.
So the question is/are:
Do I need to release each COM object explicit by a call to
Marshal.Release ComObject, does the RCW take care of that or does it
leaks
unmanaged resources?
If I understand the docs correctly without the explicit call to
Marshal.Release ComObject the RCW objects release the COM objects in
their
finalizer. But as I read several times in this NG, it's a bad thing to
depend
on the finalizer to release unmanaged resources because the garbage
collector
runs non-deterministic so someone never knows when.
Unfortunately the RCW objects don't implement the dispose pattern so
someone
could dispose the underlying COM object deterministic. And even then,
the
codingstyle is a mess (as you'll see in my examples later).
So what is the best (or common) practice for COM automation:
Example 1: Explicit calls of Marshal.Release ComObject
=============== ===========
Excel.Applicati onClass excelApp = null;
Excel.Workbooks workbooks = null;
Excel.Workbook wb = null;
Excel.Worksheet ws = null;
try
{
excelApp = new Excel.Applicati onClass();
excelApp.Displa yAlerts = false;
excelApp.Enable Events = false;
// enumerate all available worsheets
workbooks = excelApp.Workbo oks;
wb = workbooks.Open( path, 0, true, 5, "", "", true,
Excel.XlPlatfor m.xlWindows,
"", false, false, 0, false, false,
Excel.XlCorrupt Load.xlNormalLo ad);
foreach (ws in wb.Sheets)
{
Console.WriteLi ne("Sheet: {0}\n", ws.Name);
Marshal.Release ComObject(ws); // don't even know if thats allowed
here within the iterator loop
}
}
finally
{
if (ws != null) Marshal.Release ComObject(ws);
if (wb != null) Marshal.Release ComObject(wb);
if (workbooks != null) Marshal.Release ComObject(workb ooks);
if (excelApp != null)
{
excelApp.Quit() ;
Marshal.Release ComObject(excel App);
}
}
Example 2: Using a wrapper to implement dispose pattern
=============== =========
public class ComObj<T: IDisposable where T : class
{
private T _obj;
public ComObj() { _obj = null; }
public ComObj(T x) { _obj = x; }
~ComObj() { Dispose(false); }
public T Obj {
get { return _obj; }
set {
if (_obj != null) Marshal.Release ComObject(_obj) ;
_obj = value;
}
}
protected virtual void Dispose(bool disposing)
{
// clean up unmanaged resources
if (_obj != null) Marshal.Release ComObject(_obj) ;
}
void IDisposable.Dis pose()
{
Dispose(true);
GC.SuppressFina lize(this);
}
}
using (ComObj<Excel.A pplicationClass excelApp = new
ComObj<Excel.Ap plicationClass> (new Excel.Applicati onClass()))
{
excelApp.Obj.Di splayAlerts = false;
excelApp.Obj.En ableEvents = false;
// enumerate all available worsheets
using (ComObj<Excel.W orkbooksworkboo ks = new
ComObj<Excel.Wo rkbooks>(excelA pp.Obj.Workbook s))
using (ComObj<Excel.W orkbookwb = new
ComObj<Excel.Wo rkbook>(workboo ks.Obj.Open(pat h, 0, true, 5, "", "",
true, Excel.XlPlatfor m.xlWindows, "", false, false, 0,
false, false,
Excel.XlCorrupt Load.xlNormalLo ad)))
foreach (Excel.Workshee t x in wb.Sheets)
using (ComObj<Excel.W orksheetws = new
ComObj<Excel.Wo rksheet>(x))
Console.WriteLi ne("Sheet: {0}\n", ws.Obj.Name);
excelApp.Obj.Qu it();
}
Example 3: Let the finalizer of RCW free the COM objects
=============== ========
Excel.Applicati onClass excelApp = new Excel.Applicati onClass();
excelApp.Displa yAlerts = false;
excelApp.Enable Events = false;
// enumerate all available worsheets
Excel.Workbook wb = excelApp.Workbo oks.Open(path, 0, true, 5, "", "",
true, Excel.XlPlatfor m.xlWindows,
"", false, false, 0, false, false,
Excel.XlCorrupt Load.xlNormalLo ad);
foreach (Excel.Workshee t ws in wb.Sheets)
Console.WriteLi ne("Sheet: {0}\n", ws.Name);
excelApp.Quit() ;
Example 3 is the most short and readable code but I'm not sure if I
should depend on the finalizer to
clean up the unmanaged (COM) resources.
Example 1 and 2 seems the most relieable mechanism but had some big
disadvantages:
- each COM object has to be wrapped in a variable (Ex1) or wrapper
object (Ex2)
- the foreach loop is a pain in the butt
- unused return values (COM objects) had to be freed explicitly
- property chaining (aaa.bbb.ccc.dd d) is not possible, otherwise the
intermediate objects would not be released.
So what is the best/usual practice to implement COM automation?
Regards,
Martin
I have some doubts about the best practice for using COM automation,
the Runtime
Callable Wrapper (RCW) and Marshal.Release ComObject.
So the question is/are:
Do I need to release each COM object explicit by a call to
Marshal.Release ComObject, does the RCW take care of that or does it
leaks
unmanaged resources?
If I understand the docs correctly without the explicit call to
Marshal.Release ComObject the RCW objects release the COM objects in
their
finalizer. But as I read several times in this NG, it's a bad thing to
depend
on the finalizer to release unmanaged resources because the garbage
collector
runs non-deterministic so someone never knows when.
Unfortunately the RCW objects don't implement the dispose pattern so
someone
could dispose the underlying COM object deterministic. And even then,
the
codingstyle is a mess (as you'll see in my examples later).
So what is the best (or common) practice for COM automation:
Example 1: Explicit calls of Marshal.Release ComObject
=============== ===========
Excel.Applicati onClass excelApp = null;
Excel.Workbooks workbooks = null;
Excel.Workbook wb = null;
Excel.Worksheet ws = null;
try
{
excelApp = new Excel.Applicati onClass();
excelApp.Displa yAlerts = false;
excelApp.Enable Events = false;
// enumerate all available worsheets
workbooks = excelApp.Workbo oks;
wb = workbooks.Open( path, 0, true, 5, "", "", true,
Excel.XlPlatfor m.xlWindows,
"", false, false, 0, false, false,
Excel.XlCorrupt Load.xlNormalLo ad);
foreach (ws in wb.Sheets)
{
Console.WriteLi ne("Sheet: {0}\n", ws.Name);
Marshal.Release ComObject(ws); // don't even know if thats allowed
here within the iterator loop
}
}
finally
{
if (ws != null) Marshal.Release ComObject(ws);
if (wb != null) Marshal.Release ComObject(wb);
if (workbooks != null) Marshal.Release ComObject(workb ooks);
if (excelApp != null)
{
excelApp.Quit() ;
Marshal.Release ComObject(excel App);
}
}
Example 2: Using a wrapper to implement dispose pattern
=============== =========
public class ComObj<T: IDisposable where T : class
{
private T _obj;
public ComObj() { _obj = null; }
public ComObj(T x) { _obj = x; }
~ComObj() { Dispose(false); }
public T Obj {
get { return _obj; }
set {
if (_obj != null) Marshal.Release ComObject(_obj) ;
_obj = value;
}
}
protected virtual void Dispose(bool disposing)
{
// clean up unmanaged resources
if (_obj != null) Marshal.Release ComObject(_obj) ;
}
void IDisposable.Dis pose()
{
Dispose(true);
GC.SuppressFina lize(this);
}
}
using (ComObj<Excel.A pplicationClass excelApp = new
ComObj<Excel.Ap plicationClass> (new Excel.Applicati onClass()))
{
excelApp.Obj.Di splayAlerts = false;
excelApp.Obj.En ableEvents = false;
// enumerate all available worsheets
using (ComObj<Excel.W orkbooksworkboo ks = new
ComObj<Excel.Wo rkbooks>(excelA pp.Obj.Workbook s))
using (ComObj<Excel.W orkbookwb = new
ComObj<Excel.Wo rkbook>(workboo ks.Obj.Open(pat h, 0, true, 5, "", "",
true, Excel.XlPlatfor m.xlWindows, "", false, false, 0,
false, false,
Excel.XlCorrupt Load.xlNormalLo ad)))
foreach (Excel.Workshee t x in wb.Sheets)
using (ComObj<Excel.W orksheetws = new
ComObj<Excel.Wo rksheet>(x))
Console.WriteLi ne("Sheet: {0}\n", ws.Obj.Name);
excelApp.Obj.Qu it();
}
Example 3: Let the finalizer of RCW free the COM objects
=============== ========
Excel.Applicati onClass excelApp = new Excel.Applicati onClass();
excelApp.Displa yAlerts = false;
excelApp.Enable Events = false;
// enumerate all available worsheets
Excel.Workbook wb = excelApp.Workbo oks.Open(path, 0, true, 5, "", "",
true, Excel.XlPlatfor m.xlWindows,
"", false, false, 0, false, false,
Excel.XlCorrupt Load.xlNormalLo ad);
foreach (Excel.Workshee t ws in wb.Sheets)
Console.WriteLi ne("Sheet: {0}\n", ws.Name);
excelApp.Quit() ;
Example 3 is the most short and readable code but I'm not sure if I
should depend on the finalizer to
clean up the unmanaged (COM) resources.
Example 1 and 2 seems the most relieable mechanism but had some big
disadvantages:
- each COM object has to be wrapped in a variable (Ex1) or wrapper
object (Ex2)
- the foreach loop is a pain in the butt
- unused return values (COM objects) had to be freed explicitly
- property chaining (aaa.bbb.ccc.dd d) is not possible, otherwise the
intermediate objects would not be released.
So what is the best/usual practice to implement COM automation?
Regards,
Martin