1

When I run my program (code below) and insert a hard drive via a USB cable, the WindowProcedure is called for a WM_DEVICECHANGE message for device-change event type DBT_DEVICEARRIVAL.

However, GetMessage does not return. The documentation for GetMessage says GetMessage

Retrieves a message from the calling thread's message queue.

Thus, it sounds like there are no messages in the thread's message queue.

Why are there no messages in my calling thread's message queue?

If there are no messages in my calling thread's message queue, how/why is my WindowProcedure function being called for the WM_DEVICECHANGE message for device-change event type DBT_DEVICEARRIVAL?

Note: I've read some related posts and pages. This stackoverflow post seems like it might be related. If so, how do I know what messages actually get placed on the message queue?

namespace {
    LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {

        if( uMsg == WM_DEVICECHANGE )
        {
            switch(wParam)
            {
                case DBT_DEVICEARRIVAL:
                {
                    PostQuitMessage('L');
                    break;
                }

                case DBT_DEVNODES_CHANGED:
                {
                    break;
                }

            }
    }

        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

BOOL DoRegisterDeviceInterfaceToHwnd(IN GUID InterfaceClassGuid, IN HWND hWnd, OUT HDEVNOTIFY *hDeviceNotify)
{
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;

    ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    NotificationFilter.dbcc_classguid = InterfaceClassGuid;

    *hDeviceNotify = RegisterDeviceNotification( 
        hWnd,                       // events recipient
        &NotificationFilter,        // type of device
        DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES // type of recipient handle
        );

    if ( NULL == *hDeviceNotify ) 
    {
        //ErrorHandler(TEXT("RegisterDeviceNotification"));
        return FALSE;
    }

    return TRUE;
}

int processWindowsMessages()
{
    WNDCLASS windowClass = {};

    windowClass.lpfnWndProc = WindowProcedure;
    LPCSTR windowClassName = "DetecatAndMountMessageOnlyWindow";; 
    windowClass.lpszClassName = windowClassName;
    if (!RegisterClass(&windowClass)) {
        std::cout << "Failed to register window class" << std::endl;
        return 1;
    }

    HWND messageWindow = CreateWindow (windowClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0);
    //HWND messageWindow = CreateWindow (windowClassName, 0, 0, 0, 0, 0, 0, (HWND) NULL, 0, 0, 0);
    if (!messageWindow) {
        std::cout << "Failed to create message-only window" << std::endl;
        return 1;
    }
    static HDEVNOTIFY hDeviceNotify;

    DoRegisterDeviceInterfaceToHwnd(GUID_DEVINTERFACE_VOLUME, messageWindow, &hDeviceNotify);

    MSG msg;
    BOOL bRet;
    std::cout << "before loop" << std::endl;

    while ( (bRet = GetMessage (&msg, 0, 0, 0)) != 0 )
    {

        std::cout << "inside loop" << std::endl;
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg);

        }
    }
    std::cout << msg.wParam << std::endl;
    return msg.wParam;
}

int main()
{
    int result = processWindowsMessages();
    return 0;
}
Community
  • 1
  • 1
user3731622
  • 4,844
  • 8
  • 45
  • 84
  • 3
    `GetMessage` will only return messages that are posted to the message queue. Messages that are sent are dispatched inside `GetMessage` itself and the WndProc called directly. – Jonathan Potter Dec 04 '15 at 20:01
  • One clue that `WM_DEVICECHANGE` can't be posted is that `lParam` is a pointer to a structure. Only sent messages can (normally) provide pointers to memory as the memory is usually freed or re-used by the sender once the `SendMessage` call returns. – Jonathan Potter Dec 04 '15 at 20:54
  • @JonathanPotter So messages sent go directly to the WndProc and messages posted go to the message queue. However, if I only wanted to handle sent messages, I still need to call `GetMessage` because this starts the process for which sent messages get dispatched to the WndProc. Is this correct? – user3731622 Dec 04 '15 at 21:07
  • 1
    Yes you need to call something that dispatches messages in order to have them dispatched - usually `GetMessage` or `PeekMessage`. – Jonathan Potter Dec 04 '15 at 21:12

1 Answers1

1

The documentation for WM_DEVICECHANGE says:

A window receives this message through its WindowProc function.

That means this is not a queued message. It is not placed on the message queue. It is not retrieved by GetMessage.

Instead it is sent directly to the window procedure of a window. The message is broadcast to top-level windows, and sent to windows that register with RegisterDeviceNotification.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    I was going to use that quote as an example too, but then I noticed that the docs for `WM_MOUSEMOVE` say the same thing (they also say the message is posted, but in typical MSDN fashion it's not that straight-forward). – Jonathan Potter Dec 04 '15 at 20:17
  • @JonathanPotter Oh well, I guess this is something that one has to just know – David Heffernan Dec 04 '15 at 20:35
  • I'm thinking that in most cases, you don't actually need to know whether any particular message will be posted or sent anyway? At least not in order to process it. So long as you're aware that it might happen either way, it generally shouldn't matter. – Harry Johnston Dec 04 '15 at 23:58
  • @HarryJohnston Yes sounds like a bit of an XY problem to me. – Jonathan Potter Dec 05 '15 at 04:38