Link to home
Start Free TrialLog in
Avatar of yehiaeg
yehiaegFlag for Egypt

asked on

WH_CBT Strange Behavior

Hello,

I'm trying to use WH_CBT hooking to get a list of any activated process, however while testing i only get several HCBT_CLICKSKIPPED message codes at first and that's its, i don't receive any other messages which i am interested in like HCBT_CREATEWND or HCBT_ACTIVATE

Here is my full implementation:
//*****************************************************************************************
library HookLib;

uses
  SysUtils, Classes, Windows;

  type
  TClientCallBack = procedure(Code,wParam : integer) of object;


  var fHookhandle: THandle;
      clientFunction : TClientCallBack;

{$R *.res}

function callbackFunction(Code, wParam, lParam: Integer): Integer; stdcall;
begin
  OutputDebugString(PChar('code from dll' + InttoStr(Code))); // always prints 6 (HCBT_CLICKSKIPPED)
      if (Code < 0) then begin
     result := CallNextHookEx(fHookhandle, Code, wParam, lParam);
     exit;
  end;

  clientFunction(Code,wParam); //Calls client callback function

      result := CallNextHookEx(fHookhandle, Code, wParam, lParam);

end;


function InstallCBTHook(ClientCallBackFunction: TClientCallBack):boolean; stdcall;
begin

  clientfunction := ClientCallBackFunction;
      fHookhandle := SetWindowsHookEx(WH_CBT, @callbackFunction, hInstance, 0);
      if fHookhandle > 0 then result := true else result := false;

end;

procedure UninstallCBTHook();stdcall;
begin
      UnhookWindowsHookEx(fHookhandle);

end;


exports
   InstallCBTHook, UninstallCBTHook;

begin
end.
//*************************************************************************
Avatar of yehiaeg
yehiaeg
Flag of Egypt image

ASKER

ahh this behavior was on Windows XP, i just tested the executable on Windows Vista and it caused explorer.exe to crash instantaneously, so obviously something is going wrong
>> clientfunction := ClientCallBackFunction;
You're setting this value only in 1 process (in that one which sets the hook). This .dll is then loaded into other processes, which have  their own memory space - value of clientfunction is not ClientCallBackFunction in their memory.
You may test it by setting default value of variable when defining it (var test : integer = 0;), changing it's value in InstallCBTHook and then doing something like "if test = 0 then MessageBeep(0);" in callback function. You'll probably hear beeps, which mean that "test" variable has default value, although it's changed in InstallCBTHook.

I'm not sure what's the best way to solve this though. Could be solved by using memory mapped files (I haven't done that yet) or sending messages with SendMessage() to comunicate with main application.
function callbackFunction( Code : Integer; WParam : wParam; LParam : lParam ): LResult; stdcall;
begin
  if Code >= 0 then
    begin
      OutputDebugString( PChar( 'code from dll ' + IntToStr( Code ) ) );
      clientFunction( Code, WParam );
    end;
  result := CallNextHookEx( fHookhandle, Code, wParam, lParam );
end;
ASKER CERTIFIED SOLUTION
Avatar of arioh
arioh
Flag of Russian Federation image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of yehiaeg

ASKER

ok i followed what you were saying. ZhaawZ about using the memory mapped file, and arioh about the new function, however i still have the same behavior, several HCBT_CLICKSKIPPED messages and that's it:

library HookLib;

uses
  SysUtils, Classes, Windows;

  type
  //TClientCallBack = procedure(Code,wParam : integer) of object;

  PSharedRecord = ^TSharedRecord;
  TSharedRecord = record
      fHookhandle: THandle;
      clientHwnd : HWND;
      fInstallProcess: DWORD;
  end;

  var fMemoryFile: THandle = 0;
      sharedRec: PSharedRecord = nil;
      uiMyMsg: UINT = 0;
{$R *.res}

function callbackFunction(Code, wParam, lParam: Integer): Integer; stdcall;
begin

      if Code >= 0 then begin
      OutputDebugString(PChar('code from dll' + InttoStr(Code)));
      if sharedRec <> nil then begin
         PostMessage(sharedRec^.clientHwnd, uiMyMsg, Code, wParam);

      end;
  end;
      result := CallNextHookEx(sharedRec^.fHookhandle, Code, wParam, lParam);
     
end;


function InstallCBTHook(clientHwnd : HWND): boolean ; stdcall;
begin

 result := false;
  fMemoryFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE,0,                   // size: high 32-bits
                SizeOf(TSharedRecord), 'auniquename');

      if (fMemoryFile <> 0 ) then begin
    sharedRec := MapViewOfFile(fMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    if sharedRec <> nil then begin
        sharedRec^.clientHwnd := clientHwnd ;
        sharedRec^.fInstallProcess := GetCurrentProcessId;
             sharedRec^.fHookhandle := SetWindowsHookEx(WH_CBT, @callbackFunction, hInstance, 0);

        result := true ;
    end;
  end
  else  result := false;


end;

procedure UninstallCBTHook();stdcall;
begin
  if assigned(sharedRec) then begin
    if sharedRec^.fInstallProcess = GetCurrentProcessId then begin
      UnhookWindowsHookEx(sharedRec^.fHookhandle);
      sharedRec^.fHookhandle := 0;
      sharedRec^.clientHwnd := 0;
      sharedRec^.fInstallProcess := 0;
    end;
    UnmapViewOfFile(sharedRec);
    sharedRec := nil;
  end;
  if (fMemoryFile <> 0 ) then begin
     CloseHandle(fMemoryFile);
     fMemoryFile := 0;
  end;

end;

procedure DllEntry(dwReason : DWORD);
begin
  if (dwReason = Dll_Process_Attach) then begin
      uiMyMsg := RegisterWindowMessage('auniquemsgname');

       if uiMyMsg <> 0 then begin
          fMemoryFile := OpenFileMapping(FILE_MAP_WRITE, False, 'auniquemsgname');
          sharedRec := MapViewOfFile(fMemoryFile, FILE_MAP_READ, 0, 0, 0);
           if sharedRec = nil then UninstallCBTHook();

      end;
  end
  else if (dwReason = Dll_Process_Detach) then begin
      UninstallCBTHook();
   end;
end;

exports
   InstallCBTHook, UninstallCBTHook, callbackFunction;

begin
  DisableThreadLibraryCalls(hInstance);
  DllProc := @DLLEntry;
  DllEntry(DLL_PROCESS_ATTACH);

end.
Forced accept.

Computer101
EE Admin