Using a Message-Only Window to Receive Device Change Notification Messages

I'm trying to get write a message-only window to receive device change notification messages for a USB device. I am using MFC, C++, and Visual Studio 2008. Everything compiles, and it runs without crashing or locking up, but the event handler is never triggered. The device of interest is installed on Windows as a virtual COM port.

My main application instantiates the class described below then waits for a character input from the keyboard polling using a while loop. It is during this wait time that I remove and insert my USB device expecting the event to get fired.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CMessageOnlyWindow : public CWnd
{
    DECLARE_DYNAMIC(CMessageOnlyWindow)
private:
    DEV_BROADCAST_DEVICEINTERFACE * _pDevIF; // The notification filter.
    HDEVNOTIFY _hNotifyDev;             // The device notification handle.
public:
    CMessageOnlyWindow();
    virtual ~CMessageOnlyWindow();
protected:
    afx_msg BOOL OnDeviceChange( UINT nEventType, DWORD dwData );
private:
    void RegisterNotification( void );
    void UnregisterNotification( void );
protected:
    DECLARE_MESSAGE_MAP()               // Must be last.
};


For simplicity, I've removed all the cleanup and error-handling:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
DEFINE_GUID(GUID_INTERFACE_CP210x, 0x993f7832, 0x6e2d, 0x4a0f, \
    0xb2, 0x72, 0xe2, 0xc7, 0x8e, 0x74, 0xf9, 0x3e);

IMPLEMENT_DYNAMIC(CMessageOnlyWindow, CWnd)

CMessageOnlyWindow::CMessageOnlyWindow()
{
    CString cstrWndClassName = ::AfxRegisterWndClass( NULL );
    BOOL bCreated = this->CreateEx( 0, cstrWndClassName,
        L"CMessageOnlyWindow", 0, 0, 0, 0, 0, HWND_MESSAGE, 0 );
    this->RegisterNotification();
}

CMessageOnlyWindow::~CMessageOnlyWindow() {}

BEGIN_MESSAGE_MAP(CMessageOnlyWindow, CWnd)
    ON_WM_DEVICECHANGE()
END_MESSAGE_MAP()

afx_msg BOOL CMessageOnlyWindow::OnDeviceChange( UINT nEventType, DWORD dwData )
{
    switch ( nEventType ) // <-- Never gets here.
    {
    case DBT_DEVICEARRIVAL:
        break;

    case DBT_DEVICEREMOVECOMPLETE:
        break;

    default:
        break;
    }

    return TRUE;
}

void CMessageOnlyWindow::RegisterNotification(void)
{
    _pDevIF = (DEV_BROADCAST_DEVICEINTERFACE *)malloc( sizeof(DEV_BROADCAST_DEVICEINTERFACE) );
    memset( _pDevIF, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE) );
    _pDevIF->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    _pDevIF->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    _pDevIF->dbcc_classguid = GUID_INTERFACE_CP210x;
    _hNotifyDev = RegisterDeviceNotification( this->m_hWnd, _pDevIF, DEVICE_NOTIFY_WINDOW_HANDLE );
}

void CMessageOnlyWindow::UnregisterNotification(void)
{
    UnregisterDeviceNotification( _hNotifyDev );
}


Any thoughts or suggestions would be much appreciated. If any details are missing, let me know, and I will be glad to add them. Thanks.

Does the message-only window need to be started in a new thread, or does creating a new window automatically spin off a new thread?
Last edited on
I don't know what a message-only window is.

You need to handle WM_DEVICECHANGE.
http://msdn.microsoft.com/en-us/library/aa363208%28VS.85%29.aspx
@kbw: A message-only window is just used for sending and receiving Windows messages. This may interest you:

http://www.codeproject.com/KB/dialog/messageonly.aspx

I have a message-only window because my MFC DLL has no window associated with it. I have found that dhanging the type of recipient handle passed to `RegisterDeviceNotification` to `DEVICE_NOTIFY_ALL_INTERFACE_CLASSES` caused it to start working. Do you know why that would make a difference, or are there any problems, if I leave it like this?
Interesting.

Here's a quote from that link.
A message-only window enables you to send and receive messages. It is not visible, has no z-order, cannot be enumerated, and does not receive broadcast messages.

I believe you're trying to intercept a broadcast message.
I think that may explain it. Tell me if this sounds reasonable to you:

My message-only window was not able to receive messages pertaining to my USB device because RegisterDeviceNotification was called with a DEV_BROADCAST_DEVICEINTERFACE using a DEVICE_NOTIFY_WINDOW_HANDLE type of recipient handle. Because message-only windows cannot receive broadcast messages, it did not receive the WM_DEVICECHANGE message (handled in the MESSAGE_MAP). Changing the type of receipt handle to DEVICE_NOTIFY_ALL_INTERFACE_CLASSES somehow overrides this.

Does that sound reasonable, or do you think I'm overstretching it a bit.
I can't comment on your suggestion, but you could just use a hidden Window as that would avoid all the technical restrictions of this message-only Window thing. Afterall, that's what the old school DDE/OLE servers used to do.
Topic archived. No new replies allowed.