MahdiSafsafi / DDetours

Delphi Detours Library
Mozilla Public License 2.0
373 stars 157 forks source link

memory exception error #29

Closed jamacoe closed 8 years ago

jamacoe commented 8 years ago

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?

MahdiSafsafi commented 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;
jamacoe commented 8 years ago

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

MahdiSafsafi commented 8 years ago

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.