0

I use a global CBT hook to recognize windows setfocus messages.
When keyboard focus changes, I want my application to notice that.

Therefore, I store the handle of my application using memory mapped files so that every process can use it for sending a message to the application after the focus changed.

I used 32-bit windows as target platform in both the hook.dll and the application.

Now, as far as I know, 32 bit processes should be hooked and 64 bit processes should be ignored. On a 32 bit system, the application works great.
When it is used it on a 64 bit windows, it also works in 32 bit processes (e.g. the delphi IDE),
but sometimes the application freezes.

for example when I start the internet explorer. I noticed that there is a 32 bit and a 64 bit iexplore.exe in the task manager when Internet Explorer is running.

Could this be the problem? I don't understand why 64 bit processes are not simply ignored... Please help!

Below is the code of the hook.dll which is called by the main application:

library Project1;

uses
  {System.SysUtils,
    System.Classes,
    sharemem,
    windows,
    messages,}
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants;

const
  WM_MYFOCUSCHANGED = WM_USER + 1;

type
  PHookRec = ^THookRec;
  THookRec = packed Record
    HookHandle: hhook;
    WindowHandle: hwnd;
  End;



var
  MapHandle: THandle;     // File Mapping Objekt
  IpHookRec: PHookRec;    // Zeiger auf Hook Record

{$R *.res}



 procedure MapFileMemory(dwAllocSize: DWORD);
begin
  {Create a process wide memory mapped variable}
  MapHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,     dwAllocSize, 'HookRecMemBlock');
  if (MapHandle = 0) then
  begin
    MessageBox(0, 'Hook DLL', 'Could not create file map object', MB_OK);
    exit;
  end;

  {Get a pointer to our process wide memory mapped variable}
  ipHookRec := MapViewOfFile(MapHandle, FILE_MAP_WRITE, 0, 0, dwAllocSize);
  if (ipHookRec = nil) then
  begin
    CloseHandle(MapHandle);
    MessageBox(0, 'Hook DLL', 'Could not map file', MB_OK);
    exit;
  end;
end;



procedure UnMapFileMemory;
begin
  {Delete our process wide memory mapped variable}
  if (ipHookRec <> nil) then
  begin
    UnMapViewOfFile(ipHookRec);
    ipHookRec := nil;
  end;
  if (MapHandle > 0) then
  begin
    CloseHandle(MapHandle);
    MapHandle := 0;
  end;
end;




function GetHookRecPointer: pointer stdcall;
begin
  {Return a pointer to our process wide memory mapped variable}
  result := ipHookRec;
end;




function FocusHookProc(code: integer; wParam: wParam; lParam: lParam):     LResult; stdcall;
begin
 if (code < 0) then
  begin
    result := CallNextHookEx(ipHookRec^.HookHandle, code, wParam, lParam);
    exit;
  end;

  result := 0;

  if (code = HCBT_SETFOCUS) then
  begin
    if (ipHookRec^.WindowHandle <> INVALID_HANDLE_VALUE) then
      PostMessage(ipHookRec^.WindowHandle, WM_MYFOCUSCHANGED, wParam,     lParam);
    // wParam: Handle to the window gaining the keyboard focus

  end;
end;



procedure InstallHook(Hwnd: Cardinal); stdcall;
begin

  if ((ipHookRec <> nil) and (ipHookRec^.HookHandle = 0) and     (ipHookRec^.WindowHandle = 0)) then
  begin
    ipHookRec^.WindowHandle := Hwnd;   // handle to the application window
    ipHookRec^.HookHandle := SetWindowsHookEx(WH_CBT, @FocusHookProc,     Hinstance, 0);
  end;
end;



procedure UninstallHook; stdcall;
begin
   if ((ipHookRec <> nil) and (ipHookRec^.HookHandle <> 0)) then
  begin
    {Remove our hook and clear our hook handle}
    if (UnHookWindowsHookEx(ipHookRec^.HookHandle) <> FALSE) then
    begin
      ipHookRec^.HookHandle := 0;
      ipHookRec^.WindowHandle := 0;
    end;
  end;
end;



procedure DllEntryPoint(dwReason: DWORD);
var
currHwnd: Hwnd;
is64: Boolean;
begin
  case dwReason of
    Dll_Process_Attach:
      begin
        {If we are getting mapped into a process, then get a pointer to our
                                process wide memory mapped variable}
        MapHandle := 0;
        ipHookRec := nil;
        MapFileMemory(sizeof(ipHookRec^));
      end;
    Dll_Process_Detach:
      begin
        {If we are getting unmapped from a process then, remove the pointer     to
                                our process wide memory mapped variable}
        UnMapFileMemory;
      end;
  end;
end;


exports
  InstallHook name 'INSTALLHOOK',
  UninstallHook name 'UNINSTALLHOOK',
  GetHookRecPointer name 'GETHOOKRECPOINTER';

begin
  DLLProc := @DllEntryPoint;         // set DLL main entry point
  DllEntryPoint(Dll_Process_Attach); // call DLL main entry point
end.
moskito-x
  • 11,832
  • 5
  • 47
  • 60
Airogat
  • 199
  • 1
  • 1
  • 10
  • 1
    You should consider using [`SetWinEventHook()`](https://msdn.microsoft.com/en-us/library/windows/desktop/dd373640.aspx) instead of `SetWindowsHookEx()`, filtering for `EVENT_OBJECT_FOCUS` events. You can also monitor 32bit and 64bit apps without needing a separate DLL (though you can also use a DLL if you want to, for performance gains). – Remy Lebeau May 06 '15 at 18:25
  • Why do you think 64bit processes are hooked? – Sertac Akyuz May 06 '15 at 20:36
  • I don't think that they are hooked, but I think it has something to do with those "mixed" 32/64 bit programs (e.g. Internet Explorer as mentioned above) that the application freezes. – Airogat May 07 '15 at 06:06
  • Inspect.exe (of the windows SDK) tells me that the application freezes when I click on the toolbar, which is a 32 bit class named "ToolBarWin32". I just noticed that when I start Internet Explorer with administrator rights the application doesn't freeze. The ToolBarWin32 now shows the entry "?? bit class" instead of "32 bit class". – Airogat May 07 '15 at 06:22
  • Remy, thanks for your advice! I used SetWinEventHook instead of SetWindowsHookEx and it works great for every process without freezing anymore! – Airogat May 07 '15 at 15:01

1 Answers1

3

Your 32 bit hook will not be loaded into a 64 bit process. This means that your problem is likely elsewhere.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490