0

I'm a little bit confused about how to notify my c++ application with event that the user has plugged in a device (USB, HID etc.). Application type is not defined. I'm trying to play around with console/message-only/service example apps, but there is no result. I'm using VS2015 and Windows 10.

I've found out that there are multiple ways to deal with it:

  1. Using WMI like here. But I can not actually understand where is WMI here.
  2. Using RegisterDeviceNotification and WM_DEVICECHANGE. As far as I can understand, there is no way to do that for the console applications, only for once with the GUI (real window) or for the message-only window. I've tried the last one with the example from this answer but my app doesn't receive any notifications when I plug in my USB flash drive. I've found this answer (from the same question as the answer mentioned above) and tried to use ChangeWindowMessageFilterEx() function with GetProcAddress from user32.dll to load it without connection dll to my app in such way:

    BOOL InitInstance(HWND hWnd)
    {            
        HMODULE hDll = GetModuleHandle(TEXT("user32.dll"));
        if (hDll)
        {   
            typedef BOOL(WINAPI *MESSAGEFILTERFUNCEX)(HWND hWnd, UINT message, DWORD action, VOID* pChangeFilterStruct);
            const DWORD MSGFLT_ALLOW = 1;
    
            MESSAGEFILTERFUNCEX ChangeWindowMessageFilterEx= (MESSAGEFILTERFUNCEX)::GetProcAddress(hDll, "ChangeWindowMessageFilterEx");
    
            if (ChangeWindowMessageFilterEx) return func(hWnd, WM_COPYDATA, MSGFLT_ALLOW, NULL);
    
        }
    
        return FALSE;    }
    

    And the usage of this function is:

        hWnd = CreateWindowEx(0, CLS_NAME, "DevNotifWnd", WS_ICONIC,
            0, 0, CW_USEDEFAULT, 0, HWND_MESSAGE,
            NULL, GetModuleHandle(0), (void*)&guid);
        InitInstance(hWnd);
    

    But there is no effect.

  3. Using while(true){...} loop and call appropriate Win API functions like in this answer. But this way seems not be a perfect solution for my problem.

My questions are:

  1. Could anybody explain me what is the best way? And if it is the second one with RegisterDeviceNotification, why it's not working in case of message-only window app?
  2. Do other ways exist? And if not, what can I do, for example, to notify application when some certain software was installed?

Any comments are appreciated.

Community
  • 1
  • 1
heyjohnnyfunt
  • 89
  • 2
  • 9
  • 1
    Message-only windows are a common pattern in Win32. There should be no problem with a console application creating a message-only window, except that you might want to do it on a different thread if your main thread is not event-driven. – user253751 Aug 03 '16 at 10:09
  • When you say "I tried the last one with the example from this answer" you mean you compiled and ran that example without any changes, right? – user253751 Aug 03 '16 at 10:09
  • @immibis yes, I meant that. So I should create new thread for message-only window? – heyjohnnyfunt Aug 03 '16 at 10:35
  • @heyjohnnyfunt: The core of the problem is that you have to [call `GetMessage` and `DispatchMessage`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644928(v=vs.85).aspx) repeatedly. As immibis tried to explain, you may do so from your main thread, or from another thread if that's more convenient. (I strongly recommend to call `CreateWindowEx` from the same thread as well) – MSalters Aug 03 '16 at 11:58
  • 1
    @MSalters: But I'm trying to do exactly what you say. I have the while loop with `GetMessage` from example on MSDN you provided and also use `CreateWindowEx`, but I can not see any messages in console. That means my app does not receive `WM_DEVICECHANGE` event. I've also tried to do that in another thread, but result is the same. – heyjohnnyfunt Aug 03 '16 at 12:13
  • @heyjohnnyfunt: Well, we can't guess what's wrong with that loop if you don't post it. On an unrelated note, your `WM_COPYDATA` code doesn't apply to `WM_DEVICECHANGE` (different messages). – MSalters Aug 03 '16 at 12:24
  • @MSalters as I said above, I'm playing around with code from [this answer](http://stackoverflow.com/a/18553747/3103181). The only edits I've done is that I've added a function, that I've pasted in the question, and I've changed `CreateWindow` function to `CreateWindowEx`. I can paste the whole code, if necessary. – heyjohnnyfunt Aug 03 '16 at 12:42
  • @heyjohnnyfunt Which device interface GUID do you pass to `RegisterDeviceNotification`? Keep in mind that this API notifies you about arriving device interfaces. A device interface, although also identified by a GUID, is not the same thing as a device (setup) class. One device may export multiple device interfaces but it can belong only to one device setup class. – Martin Drab Aug 03 '16 at 18:49
  • @MartinDrab I'm setting guid that way: `LPCREATESTRUCT params = (LPCREATESTRUCT) lparam; GUID InterfaceClassGuid = *((GUID*)params->lpCreateParams); ... NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; NotificationFilter.dbcc_classguid = InterfaceClassGuid; HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);` – heyjohnnyfunt Aug 04 '16 at 09:08
  • @heyjohnnyfunt Exactly what interface GUID are you actually passing to `RegisterDeviceNotification`? – Martin Drab Aug 04 '16 at 09:50
  • @MartinDrab wow, when I've tried to run code I provided yesterday, it stopped with a fault that my `*((GUID*)params->lpCreateParams` is null. So I've passed this GUID: `GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72,0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };` from [this example](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363432). As I could understand, this GUID stands for all USB devices. But what can I do if I want also register CD-ROM device changes? – heyjohnnyfunt Aug 04 '16 at 10:33
  • The device interface GUID for CD-ROM devices is `{53F56308-B6BF-11D0-94F2-00A0C91EFB8B}`. I expect you can call `RegisterDeviceNotification` again with this GUID (I hope it is possible to registe multiple notifications per windows... or you can create more message-only windows). You can also specify the `DEVICE_NOTIFY_ALL_INTERFACE_CLASSES` flag when calling `RegisterDeviceNotification` and then work only with messages reporting interfaces that interest you. – Martin Drab Aug 04 '16 at 13:04
  • @MartinDrab thank's very much! BTW, don't you know another WinAPI functions, such as `RegisterDeviceNotification`? I've been googling a lot but can not find any lists of the available notification registers that can perform similar works as RegisterDeviceNotification. – heyjohnnyfunt Aug 04 '16 at 13:36
  • If you want to monitor other types of devices, have look at https://msdn.microsoft.com/en-us/library/windows/hardware/ff553412(v=vs.85).aspx and search for GUID_DEVINTEFACE_XXX contants. It depends, what do you want to accomplish. Better monitoring options may be available for kernel drivers. – Martin Drab Aug 04 '16 at 13:47
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/120134/discussion-between-heyjohnnyfunt-and-martin-drab). – heyjohnnyfunt Aug 04 '16 at 14:26

1 Answers1

0

So I've finally found sort of answers to the questions.

  1. The issue was with the GUID I've provided for the NotificationFilter. So I've set it to receive notifications from all devices with this code: DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;

    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));

    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    // No need to set up dbcc_classguid as it is ignored when 
    // DEVICE_NOTIFY_ALL_INTERFACE_CLASSES is setted (see line down below)
    
    HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
    
  2. As far as for other types of notifications in windows that the app could sign up for, I found only one partially deprecated list of all Win32 API functions, where I found some new Notifications with Ctrl+F search :)

Hope this could save somebody's time.

heyjohnnyfunt
  • 89
  • 2
  • 9