WinAPI设备通知 - 不进入消息循环

时间:2012-09-25 12:56:39

标签: c++ winapi

我正在尝试检测何时插入USB驱动器。现在,我正在创建一个虚拟窗口并RegisterDeviceNotification。但是,我不认为我的方法是正确的,因为窗口似乎没有接收消息。

#include <iostream>
#define WINVER 0x501
#include <windows.h>
#include <dbt.h>
#include "devicehandler.h"
#include "remover.h"

DeviceHandler::DeviceHandler(Remover* remover)
{
    this->remover = remover;
    this->hWnd = this->createHandleWindow();
    this->registerDeviceHandler();
    this->messageLoop(this->hWnd);
}

DeviceHandler::~DeviceHandler()
{
    this->unregisterDeviceHandler();
}

void DeviceHandler::messageLoop(HWND hWnd)
{
    std::cerr << "Entering message loop." << std::endl; // Gets here!

    MSG msg;
    while (GetMessage(&msg, this->hWnd, 0, 0)) {
        std::cerr << "Loop!" << std::endl; // Does not get here!
        switch (msg.message) {
            case WM_DEVICECHANGE:
                {
                    PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR) msg.lParam;
                    switch(msg.wParam) {
                        case DBT_DEVICEARRIVAL:
                            std::cerr << "Device added!" << std::endl;
                            break;
                        default:
                            std::cerr << "Other device event." << std::endl;
                            break;
                    }
                    break;
                }
            default:
                break;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

HWND DeviceHandler::createHandleWindow()
{
    std::cerr << "Creating handle window... ";

    HWND hWnd = CreateWindow(NULL, NULL, WS_ICONIC, 0, 0, CW_USEDEFAULT, 0,
                             NULL, NULL, GetModuleHandle(NULL), NULL);
    ShowWindow(hWnd, SW_HIDE);

    std::cerr << "done!" << std::endl;
    return hWnd;
}

void DeviceHandler::registerDeviceHandler()
{
    std::cerr << "Device notification handling... ";
    // GUID guid = { 0xa5dcbf10, 0x6530, 0x11d2, { 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed } };
    GUID guid = { 0x25dbce51, 0x6c8f, 0x4a72, { 0x8a, 0x6d, 0xb5, 0x4c, 0x2b, 0x4f, 0xc8, 0x35 } };
    DEV_BROADCAST_DEVICEINTERFACE notificationFilter;
    ZeroMemory(&notificationFilter, sizeof(notificationFilter));
    notificationFilter.dbcc_size       = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    notificationFilter.dbcc_classguid  = guid;

    this->deviceNotifier = RegisterDeviceNotification(this->hWnd,
                                                      &notificationFilter,
                                                      DEVICE_NOTIFY_WINDOW_HANDLE);
    std::cerr << "done!" << std::endl;
}

void DeviceHandler::unregisterDeviceHandler()
{
    UnregisterDeviceNotification(this->deviceNotifier);
}

我猜这不是放置消息循环的正确位置,但我对WinAPI不太满意。如何让程序进入消息循环? (还最好注册设备通知。)

2 个答案:

答案 0 :(得分:2)

您应该创建一个message only Window。它可以接收它注册的消息,如设备通知和电源事件,但它永远不会显示。

仅留言window must be registered with RegisterClassEx

注册窗口类后,将窗口类名称与HWND_MESSAGE作为父窗口一起传递给CreateWindowEx。您的CreateWindow应该使用CreateWindowEx来代替:

HWND hWnd = CreateWindowEx(0, myClassName, _T("This is not the class name"), 
                0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, this);

您仍然会使用GetMessage以及TranslateMessageDispathMessage,这会将您的WNDPROC称为回调。没错,但是你在Windows程序中丢失了指向DeviceHandler类的指针。

这就是您将this作为CreateWindowEx的最后一个参数传递的原因。您可以在收到WM_CREATE消息时对其进行检索,并使用SetWindowLongPtrGWLP_USERDATA将其设置为您的Windows类用户数据。之后的每次调用都将使用GetWindowLongPtr检索指针并将其强制转换为DeviceHandler对象。

这是a good example of the technique

play by the rules,您应该注册自己的窗口类以使用GWLP_USERDATA,尽管它仍然可以使用STATIC窗口类。

最后注意事项:请务必致电DefWindowProc查看您未处理的邮件。

答案 1 :(得分:1)

看起来问题是您的窗口未创建,因为您没有指定有效的类名。在这种情况下返回的HWNDNULL,设备无法注册并向其发送消息。

正如在其他答案中提出的那样,您可以使用Message-Only Window来接收设备通知。但是想提一下,在这种情况下不需要注册窗口类,你可以使用预定义的类名,例如STATIC(因为您实际上不需要指定自己的窗口proc):

HWND hwnd = CreateWindowEx(0, "STATIC", 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0);