Accessing a Devices Interface/Class GUID always causes an error

Started by
4 comments, last by gretty 11 years, 3 months ago

Hello

Using C++ and native Win32 functions, I am attempting to get the class/interface GUID of a connected device such as a TV or projector. I am using the function RegisterDeviceNotification() to give me the GUID when a TV is connected.

My Problem: When the TV is connected I can successfully be notified but when I go to access the GUID of the device(by inspecting the lParam structure) I get an access violation or error.

I cant figure out whats going wrong? Whenever I go to access or use the GUID my program fails, note my program doesn't crash but the output window writes something like First-chance exception at 0x001c1a9d in myProgram.exe... and I cant figure out whats going wrong?


HDEVNOTIFY *hDeviceNotify;
    GUID interfaceClassGuid = { 0x25dbce51, 0x6c8f, 0x4a72, 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        int wmId, wmEvent;
        PAINTSTRUCT ps;
        HDC hdc;
    
        switch (message)
        {
            case WM_CREATE:
            {                  
                 openConsoleWindow();
    
                 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, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE );
             
                 if (*hDeviceNotify == NULL)
                     printf("hDeviceNotify = NULL \n");
            }    
            break;
            case WM_DEVICECHANGE:
            {
                PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE) lParam;
                    
                // The following printf NEVER prints out.
                // When accessing the below GUID I get an error:
                // "First-chance exception at 0x001c1a9d in myProgram.exe: 0xC0000005: Access violation writing location 0x00000000."
                printf("GUID: Data1: %x, Data2: %x, Data3: %x, Data4: %s \n", b->dbcc_classguid.Data1,
                    b->dbcc_classguid.Data2, b->dbcc_classguid.Data3, (char*)b->dbcc_classguid.Data4);
                        
                // The following function ALWAYS fails.
                // GetLastError() gives the error "The parameter is incorrect"
                HDEVINFO hDevInfo = SetupDiGetClassDevs(&b->dbcc_classguid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
                if (hDevInfo == INVALID_HANDLE_VALUE) {
                     //printf("hDevInfo == INVALID_HANDLE_VALUE \n");
                   outputLastError(_T("hDevInfo == INVALID_HANDLE_VALUE \n"));
                }
    
            }
            break;
            ...

Advertisement

Have you checked wparam? If it's something like DBT_DEVICEREMOVECOMPLETE, you're probably casting lParam to the wrong type in the first place.

In general, it's my understanding that you should always first cast lparam to a DEV_BROADCAST_HDR* and only cast to something further once you have confirmed the value of its dbch_devicetype.

Thanks for the reply

For my TV, the wParam value is always DBT_DEVNODES_CHANGED, even when I connect and remove the device(instead of having DBT_DEVICEARRIVAL/DBT_DEVICEREMOVE sent).

The following code takes your advice into account but it reproduces the same errors(exception and same GetLastError() value):


        case WM_DEVICECHANGE:
        {
            if (wParam != DBT_DEVNODES_CHANGED) {
                printf("1: \n");
                break;
            }

            PDEV_BROADCAST_HDR h = (PDEV_BROADCAST_HDR) lParam;
            if (h->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) {
                printf("2\n");
                break;
            }

            PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE) h;
                
            // When accessing the below GUID I get an error:
            // "First-chance exception at 0x001c1a9d in TEST GUID Error.exe: 0xC0000005: Access violation writing location 0x00000000."
            printf("GUID: Data1: %x, Data2: %x, Data3: %x, Data4: %s \n", b->dbcc_classguid.Data1,
                b->dbcc_classguid.Data2, b->dbcc_classguid.Data3, b->dbcc_classguid.Data4);
                    
            // The following function ALWAYS fails.
            // GetLastError() gives the error "The parameter is incorrect"
            HDEVINFO hDevInfo = SetupDiGetClassDevs(&b->dbcc_classguid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
            if (hDevInfo == INVALID_HANDLE_VALUE) {
                 //printf("hDevInfo == INVALID_HANDLE_VALUE \n");
               outputLastError(_T("hDevInfo == INVALID_HANDLE_VALUE \n"));
            }

        }
        break;

MSDN says that lParam is 0 when wParam is DBT_DEVNODES_CHANGED (which IMHO, you should really assert on anyway). So your code behaves as expected -- undefined behaviour.

It appears you have copied the GUID passed to RegisterDeviceNotification from the MSDN example code. I don't know much about Windows' device handling but I have a strong suspicion that this GUID is not the one you should be using.

Have you tried adding DEVICE_NOTIFY_ALL_INTERFACE_CLASSES to the flags in your call to RegisterDeviceNotification()? In this case the GUID is ignored and you get messages for all devices. This may give you a better indication of what's really happening and help you detect your TV.

Just out of curiosity, are you attempting to detect your telly to automatically enable some kind of out-of-band debug console for a game? That would be cool :)

I'll try adding DEVICE_NOTIFY_ALL_INTERFACE_CLASSES and see what messages I receive.

Just out of curiosity, are you attempting to detect your telly to automatically enable some kind of out-of-band debug console for a game? That would be cool smile.png

Nah, the ultimate goal is so when I connect my laptop to the TV it will open my folder that contains all my TV shows and start playing the video file I was playing when I last disconnected from the TV(maybe even at the same position/time in the file). I'm moving into a new unit and I'm too cheap to pay for Foxtel(cable TV) :P so I want this application to let me play tv shows off my laptop :)

The code above is the first step:

- Detect a device arrival - get the class/interface GUID of the device

- Determine if the connect device is a TV (I have no idea how I'll do this but I suspect using a SetupDi..() function which is why I need the GUID)

- If the device is a TV:

- Open the tv show folder

- Start playing the video file I was playing when I last disconnected from the TV

Thanks Edd :)

Adding that flag worked. Now I receive DBT_DEVICEARRIVAL message upon connection and the GUID is inside the structure also.

This topic is closed to new replies.

Advertisement