Pavel Vlasov
Pavel Vlasov

Reputation: 4331

Why PostMessage has no effect when called from within a global hotkey handler?

A GUI app I'm writing does send a keydown event to another window, a cmd.exe.

PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);

The event is sent just fine when it's done on events like WM_CREATE, WM_KEYUP, etc (a new line appears in cmd.exe).

Then I setup a global hotkey with RegisterHotKey. In a WM_HOTKEY handler I successfully receive key presses but PostMessage has no effect anymore.

How to fix that?

Full example, minified as possible:

#include <iostream>
#include <Windows.h>

using namespace std;

const char g_szClassName[] = "myWindowClass";

BOOL CALLBACK enumWindows(HWND hwnd, LPARAM lParam) {
    char winTitle[1024*10];
    GetWindowText(hwnd, winTitle, sizeof(winTitle));
    if (strstr(winTitle, "cmd.exe") != NULL) {
        cout << "Sending a message to window " << hwnd << ": " << winTitle << endl;
        PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
    }
    return TRUE;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg) {
        case WM_CREATE:
            // register hotkey ctrl+alt+s
            RegisterHotKey(hwnd, 100, MOD_ALT | MOD_CONTROL, 'S');
            break;
        case WM_CLOSE:
            DestroyWindow(hwnd);
            break;
        case WM_DESTROY:
            EnumWindows(enumWindows, 0);
            PostQuitMessage(0);
            break;
        case WM_HOTKEY:
            // hotkey ctrl+alt+s fired
            EnumWindows(enumWindows, 0);
            break;
        case WM_KEYUP:
            EnumWindows(enumWindows, 0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

// just init stuff, do not waste your time
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassEx(&wc);
    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "Test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&Msg, NULL, 0, 0) > 0) {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

Windows 7 64-bit

Upvotes: 0

Views: 196

Answers (1)

Ben Voigt
Ben Voigt

Reputation: 283614

Raymond Chen has documented why this doesn't work the way you expect (PostMessage IS working just fine, but the response of the other window depends on actual keyboard state, just as I surmised in my comment). See his blog post:

Upvotes: 5

Related Questions