Migrate WinUSBNet code to a standalone project dependency

This commit is contained in:
Gustave Monce
2025-11-01 09:28:08 +01:00
parent 1cc7a5cee4
commit 058cde0d91
25 changed files with 659 additions and 15 deletions
+48
View File
@@ -0,0 +1,48 @@
/* WinUSBNet library
* (C) 2010 Thomas Bleeker (www.madwizard.org)
*
* Licensed under the MIT license, see license.txt or:
* http://www.opensource.org/licenses/mit-license.php
*/
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace MadWizard.WinUSBNet.API
{
/// <summary>
/// Exception used internally to catch Win32 API errors. This exception should
/// not be thrown to the library's caller.
/// </summary>
internal class APIException : Exception
{
public APIException(string message) :
base(message)
{
}
public APIException(string message, Exception innerException) : base(message, innerException)
{
}
public APIException() : base()
{
}
public static APIException Win32(string message)
{
return Win32(message, Marshal.GetLastWin32Error());
// TEST!!
// int ErrorCode = Marshal.GetLastWin32Error();
// if ((ErrorCode & 0xffff) == 0x1f)
// ErrorCode = ErrorCode; // Break here
// return APIException.Win32(message, ErrorCode);
}
public static APIException Win32(string message, int errorCode)
{
return new APIException(message, new Win32Exception(errorCode));
}
}
}
+21
View File
@@ -0,0 +1,21 @@
/* WinUSBNet library
* (C) 2010 Thomas Bleeker (www.madwizard.org)
*
* Licensed under the MIT license, see license.txt or:
* http://www.opensource.org/licenses/mit-license.php
*/
namespace MadWizard.WinUSBNet.API
{
internal struct DeviceDetails
{
public string DevicePath;
public string Manufacturer;
public string DeviceDescription;
public ushort VID;
public ushort PID;
// Heathcliff74
public string BusName;
}
}
+372
View File
@@ -0,0 +1,372 @@
/* WinUSBNet library
* (C) 2010 Thomas Bleeker (www.madwizard.org)
*
* Licensed under the MIT license, see license.txt or:
* http://www.opensource.org/licenses/mit-license.php
*/
/* NOTE: Parts of the code in this file are based on the work of Jan Axelson
* See http://www.lvr.com/winusb.htm for more information
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace MadWizard.WinUSBNet.API
{
/// <summary>
/// Routines for detecting devices and receiving device notifications.
/// </summary>
internal static partial class DeviceManagement
{
// Get device name from notification message.
// Also checks checkGuid with the GUID from the message to check the notification
// is for a relevant device. Other messages might be received.
public static string GetNotifyMessageDeviceName(IntPtr pDevBroadcastHeader, Guid checkGuid)
{
int stringSize;
DEV_BROADCAST_DEVICEINTERFACE_1 devBroadcastDeviceInterface = new();
DEV_BROADCAST_HDR devBroadcastHeader = new();
// The LParam parameter of Message is a pointer to a DEV_BROADCAST_HDR structure.
Marshal.PtrToStructure(pDevBroadcastHeader, devBroadcastHeader);
if (devBroadcastHeader.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
// The dbch_devicetype parameter indicates that the event applies to a device interface.
// So the structure in LParam is actually a DEV_BROADCAST_INTERFACE structure,
// which begins with a DEV_BROADCAST_HDR.
// Obtain the number of characters in dbch_name by subtracting the 32 bytes
// in the strucutre that are not part of dbch_name and dividing by 2 because there are
// 2 bytes per character.
stringSize = Convert.ToInt32((devBroadcastHeader.dbch_size - 32) / 2);
// The dbcc_name parameter of devBroadcastDeviceInterface contains the device name.
// Trim dbcc_name to match the size of the String.
devBroadcastDeviceInterface.dbcc_name = new char[stringSize + 1];
// Marshal data from the unmanaged block pointed to by m.LParam
// to the managed object devBroadcastDeviceInterface.
Marshal.PtrToStructure(pDevBroadcastHeader, devBroadcastDeviceInterface);
// Check if message is for the GUID
if (devBroadcastDeviceInterface.dbcc_classguid != checkGuid)
{
return null;
}
// Store the device name in a String.
return (string)(new(devBroadcastDeviceInterface.dbcc_name, 0, stringSize));
}
else if (devBroadcastHeader.dbch_devicetype == DBT_DEVTYP_VOLUME)
{
DEV_BROADCAST_VOLUME vol = new();
Marshal.PtrToStructure(pDevBroadcastHeader, vol);
Int32 Mask = vol.dbcv_unitmask;
Int32 DriveInt = Convert.ToInt32('A') - 1;
do
{
Mask /= 2;
DriveInt++;
}
while (Mask > 0);
return @"\\.\" + Convert.ToChar(DriveInt) + ":";
}
return null;
}
private static byte[] GetProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property, out int regType)
{
if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, property, IntPtr.Zero, IntPtr.Zero, 0, out uint requiredSize) && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER)
{
throw APIException.Win32("Failed to get buffer size for device registry property.");
}
byte[] buffer = new byte[requiredSize];
if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, property, out regType, buffer, (uint)buffer.Length, out requiredSize))
{
throw APIException.Win32("Failed to get device registry property.");
}
return buffer;
}
//DEFINE_DEVPROPKEY(DEVPKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
//DEFINE_DEVPROPKEY(DEVPKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID
//DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING
//DEFINE_DEVPROPKEY(DEVPKEY_DeviceDisplay_Category, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x5a); // DEVPROP_TYPE_STRING_LIST
//DEFINE_DEVPROPKEY(DEVPKEY_Device_LocationInfo, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15); // DEVPROP_TYPE_STRING
//DEFINE_DEVPROPKEY(DEVPKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING
//DEFINE_DEVPROPKEY(DEVPKEY_Device_SecuritySDS, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
// Heathcliff74
private static byte[] GetProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, DEVPROPKEY property, out uint propertyType)
{
if (!SetupDiGetDeviceProperty(deviceInfoSet, ref deviceInfoData, ref property, out propertyType, null, 0, out int requiredSize, 0) && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER)
{
throw APIException.Win32("Failed to get buffer size for device registry property.");
}
byte[] buffer = new byte[requiredSize];
if (!SetupDiGetDeviceProperty(deviceInfoSet, ref deviceInfoData, ref property, out propertyType, buffer, buffer.Length, out requiredSize, 0))
{
throw APIException.Win32("Failed to get device registry property.");
}
return buffer;
}
// todo: is the queried data always available, or should we check ERROR_INVALID_DATA?
private static string GetStringProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property)
{
byte[] buffer = GetProperty(deviceInfoSet, deviceInfoData, property, out int regType);
if (regType != (int)RegTypes.REG_SZ)
{
throw new APIException("Invalid registry type returned for device property.");
}
// sizof(char), 2 bytes, are removed to leave out the string terminator
return System.Text.Encoding.Unicode.GetString(buffer, 0, buffer.Length - sizeof(char));
}
// Heathcliff74
// todo: is the queried data always available, or should we check ERROR_INVALID_DATA?
private static string GetStringProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, DEVPROPKEY property)
{
byte[] buffer = GetProperty(deviceInfoSet, deviceInfoData, property, out uint propertyType);
if (propertyType != 0x00000012) // DEVPROP_TYPE_STRING
{
throw new APIException("Invalid registry type returned for device property.");
}
// sizof(char), 2 bytes, are removed to leave out the string terminator
return System.Text.Encoding.Unicode.GetString(buffer, 0, buffer.Length - sizeof(char));
}
private static string[] GetMultiStringProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property)
{
byte[] buffer = GetProperty(deviceInfoSet, deviceInfoData, property, out int regType);
if (regType != (int)RegTypes.REG_MULTI_SZ)
{
throw new APIException("Invalid registry type returned for device property.");
}
string fullString = System.Text.Encoding.Unicode.GetString(buffer);
return fullString.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
}
private static DeviceDetails GetDeviceDetails(string devicePath, IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData)
{
DeviceDetails details = new()
{
DevicePath = devicePath,
DeviceDescription = GetStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_DEVICEDESC),
Manufacturer = GetStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_MFG),
// Heathcliff74
BusName = ""
};
try
{
details.BusName = GetStringProperty(deviceInfoSet, deviceInfoData, new DEVPROPKEY(new Guid(0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2), 4));
}
catch { }
string[] hardwareIDs = GetMultiStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_HARDWAREID);
Regex regex = new("^USB\\\\VID_([0-9A-F]{4})&PID_([0-9A-F]{4})", RegexOptions.IgnoreCase);
foreach (string hardwareID in hardwareIDs)
{
Match match = regex.Match(hardwareID);
if (match.Success)
{
details.VID = ushort.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.AllowHexSpecifier);
details.PID = ushort.Parse(match.Groups[2].Value, System.Globalization.NumberStyles.AllowHexSpecifier);
break;
}
}
// Heathcliff74
// Not all devices have numeric VID and PID
//
// if (!foundVidPid)
// throw new APIException("Failed to find VID and PID for USB device. No hardware ID could be parsed.");
return details;
}
public static DeviceDetails[] FindDevicesFromGuid(Guid guid)
{
IntPtr deviceInfoSet = IntPtr.Zero;
List<DeviceDetails> deviceList = [];
try
{
deviceInfoSet = SetupDiGetClassDevs(ref guid, IntPtr.Zero, IntPtr.Zero,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfoSet == FileIO.INVALID_HANDLE_VALUE)
{
throw APIException.Win32("Failed to enumerate devices.");
}
int memberIndex = 0;
while (true)
{
// Begin with 0 and increment through the device information set until
// no more devices are available.
SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new();
// The cbSize element of the deviceInterfaceData structure must be set to
// the structure's size in bytes.
// The size is 28 bytes for 32-bit code and 32 bytes for 64-bit code.
deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData);
bool success = SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref guid, memberIndex, ref deviceInterfaceData);
// Find out if a device information set was retrieved.
if (!success)
{
int lastError = Marshal.GetLastWin32Error();
if (lastError == ERROR_NO_MORE_ITEMS)
{
break;
}
throw APIException.Win32("Failed to get device interface.");
}
// A device is present.
int bufferSize = 0;
success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
ref deviceInterfaceData,
IntPtr.Zero,
0,
ref bufferSize,
IntPtr.Zero);
if (!success && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER)
{
throw APIException.Win32("Failed to get interface details buffer size.");
}
IntPtr detailDataBuffer = IntPtr.Zero;
try
{
// Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size.
detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
// Store cbSize in the first bytes of the array. The number of bytes varies with 32- and 64-bit systems.
Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
// Call SetupDiGetDeviceInterfaceDetail again.
// This time, pass a pointer to DetailDataBuffer
// and the returned required buffer size.
// build a DevInfo Data structure
SP_DEVINFO_DATA da = new();
da.cbSize = Marshal.SizeOf(da);
success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
ref deviceInterfaceData,
detailDataBuffer,
bufferSize,
ref bufferSize,
ref da);
if (!success)
{
throw APIException.Win32("Failed to get device interface details.");
}
// Skip over cbsize (4 bytes) to get the address of the devicePathName.
IntPtr pDevicePathName = new(detailDataBuffer.ToInt64() + 4);
string pathName = Marshal.PtrToStringUni(pDevicePathName);
// Get the String containing the devicePathName.
DeviceDetails details = GetDeviceDetails(pathName, deviceInfoSet, da);
deviceList.Add(details);
}
finally
{
if (detailDataBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(detailDataBuffer);
detailDataBuffer = IntPtr.Zero;
}
}
memberIndex++;
}
}
finally
{
if (deviceInfoSet != IntPtr.Zero && deviceInfoSet != FileIO.INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(deviceInfoSet);
}
}
return [.. deviceList];
}
public static void RegisterForDeviceNotifications(IntPtr controlHandle, Guid classGuid, ref IntPtr deviceNotificationHandle)
{
DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new();
IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero;
try
{
int size = Marshal.SizeOf(devBroadcastDeviceInterface);
devBroadcastDeviceInterface.dbcc_size = size;
devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
devBroadcastDeviceInterface.dbcc_reserved = 0;
devBroadcastDeviceInterface.dbcc_classguid = classGuid;
devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size);
// Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer.
// Set fDeleteOld True to prevent memory leaks.
Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true);
deviceNotificationHandle = RegisterDeviceNotification(controlHandle, devBroadcastDeviceInterfaceBuffer, DEVICE_NOTIFY_WINDOW_HANDLE);
if (deviceNotificationHandle == IntPtr.Zero)
{
throw APIException.Win32("Failed to register device notification");
}
// Marshal data from the unmanaged block devBroadcastDeviceInterfaceBuffer to
// the managed object devBroadcastDeviceInterface
Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface);
}
finally
{
// Free the memory allocated previously by AllocHGlobal.
if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer);
}
}
}
public static void StopDeviceDeviceNotifications(IntPtr deviceNotificationHandle)
{
if (!UnregisterDeviceNotification(deviceNotificationHandle))
{
throw APIException.Win32("Failed to unregister device notification");
}
}
}
}
+180
View File
@@ -0,0 +1,180 @@
/* WinUSBNet library
* (C) 2010 Thomas Bleeker (www.madwizard.org)
*
* Licensed under the MIT license, see license.txt or:
* http://www.opensource.org/licenses/mit-license.php
*/
/* NOTE: Parts of the code in this file are based on the work of Jan Axelson
* See http://www.lvr.com/winusb.htm for more information
*/
using System;
using System.Runtime.InteropServices;
namespace MadWizard.WinUSBNet.API
{
/// <summary>
/// API declarations relating to device management (SetupDixxx and
/// RegisterDeviceNotification functions).
/// </summary>
internal static partial class DeviceManagement
{
// from dbt.h
internal const Int32 DBT_DEVICEARRIVAL = 0X8000;
internal const Int32 DBT_DEVICEREMOVECOMPLETE = 0X8004;
internal const Int32 DBT_QUERYCHANGECONFIG = 0x0017;
private const Int32 DBT_DEVTYP_DEVICEINTERFACE = 5;
private const Int32 DBT_DEVTYP_VOLUME = 2; // drive type is logical volume
private const Int32 DBT_DEVTYP_HANDLE = 6;
private const Int32 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 4;
private const Int32 DEVICE_NOTIFY_SERVICE_HANDLE = 1;
private const Int32 DEVICE_NOTIFY_WINDOW_HANDLE = 0;
internal const Int32 WM_DEVICECHANGE = 0X219;
internal const Int32 DBT_DEVNODES_CHANGED = 7;
// from setupapi.h
private const Int32 DIGCF_PRESENT = 2;
private const Int32 DIGCF_DEVICEINTERFACE = 0X10;
// Two declarations for the DEV_BROADCAST_DEVICEINTERFACE structure.
// Use this one in the call to RegisterDeviceNotification() and
// in checking dbch_devicetype in a DEV_BROADCAST_HDR structure:
[StructLayout(LayoutKind.Sequential)]
private class DEV_BROADCAST_DEVICEINTERFACE
{
internal Int32 dbcc_size;
internal Int32 dbcc_devicetype;
internal Int32 dbcc_reserved;
internal Guid dbcc_classguid;
internal Int16 dbcc_name;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private class DEV_BROADCAST_DEVICEINTERFACE_1
{
internal Int32 dbcc_size;
internal Int32 dbcc_devicetype;
internal Int32 dbcc_reserved;
internal Guid dbcc_classguid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
internal Char[] dbcc_name;
}
[StructLayout(LayoutKind.Sequential)]
public class DEV_BROADCAST_VOLUME
{
public Int32 dbcv_size;
public Int32 dbcv_devicetype;
public Int32 dbcv_reserved;
public Int32 dbcv_unitmask;
}
[StructLayout(LayoutKind.Sequential)]
private class DEV_BROADCAST_HDR
{
internal Int32 dbch_size;
internal Int32 dbch_devicetype;
internal Int32 dbch_reserved;
}
private struct SP_DEVICE_INTERFACE_DATA
{
internal Int32 cbSize;
internal Guid InterfaceClassGuid;
internal Int32 Flags;
internal IntPtr Reserved;
}
private struct SP_DEVINFO_DATA
{
internal Int32 cbSize;
internal Guid ClassGuid;
internal Int32 DevInst;
internal IntPtr Reserved;
}
// from pinvoke.net
private enum SPDRP : uint
{
SPDRP_DEVICEDESC = 0x00000000,
SPDRP_HARDWAREID = 0x00000001,
SPDRP_COMPATIBLEIDS = 0x00000002,
SPDRP_NTDEVICEPATHS = 0x00000003,
SPDRP_SERVICE = 0x00000004,
SPDRP_CONFIGURATION = 0x00000005,
SPDRP_CONFIGURATIONVECTOR = 0x00000006,
SPDRP_CLASS = 0x00000007,
SPDRP_CLASSGUID = 0x00000008,
SPDRP_DRIVER = 0x00000009,
SPDRP_CONFIGFLAGS = 0x0000000A,
SPDRP_MFG = 0x0000000B,
SPDRP_FRIENDLYNAME = 0x0000000C,
SPDRP_LOCATION_INFORMATION = 0x0000000D,
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E,
SPDRP_CAPABILITIES = 0x0000000F,
SPDRP_UI_NUMBER = 0x00000010,
SPDRP_UPPERFILTERS = 0x00000011,
SPDRP_LOWERFILTERS = 0x00000012,
SPDRP_MAXIMUM_PROPERTY = 0x00000013,
SPDRP_ENUMERATOR_NAME = 0x16,
};
// Device Property
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct DEVPROPKEY
{
public DEVPROPKEY(Guid ifmtid, UInt32 ipid)
{ fmtid = ifmtid; pid = ipid; }
public Guid fmtid;
public UInt32 pid;
}
private enum RegTypes : int
{
// incomplete list, these are just the ones used.
REG_SZ = 1,
REG_MULTI_SZ = 7
}
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, Int32 Flags);
//[DllImport("setupapi.dll", SetLastError = true)]
//internal static extern Int32 SetupDiCreateDeviceInfoList(ref System.Guid ClassGuid, Int32 hwndParent);
[DllImport("setupapi.dll", SetLastError = true)]
private static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
[DllImport("setupapi.dll", SetLastError = true)]
private static extern bool SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
[DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP Property, out int PropertyRegDataType, byte[] PropertyBuffer, uint PropertyBufferSize, out UInt32 RequiredSize);
[DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP Property, IntPtr PropertyRegDataType, IntPtr PropertyBuffer, uint PropertyBufferSize, out UInt32 RequiredSize);
[DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern unsafe bool SetupDiGetDeviceProperty(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, ref DEVPROPKEY propertyKey, out UInt32 propertyType, byte[] propertyBuffer, Int32 propertyBufferSize, out int requiredSize, UInt32 flags);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, Int32 Flags);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, ref SP_DEVINFO_DATA DeviceInfoData);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, IntPtr DeviceInfoData);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnregisterDeviceNotification(IntPtr Handle);
private const int ERROR_NO_MORE_ITEMS = 259;
private const int ERROR_INSUFFICIENT_BUFFER = 122;
}
}
+37
View File
@@ -0,0 +1,37 @@
/* WinUSBNet library
* (C) 2010 Thomas Bleeker (www.madwizard.org)
*
* Licensed under the MIT license, see license.txt or:
* http://www.opensource.org/licenses/mit-license.php
*/
/* NOTE: Parts of the code in this file are based on the work of Jan Axelson
* See http://www.lvr.com/winusb.htm for more information
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
namespace MadWizard.WinUSBNet.API
{
/// <summary>
/// API declarations relating to file I/O (and used by WinUsb).
/// </summary>
sealed internal class FileIO
{
public const Int32 FILE_ATTRIBUTE_NORMAL = 0X80;
public const Int32 FILE_FLAG_OVERLAPPED = 0X40000000;
public const Int32 FILE_SHARE_READ = 1;
public const Int32 FILE_SHARE_WRITE = 2;
public const UInt32 GENERIC_READ = 0X80000000;
public const UInt32 GENERIC_WRITE = 0X40000000;
public static readonly IntPtr INVALID_HANDLE_VALUE = new(-1);
public const Int32 OPEN_EXISTING = 3;
public const Int32 ERROR_IO_PENDING = 997;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, Int32 hTemplateFile);
}
}
+534
View File
@@ -0,0 +1,534 @@
/* WinUSBNet library
* (C) 2010 Thomas Bleeker (www.madwizard.org)
*
* Licensed under the MIT license, see license.txt or:
* http://www.opensource.org/licenses/mit-license.php
*/
/* NOTE: Parts of the code in this file are based on the work of Jan Axelson
* See http://www.lvr.com/winusb.htm for more information
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace MadWizard.WinUSBNet.API
{
/// <summary>
/// Wrapper for a WinUSB device dealing with the WinUSB and additional interface handles
/// </summary>
internal partial class WinUSBDevice : IDisposable
{
private bool _disposed = false;
private SafeFileHandle _deviceHandle;
private IntPtr _winUsbHandle = IntPtr.Zero;
private IntPtr[] _addInterfaces = null;
public WinUSBDevice()
{
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~WinUSBDevice()
{
Dispose(false);
}
private void CheckNotDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException("USB device object has been disposed.");
}
}
// TODO: check if not disposed on methods (although this is already checked by USBDevice)
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// Dispose managed resources
if (_deviceHandle?.IsInvalid == false)
{
_deviceHandle.Dispose();
}
_deviceHandle = null;
}
// Dispose unmanaged resources
FreeWinUSB();
_disposed = true;
}
private void FreeWinUSB()
{
if (_addInterfaces != null)
{
for (int i = 0; i < _addInterfaces.Length; i++)
{
WinUsb_Free(_addInterfaces[i]);
}
_addInterfaces = null;
}
if (_winUsbHandle != IntPtr.Zero)
{
WinUsb_Free(_winUsbHandle);
}
_winUsbHandle = IntPtr.Zero;
}
public USB_DEVICE_DESCRIPTOR GetDeviceDescriptor()
{
uint size = (uint)Marshal.SizeOf(typeof(USB_DEVICE_DESCRIPTOR));
bool success = WinUsb_GetDescriptor(_winUsbHandle, USB_DEVICE_DESCRIPTOR_TYPE,
0, 0, out USB_DEVICE_DESCRIPTOR deviceDesc, size, out uint transfered);
if (!success)
{
throw APIException.Win32("Failed to get USB device descriptor.");
}
if (transfered != size)
{
throw APIException.Win32("Incomplete USB device descriptor.");
}
return deviceDesc;
}
private int ReadStringDescriptor(byte index, ushort languageID, byte[] buffer)
{
bool success = WinUsb_GetDescriptor(_winUsbHandle, USB_STRING_DESCRIPTOR_TYPE,
index, languageID, buffer, (uint)buffer.Length, out uint transfered);
if (!success)
{
throw APIException.Win32("Failed to get USB string descriptor (" + index + ").");
}
if (transfered == 0)
{
throw new APIException("No data returned when reading USB descriptor.");
}
int length = buffer[0];
if (length != transfered)
{
throw new APIException("Unexpected length when reading USB descriptor.");
}
return length;
}
public ushort[] GetSupportedLanguageIDs()
{
byte[] buffer = new byte[256];
int length = ReadStringDescriptor(0, 0, buffer);
length -= 2; // Skip length byte and descriptor type
if (length < 0 || (length % 2) != 0)
{
throw new APIException("Unexpected length when reading supported languages.");
}
ushort[] langIDs = new ushort[length / 2];
Buffer.BlockCopy(buffer, 2, langIDs, 0, length);
return langIDs;
}
public string GetStringDescriptor(byte index, ushort languageID)
{
byte[] buffer = new byte[256];
int length = ReadStringDescriptor(index, languageID, buffer);
length -= 2; // Skip length byte and descriptor type
if (length < 0)
{
return null;
}
char[] chars = System.Text.Encoding.Unicode.GetChars(buffer, 2, length);
return new string(chars);
}
public int ControlTransfer(byte requestType, byte request, ushort value, ushort index, ushort length, byte[] data)
{
uint bytesReturned = 0;
WINUSB_SETUP_PACKET setupPacket;
setupPacket.RequestType = requestType;
setupPacket.Request = request;
setupPacket.Value = value;
setupPacket.Index = index;
setupPacket.Length = length;
bool success = WinUsb_ControlTransfer(_winUsbHandle, setupPacket, data, length, ref bytesReturned, IntPtr.Zero);
if (!success) // todo check bytes returned?
{
throw APIException.Win32("Control transfer on WinUSB device failed.");
}
return (int)bytesReturned;
}
public void OpenDevice(string devicePathName)
{
try
{
_deviceHandle = FileIO.CreateFile(devicePathName,
FileIO.GENERIC_WRITE | FileIO.GENERIC_READ,
FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE,
IntPtr.Zero,
FileIO.OPEN_EXISTING,
FileIO.FILE_ATTRIBUTE_NORMAL | FileIO.FILE_FLAG_OVERLAPPED,
0);
if (_deviceHandle.IsInvalid)
{
throw APIException.Win32("Failed to open WinUSB device handle.");
}
InitializeDevice();
}
catch (Exception)
{
if (_deviceHandle != null)
{
_deviceHandle.Dispose();
_deviceHandle = null;
}
FreeWinUSB();
throw;
}
}
private IntPtr InterfaceHandle(int index)
{
if (index == 0)
{
return _winUsbHandle;
}
return _addInterfaces[index - 1];
}
public int InterfaceCount
{
get
{
return 1 + ((_addInterfaces?.Length) ?? 0);
}
}
public void GetInterfaceInfo(int interfaceIndex, out USB_INTERFACE_DESCRIPTOR descriptor, out WINUSB_PIPE_INFORMATION[] pipes)
{
var pipeList = new List<WINUSB_PIPE_INFORMATION>();
bool success = WinUsb_QueryInterfaceSettings(InterfaceHandle(interfaceIndex), 0, out descriptor);
if (!success)
{
throw APIException.Win32("Failed to get WinUSB device interface descriptor.");
}
IntPtr interfaceHandle = InterfaceHandle(interfaceIndex);
for (byte pipeIdx = 0; pipeIdx < descriptor.bNumEndpoints; pipeIdx++)
{
success = WinUsb_QueryPipe(interfaceHandle, 0, pipeIdx, out WINUSB_PIPE_INFORMATION pipeInfo);
pipeList.Add(pipeInfo);
if (!success)
{
throw APIException.Win32("Failed to get WinUSB device pipe information.");
}
}
pipes = [.. pipeList];
}
private void InitializeDevice()
{
bool success = WinUsb_Initialize(_deviceHandle, ref _winUsbHandle);
if (!success)
{
throw APIException.Win32("Failed to initialize WinUSB handle. Device might not be connected.");
}
List<IntPtr> interfaces = [];
byte numAddInterfaces = 0;
byte idx = 0;
try
{
while (true)
{
IntPtr ifaceHandle = IntPtr.Zero;
success = WinUsb_GetAssociatedInterface(_winUsbHandle, idx, out ifaceHandle);
if (!success)
{
if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS)
{
break;
}
throw APIException.Win32("Failed to enumerate interfaces for WinUSB device.");
}
interfaces.Add(ifaceHandle);
idx++;
numAddInterfaces++;
}
}
finally
{
// Save interface handles (will be cleaned by Dispose)
// also in case of exception (which is why it is in finally block),
// because some handles might have already been opened and need
// to be disposed.
_addInterfaces = [.. interfaces];
}
// Bind handle (needed for overlapped I/O thread pool)
ThreadPool.BindHandle(_deviceHandle);
// TODO: bind interface handles as well? doesn't seem to be necessary
}
public void ReadPipe(int ifaceIndex, byte pipeID, byte[] buffer, int offset, int bytesToRead, out uint bytesRead)
{
bool success;
unsafe
{
fixed (byte* pBuffer = buffer)
{
//WPinternals.LogFile.Log("Start WinUSB_ReadPipe");
success = WinUsb_ReadPipe(InterfaceHandle(ifaceIndex), pipeID, pBuffer + offset, (uint)bytesToRead,
out bytesRead, IntPtr.Zero);
//WPinternals.LogFile.Log("End WinUSB_ReadPipe: " + (success ? "True" : "False"));
}
}
if (!success)
{
throw APIException.Win32("Failed to read pipe on WinUSB device.");
}
}
private unsafe void HandleOverlappedAPI(bool success, string errorMessage, NativeOverlapped* pOverlapped, USBAsyncResult result, int bytesTransfered)
{
if (!success)
{
if (Marshal.GetLastWin32Error() != FileIO.ERROR_IO_PENDING)
{
Overlapped.Unpack(pOverlapped);
Overlapped.Free(pOverlapped);
throw APIException.Win32(errorMessage);
}
}
else
{
// Immediate success!
Overlapped.Unpack(pOverlapped);
Overlapped.Free(pOverlapped);
result.OnCompletion(true, null, bytesTransfered, false);
// is the callback still called in this case?? todo
}
}
public void ReadPipeOverlapped(int ifaceIndex, byte pipeID, byte[] buffer, int offset, int bytesToRead, USBAsyncResult result)
{
Overlapped overlapped = new()
{
AsyncResult = result
};
unsafe
{
NativeOverlapped* pOverlapped = null;
uint bytesRead;
pOverlapped = overlapped.Pack(PipeIOCallback, buffer);
bool success;
// Buffer is pinned already by overlapped.Pack
fixed (byte* pBuffer = buffer)
{
success = WinUsb_ReadPipe(InterfaceHandle(ifaceIndex), pipeID, pBuffer + offset, (uint)bytesToRead,
out bytesRead, pOverlapped);
}
HandleOverlappedAPI(success, "Failed to asynchronously read pipe on WinUSB device.", pOverlapped, result, (int)bytesRead);
}
}
public void WriteOverlapped(int ifaceIndex, byte pipeID, byte[] buffer, int offset, int bytesToWrite, USBAsyncResult result)
{
Overlapped overlapped = new()
{
AsyncResult = result
};
unsafe
{
NativeOverlapped* pOverlapped = null;
uint bytesWritten;
pOverlapped = overlapped.Pack(PipeIOCallback, buffer);
bool success;
// Buffer is pinned already by overlapped.Pack
fixed (byte* pBuffer = buffer)
{
success = WinUsb_WritePipe(InterfaceHandle(ifaceIndex), pipeID, pBuffer + offset, (uint)bytesToWrite,
out bytesWritten, pOverlapped);
}
HandleOverlappedAPI(success, "Failed to asynchronously write pipe on WinUSB device.", pOverlapped, result, (int)bytesWritten);
}
}
public void ControlTransferOverlapped(byte requestType, byte request, ushort value, ushort index, ushort length, byte[] data, USBAsyncResult result)
{
uint bytesReturned = 0;
WINUSB_SETUP_PACKET setupPacket;
setupPacket.RequestType = requestType;
setupPacket.Request = request;
setupPacket.Value = value;
setupPacket.Index = index;
setupPacket.Length = length;
Overlapped overlapped = new()
{
AsyncResult = result
};
unsafe
{
NativeOverlapped* pOverlapped = null;
pOverlapped = overlapped.Pack(PipeIOCallback, data);
bool success = WinUsb_ControlTransfer(_winUsbHandle, setupPacket, data, length, ref bytesReturned, pOverlapped);
HandleOverlappedAPI(success, "Asynchronous control transfer on WinUSB device failed.", pOverlapped, result, (int)bytesReturned);
}
}
private unsafe void PipeIOCallback(uint errorCode, uint numBytes, NativeOverlapped* pOverlapped)
{
try
{
Exception error = null;
if (errorCode != 0)
{
error = APIException.Win32("Asynchronous operation on WinUSB device failed.", (int)errorCode);
}
Overlapped overlapped = Overlapped.Unpack(pOverlapped);
USBAsyncResult result = (USBAsyncResult)overlapped.AsyncResult;
Overlapped.Free(pOverlapped);
pOverlapped = null;
result.OnCompletion(false, error, (int)numBytes, true);
}
finally
{
if (pOverlapped != null)
{
Overlapped.Unpack(pOverlapped);
Overlapped.Free(pOverlapped);
}
}
}
public void AbortPipe(int ifaceIndex, byte pipeID)
{
bool success = WinUsb_AbortPipe(InterfaceHandle(ifaceIndex), pipeID);
if (!success)
{
throw APIException.Win32("Failed to abort pipe on WinUSB device.");
}
}
public void ResetPipe(int ifaceIndex, byte pipeID)
{
bool success = WinUsb_ResetPipe(InterfaceHandle(ifaceIndex), pipeID);
if (!success)
{
throw APIException.Win32("Failed to reset pipe on WinUSB device.");
}
}
public void WritePipe(int ifaceIndex, byte pipeID, byte[] buffer, int offset, int length)
{
uint bytesWritten;
bool success;
unsafe
{
fixed (byte* pBuffer = buffer)
{
//WPinternals.LogFile.Log("Start WinUSB_WritePipe");
success = WinUsb_WritePipe(InterfaceHandle(ifaceIndex), pipeID, pBuffer + offset, (uint)length,
out bytesWritten, IntPtr.Zero);
//WPinternals.LogFile.Log("End WinUSB_WritePipe: " + (success ? "True" : "False"));
}
}
if (!success || (bytesWritten != length))
{
throw APIException.Win32("Failed to write pipe on WinUSB device.");
}
}
public void FlushPipe(int ifaceIndex, byte pipeID)
{
bool success = WinUsb_FlushPipe(InterfaceHandle(ifaceIndex), pipeID);
if (!success)
{
throw APIException.Win32("Failed to flush pipe on WinUSB device.");
}
}
public void SetPipePolicy(int ifaceIndex, byte pipeID, POLICY_TYPE policyType, bool value)
{
byte byteVal = (byte)(value ? 1 : 0);
bool success = WinUsb_SetPipePolicy(InterfaceHandle(ifaceIndex), pipeID, (uint)policyType, 1, ref byteVal);
if (!success)
{
throw APIException.Win32("Failed to set WinUSB pipe policy.");
}
}
public void SetPipePolicy(int ifaceIndex, byte pipeID, POLICY_TYPE policyType, uint value)
{
bool success = WinUsb_SetPipePolicy(InterfaceHandle(ifaceIndex), pipeID, (uint)policyType, 4, ref value);
if (!success)
{
throw APIException.Win32("Failed to set WinUSB pipe policy.");
}
}
public bool GetPipePolicyBool(int ifaceIndex, byte pipeID, POLICY_TYPE policyType)
{
uint length = 1;
bool success = WinUsb_GetPipePolicy(InterfaceHandle(ifaceIndex), pipeID, (uint)policyType, ref length, out byte result);
if (!success || length != 1)
{
throw APIException.Win32("Failed to get WinUSB pipe policy.");
}
return result != 0;
}
public uint GetPipePolicyUInt(int ifaceIndex, byte pipeID, POLICY_TYPE policyType)
{
uint length = 4;
bool success = WinUsb_GetPipePolicy(InterfaceHandle(ifaceIndex), pipeID, (uint)policyType, ref length, out uint result);
if (!success || length != 4)
{
throw APIException.Win32("Failed to get WinUSB pipe policy.");
}
return result;
}
}
}
+199
View File
@@ -0,0 +1,199 @@
/* WinUSBNet library
* (C) 2010 Thomas Bleeker (www.madwizard.org)
*
* Licensed under the MIT license, see license.txt or:
* http://www.opensource.org/licenses/mit-license.php
*/
/* NOTE: Parts of the code in this file are based on the work of Jan Axelson
* See http://www.lvr.com/winusb.htm for more information
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace MadWizard.WinUSBNet.API
{
[StructLayout(LayoutKind.Sequential)]
internal struct USB_DEVICE_DESCRIPTOR
{
public byte bLength;
public byte bDescriptorType;
public ushort bcdUSB;
public byte bDeviceClass;
public byte bDeviceSubClass;
public byte bDeviceProtocol;
public byte bMaxPacketSize0;
public ushort idVendor;
public ushort idProduct;
public ushort bcdDevice;
public byte iManufacturer;
public byte iProduct;
public byte iSerialNumber;
public byte bNumConfigurations;
};
[StructLayout(LayoutKind.Sequential)]
internal struct USB_CONFIGURATION_DESCRIPTOR
{
public byte bLength;
public byte bDescriptorType;
public ushort wTotalLength;
public byte bNumInterfaces;
public byte bConfigurationValue;
public byte iConfiguration;
public byte bmAttributes;
public byte MaxPower;
}
[StructLayout(LayoutKind.Sequential)]
internal struct USB_INTERFACE_DESCRIPTOR
{
public byte bLength;
public byte bDescriptorType;
public byte bInterfaceNumber;
public byte bAlternateSetting;
public byte bNumEndpoints;
public byte bInterfaceClass;
public byte bInterfaceSubClass;
public byte bInterfaceProtocol;
public byte iInterface;
};
internal enum USBD_PIPE_TYPE : int
{
UsbdPipeTypeControl,
UsbdPipeTypeIsochronous,
UsbdPipeTypeBulk,
UsbdPipeTypeInterrupt,
}
[StructLayout(LayoutKind.Sequential)]
internal struct WINUSB_PIPE_INFORMATION
{
public USBD_PIPE_TYPE PipeType;
public byte PipeId;
public ushort MaximumPacketSize;
public byte Interval;
}
internal enum POLICY_TYPE : int
{
SHORT_PACKET_TERMINATE = 1,
AUTO_CLEAR_STALL,
PIPE_TRANSFER_TIMEOUT,
IGNORE_SHORT_PACKETS,
ALLOW_PARTIAL_READS,
AUTO_FLUSH,
RAW_IO,
}
internal partial class WinUSBDevice
{
private const UInt32 DEVICE_SPEED = 1;
private enum USB_DEVICE_SPEED : int
{
UsbLowSpeed = 1,
UsbFullSpeed,
UsbHighSpeed,
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct WINUSB_SETUP_PACKET
{
public byte RequestType;
public byte Request;
public ushort Value;
public ushort Index;
public ushort Length;
}
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, Byte[] Buffer, UInt32 BufferLength, ref UInt32 LengthTransferred, IntPtr Overlapped);
[DllImport("winusb.dll", SetLastError = true)]
private static unsafe extern bool WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, Byte[] Buffer, UInt32 BufferLength, ref UInt32 LengthTransferred, NativeOverlapped* pOverlapped);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_Free(IntPtr InterfaceHandle);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, ref IntPtr InterfaceHandle);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_QueryDeviceInformation(IntPtr InterfaceHandle, UInt32 InformationType, ref UInt32 BufferLength, out byte Buffer);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_QueryInterfaceSettings(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, out USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_QueryPipe(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, Byte PipeIndex, out WINUSB_PIPE_INFORMATION PipeInformation);
[DllImport("winusb.dll", SetLastError = true)]
private static unsafe extern bool WinUsb_ReadPipe(IntPtr InterfaceHandle, byte PipeID, byte* pBuffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);
[DllImport("winusb.dll", SetLastError = true)]
private static unsafe extern bool WinUsb_ReadPipe(IntPtr InterfaceHandle, byte PipeID, byte* pBuffer, uint BufferLength, out uint LengthTransferred, NativeOverlapped* pOverlapped);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_AbortPipe(IntPtr InterfaceHandle, byte PipeID);
// Two declarations for WinUsb_SetPipePolicy.
// Use this one when the returned Value is a Byte (all except PIPE_TRANSFER_TIMEOUT):
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_SetPipePolicy(IntPtr InterfaceHandle, Byte PipeID, UInt32 PolicyType, UInt32 ValueLength, ref byte Value);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_GetPipePolicy(IntPtr InterfaceHandle, Byte PipeID, UInt32 PolicyType, ref UInt32 ValueLength, out byte Value);
// Use this alias when the returned Value is a UInt32 (PIPE_TRANSFER_TIMEOUT only):
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_SetPipePolicy(IntPtr InterfaceHandle, Byte PipeID, UInt32 PolicyType, UInt32 ValueLength, ref UInt32 Value);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_GetPipePolicy(IntPtr InterfaceHandle, Byte PipeID, UInt32 PolicyType, ref UInt32 ValueLength, out UInt32 Value);
[DllImport("winusb.dll", SetLastError = true)]
private static unsafe extern bool WinUsb_WritePipe(IntPtr InterfaceHandle, byte PipeID, byte* pBuffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);
[DllImport("winusb.dll", SetLastError = true)]
private static unsafe extern bool WinUsb_WritePipe(IntPtr InterfaceHandle, byte PipeID, byte* pBuffer, uint BufferLength, out uint LengthTransferred, NativeOverlapped* pOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
private static unsafe extern bool CancelIo(IntPtr hFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static unsafe extern bool CancelIoEx(IntPtr hFile, NativeOverlapped* pOverlapped);
[DllImport("winusb.dll", SetLastError = true)]
private static unsafe extern bool WinUsb_ResetPipe(IntPtr InterfaceHandle, byte PipeID);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_FlushPipe(IntPtr InterfaceHandle, byte PipeID);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_GetDescriptor(IntPtr InterfaceHandle, byte DescriptorType,
byte Index, UInt16 LanguageID, byte[] Buffer, UInt32 BufferLength, out UInt32 LengthTransfered);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_GetDescriptor(IntPtr InterfaceHandle, byte DescriptorType,
byte Index, UInt16 LanguageID, out USB_DEVICE_DESCRIPTOR deviceDesc, UInt32 BufferLength, out UInt32 LengthTransfered);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_GetDescriptor(IntPtr InterfaceHandle, byte DescriptorType,
byte Index, UInt16 LanguageID, out USB_CONFIGURATION_DESCRIPTOR deviceDesc, UInt32 BufferLength, out UInt32 LengthTransfered);
[DllImport("winusb.dll", SetLastError = true)]
private static extern bool WinUsb_GetAssociatedInterface(IntPtr InterfaceHandle, byte AssociatedInterfaceIndex,
out IntPtr AssociatedInterfaceHandle);
private const int USB_DEVICE_DESCRIPTOR_TYPE = 0x01;
private const int USB_CONFIGURATION_DESCRIPTOR_TYPE = 0x02;
private const int USB_STRING_DESCRIPTOR_TYPE = 0x03;
private const int ERROR_NO_MORE_ITEMS = 259;
}
}