Jump to PiXCL Home page

 SetupDiEnumDeviceInterfaces Fails with Error 259, and a Solution

Last updated : 05-Jan-2013

If you reached this page, you've been trying to get SetupDiEnumDeviceInterfaces to work, and you're probably tearing your hair out by now.

The problem

When working with USB devices, it's often needed to identify the device path and other parameters. Various SetupDi_ API functions are called in sequence to do this.

SetupDiEnumDeviceInterfaces args appear to be correct, the Device Manager reports the device(s) as functional, but the call always fails with error 259.


Let's see if we can clarify this for you!

Suppose that we want to identify all the cameras in the Imaging Devices class, with the aim of getting the device path strings.

The usual calling sequence starts with

SetupDiGetClassDevs(...)

This gets the HDEVINFO to a list of the devices. This is where the problem starts...the GUID used (or not used) has to be correct, and the Microsoft help is particularly clear.

Include file devguid.h contains a set of GUID_DEVCLASS values. These are NOT the same as GUID_DEVINTERFACE_* values which are the one you need. GUID_DEVCLASS values are used when installing devices.

You can use the Device Manager to get the Device Class GUID for a USB device. For Imaging Device class devices, this is the same value found in devguid.h.

Look at the content of devguid.h we can see that GUIDs

GUID_DEVCLASS_IMAGE and GUID_DEVCLASS_MEDIA

are relevent to Imaging devices.

Consider this code fragment:

HDEVINFO hDevInfo;
GUID guid = GUID_DEVCLASS_IMAGE; // this would seem logical (if wrong)
SP_DEVICE_INTERFACE_DATA ifData;

hDevInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT |
DIGCF_DEVICEINTERFACE)

// hDevInfo returns a valid handle. So everything should be OK to
// enumerate the device interfaces, right?
Wrong!

BOOL bRtn = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &guid, devIndex, &ifData); 

DWORD dwError = GetLastError();

SetupDiEnumDeviceInterfaces returns FALSE and dwError = 259 ( "No more data is available" )

What's wrong?

The problem here is the GUID used in SetupDiGetClassDevs , with the DIGCF_DEVICEINTERFACE flag.

guid has to be a GUID_DEVINTERFACE value, NOT a GUID_DEVCLASS value. Looking in usbiodef.h we find GUID_DEVINTERFACE_USB_HUB, GUID_DEVINTERFACE_USB_DEVICE, and GUID_DEVINTERFACE_USB_HOST_CONTROLLER.

The correct code is


guid = GUID_DEVINTERFACE_USB_DEVICE;

hDevInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT |
DIGCF_DEVICEINTERFACE);

SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &guid, devIndex, &ifData);

which now returns TRUE and fills ifData because guid is the correct one when the DIGCF_DEVICEINTERFACE flag is used.

Locating all the devices requires a loop on SetupDiEnumDeviceInterfaces , and calling SetupDiGetDeviceInterfaceDetail internally.

e.g. repeated calls to SetupDiEnumDeviceInterfaces gets device info until an error occurs and the loop exits.

int devIndex, requiredSize;
for (devIndex = 0;SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &guid,
devIndex,&ifData);++devIndex)
{
// First we get the required buffer size
SetupDiGetDeviceInterfaceDetail(hDevInfo, &ifData, NULL, 0, &requiredSize, NULL);
detail->cbSize = > sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
SP_DEVINFO_DATA did = { sizeof (SP_DEVINFO_DATA) };
PSP_INTERFACE_DEVICE_DETAIL_DATA detail = 
            (PSP_INTERFACE_DEVICE_DETAIL_DATA) 
new BYTE[requiredSize];
if (TRUE == SetupDiGetDeviceInterfaceDetail(hDevInfo, &ifData, detail,
requiredSize, NULL, &did))
{
// detail->DevicePath ; // copy as needed.
}
}
// The last thing to do is to clean up
SetupDiDestroyDeviceInfoList(hDevInfo);

Discussion:

If you are working with HID devices, then we can call

HidD_GetHidGuid(&guid);   which returns the HID device interface class  GUID.

 hidGuid {4D1E55B2-F16F-11CF-88CB-001111000030}   found in the Registry, also see below
 testGuid {745A17A0-74D3-11D0-B6FE-00A0C90F57DA}   found in devguid.h

The first arg for SetupDiGetClassDevs is

ClassGuid
A pointer to the GUID for a device setup class or a device interface class .

The clue here (and poorly explained in the function help) is that you can use values that are mutually exclusive. If you are calling

Poking around with Regedit can be instructive too. See

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DeviceDisplayObjects and sub keys.

The returned value of hidGuid, as above, is found in

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses. In hidGuid key we find entries like

##?#HID#VID_0483&PID_5750#6&137c9d83&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} i.e. an HID device, as expected.

Let's define vidGuid for our video devices. We can search for the camera VID/PID entry, and we find

vidGuid = {65E8773D-8F56-11D0-A3B9-00A0C9223196};

with subkeys of all the video devices. Put another way, {65E8773D-8F56-11D0-A3B9-00A0C9223196} is the Windows Imaging Devices device interface class GUID.

You would think this GUID is declared in an include file, and sure enough it is. See  ksuuids.h  it's declared as

AM_KSCATEGORY_CAPTURE     here "AM" refers to "ActiveMovie", now known as DirectShow.

Add   #include <uuids.h>    to your code. ksuuids.h is included by this.

Here's a couple of helper functions for the Imaging Device class, similar to HidD_GetHidGuid(GUID*);

 

#include <uuids.h>

VOID ImgD_GetVidCapGuid (GUID *pVidGuid)
{
      *pVidGuid = AM_KSCATEGORY_CAPTURE;
}


VOID ImgD_GetVidRenderGuid (GUID *pVidGuid)
{
      *pVidGuid = AM_KSCATEGORY_RENDER;
}

 

 


Since you are here, please do have a look at our products and services.

Jump to PiXCL Home page Jump to USB Endoscope Products Jump To Smart Touch Screen FAQ

Like us on Facebook.


Copyright 2005-2013 PiXCL Automation Technologies Inc, Canada. All Rights Reserved.