我正在对一个凌乱的项目进行一些调试,这个项目是我以前的开发人员不知道他们在做什么的,而主要问题是尝试多线程应用程序失败.我现在正在清理乱七八糟的东西,试图找出出错的地方.其中一个问题是CoInitialize为了使用ADO组件而不一致的调用.
继续我之前的问题,我怎样才能确定CoInitialize调用了多少级别?
例如,考虑以下代码:
CoInitialize(nil);
try
CoInitialize(nil);
try
//2 levels have been called, how to programatically check this?
finally
CoUninitialize;
end;
finally
CoUninitialize;
end;
Run Code Online (Sandbox Code Playgroud)
Dav*_*nan 10
如果让我来解决这个问题,我想通过插于电话解决它CoInitialize,CoInitializeEx和CoUninitialize.我会挂钩对这些函数的调用,并使用线程局部变量来计算调用.
您可以通过将以下单元添加到项目中来完成此操作.
unit InstrumentCOMinit;
interface
uses
SysUtils, Windows, ComObj, ActiveX;
threadvar
COMinitCount: Integer;
implementation
function CoInitialize(pvReserved: Pointer): HResult; stdcall; external 'ole32.dll';
function CoInitializeEx(pvReserved: Pointer; coInit: Longint): HResult; stdcall; external 'ole32.dll';
procedure CoUninitialize; stdcall; external 'ole32.dll';
function InstrumentedCoInitialize(pvReserved: Pointer): HResult; stdcall;
begin
Result := CoInitialize(pvReserved);
if Succeeded(Result) then
inc(COMinitCount);
end;
function InstrumentedCoInitializeEx(pvReserved: Pointer; coInit: Longint): HResult; stdcall;
begin
Result := CoInitializeEx(pvReserved, coInit);
if Succeeded(Result) then
inc(COMinitCount);
end;
procedure InstrumentedCoUninitialize; stdcall;
begin
CoUninitialize;
dec(COMinitCount);
end;
procedure Fail;
begin
raise EAssertionFailed.Create('Fixup failed.');
end;
procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
OldProtect: DWORD;
begin
if not VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then begin
Fail;
end;
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, nil, 0);
if not VirtualProtect(Address, Size, OldProtect, @OldProtect) then begin
Fail;
end;
end;
type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;
procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;//jump relative
NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;
initialization
RedirectProcedure(@ActiveX.CoInitialize, @InstrumentedCoInitialize);
RedirectProcedure(@ActiveX.CoInitializeEx, @InstrumentedCoInitializeEx);
RedirectProcedure(@ActiveX.CoUninitialize, @InstrumentedCoUninitialize);
ComObj.CoInitializeEx := InstrumentedCoInitializeEx;
end.
Run Code Online (Sandbox Code Playgroud)
与Serg的方法不同,这种技术不会改变程序的语义.
你可以这样做:
function CoInitializeCount: Integer;
var
HR: HResult;
I: Integer;
begin
Result:= 0;
repeat
HR:= CoInitialize(nil);
if (HR and $80000000 <> 0) then begin
Result:= -1;
Exit;
end;
CoUnInitialize;
if (HR <> S_OK) then begin
CoUnInitialize;
Inc(Result);
end
else Break;
until False;
for I:= 0 to Result - 1 do
CoInitialize(nil);
end;
Run Code Online (Sandbox Code Playgroud)
警告!由于上面的函数关闭COM,它不能在COM应用程序中使用,只能在调试时回答特定问题.
| 归档时间: |
|
| 查看次数: |
1551 次 |
| 最近记录: |