Have you ever been thinking about something and started noticing it all over the place? I find this happens when looking to buy a car. This phenomenon started happening for me lately with CoInitialize. CoInitialize has come up a dozen or more times in the last few months and then again last week, so I decided to start a little series on CoInitialize and CoUninitialize. Since this is a common source of problems for COM applications, even people who know better, I think everyone will benefit from reading this.
In this post I want to go over a bit more than just CoInitialize and CoUniniitalize, I want to show you how Delphi compiler magic can cause you problems when initializing the COM Library. Take the following program, that does just about nothing but cause an error:
program Project1;
{$APPTYPE CONSOLE}
uses SysUtils, ActiveX, XMLintf, XMLDoc;
var
Document: IXMLDocument;
begin
CoInitialize(nil);
Document := TXMLDocument.Create('foo.xml');
CoUninitialize;
end.
This very simple program, calls CoInitialize, creates a TXMLDocument and then calls CoUninitialize. The failure happens after the CoUninitialize. Do you know why?
Delphi manages the lifetime of interfaces calling IUnknown._AddRef on an interface assignment and IUnknown._Release on cleanup of the method. In this case, the COM Library has already been cleaned up when the destructor of TXMLDocument occurs. So really this very simple program, calls CoInitialize, creates a TXMLDocument, increments the reference count of IXMLDocument, calls CoUninitialize, decrements the reference count and destroys the object. We need to change the program so the call to IUnknown_Release happens before CoUninitialize. The simplest way to solve this problem is to change the program by adding a method:
program Project2;
{$APPTYPE CONSOLE}
uses SysUtils, ActiveX, XMLintf, XMLDoc;
procedure DoSomething;
var
Document: IXMLDocument;
begin
Document := TXMLDocument.Create('foo.xml');
end;
begin
CoInitialize(nil);
DoSomething;
CoUninitialize;
end.
Now this very simple program, calls CoInitialize, creates a TXMLDocument, increments the reference count of IXMLDocument, decrements the reference count and destroys the object, calls CoUninitialize.