// The following procedure works with the USB device driver; upon finding all instances of USB devices // that match the requested Guid, the procedure checks the corresponding registry keys to find the unique // serial number to show to the user; the serial number is decided by the device driver at installation // time and stored in a registry key whose name is the hash of the laser etched security key of the device private static IEnumerable<PortDefinition> EnumeratePorts( Guid guid ) { var devInfo = NativeMethods.SetupDiGetClassDevs( ref guid, null, 0, NativeMethods.DIGCF_DEVICEINTERFACE | NativeMethods.DIGCF_PRESENT ); if( devInfo == NativeMethods.INVALID_HANDLE_VALUE ) yield break; try { var interfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA( ); interfaceData.cbSize = Marshal.SizeOf( interfaceData ); var index = 0; while( NativeMethods.SetupDiEnumDeviceInterfaces( devInfo, 0, ref guid, index++, ref interfaceData ) ) { PortDefinition pd = null; try { var detail = new NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA( ); // explicit size of unmanaged structure must be provided, because it does not include transfer buffer // for whatever reason on 64 bit machines the detail size is 8 rather than 5, likewise the interfaceData.cbSize // is 32 rather than 28 for non 64bit machines, therefore, we make the detemination of the size based // on the interfaceData.cbSize (kind of hacky but it works). detail.cbSize = interfaceData.cbSize == 32 ? 8 : 5; // get device interface details to allow opening the port for querying the friendly name if( !NativeMethods.SetupDiGetDeviceInterfaceDetail( devInfo, ref interfaceData, ref detail, Marshal.SizeOf( detail ) * 2, 0, 0 ) ) continue; var port = detail.DevicePath.ToLower( ); using( var s = new WinUsb_AsyncUsbStream( port ) ) { var displayName = s.RetrieveStringFromDevice( USB_DISPLAY_STRING_INDEX ); var hash = s.RetrieveStringFromDevice( USB_FRIENDLY_STRING_INDEX ); if( ( displayName == null ) || ( hash == null ) ) yield break; displayName += "_" + hash; pd = PortDefinition.CreateInstanceForWinUsb( displayName, port ); if( !pd.Properties.Contains( DeviceHash ) ) pd.Properties.Add( DeviceHash, hash ); } } catch(IOException) { // go to next device } if( pd != null ) yield return pd; } } finally { NativeMethods.SetupDiDestroyDeviceInfoList( devInfo ); } }
// The following procedure works with the USB device driver; upon finding all instances of USB devices // that match the requested Guid, the procedure checks the corresponding registry keys to find the unique // serial number to show to the user; the serial number is decided by the device driver at installation // time and stored in a registry key whose name is the hash of the laser etched security key of the device private static void EnumeratePorts(Guid inquiriesInterface, string driverVersion, SortedList lst) { IntPtr devInfo = NativeMethods.SetupDiGetClassDevs(ref inquiriesInterface, null, 0, NativeMethods.DIGCF_DEVICEINTERFACE | NativeMethods.DIGCF_PRESENT); if (devInfo == NativeMethods.INVALID_HANDLE_VALUE) { return; } NativeMethods.SP_DEVICE_INTERFACE_DATA interfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA(); interfaceData.cbSize = Marshal.SizeOf(interfaceData); int index = 0; while (NativeMethods.SetupDiEnumDeviceInterfaces(devInfo, 0, ref inquiriesInterface, index++, ref interfaceData)) { NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA detail = new NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA(); // explicit size of unmanaged structure must be provided, because it does not include transfer buffer // for whatever reason on 64 bit machines the detail size is 8 rather than 5, likewise the interfaceData.cbSize // is 32 rather than 28 for non 64bit machines, therefore, we make the detemination of the size based // on the interfaceData.cbSize (kind of hacky but it works). if (interfaceData.cbSize == 32) { detail.cbSize = 8; } else { detail.cbSize = 5; } if (NativeMethods.SetupDiGetDeviceInterfaceDetail(devInfo, ref interfaceData, ref detail, Marshal.SizeOf(detail) * 2, 0, 0)) { string port = detail.DevicePath.ToLower(); AsyncUsbStream s = null; try { s = new AsyncUsbStream(port); string displayName = s.RetrieveStringFromDevice(IOCTL_SPOTUSB_DISPLAY_NAME); string hash = s.RetrieveStringFromDevice(IOCTL_SPOTUSB_DEVICE_HASH); string operationalPort = s.RetrieveStringFromDevice(IOCTL_SPOTUSB_PORT_NAME); if ((operationalPort == null) || (displayName == null) || (hash == null)) { continue; } // convert kernel format to user mode format // kernel : @"\??\USB#Vid_beef&Pid_0009#5&4162af8&0&1#{09343630-a794-10ef-334f-82ea332c49f3}" // user : @"\\?\usb#vid_beef&pid_0009#5&4162af8&0&1#{09343630-a794-10ef-334f-82ea332c49f3}" StringBuilder operationalPortUser = new StringBuilder(); operationalPortUser.Append(@"\\?"); operationalPortUser.Append(operationalPort.Substring(3)); // change the display name if there is a collision (otherwise you will only be able to use one of the devices) displayName += "_" + hash; if (lst.ContainsKey(displayName)) { int i = 2; while (lst.ContainsKey(displayName + " (" + i + ")")) { i++; } displayName += " (" + i + ")"; } PortDefinition pd = PortDefinition.CreateInstanceForUsb(displayName, operationalPortUser.ToString()); RetrieveProperties(hash, ref pd, s); lst.Add(pd.DisplayName, pd); } catch { } finally { if (s != null) { s.Close(); } } } } NativeMethods.SetupDiDestroyDeviceInfoList(devInfo); }
// The following procedure works with the USB device driver; upon finding all instances of USB devices // that match the requested Guid, the procedure checks the corresponding registry keys to find the unique // serial number to show to the user; the serial number is decided by the device driver at installation // time and stored in a registry key whose name is the hash of the laser etched security key of the device private static IEnumerable <PortDefinition> EnumeratePorts(Guid guid) { var devInfo = NativeMethods.SetupDiGetClassDevs(ref guid, null, 0, NativeMethods.DIGCF_DEVICEINTERFACE | NativeMethods.DIGCF_PRESENT); if (devInfo == NativeMethods.INVALID_HANDLE_VALUE) { yield break; } try { var interfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA( ); interfaceData.cbSize = Marshal.SizeOf(interfaceData); var index = 0; while (NativeMethods.SetupDiEnumDeviceInterfaces(devInfo, 0, ref guid, index++, ref interfaceData)) { PortDefinition pd = null; try { var detail = new NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA( ); // explicit size of unmanaged structure must be provided, because it does not include transfer buffer // for whatever reason on 64 bit machines the detail size is 8 rather than 5, likewise the interfaceData.cbSize // is 32 rather than 28 for non 64bit machines, therefore, we make the detemination of the size based // on the interfaceData.cbSize (kind of hacky but it works). detail.cbSize = interfaceData.cbSize == 32 ? 8 : 5; // get device interface details to allow opening the port for querying the friendly name if (!NativeMethods.SetupDiGetDeviceInterfaceDetail(devInfo, ref interfaceData, ref detail, Marshal.SizeOf(detail) * 2, 0, 0)) { continue; } var port = detail.DevicePath.ToLower( ); using (var s = new WinUsb_AsyncUsbStream(port)) { var displayName = s.RetrieveStringFromDevice(USB_DISPLAY_STRING_INDEX); var hash = s.RetrieveStringFromDevice(USB_FRIENDLY_STRING_INDEX); if ((displayName == null) || (hash == null)) { yield break; } displayName += "_" + hash; pd = PortDefinition.CreateInstanceForWinUsb(displayName, port); if (!pd.Properties.Contains(DeviceHash)) { pd.Properties.Add(DeviceHash, hash); } } } catch (IOException) { // go to next device } if (pd != null) { yield return(pd); } } } finally { NativeMethods.SetupDiDestroyDeviceInfoList(devInfo); } }
// The following procedure works with the USB device driver; upon finding all instances of USB devices // that match the requested Guid, the procedure checks the corresponding registry keys to find the unique // serial number to show to the user; the serial number is decided by the device driver at installation // time and stored in a registry key whose name is the hash of the laser etched security key of the device private static void EnumeratePorts( Guid inquiriesInterface, string driverVersion, SortedList lst ) { IntPtr devInfo = NativeMethods.SetupDiGetClassDevs( ref inquiriesInterface, null, 0, NativeMethods.DIGCF_DEVICEINTERFACE | NativeMethods.DIGCF_PRESENT ); if(devInfo == NativeMethods.INVALID_HANDLE_VALUE) { return; } NativeMethods.SP_DEVICE_INTERFACE_DATA interfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA(); interfaceData.cbSize = Marshal.SizeOf(interfaceData); int index = 0; while(NativeMethods.SetupDiEnumDeviceInterfaces( devInfo, 0, ref inquiriesInterface, index++, ref interfaceData )) { NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA detail = new NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA(); // explicit size of unmanaged structure must be provided, because it does not include transfer buffer // for whatever reason on 64 bit machines the detail size is 8 rather than 5, likewise the interfaceData.cbSize // is 32 rather than 28 for non 64bit machines, therefore, we make the detemination of the size based // on the interfaceData.cbSize (kind of hacky but it works). if( interfaceData.cbSize == 32 ) { detail.cbSize = 8; } else { detail.cbSize = 5; } if(NativeMethods.SetupDiGetDeviceInterfaceDetail( devInfo, ref interfaceData, ref detail, Marshal.SizeOf(detail) * 2, 0, 0 )) { string port = detail.DevicePath.ToLower(); AsyncUsbStream s = null; try { s = new AsyncUsbStream( port ); string displayName = s.RetrieveStringFromDevice( IOCTL_SPOTUSB_DISPLAY_NAME ); string hash = s.RetrieveStringFromDevice( IOCTL_SPOTUSB_DEVICE_HASH ); string operationalPort = s.RetrieveStringFromDevice( IOCTL_SPOTUSB_PORT_NAME ); if((operationalPort == null) || (displayName == null) || (hash == null)) { continue; } // convert kernel format to user mode format // kernel : @"\??\USB#Vid_beef&Pid_0009#5&4162af8&0&1#{09343630-a794-10ef-334f-82ea332c49f3}" // user : @"\\?\usb#vid_beef&pid_0009#5&4162af8&0&1#{09343630-a794-10ef-334f-82ea332c49f3}" StringBuilder operationalPortUser = new StringBuilder(); operationalPortUser.Append( @"\\?" ); operationalPortUser.Append( operationalPort.Substring( 3 ) ); // change the display name if there is a collision (otherwise you will only be able to use one of the devices) displayName += "_" + hash; if (lst.ContainsKey(displayName)) { int i = 2; while (lst.ContainsKey(displayName + " (" + i + ")")) { i++; } displayName += " (" + i + ")"; } PortDefinition pd = PortDefinition.CreateInstanceForUsb( displayName, operationalPortUser.ToString() ); RetrieveProperties( hash, ref pd, s ); lst.Add( pd.DisplayName, pd ); } catch { } finally { if(s != null) s.Close(); } } } NativeMethods.SetupDiDestroyDeviceInfoList( devInfo ); }