What do I have to do to make my WH_SHELL or WH_CBT hook procedure receive events from other processes?

前端 未结 5 863
悲哀的现实
悲哀的现实 2020-12-09 19:24

I\'m trying to use SetWindowsHookEx to set up a WH_SHELL hook to get notified of system-wide HSHELL_WINDOWCREATED and HSHELL_WIN

相关标签:
5条回答
  • 2020-12-09 19:52

    Lol, it looks like the error is in the test code.

    If you create two separate buttons, one for Init and one for UnInit (I prefer Exit).

    procedure THooktest_FO.UnInitClick(Sender: TObject);
    begin
      UninitHook;
    end;
    
    procedure THooktest_FO.InitClick(Sender: TObject);
    begin
      InitHook(HookCallback)
    end;
    

    Start the app. Click Init and then The test button, the following output is shown:

    created handle #1902442
    destroyed handle #1902442
    created handle #1967978
    created handle #7276488
    

    Then the messagebox is shown.

    If you click ok you get:

    destroyed handle #1967978
    

    HTH

    0 讨论(0)
  • 2020-12-09 19:54

    The problem is that your hook DLL is actually being loaded into several different address spaces. Any time Windows detects an event in some foreign process that must be processed by your hook, it loads the hook DLL into that process (if it's not already loaded, of course).

    However, each process has its own address space. This means that the callback function pointer that you passed in InitHook() only makes sense in the context of your EXE (that's why it works for events in your app). In any other process that pointer is garbage; it may point to an invalid memory location or (worse) into some random code section. The result can either be an access violation or silent memory corruption.

    Generally, the solution is to use some sort of interprocess communication (IPC) to properly notify your EXE. The most painless way for your case would be to post a message and cram the needed info (event and HWND) into its WPARAM/LPARAM. You could either use a WM_APP+n or create one with RegisterWindowMessage(). Make sure the message is posted and not sent, to avoid any deadlocks.

    0 讨论(0)
  • 2020-12-09 19:56

    Just to clarify something that "efotinis" mentioned about posting messages back to your process - the wParam and lParam that you post to your main process can't be pointers, they can just be "numbers".

    For example, lets say you hook the WM_WINDOWPOSCHANGING message, windows passes you a pointer to a WINDOWPOS in the lparam. You can't just post that lparam back to your main process because the memory the lparam is pointing to is only valid in the process that recieves the message.

    This is what "efotinis" meant when he said " cram the needed info (event and HWND) into its WPARAM/LPARAM". If you want to pass more complex messages back your going to need to use some other IPC (like named pipes, TCP or memory mapped files).

    0 讨论(0)
  • 2020-12-09 20:07

    This might be tertiary to your question, but as you're seeing, hooks are very hard to get right - if you can avoid using this by any means, do it. You're going to run into all sorts of problems with them, especially on Vista where you'll have to deal with UIPI.

    0 讨论(0)
  • 2020-12-09 20:11

    I found the Delphi base documentation for SetWindowsHookEx. But the text is a bit vague.

    function SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; 
      hmod: HInst; dwThreadId: DWORD): HHOOK;
    
    • hmod: A handle to the module (a DLL) containing the hook function pointed to by the lpfn parameter. This parameter must be set to zero if dwThreadId identifies a thread created by the current process an dlpfn points to a hook function located in the code associated with the current process.

    • dwThreadId: The identifier of the thread to which the installed hook function will be associated. If this parameter is set to zero, the hook will be a system-wide hook that is associated with all existing threads.

    By the way, for the hmod parameter you should have used a module handle. (HINSTANCE points to the application handle).

    hand := GetModuleHandle('hookhelper.dll');
    Hook := SetWindowsHookEx(WH_SHELL, @HookProc, hand, 0);
    

    But although hand differs from HINSTANCE it still shows the same result.

    0 讨论(0)
提交回复
热议问题