USB_DESCRIPTOR_REQUEST (Structures)
Last changed: egray1@hot.rr.com-24.26.210.211

.
Summary

C# Definition:

[StructLayout(LayoutKind.Sequential)]
struct USB_SETUP_PACKET
{
   public byte bmRequest;
   public byte bRequest;
   public short wValue;
   public short wIndex;
   public short wLength;
}
[StructLayout(LayoutKind.Sequential)]
struct USB_DESCRIPTOR_REQUEST
{
   public int ConnectionIndex;
   public USB_SETUP_PACKET SetupPacket;
   //public byte[] Data;
}

VB Definition:

Structure USB_DESCRIPTOR_REQUEST
   Public TODO
End Structure

User-Defined Field Types:

const int USB_DEVICE_DESCRIPTOR_TYPE = 1;
const int USB_STRING_DESCRIPTOR_TYPE = 3;

Notes:

The USB_DESCRIPTOR_REQUEST structure is always followed by either a USB_STRING_DESCRIPTOR or USB_DEVICE_DESCRIPTOR structure.

The use of a a zero-length array at the end of the structure requires that you read and write "off the edge" of the structure. This concept is not well supported in C#/VB.Net so you have make sure that you allocate sufficient buffer space to accommodate a the USB_STRING_DESCRIPTOR or USB_DEVICE_DESCRIPTOR structure.

Although nested structures are support in C#/VB.Net, you cannot use them in API calls without writing a custom marshaler. An alternative approach is to separate the nested structure into two parts. The use of "Pack=1" may be required to keep the "native" size of the "interior" structure.

typedef struct _USB_DESCRIPTOR_REQUEST {
   ULONG ConnectionIndex;
   struct {
     UCHAR  bmRequest;
     UCHAR  bRequest;
     USHORT  wValue;
     USHORT  wIndex;
     USHORT  wLength;
   } SetupPacket;
   UCHAR  Data[0];
} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST

Documentation

Example:

if (PortDeviceDescriptor.iManufacturer > 0) {
   int nBytesReturned;
   int nBytes = BUFFER_SIZE;

   // build a request for string descriptor
   USB_DESCRIPTOR_REQUEST Request = new USB_DESCRIPTOR_REQUEST();
   Request.ConnectionIndex = PortPortNumber;
   Request.SetupPacket.wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iManufacturer);
   Request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(Request));
   Request.SetupPacket.wIndex = 0x409; // Language Code

   // Geez, I wish C# had a Marshal.MemSet() method
   string NullString = new string((char)0, nBytes  / Marshal.SystemDefaultCharSize);
   IntPtr ptrRequest = Marshal.StringToHGlobalAuto(NullString);
   Marshal.StructureToPtr(Request, ptrRequest, true);

   // Use an IOCTL call to request the String Descriptor
   if (DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ptrRequest, nBytes, ptrRequest, nBytes, out nBytesReturned, IntPtr.Zero))
   {
     // The location of the string descriptor is immediately after
     // the Request structure.  Because this location is not "covered"
     // by the structure allocation, we're forced to zero out this
     // chunk of memory by using the StringToHGlobalAuto() hack above
     IntPtr ptrStringDesc = new IntPtr(ptrRequest.ToInt32() + Marshal.SizeOf(Request));
     USB_STRING_DESCRIPTOR StringDesc = (USB_STRING_DESCRIPTOR)Marshal.PtrToStructure(ptrStringDesc, typeof(USB_STRING_DESCRIPTOR));
     string DeviceManufacturer = StringDesc.bString;
   }
   Marshal.FreeHGlobal(ptrRequest);
}