As far as Coinitialize and CoUninitialize would have to be counted per thread and CoUninitialize should not be called for counting as far as COM will be broken, you could use the following code for debugging.
unit CoinitCounter;
interface
uses Classes, Generics.Collections, ActiveX, SyncObjs, Windows;
Type
TCoIniRec = Record
ThreadID: Cardinal;
Init: Integer;
InvalidInit:Integer;
CoInit: Integer;
IsCoinitialized:Boolean;
End;
TCoIniList = TList<TCoIniRec>;
TCoinitCounter = Class
private
FCS: TCriticalSection;
FList: TCoIniList;
Constructor Create;
Destructor Destroy; override;
public
Function Coinitialize(p: Pointer): HRESULT;
Procedure CoUninitialize;
Function LeftInitCount: Integer;
Function ValidInits: Integer;
Function InValidInits: Integer;
Function IsCoinitialized:Boolean;
End;
var
FCoinitCounter: TCoinitCounter;
implementation
{ TCoinitCounter }
function TCoinitCounter.Coinitialize(p: Pointer): HRESULT;
var
r: TCoIniRec;
i, x: Integer;
begin
FCS.Enter;
Result := ActiveX.Coinitialize(p);
if Succeeded(Result) then
begin
x := -1;
for i := 0 to FList.Count - 1 do
if FList[i].ThreadID = GetCurrentThreadID then
x := i;
if x > -1 then
begin
r := FList[x];
r.IsCoinitialized := true;
if Result = s_OK then r.Init := r.Init + 1
else r.InvalidInit := r.InvalidInit + 1;
FList[x] := r;
end
else
begin
ZeroMemory(@r,SizeOf(r));
r.ThreadID := GetCurrentThreadID;
r.IsCoinitialized := true;
if Result = s_OK then r.Init := 1
else r.InvalidInit := 1;
FList.Add(r);
end;
end;
FCS.Leave;
end;
procedure TCoinitCounter.CoUninitialize;
var
r: TCoIniRec;
i, x: Integer;
begin
FCS.Enter;
x := -1;
ActiveX.CoUninitialize;
for i := 0 to FList.Count - 1 do
if FList[i].ThreadID = GetCurrentThreadID then
x := i;
if x > -1 then
begin
r := FList[x];
r.IsCoinitialized := false;
r.CoInit := r.CoInit + 1;
FList[x] := r;
end
else
begin
r.ThreadID := GetCurrentThreadID;
r.IsCoinitialized := false;
r.CoInit := 1;
FList.Add(r);
end;
FCS.Leave;
end;
constructor TCoinitCounter.Create;
begin
inherited;
FCS := TCriticalSection.Create;
FList := TCoIniList.Create;
end;
destructor TCoinitCounter.Destroy;
begin
FCS.Free;
FList.Free;
inherited;
end;
function TCoinitCounter.InValidInits: Integer;
var
i, x: Integer;
begin
FCS.Enter;
x := -1;
for i := 0 to FList.Count - 1 do
if FList[i].ThreadID = GetCurrentThreadID then
x := i;
if x > -1 then
Result := FList[x].InvalidInit
else
Result := 0;
FCS.Leave;
end;
function TCoinitCounter.LeftInitCount: Integer;
var
i, x: Integer;
begin
FCS.Enter;
x := -1;
for i := 0 to FList.Count - 1 do
if FList[i].ThreadID = GetCurrentThreadID then
x := i;
if x > -1 then
Result := FList[x].Init + FList[x].InvalidInit - FList[x].CoInit
else
Result := 0;
FCS.Leave;
end;
function TCoinitCounter.IsCoinitialized: Boolean;
var
i, x: Integer;
begin
FCS.Enter;
x := -1;
for i := 0 to FList.Count - 1 do
if FList[i].ThreadID = GetCurrentThreadID then
x := i;
if x > -1 then
Result := FList[x].IsCoinitialized
else
Result := false;
FCS.Leave;
end;
function TCoinitCounter.ValidInits: Integer;
var
i, x: Integer;
begin
FCS.Enter;
x := -1;
for i := 0 to FList.Count - 1 do
if FList[i].ThreadID = GetCurrentThreadID then
x := i;
if x > -1 then
Result := FList[x].Init
else
Result := 0;
FCS.Leave;
end;
initialization
FCoinitCounter := TCoinitCounter.Create;
finalization
FCoinitCounter.Free;
end.
This
ThreadID 6968 deserved: 0 counted: 0 valid: 0 invalid 0
ThreadID 2908 deserved: 4 counted: 4 valid: 1 invalid 3
ThreadID 5184 deserved: 1 counted: 1 valid: 1 invalid 0
ThreadID 7864 deserved: 8 counted: 8 valid: 1 invalid 7
ThreadID 7284 deserved: 2 counted: 2 valid: 1 invalid 1
ThreadID 6352 deserved: 5 counted: 5 valid: 1 invalid 4
ThreadID 3624 deserved: 4 counted: 4 valid: 1 invalid 3
ThreadID 5180 deserved: 0 counted: 0 valid: 0 invalid 0
ThreadID 7384 deserved: 6 counted: 6 valid: 1 invalid 5
ThreadID 6860 deserved: 9 counted: 9 valid: 1 invalid 8
would be an example output of the following unit:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
procedure DispOnTerminate(Sender: TObject);
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
uses CoinitCounter;
{$R *.dfm}
Type
TTestThread=Class(TThread)
private
FCounted,FTestCoinits:Integer;
FValidInits: Integer;
FInValidInits: Integer;
protected
Procedure Execute;override;
public
Constructor Create(cnt:Integer);overload;
Property TestCoinits:Integer read FTestCoinits;
Property Counted:Integer Read FCounted;
Property ValidInits:Integer Read FValidInits;
Property InivalidInits:Integer Read FInValidInits;
End;
{ TTestThread }
constructor TTestThread.Create(cnt: Integer);
begin
inherited Create(false);
FTestCoinits:= cnt;
end;
procedure TTestThread.Execute;
var
i:Integer;
begin
inherited;
for I := 1 to FTestCoinits do
FCoinitCounter.Coinitialize(nil);
FCounted := FCoinitCounter.LeftInitCount;
FValidInits := FCoinitCounter.ValidInits;
FInValidInits := FCoinitCounter.InValidInits;
for I := 1 to FCounted do
FCoinitCounter.CoUninitialize;
end;
procedure TForm1.DispOnTerminate(Sender: TObject);
begin
Memo1.Lines.Add(Format('ThreadID %d deserved: %d counted: %d valid: %d invalid %d'
,[TTestThread(Sender).ThreadID, TTestThread(Sender).TestCoinits,TTestThread(Sender).Counted,TTestThread(Sender).ValidInits,TTestThread(Sender).InivalidInits]));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
begin
for I := 1 to 10 do
with TTestThread.Create(Random(10)) do OnTerminate := DispOnTerminate;
end;
end.