private String GetStringSafe(Byte id) { if (id == 0) { return(null); } if (languages == null) { Byte[] buff = new Byte[256]; int len = GetDescriptor((Byte)UsbDescriptorType.String, 0, 0, buff, 0, buff.Length); if (len > 1) { languages = new short[len / 2 - 1]; for (int i = 0; i < languages.Length; i++) { languages[i] = BitConverter.ToInt16(buff, i * 2 + 2); } } } short language = (languages == null || languages.Length == 0) ? (short)0 : languages[0]; String s = UsbStringDescriptor.GetStringFromDevice(this, id, language); if (s == null) { return(s); } return(s.Trim(' ', '\0')); }
/// <summary> /// return a down stream external hub /// </summary> /// <returns>Downstream external hub</returns> internal UsbDevice GetDevice() { if (!PortIsDeviceConnected) { return(null); } // Copy over some values from the Port class // Ya know, I've given some thought about making Device a derived class... UsbDevice device = new UsbDevice { DevicePortNumber = PortPortNumber, DeviceHubDevicePath = PortHubDevicePath, DeviceDescriptor = PortDeviceDescriptor }; // Open a handle to the Hub device IntPtr h = CreateFile(PortHubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); if (h.ToInt32() == INVALID_HANDLE_VALUE) { return(device); } int nBytesReturned; int nBytes = BUFFER_SIZE; // We use this to zero fill a buffer string nullString = new string((char)0, BUFFER_SIZE / Marshal.SystemDefaultCharSize); // The iManufacturer, iProduct and iSerialNumber entries in the // Device Descriptor are really just indexes. So, we have to // request a String Descriptor to get the values for those strings. if (PortDeviceDescriptor.iManufacturer > 0) { // build a request for string descriptor UsbDescriptorRequest request = new UsbDescriptorRequest { ConnectionIndex = PortPortNumber, SetupPacket = { // Language Code wIndex = 0x409, wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iManufacturer) } }; request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(request)); // Geez, I wish C# had a Marshal.MemSet() method 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)); UsbStringDescriptor stringDesc = (UsbStringDescriptor)Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)); device.DeviceManufacturer = stringDesc.bString; } Marshal.FreeHGlobal(ptrRequest); } if (PortDeviceDescriptor.iProduct > 0) { // build a request for string descriptor UsbDescriptorRequest request = new UsbDescriptorRequest { ConnectionIndex = PortPortNumber, SetupPacket = { // Language Code wIndex = 0x409, wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iProduct) } }; request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(request)); // Geez, I wish C# had a Marshal.MemSet() method 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 IntPtr ptrStringDesc = new IntPtr(ptrRequest.ToInt32() + Marshal.SizeOf(request)); UsbStringDescriptor stringDesc = (UsbStringDescriptor)Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)); device.DeviceProduct = stringDesc.bString; } Marshal.FreeHGlobal(ptrRequest); } if (PortDeviceDescriptor.iSerialNumber > 0) { // build a request for string descriptor UsbDescriptorRequest request = new UsbDescriptorRequest { ConnectionIndex = PortPortNumber, SetupPacket = { // Language Code wIndex = 0x409, wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iSerialNumber) } }; request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(request)); // Geez, I wish C# had a Marshal.MemSet() method 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 IntPtr ptrStringDesc = new IntPtr(ptrRequest.ToInt32() + Marshal.SizeOf(request)); UsbStringDescriptor stringDesc = (UsbStringDescriptor)Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)); device.DeviceSerialNumber = stringDesc.bString; } Marshal.FreeHGlobal(ptrRequest); } // build a request for configuration descriptor UsbDescriptorRequest dcrRequest = new UsbDescriptorRequest { ConnectionIndex = PortPortNumber, SetupPacket = { wIndex = 0, wValue = USB_CONFIGURATION_DESCRIPTOR_TYPE << 8 } }; dcrRequest.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(dcrRequest)); // Geez, I wish C# had a Marshal.MemSet() method IntPtr dcrPtrRequest = Marshal.StringToHGlobalAuto(nullString); Marshal.StructureToPtr(dcrRequest, dcrPtrRequest, true); // Use an IOCTL call to request the String Descriptor if (DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, dcrPtrRequest, nBytes, dcrPtrRequest, nBytes, out nBytesReturned, IntPtr.Zero)) { IntPtr ptrStringDesc = new IntPtr(dcrPtrRequest.ToInt32() + Marshal.SizeOf(dcrRequest)); device.BinaryDeviceDescriptors = new byte[nBytesReturned]; Marshal.Copy(ptrStringDesc, device.BinaryDeviceDescriptors, 0, nBytesReturned); } Marshal.FreeHGlobal(dcrPtrRequest); // Get the Driver Key Name (usefull in locating a device) UsbNodeConnectionDriverkeyName driverKey = new UsbNodeConnectionDriverkeyName { ConnectionIndex = PortPortNumber }; nBytes = Marshal.SizeOf(driverKey); IntPtr ptrDriverKey = Marshal.AllocHGlobal(nBytes); Marshal.StructureToPtr(driverKey, ptrDriverKey, true); // Use an IOCTL call to request the Driver Key Name if (DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ptrDriverKey, nBytes, ptrDriverKey, nBytes, out nBytesReturned, IntPtr.Zero)) { driverKey = (UsbNodeConnectionDriverkeyName)Marshal.PtrToStructure(ptrDriverKey, typeof( UsbNodeConnectionDriverkeyName )); device.DeviceDriverKey = driverKey.DriverKeyName; // use the DriverKeyName to get the Device Description and Instance ID device.DeviceName = GetDescriptionByKeyName(device.DeviceDriverKey); device.DeviceInstanceId = GetInstanceIdByKeyName(device.DeviceDriverKey); } Marshal.FreeHGlobal(ptrDriverKey); CloseHandle(h); return(device); }