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

.
Summary

C# Definition:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
struct USB_STRING_DESCRIPTOR
{
   public byte bLength;
   public byte bDescriptorType;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAXIMUM_USB_STRING_LENGTH)]
   public string bString;
}

VB Definition:

Structure USB_STRING_DESCRIPTOR
   Public TODO
End Structure

User-Defined Field Types:

const int MAXIMUM_USB_STRING_LENGTH = 255;
const int USB_STRING_DESCRIPTOR_TYPE = 3;

Notes:

typedef struct _USB_STRING_DESCRIPTOR {
   UCHAR bLength;
   UCHAR bDescriptorType;
   WCHAR bString[1];
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;

You don't use an IOCTL call directly with a USB_STRING_DESCRIPTOR structure. Instead you use a USB_DESCRIPTOR_REQUEST "request packet" with IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION. The USB_STRING_DESCRIPTOR structure is returned at the very end of the request packet. The whole idea of "writing off the edge" of a structure is counter to the way C#/VB.Net was designed to work, so you'll have to make sure to allocate sufficient amount of memory to handle both the "request packet" and the USB_STRING_DESCRIPTOR structure.

There is no Marshal.MemSet method to zero-out the buffer prior to use, so you might consider the following hack

string NullString = new string((char)0, BUFFER_SIZE / Marshal.SystemDefaultCharSize);
IntPtr ptrRequest = Marshal.StringToHGlobalAuto(NullString);

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);
}