至于 Coinitialize 和 CoUninitialize 必须按线程计数,并且不应调用 CoUninitialize 进行计数,因为 COM 将被破坏,您可以使用以下代码进行调试。
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.
这
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
将是以下单元的示例输出:
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.