Closed jamacoe closed 8 years ago
Hi, This not a bug related to the DDL! Your function arguments aren't declared as the original method. InterceptMethod and TrampolineMethod must have the same arguments as the hooked method. Here is a simple example to hook DrawTextW:
implementation
uses DDetours;
{$R *.dfm}
var
TrampolineDrawTextW: function(hDC: hDC; lpString: LPCWSTR; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer;
stdcall = nil;
function InterceptDrawTextW(hDC: hDC; lpString: LPCWSTR; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall;
begin
Result := TrampolineDrawTextW(hDC, lpString, nCount, lpRect, uFormat);
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
if not Assigned(TrampolineDrawTextW) then
begin
@TrampolineDrawTextW := InterceptCreate(@DrawTextW, @InterceptDrawTextW);
end;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
var
lpRect: TRect;
begin
lpRect := Rect((Screen.width - 1) shr 1, 0, Screen.width - 1, Screen.height - 1);
DrawTextW(GetDC(0), 'Test Text', 9, lpRect, $00000900);
end;
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
if Assigned(TrampolineDrawTextW) then
begin
InterceptRemove(@TrampolineDrawTextW);
TrampolineDrawTextW := nil;
end;
end;
Thank you so much, now it works and I'd never have figured this out myself. The MSDN definition is
int DrawText( In HDC hDC, Inout LPCTSTR lpchText, In int nCount, Inout LPRECT lpRect, In UINT uFormat );
so the bug was that I had to make the lpRect parameter a variable, because it is Inout. But what about lpchText, shouldn't it be 'var' as well, and of type LPCTSTR? So now I have a working code with these function parameters: hDC: HDC; var lpchText: LPCTSTR; nCount: Integer; var lpRect: TRect; uFormat: UINT
Always refer to to Delphi implementation... Most WinApi functions are already defined. For example you can find DrawTextW in "Winapi.Windows.pas" unit. I strongly recommend to use definition declared by Delphi itself rather than using MSDN definition.
I altered the code of the demo project DetoursDemo\win32api\Demo1 to intercept a different function (DrawTextW). This is what I did:
var TrampolineDrawTextW: function(hDCx: HDC; lpchText: LPCTSTR; nCount: Integer; lpRect: TRect; uFormat: UINT): Integer; stdcall = nil;
function InterceptDrawTextW(hDCx: HDC; lpchText: LPCTSTR; nCount: Integer; lpRect: TRect; uFormat: UINT): Integer; stdcall; begin Result := TrampolineDrawTextW(hDCx, lpchText, nCount, lpRect, uFormat); end;
procedure TMain.BtnHookClick(Sender: TObject); begin if not Assigned(TrampolineDrawTextW) then begin @TrampolineDrawTextW := InterceptCreate(@DrawTextW, @InterceptDrawTextW); end; end;
procedure TMain.BtnTestMsgBoxClick(Sender: TObject); var lpRect: TRect; begin lpRect := Rect((Screen.width-1) shr 1,0,Screen.width-1,Screen.height-1); DrawTextW(GetDC(0),'Test Text', 9, lpRect, $00000900); end;
(Works unhooked)
procedure TMain.BtnUnHookClick(Sender: TObject); begin if Assigned(TrampolineDrawTextW) then begin InterceptRemove(@TrampolineDrawTextW); TrampolineDrawTextW := nil; end;
This works unhooked with the desired output. After hooking, the DrawTextW function is also being called from the trampoline function, so the detour works. But then, the program aborts with a memory exception error. Is it a library error, or what's wrong?