# HG changeset patch # User Ivo Smits # Date 1380561789 -7200 # Node ID 556b4fb511bdcadee104ae27995665ddac35d2f4 # Parent 15ddb1e0e2a505e56d54489e7b37732b529dd45e Added HWLib and USBLib functions to support USB Driver Installer diff -r 15ddb1e0e2a5 -r 556b4fb511bd USBLib/Communication/WindowsUsbDeviceRegistry.cs --- a/USBLib/Communication/WindowsUsbDeviceRegistry.cs Tue Jul 16 13:16:04 2013 +0200 +++ b/USBLib/Communication/WindowsUsbDeviceRegistry.cs Mon Sep 30 19:23:09 2013 +0200 @@ -9,6 +9,29 @@ public abstract class WindowsUsbDeviceRegistry { public DeviceNode DeviceNode { get; private set; } + public static Boolean DecodeDeviceIDs(DeviceNode device, out int vendorID, out int productID, out int revision, out int interfaceID) { + String[] hwids = device.GetPropertyStringArray(CMRDP.HARDWAREID); + String hwid = null; + if (hwids == null || hwids.Length < 1 || hwids[0].Length == 0) { + hwid = device.DeviceID; + } else { + hwid = hwids[0]; + } + vendorID = productID = revision = interfaceID = -1; + foreach (String token in hwid.Split(new Char[] { '\\', '#', '&' }, StringSplitOptions.None)) { + if (token.StartsWith("VID_", StringComparison.InvariantCultureIgnoreCase)) { + if (!Int32.TryParse(token.Substring(4), NumberStyles.HexNumber, null, out vendorID)) vendorID = -1; + } else if (token.StartsWith("PID_", StringComparison.InvariantCultureIgnoreCase)) { + if (!Int32.TryParse(token.Substring(4), NumberStyles.HexNumber, null, out productID)) productID = -1; + } else if (token.StartsWith("REV_", StringComparison.InvariantCultureIgnoreCase)) { + if (!Int32.TryParse(token.Substring(4), NumberStyles.Integer, null, out revision)) revision = -1; + } else if (token.StartsWith("MI_", StringComparison.InvariantCultureIgnoreCase)) { + if (!Int32.TryParse(token.Substring(3), NumberStyles.HexNumber, null, out interfaceID)) interfaceID = -1; + } + } + return vendorID != -1 && productID != -1; + } + // Parsed out of the device ID private bool mIsDeviceIDParsed; private byte mInterfaceID; @@ -22,8 +45,6 @@ public String DeviceID { get; private set; } public String SymbolicName { get { return DevicePath; } } - private static Regex RegHardwareID = null; - protected WindowsUsbDeviceRegistry(DeviceNode device, String interfacepath) { DeviceNode = device; DeviceID = device.DeviceID; @@ -39,28 +60,12 @@ private void parseDeviceID() { if (mIsDeviceIDParsed) return; - if (RegHardwareID == null) { - RegexOptions OPTIONS = RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase; - string PATTERN = "(Vid_(?[0-9A-F]{1,4}))|(Pid_(?[0-9A-F]{1,4}))|(Rev_(?[0-9]{1,4}))|(MI_(?[0-9A-F]{1,2}))"; - RegHardwareID = new Regex(PATTERN, OPTIONS); - } - String[] HardwareIDs = DeviceNode.GetPropertyStringArray(CMRDP.HARDWAREID); - String HardwareID = null; - if (HardwareIDs == null || HardwareIDs.Length < 1 || HardwareIDs[0].Length == 0) { - HardwareID = DeviceID; - } else { - HardwareID = HardwareIDs[0]; - } - foreach (Match match in RegHardwareID.Matches(HardwareID)) { - Group group = match.Groups["Vid"]; - if (group.Success) ushort.TryParse(group.Value, NumberStyles.HexNumber, null, out mVid); - group = match.Groups["Pid"]; - if (group.Success) ushort.TryParse(group.Value, NumberStyles.HexNumber, null, out mPid); - group = match.Groups["Rev"]; - if (group.Success) ushort.TryParse(group.Value, NumberStyles.Integer, null, out mRevision); - group = match.Groups["MI"]; - if (group.Success) Byte.TryParse(group.Value, NumberStyles.HexNumber, null, out mInterfaceID); - } + int vid, pid, rev, mid; + if (!DecodeDeviceIDs(DeviceNode, out vid, out pid, out rev, out mid)) return; + mVid = (UInt16)vid; + mPid = (UInt16)pid; + mRevision = (UInt16)rev; + mInterfaceID = (Byte)mid; mIsDeviceIDParsed = true; } public int Vid { diff -r 15ddb1e0e2a5 -r 556b4fb511bd USBLib/Internal/Windows/SetupApi.cs --- a/USBLib/Internal/Windows/SetupApi.cs Tue Jul 16 13:16:04 2013 +0200 +++ b/USBLib/Internal/Windows/SetupApi.cs Mon Sep 30 19:23:09 2013 +0200 @@ -41,14 +41,21 @@ public static extern bool SetupDiGetCustomDeviceProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, string CustomPropertyName, DICUSTOMDEVPROP Flags, out RegistryValueKind PropertyRegDataType, Byte[] PropertyBuffer, int PropertyBufferSize, out int RequiredSize); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Ansi)] public static extern bool SetupDiGetDeviceInstanceIdA(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, StringBuilder DeviceInstanceId, int DeviceInstanceIdSize, out int RequiredSize); - [DllImport("setupapi.dll", CharSet = CharSet.Auto)] - public static extern bool SetupDiGetDeviceInterfacePropertyKeys(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, byte[] propKeyBuffer, int propKeyBufferElements, out int RequiredPropertyKeyCount, int Flags); [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool SetupDiGetDeviceRegistryProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP Property, out RegistryValueKind PropertyRegDataType, byte[] PropertyBuffer, int PropertyBufferSize, out int RequiredSize); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool SetupDiGetDeviceRegistryProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP iProperty, out int PropertyRegDataType, IntPtr PropertyBuffer, int PropertyBufferSize, out int RequiredSize); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool SetupDiGetDeviceRegistryProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP iProperty, out int PropertyRegDataType, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder PropertyBuffer, int PropertyBufferSize, out int RequiredSize); + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern bool SetupDiSetDeviceRegistryProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP Property, Byte[] PropertyBuffer, UInt32 PropertyBufferSize); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr SetupDiOpenDevRegKey(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, UInt32 Scope, UInt32 HwProfile, UInt32 KeyType, UInt32 samDesired); + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool SetupDiGetDeviceProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, ref DEVPROPKEY PropertyKey, out UInt32 PropertyType, Byte[] PropertyBuffer, UInt32 PropertyBufferSize, out UInt32 RequiredSize, UInt32 Flags); + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool SetupDiGetDeviceInterfacePropertyKeys(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, byte[] propKeyBuffer, int propKeyBufferElements, out int RequiredPropertyKeyCount, int Flags); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool SetupDiGetDeviceInstanceId(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, StringBuilder DeviceInstanceId, int DeviceInstanceIdSize, out int RequiredSize); @@ -84,7 +91,8 @@ public static extern CR CM_Enumerate_Classes(UInt32 ulClassIndex, out Guid ClassGuid, UInt32 ulFlags); [DllImport("setupapi.dll", CharSet = CharSet.Auto)] public static extern CR CM_Get_DevNode_Status(out UInt32 pulStatus, out UInt32 pulProblemNumber, UInt32 dnDevInst, UInt32 ulFlags); - + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Reenumerate_DevNode(UInt32 dnDevInst, UInt32 ulFlags); //public const int DIGCF_DEFAULT = 0x00000001; // only valid with DIGCF_DEVICEINTERFACE public const int DIGCF_PRESENT = 0x00000002; @@ -196,6 +204,12 @@ } } + [StructLayout(LayoutKind.Sequential)] + struct DEVPROPKEY { + public Guid fmtid; + public UInt32 pid; + } + enum CR { SUCCESS = (0x00000000), DEFAULT = (0x00000001), diff -r 15ddb1e0e2a5 -r 556b4fb511bd USBLib/Windows/Devices/DeviceNode.cs --- a/USBLib/Windows/Devices/DeviceNode.cs Tue Jul 16 13:16:04 2013 +0200 +++ b/USBLib/Windows/Devices/DeviceNode.cs Mon Sep 30 19:23:09 2013 +0200 @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Reflection; using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32; +using Microsoft.Win32.SafeHandles; using UCIS.USBLib.Internal.Windows; namespace UCIS.HWLib.Windows.Devices { @@ -52,7 +54,10 @@ } } public static IList GetDevices(String enumerator) { - using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, enumerator, IntPtr.Zero, DICFG.PRESENT | DICFG.ALLCLASSES)) { + return GetDevices(enumerator, true); + } + public static IList GetDevices(String enumerator, Boolean present) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, enumerator, IntPtr.Zero, (present ? DICFG.PRESENT : 0) | DICFG.ALLCLASSES)) { //using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, enumerator, IntPtr.Zero, DICFG.ALLCLASSES | DICFG.DEVICEINTERFACE)) { return GetDevicesInSet(dis); } @@ -126,6 +131,17 @@ return SetupApi.GetAsStringArray(buffer, buffer.Length); } + public void SetProperty(SPDRP property, Byte[] value) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, DeviceID, IntPtr.Zero, DICFG.DEVICEINTERFACE | DICFG.ALLCLASSES)) { + if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + if (!SetupApi.SetupDiEnumDeviceInfo(dis, 0, ref dd)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + if (!SetupApi.SetupDiSetDeviceRegistryProperty(dis, ref dd, property, value, (uint)value.Length)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + public Byte[] GetCustomProperty(String name) { using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, DeviceID, IntPtr.Zero, DICFG.DEVICEINTERFACE | DICFG.ALLCLASSES)) { if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); @@ -158,6 +174,63 @@ return SetupApi.GetAsStringArray(buffer, buffer.Length); } + public RegistryKey OpenRegistryKey(UInt32 scope, UInt32 hwProfile, UInt32 keyType, UInt32 samDesired) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, DeviceID, IntPtr.Zero, DICFG.DEVICEINTERFACE | DICFG.ALLCLASSES)) { + if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + if (!SetupApi.SetupDiEnumDeviceInfo(dis, 0, ref dd)) + return null; + IntPtr handle = SetupApi.SetupDiOpenDevRegKey(dis, ref dd, scope, hwProfile, keyType, samDesired); + if (handle == (IntPtr)(-1)) return null; + return RegistryKeyFromHandle(handle, true, (samDesired & (0x00000002 | 0x00000004 | 0x00000020)) != 0); + } + } + + private RegistryKey RegistryKeyFromHandle(IntPtr hKey, bool writable, bool ownsHandle) { + BindingFlags privateConstructors = BindingFlags.Instance | BindingFlags.NonPublic; + Type safeRegistryHandleType = typeof(SafeHandleZeroOrMinusOneIsInvalid).Assembly.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle"); + Type[] safeRegistryHandleCtorTypes = new Type[] { typeof(IntPtr), typeof(bool) }; + ConstructorInfo safeRegistryHandleCtorInfo = safeRegistryHandleType.GetConstructor(privateConstructors, null, safeRegistryHandleCtorTypes, null); + Object safeHandle = safeRegistryHandleCtorInfo.Invoke(new Object[] { hKey, ownsHandle }); + Type registryKeyType = typeof(RegistryKey); + Type[] registryKeyConstructorTypes = new Type[] { safeRegistryHandleType, typeof(bool) }; + ConstructorInfo registryKeyCtorInfo = registryKeyType.GetConstructor(privateConstructors, null, registryKeyConstructorTypes, null); + RegistryKey resultKey = (RegistryKey)registryKeyCtorInfo.Invoke(new Object[] { safeHandle, writable }); + return resultKey; + } + + public Byte[] GetDeviceProperty(Guid fmtid, UInt32 pid) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, DeviceID, IntPtr.Zero, DICFG.DEVICEINTERFACE | DICFG.ALLCLASSES)) { + if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + if (!SetupApi.SetupDiEnumDeviceInfo(dis, 0, ref dd)) + return null; + byte[] propBuffer = new byte[256]; + UInt32 requiredSize; + UInt32 propertyType; + DEVPROPKEY propertyKey = new DEVPROPKEY() { fmtid = fmtid, pid = pid }; + if (!SetupApi.SetupDiGetDeviceProperty(dis, ref dd, ref propertyKey, out propertyType, propBuffer, (uint)propBuffer.Length, out requiredSize, 0)) + return null; + if (requiredSize > propBuffer.Length) { + propBuffer = new Byte[requiredSize]; + if (!SetupApi.SetupDiGetDeviceProperty(dis, ref dd, ref propertyKey, out propertyType, propBuffer, (uint)propBuffer.Length, out requiredSize, 0)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + if (requiredSize < propBuffer.Length) Array.Resize(ref propBuffer, (int)requiredSize); + return propBuffer; + } + } + public String GetDevicePropertyString(Guid fmtid, UInt32 pid) { + Byte[] buffer = GetDeviceProperty(fmtid, pid); + if (buffer == null) return null; + return SetupApi.GetAsString(buffer, buffer.Length); + } + + public void Reenumerate(UInt32 flags) { + CR ret = SetupApi.CM_Reenumerate_DevNode(DevInst, flags); + CMException.Throw(ret, "CM_Reenumerate_DevNode"); + } + public String DeviceDescription { get { return GetPropertyString(CMRDP.DEVICEDESC); } } public String[] HardwareID { get { return GetPropertyStringArray(CMRDP.HARDWAREID); } } public String[] CompatibleIDs { get { return GetPropertyStringArray(CMRDP.COMPATIBLEIDS); } }