4

I have a windowless program that handles some window management hotkeys. I'd like to provide features such as the ability to move a window between monitors. I've used EnumDisplayMonitors to enumerate all existing monitors in the system, and I've written code to handle WM_DEVICECHANGE, but I'm not actually receiving the message.

Here's my message loop:

// I've tried GetMessage(&msg, (HWND) NULL, 0, 0) here too
while (GetMessage(&msg, (HWND) -1, 0, 0) > 0)
{
    int key;
    int mod;

    MessageBox(NULL, (LPCWSTR) ((std::wostringstream&) (std::wostringstream() << L"You got a message: " << msg.message)).str().c_str(), L"Got Message", MB_OK);

    switch (msg.message)
    {
    case WM_HOTKEY:
        key = HIWORD(msg.lParam);
        mod = LOWORD(msg.lParam);

        if (mod != MOD_WIN) continue;
        ProcessHotkey(key);
        break;
    case WM_DEVICECHANGE:
        InitMonitorInfo();
    }
}

The program compiles and runs fine, and the hotkeys work. Upon adding or removing a monitor though, nothing happens. The message box to indicate a message has been received never appears.

I suppose I could just poll the monitor configuration every 5 seconds, but that's not the right way to solve the problem.

Do I need to actually create a window to receive WM_DEVICECHANGE? Because I don't. The hotkeys post their messages to NULL when they fire since they're not bound to a window, to be handled by the main thread.

Wug
  • 12,956
  • 4
  • 34
  • 54
  • 2
    Registering for device change messages: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx – Taylor Brandstetter May 30 '13 at 16:18
  • I saw that as I was looking, do I have to pass it an actual HWND or will it accept NULL and post messages to the thread? – Wug May 30 '13 at 16:23
  • 1
    It sounds like a window handle may be required. When I did this I was using a hidden window. So you'll probably have to create the window, change your message loop to "GetMessage, TranslateMessage, DispatchMessage", and then handle the WM_DEVICECHANGE in your WinProc function. – Taylor Brandstetter May 30 '13 at 16:31
  • 1
    You do need a window for this. You can use the styles `WS_EX_NOACTIVATE` and `WS_DISABLED` to create a window that isn't displayed. – Collin Dauphinee May 30 '13 at 18:12

1 Answers1

7

You must create a window to get the WM_DEVICECHANGE message.

WM_DEVICECHANGE is a message that's broadcast, SendMessage(HWND_BROADCAST,...) style. Only top-level windows can receive it. The window doesn't need to be visible so there's little reason to look for an alternative.

RegisterDeviceNotification() is an alternative. But that still needs a window. Or a service handle, but you don't want to move windows around from a service. They run in an isolated session with their own desktop. So creating a window is a hard requirement.

Wug
  • 12,956
  • 4
  • 34
  • 54
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536