Tachyon
Tachyon

Reputation: 2411

Getting notification when active window changes

I am trying to get my program to get the current active window title when the focus is changed. I have the following CALLBACK:

LRESULT CALLBACK windowChangeHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (wParam == HCBT_SETFOCUS || lParam == HCBT_SETFOCUS)
        cout << GetActiveWindowTitle();

    return(CallNextHookEx(NULL, nCode, wParam, lParam));
}

And I am trying to hook WH_CBT as follows:

HHOOK hhkWindowChange = SetWindowsHookEx(WH_CBT, windowChangeHook, 0, 0);

Maybe I am just stupid but it isn't working as intended, anyone have an idea why?

EDIT: It doesn't seem like the program is detecting the window changes at all, I have tried changing the code to this to no avail:

LRESULT CALLBACK windowChangeHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HCBT_ACTIVATE || nCode == HCBT_SETFOCUS)
        cout << "TEST";

    return(CallNextHookEx(NULL, nCode, wParam, lParam));
}

Upvotes: 0

Views: 2549

Answers (2)

Anders
Anders

Reputation: 101764

  • You are not checking the return value from SetWindowsHookEx!

  • windowChangeHook needs to be in a DLL with its HMODULE in the hMod parameter.

  • The HCBT_* values are passed in the nCode parameter!

You could also try using SetWinEventHook instead...

Upvotes: 3

Remy Lebeau
Remy Lebeau

Reputation: 598289

You are not handling the WH_CBT callback correctly.

Per the CBTProc callback function documentation:

nCode [in]
Type: int

The code that the hook procedure uses to determine how to process the message. If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx. This parameter can be one of the following values.

...

HCBT_SETFOCUS
9
A window is about to receive the keyboard focus.

wParam [in]
Type: WPARAM

Depends on the nCode parameter. For details, see the following Remarks section.

lParam [in]
Type: LPARAM

Depends on the nCode parameter. For details, see the following Remarks section.

The following table describes the wParam and lParam parameters for each HCBT_ hook code.

...

HCBT_SETFOCUS
wParam: Specifies the handle to the window gaining the keyboard focus.
lParam: Specifies the handle to the window losing the keyboard focus.

You are looking for the HCBT_SETFOCUS value in the wrong parameter. You are also retrieving the title of the wrong window, since the input focus has not actually switched windows yet.

Your callback should look more like this instead (assuming your callback is implemented in a DLL, which is required to detect global events, which also means you need separate 32bit and 64bit DLLs on a 64bit system. This is explained in the SetWindowsHookEx() documentation):

LRESULT CALLBACK windowChangeHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HCBT_SETFOCUS)
    {
        HWND hwnd = (HWND) wParam;
        // retreive and use the title of hwnd as needed...
    }

    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

That being said, you should consider using SetWinEventHook() instead, which does not have the DLL requirement if you use the hook "out-of-context":

The callback function is not mapped into the address space of the process that generates the event. Because the hook function is called across process boundaries, the system must queue events. Although this method is asynchronous, events are guaranteed to be in sequential order. For more information, see Out-of-Context Hook Functions.

EVENT_OBJECT_FOCUS
0x8005

An object has received the keyboard focus. The system sends this event for the following user interface elements: list-view control, menu bar, pop-up menu, switch window, tab control, tree view control, and window object. Server applications send this event for their accessible objects.

The hwnd parameter of the WinEventProc callback function identifies the window that receives the keyboard focus.

For example:

void CALLBACK windowChangeHook(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
    // retreive and use the title of hwnd as needed...
}

HWINEVENTHOOK hEventHook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, NULL, &windowChangeHook, 0, 0, WINEVENT_OUTOFCONTEXT);
...
UnhookWinEvent(hEventHook);

Upvotes: 0

Related Questions