What's in a GUID?

Can someone please explain to me in simple English how Windows handles device interface GUIDs? When I look through the WDK header files, I see lots of stuff about DEVINTERFACE_DISK, but nothing at all about DEVINTERFACE_SOUND (or Audio, or Media, or…). Hm… the list in guiddef.h seems to be incomplete! Hm…

Here’s what I’m trying to do: I wrote an WaveCyclic miniport driver, it works fine, and it creates an unnamed device that successfully shows up in the Device Manager and in the Windows Media Player list of streamable devices. It even streams audio. Hooray.

But now, I want to send an IOCTL into it. I need to command it to do something specific that isn’t an ordinary audio function. It’s a “device specific control”, so to speak.

I started from the MSVAD sample in the WDK, and used the .inf file that came with that example. I have this audio device (call it “msvad”, but it’s actually unnamed), and it shows up in all the right places, and it actually streams audio. When I look in the registry I see that it has an interface, and it’s the right one that I specified in the .inf file.

HOWEVER… the SetupDiGetClassDevs() function only works with the class GUID, not the interface GUID. When I enumerate the members of the device class I get the correct list, but when I set the DIGCF_DEVICEINTERFACE and pass in the device interface GUID, it returns an empty information set.

When I then use DIGCF_ALLCLASSES I get the expected big huge list of everything on the system, but if I attempt to restrict that list with a DEVINFO_DATA structure I got from SetupDiEnumDeviceInfo, it doesn’t work (error 259, end of list).

So, you’re probably thinking there’s something wrong with my device interface GUID, right?

Nope… in fact, if I use one of the canned device interface classes GUID_DEVINTERFACE_DISK, I get an empty information set too.

Can someone tell me what might be going on here? My code is about as vanilla as it gets, here’s an example:

HDEVINFO deviceInfoSet;
int memberIndex = 0;
SP_DEVICE_INTERFACE_DATA MyDeviceInterfaceData;
SP_DEVINFO_DATA MyDeviceInfo;

//
// look for all audio devices that are actually present on the system
// (search by device class, not interface class)
//

deviceInfoSet = SetupDiGetClassDevs(pGuid, NULL, NULL, DIGCF_PRESENT);
if(deviceInfoSet == INVALID_HANDLE_VALUE)
{
printf(“invalid handle\n”);
return -1;
}

do
{
MyDeviceInterfaceData.cbSize = sizeof(MyDeviceInterfaceData);

success = SetupDiEnumDeviceInterfaces
(deviceInfoSet,
NULL /* &MyDeviceInfo */,
&requestedInterfaceGuid,
memberIndex,
&MyDeviceInterfaceData);

// Find out if interface data was retrieved.
if (!success)
{
// FAILS HERE - Windows says there are no devices
// exporting my interface, even though they’re
// actually present on the system
lastError = GetLastError();
// …
return -2;
}
else
{
// A device is present.
success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
&MyDeviceInterfaceData,
NULL,
0,
&bufferSize,
NULL);
if (!success)
{
lastError = GetLastError();
// …
return -3;
}

// Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size.
detailDataBuffer = (SP_DEVICE_INTERFACE_DATA *) GlobalAlloc(GPTR, bufferSize);

// Store cbSize in the first 4 bytes of the array
detailDataBuffer->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

// Call SetupDiGetDeviceInterfaceDetail again.
// This time, pass a pointer to DetailDataBuffer
// and the returned required buffer size.
success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
&MyDeviceInterfaceData,
detailDataBuffer,
bufferSize,
(DWORD *) &bufferSize,
NULL);
if (!success)
{
lastError = GetLastError();
// …
return -4;
}

// Skip over cbsize (4 bytes) to get the address of the devicePathName.
pDevicePathName = ((char *) detailDataBuffer) + 4; // sizeof(long) on XP

// Get the String containing the devicePathName
printf(“found: device path name = %s\n”, pDevicePathName);

// Free the memory allocated previously by AllocHGlobal.
GlobalFree(detailDataBuffer);
deviceFound = 1;
break;
}

memberIndex = memberIndex + 1;
}
while (!(lastDevice));

SetupDiDestroyDeviceInfoList(deviceInfoSet);

wrote in message news:xxxxx@ntdev…

> HOWEVER… the SetupDiGetClassDevs() function only works with the class
> GUID, not the interface GUID. When I enumerate the members of the device
> class I get the correct list, but when I set the DIGCF_DEVICEINTERFACE and
> pass in the device interface GUID, it returns an empty information set.
>

SetupDiGetClassDevs() with DIGCF_DEVICEINTERFACE definitely works,
so you do something wrong…

> So, you’re probably thinking there’s something wrong with my device
> interface GUID, right?
>
> Nope… in fact, if I use one of the canned device interface classes
> GUID_DEVINTERFACE_DISK, I get an empty information set too.
>
> Can someone tell me what might be going on here? My code is about as
> vanilla as it gets, here’s an example:
>
> HDEVINFO deviceInfoSet;
> int memberIndex = 0;
> SP_DEVICE_INTERFACE_DATA MyDeviceInterfaceData;
> SP_DEVINFO_DATA MyDeviceInfo;
>
> //
> // look for all audio devices that are actually present on the system
> // (search by device class, not interface class)
> //
>
> deviceInfoSet = SetupDiGetClassDevs(pGuid, NULL, NULL, DIGCF_PRESENT);

Add DIGCF_ALLCLASSES ?

– pa

Um… yeah. Thanks for the reply Pavel. It’s pretty clear I’m doing something wrong, but the question is what. Do you want to see the code for the GUID’s being passed in? Like I said, the call works for the device class, so the problem probably isn’t in the way the GUID is being built. The question is what “specifically” is going wrong here. More generally, these “unnamed devices” are turning out to be a big problem for driver developers. There’s half a dozen people here screaming about this stuff. Microsoft’s GUIDs are all over the map, it’s impossible to tell one from the other, and there’s no higher level organization that lets troubleshooters conveniently analyze a broken system. Maybe that’s the intent? (snicker)… Okay, so maybe this can be transitioned over to the WinDbg forum if the thread goes in that direction, but I’d like to know what SPECIFICALLY is going wrong in this scenario. Is there some kind of trace I can get to determine what the kernel is complaining ab
out?

wrote in message news:xxxxx@ntdev…

> Do you want to see the code for the GUID’s being passed in?

Yes, please.

- pa

Hello,

In your code , Please change

success = SetupDiEnumDeviceInterfaces
(deviceInfoSet,
NULL /* &MyDeviceInfo */,
&requestedInterfaceGuid,
memberIndex,
&MyDeviceInterfaceData);

to

success = SetupDiEnumDeviceInterfaces
(deviceInfoSet,
NULL /* &MyDeviceInfo */,

pGuid,
memberIndex,
&MyDeviceInterfaceData);

thanks,
–rc

> In your code , Please change

You assume that interface GUID (requestedInterfaceGuid) is same as the class GUID (pGuid). This is true for many device types, but not for all.
– pa

Thanks for the replies. However, I’m not getting the information I was hoping for.

Let’s try this a different way. I’m a driver, and I’m passed an interface GUID from “some other device” (in other words, not from an application ioctl, but rather from “somewhere inside the kernel” - most likely from some other driver using an internal device control).

Now, I want to locate all devices broadcasting that interface. So I make this call:

status = IoGetDeviceInterfaces(pGuid, NULL, DEVICE_INTERFACE_INCLUDE_NONACTIVE, pNameList);

This call, properly returns a name list, BUT, here is the form of the names I’m getting:

??\ROOT#MEDIA#0000#{77777777-1234-5678-9abc-123456789abc}\ABAudioV_Control

where ABAudioV is the designated name of the device, and “Control” is the name of the interface.

The Windows documentation says I’m supposed to be able to open this directly, and I assume that means using either an IoGetDeviceObjectPointer or a ZwCreateFile.

But it doesn’t work. I get an error 3a, “OBJECT_PATH_NOT_FOUND”. And the open request is being made from a kernel mode WDM driver.

Any ideas why this is bombing?

Are you passing the fully qualified device interface name? are you properly initializing the UNICODE_STRING that you are passing to IoGetDeviceObjectPointer/ZwCreateFile?

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@advancedbionics.com
Sent: Friday, November 19, 2010 1:52 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] What’s in a GUID?

Thanks for the replies. However, I’m not getting the information I was hoping for.

Let’s try this a different way. I’m a driver, and I’m passed an interface GUID from “some other device” (in other words, not from an application ioctl, but rather from “somewhere inside the kernel” - most likely from some other driver using an internal device control).

Now, I want to locate all devices broadcasting that interface. So I make this call:

status = IoGetDeviceInterfaces(pGuid, NULL, DEVICE_INTERFACE_INCLUDE_NONACTIVE, pNameList);

This call, properly returns a name list, BUT, here is the form of the names I’m getting:

??\ROOT#MEDIA#0000#{77777777-1234-5678-9abc-123456789abc}\ABAudioV_Control

where ABAudioV is the designated name of the device, and “Control” is the name of the interface.

The Windows documentation says I’m supposed to be able to open this directly, and I assume that means using either an IoGetDeviceObjectPointer or a ZwCreateFile.

But it doesn’t work. I get an error 3a, “OBJECT_PATH_NOT_FOUND”. And the open request is being made from a kernel mode WDM driver.

Any ideas why this is bombing?


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Doron Holan wrote:

-> Are you passing the fully qualified device interface name?

Yes, I think so. Isn’t that what this is?

??\ROOT#MEDIA#0000#{77777777-1234-5678-9abc-123456789abc}\ABAudioV_Control

“Control” isn’t a device, it’s an interface. There is no device or subdevice with the name “Control”. The device is called “ABAudioV” and one of its interfaces is called “Control”.

Doron Holan wrote:

-> are you properly
initializing the UNICODE_STRING that you are passing to
IoGetDeviceObjectPointer/ZwCreateFile?

Once again, “I think so”. It should be as simple as this, right (to get just the first name in the list)?

UNICODE_STRING us = { 0 };

RtlInitUnicodeString(&us, (PWSTR) pNameList); // pNameList returned from IoGetDeviceInterfaces

Here is the snippet of code that actually tries to open the device:

//
// initialize object attributes
//

InitializeObjectAttributes(&objectAttributes, &us,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);

//
// open the proto device using the path passed back
//

status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &ioStatusBlock, NULL, 0,
FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if(!NT_SUCCESS(status))
{
DbgPrint(“ENABLE PROTO: device open failed, status=%08lx\n”, status);
}

One thought did occur to me - is there anything I need to do on the remote side to somehow “enable” the interface? I’m using the DEVICE_INTERFACE_INCLUDE_NONACTIVE flag in the IoGetDeviceInterfaces() call, and I do believe that the device is present and active, and I also believe that the interface has been properly registered. Is there a way I can double check this?

Get the interface list without specifying DEVICE_INTERFACE_INCLUDE_NONACTIVE. By providing this flag, you can easily get interface names that are not currently enabled.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@advancedbionics.com
Sent: Friday, November 19, 2010 3:09 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] What’s in a GUID?

Doron Holan wrote:

-> Are you passing the fully qualified device interface name?

Yes, I think so. Isn’t that what this is?

??\ROOT#MEDIA#0000#{77777777-1234-5678-9abc-123456789abc}\ABAudioV_Control

“Control” isn’t a device, it’s an interface. There is no device or subdevice with the name “Control”. The device is called “ABAudioV” and one of its interfaces is called “Control”.

Doron Holan wrote:

-> are you properly
initializing the UNICODE_STRING that you are passing to IoGetDeviceObjectPointer/ZwCreateFile?

Once again, “I think so”. It should be as simple as this, right (to get just the first name in the list)?

UNICODE_STRING us = { 0 };

RtlInitUnicodeString(&us, (PWSTR) pNameList); // pNameList returned from IoGetDeviceInterfaces

Here is the snippet of code that actually tries to open the device:

//
// initialize object attributes
//

InitializeObjectAttributes(&objectAttributes, &us,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);

//
// open the proto device using the path passed back //

status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &ioStatusBlock, NULL, 0,
FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if(!NT_SUCCESS(status))
{
DbgPrint(“ENABLE PROTO: device open failed, status=%08lx\n”, status); }

One thought did occur to me - is there anything I need to do on the remote side to somehow “enable” the interface? I’m using the DEVICE_INTERFACE_INCLUDE_NONACTIVE flag in the IoGetDeviceInterfaces() call, and I do believe that the device is present and active, and I also believe that the interface has been properly registered. Is there a way I can double check this?


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

wrote in message news:xxxxx@ntdev…

> One thought did occur to me - is there anything I need to do on the remote
> side to somehow “enable” the interface? I’m using the
> DEVICE_INTERFACE_INCLUDE_NONACTIVE flag in the IoGetDeviceInterfaces()
> call, and I do believe that the device is present and active, and I also
> believe that the interface has been properly registered. Is there a way I
> can double check this?
>

1. call IoGetDeviceInterfaces without DEVICE_INTERFACE_INCLUDE_NONACTIVE
2. Could it be that the driver (or some filter in the middle) fails the
open?

– pa

Ha ha - well, if I were in a mood to complain, I would note that it’s very difficult to find out how to debug this stuff. Here’s where I’m at: I have an interface GUID, which I know “for sure” belongs to my device (because I created it). And, when I call IoGetDeviceInterfaces() with that GUID, lo and behold it exists (and because I’m using DEVICE_INTERFACE_INCLUDE_NONACTIVE, I can’t really tell whether that device is currently active or not, at this point).

Now - either the device exists, or the device doesn’t exist. I’m firmly convinced it’s (a), because I can actually open that device a number of different ways (“other” ways, let’s say).

So if it’s (a), and the device exists, then the only thing I’m left with is, “the device didn’t properly register the interface”. Make sense?

So now, my question becomes very specific: how do I tell whether a device has properly registered its interface? I have the GUID, and I have the physical path to the device, but perusing the DDK samples I see this “interface registration” stuff being done in several different ways. There are some samples that use an AddInterface directive, but there are also some samples that have an AddReg with a key called DeviceInterfaceGUIDs (this latter method is used, for example, by WINUSB).

What “exactly” constitutes a valid interface? The Windows documentation is “less than clear” on this point. Where can I look to find out whether my interface should be working? And if it can’t be found, what is the reason it can’t be found? (there’s no NTSTATUS codes pertaining to this, right?)

xxxxx@advancedbionics.com wrote:

…So now, my question becomes very specific: how do I tell whether a device has properly registered its interface? I have the GUID, and I have the physical path to the device, but perusing the DDK samples I see this “interface registration” stuff being done in several different ways. There are some samples that use an AddInterface directive, but there are also some samples that have an AddReg with a key called DeviceInterfaceGUIDs (this latter method is used, for example, by WINUSB).

What “exactly” constitutes a valid interface? The Windows documentation is “less than clear” on this point. Where can I look to find out whether my interface should be working? And if it can’t be found, what is the reason it can’t be found? (there’s no NTSTATUS codes pertaining to this, right?)

No INF or registry manipulation is required. You call
IoRegisterDeviceInterface to register it, and you call
IoSetDeviceInterfaceState to enable or disable it.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Of WdfDeviceAddDeviceInterface in a KMDF driver

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Tuesday, November 23, 2010 4:52 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] What’s in a GUID?

xxxxx@advancedbionics.com wrote:

…So now, my question becomes very specific: how do I tell whether a device has properly registered its interface? I have the GUID, and I have the physical path to the device, but perusing the DDK samples I see this “interface registration” stuff being done in several different ways. There are some samples that use an AddInterface directive, but there are also some samples that have an AddReg with a key called DeviceInterfaceGUIDs (this latter method is used, for example, by WINUSB).

What “exactly” constitutes a valid interface? The Windows
documentation is “less than clear” on this point. Where can I look to
find out whether my interface should be working? And if it can’t be
found, what is the reason it can’t be found? (there’s no NTSTATUS
codes pertaining to this, right?)

No INF or registry manipulation is required. You call IoRegisterDeviceInterface to register it, and you call IoSetDeviceInterfaceState to enable or disable it.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer