-2

Basically, I want to do something after user clicks X (closes) a specific window.

This is my approach:

HWND handle;

LRESULT WINAPI procedure(int code, WPARAM wParam, LPARAM, lParam){
    CWPSTRUCT* j = (CWPSTRUCT*) lParam;
    WPSTRUCT* w = (CWPSTRUCT*) wParam;

    if(w->message == WM_SYSCOMMAND && j->message == SC_CLOSE){
        //do something
    }
}

Void doSomething(){
    HINSTANCE hDLL = LoadLibrary("User32.dll");
    HWND WINAPI FindWindow(_In_opt_ LPCTSTR lpClassName, _In_opt_ LPCTSTR lpWindowName);
    HHOOK WINAPI SetWindowsHookEx(_In_ int idHook, _In_ HOOKPROC lpfn, _In_ HINSTANCE hMod, _In_ DWORD dwThreadId);

    handle = FindWindow("Notepad", NULL) //for example
    DWORD threadId = GetWindowThreadProcessId(handle, NULL);
    HHOOK hhook = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC) &procedure, (HINSTANCE) NULL, threadId);
    return;
}

This doesn't work as the application never enters the procedure().

Edit: After a suggestion from -RbMm i found threadId from handle. Thanks.

 DWORD threadId = GetWindowThreadProcessId(handle, NULL);
 HHOOK hhook = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC) &procedure, (HINSTANCE) NULL, threadId);
Crabzmatic
  • 115
  • 9
  • 2
    `GetCurrentThreadId()` - you need set this for notepad thread but not for your thread. your thread of course never got notify about message, which wil be send to window, belong to another thread – RbMm Mar 23 '18 at 11:44
  • Are you checking the return values? Error codes? – Anders Mar 23 '18 at 13:04
  • @Anders handle is valid (according to WinSpector Spy). ThreadId is not NULL. And after inspection, application actually never enters procedure(). – Crabzmatic Mar 23 '18 at 13:14
  • Is hhook NULL or a valid handle? – Anders Mar 23 '18 at 13:23
  • 1
    Ok, taking a step back. Do you actually care if the window is closed, or are you trying to detect that the process is exiting? As in, you launch an external editor, and wait for it to close. If that's the case, don't hook. Use `RegisterWaitForSingleObject` on the process handle. (Bonus: works for x86 and x64 targets, you don't throw your code into the other process, and you only need `SYNCHRONIZE` permission to the process.) – theB Mar 23 '18 at 13:39
  • but for not current process you need dll handle, but not 0 – RbMm Mar 23 '18 at 16:04
  • 1
    I'll follow up my other comment. If you need to catch the window itself closing, then UI automation is a much safer way to accomplish this. Get the window you want to watch from the automation tree, implement the `IUIAutomationEventHandler` interface, and listen for the `UIA_Window_WindowClosedEventId` event to tell you that the window closed. Still no x86/x64 issues, and still none of your code running in the other process. – theB Mar 23 '18 at 16:14

1 Answers1

1

You must pump messages after hooking and your example does not do that.

Hook procedures for threads in other applications must be in a .DLL:

A thread-specific hook procedure is called only in the context of the associated thread. If an application installs a hook procedure for one of its own threads, the hook procedure can be in either the same module as the rest of the application's code or in a DLL. If the application installs a hook procedure for a thread of a different application, the procedure must be in a DLL.

A WH_CBT or WH_SHELL hook is probably more appropriate for what you are trying to do.

Or you could try catching EVENT_OBJECT_DESTROY with a event hook. Event hooks have explicit support for out of context hooks.

Anders
  • 97,548
  • 12
  • 110
  • 164