Mercurial > hg > ucis.core
diff USBLib/Windows/Devices/DeviceNode.cs @ 21:dcfec2be27c9
Added USBLib
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 15 Apr 2013 01:04:59 +0200 |
parents | |
children | 556b4fb511bd |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Windows/Devices/DeviceNode.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Win32; +using UCIS.USBLib.Internal.Windows; + +namespace UCIS.HWLib.Windows.Devices { + public class CMException : Exception { + internal CMException(CR result, String method) + : base(method + " returned " + result.ToString()) { + } + internal static void Throw(CR result, String method) { + if (result == CR.SUCCESS) return; + throw new CMException(result, method); + } + } + public class DeviceNode { + public static DeviceNode Root { + get { + UInt32 node; + CR ret = SetupApi.CM_Locate_DevNode(out node, null, 0); + CMException.Throw(ret, "CM_Locate_DevNode"); + return new DeviceNode(node); + } + } + public static DeviceNode GetDevice(String deviceID) { + UInt32 node; + CR ret = SetupApi.CM_Locate_DevNode(out node, deviceID, 0); + CMException.Throw(ret, "CM_Locate_DevNode"); + return new DeviceNode(node); + } + private static IList<DeviceNode> GetDevicesInSet(SafeDeviceInfoSetHandle dis) { + List<DeviceNode> list = new List<DeviceNode>(); + if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + for (int index = 0; ; index++) { + if (!SetupApi.SetupDiEnumDeviceInfo(dis, index, ref dd)) break; + list.Add(new DeviceNode(dd.DevInst)); + } + return list; + } + public static IList<DeviceNode> GetDevices() { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, null, IntPtr.Zero, DICFG.PRESENT | DICFG.ALLCLASSES)) { + return GetDevicesInSet(dis); + } + } + public static IList<DeviceNode> GetDevices(Guid classGuid) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(ref classGuid, null, IntPtr.Zero, DICFG.PRESENT | DICFG.DEVICEINTERFACE)) { + return GetDevicesInSet(dis); + } + } + public static IList<DeviceNode> GetDevices(String enumerator) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, enumerator, IntPtr.Zero, DICFG.PRESENT | DICFG.ALLCLASSES)) { + //using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, enumerator, IntPtr.Zero, DICFG.ALLCLASSES | DICFG.DEVICEINTERFACE)) { + return GetDevicesInSet(dis); + } + } + + public UInt32 DevInst { get; private set; } + private String _DeviceID = null; + internal DeviceNode(UInt32 node) { + DevInst = node; + } + public String DeviceID { + get { + if (_DeviceID == null) { + uint deviceidlen; + CR ret = SetupApi.CM_Get_Device_ID_Size(out deviceidlen, DevInst, 0); + CMException.Throw(ret, "CM_Get_Device_ID_Size"); + StringBuilder deviceid = new StringBuilder((int)deviceidlen); + ret = SetupApi.CM_Get_Device_ID(DevInst, deviceid, deviceid.MaxCapacity, 0); + CMException.Throw(ret, "CM_Get_Device_ID"); + _DeviceID = deviceid.ToString(); + } + return _DeviceID; + } + } + public Byte[] GetProperty(SPDRP property) { + 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; + //throw new Win32Exception(Marshal.GetLastWin32Error()); + RegistryValueKind propertyType; + byte[] propBuffer = new byte[256]; + int requiredSize; + if (!SetupApi.SetupDiGetDeviceRegistryProperty(dis, ref dd, property, out propertyType, propBuffer, propBuffer.Length, out requiredSize)) + return null; + if (requiredSize > propBuffer.Length) { + propBuffer = new Byte[requiredSize]; + if (!SetupApi.SetupDiGetDeviceRegistryProperty(dis, ref dd, property, out propertyType, propBuffer, propBuffer.Length, out requiredSize)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + if (requiredSize < propBuffer.Length) Array.Resize(ref propBuffer, requiredSize); + return propBuffer; + } + } + public String GetPropertyString(SPDRP property) { + Byte[] buffer = GetProperty(property); + if (buffer == null) return null; + return SetupApi.GetAsString(buffer, buffer.Length); + } + public Byte[] GetProperty(CMRDP property) { + uint proplength = 0; + uint proptype; + CR ret = SetupApi.CM_Get_DevNode_Registry_Property(DevInst, property, out proptype, null, ref proplength, 0); + if (ret == CR.NO_SUCH_VALUE) return null; + if (ret != CR.BUFFER_SMALL) CMException.Throw(ret, "CM_Get_DevNode_Registry_Property"); + Byte[] propbuffer = new Byte[proplength]; + ret = SetupApi.CM_Get_DevNode_Registry_Property(DevInst, property, out proptype, propbuffer, ref proplength, 0); + CMException.Throw(ret, "CM_Get_DevNode_Registry_Property"); + if (propbuffer.Length > proplength) Array.Resize(ref propbuffer, (int)proplength); + return propbuffer; + } + public String GetPropertyString(CMRDP property) { + Byte[] buffer = GetProperty(property); + if (buffer == null) return null; + return SetupApi.GetAsString(buffer, buffer.Length); + } + public String[] GetPropertyStringArray(CMRDP property) { + Byte[] buffer = GetProperty(property); + if (buffer == null) return null; + return SetupApi.GetAsStringArray(buffer, buffer.Length); + } + + 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()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + if (!SetupApi.SetupDiEnumDeviceInfo(dis, 0, ref dd)) + return null; + //throw new Win32Exception(Marshal.GetLastWin32Error()); + RegistryValueKind propertyType; + byte[] propBuffer = new byte[256]; + int requiredSize; + if (!SetupApi.SetupDiGetCustomDeviceProperty(dis, ref dd, name, DICUSTOMDEVPROP.NONE, out propertyType, propBuffer, propBuffer.Length, out requiredSize)) + return null; + if (requiredSize > propBuffer.Length) { + propBuffer = new Byte[requiredSize]; + if (!SetupApi.SetupDiGetCustomDeviceProperty(dis, ref dd, name, DICUSTOMDEVPROP.NONE, out propertyType, propBuffer, propBuffer.Length, out requiredSize)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + if (requiredSize < propBuffer.Length) Array.Resize(ref propBuffer, requiredSize); + return propBuffer; + } + } + public String GetCustomPropertyString(String name) { + Byte[] buffer = GetCustomProperty(name); + if (buffer == null) return null; + return SetupApi.GetAsString(buffer, buffer.Length); + } + public String[] GetCustomPropertyStringArray(String name) { + Byte[] buffer = GetCustomProperty(name); + if (buffer == null) return null; + return SetupApi.GetAsStringArray(buffer, buffer.Length); + } + + public String DeviceDescription { get { return GetPropertyString(CMRDP.DEVICEDESC); } } + public String[] HardwareID { get { return GetPropertyStringArray(CMRDP.HARDWAREID); } } + public String[] CompatibleIDs { get { return GetPropertyStringArray(CMRDP.COMPATIBLEIDS); } } + public String Service { get { return GetPropertyString(CMRDP.SERVICE); } } + public String Class { get { return GetPropertyString(CMRDP.CLASS); } } + public String ClassGuid { get { return GetPropertyString(CMRDP.CLASSGUID); } } + public String DriverKey { get { return GetPropertyString(CMRDP.DRIVER); } } + public String Manufacturer { get { return GetPropertyString(CMRDP.MFG); } } + public String FriendlyName { get { return GetPropertyString(CMRDP.FRIENDLYNAME); } } + public String LocationInformation { get { return GetPropertyString(CMRDP.LOCATION_INFORMATION); } } + public String PhysicalDeviceObjectName { get { return GetPropertyString(CMRDP.PHYSICAL_DEVICE_OBJECT_NAME); } } + public Guid? BusTypeGuid { get { return SetupApi.GetAsGuid(GetProperty(CMRDP.BUSTYPEGUID)); } } + public Int32? BusNumber { get { return SetupApi.GetAsInt32(GetProperty(CMRDP.BUSNUMBER)); } } + public String EnumeratorName { get { return GetPropertyString(CMRDP.ENUMERATOR_NAME); } } + + public String[] GetInterfaces(String classGuid) { + return GetInterfaces(new Guid(classGuid)); + } + public String[] GetInterfaces(Guid classGuid) { + uint len; + CR ret = SetupApi.CM_Get_Device_Interface_List_Size(out len, ref classGuid, DeviceID, 0); + CMException.Throw(ret, "CM_Get_Device_Interface_List_Size"); + if (len <= 1) return null; + Byte[] buffer = new Byte[2 * len]; + ret = SetupApi.CM_Get_Device_Interface_List(ref classGuid, DeviceID, buffer, len, 0); + CMException.Throw(ret, "CM_Get_Device_Interface_List"); + return SetupApi.GetAsStringArray(buffer, 2 * (int)len); + } + public Boolean SupportsInterface(Guid classGuid) { + uint len; + CR ret = SetupApi.CM_Get_Device_Interface_List_Size(out len, ref classGuid, DeviceID, 0); + CMException.Throw(ret, "CM_Get_Device_Interface_List_Size"); + return len > 2; + } + + public IList<DeviceNode> GetChildren() { + UInt32 child; + CR ret = SetupApi.CM_Get_Child(out child, DevInst, 0); + if (ret == CR.NO_SUCH_DEVNODE) return null; + CMException.Throw(ret, "CM_Get_Child"); + List<DeviceNode> list = new List<DeviceNode>(); + while (true) { + list.Add(new DeviceNode(child)); + ret = SetupApi.CM_Get_Sibling(out child, child, 0); + if (ret == CR.NO_SUCH_DEVNODE) break; + CMException.Throw(ret, "CM_Get_Sibling"); + } + return list; + } + + public DeviceNode GetParent() { + UInt32 node; + CR ret = SetupApi.CM_Get_Parent(out node, DevInst, 0); + if (ret == CR.NO_SUCH_DEVNODE) return null; + CMException.Throw(ret, "CM_Get_Parent"); + return new DeviceNode(node); + } + + public Boolean Present { + get { + UInt32 status, problem; + CR ret = SetupApi.CM_Get_DevNode_Status(out status, out problem, DevInst, 0); + if (ret == CR.NO_SUCH_DEVNODE) return false; + CMException.Throw(ret, "CM_Get_DevNode_Status"); + if (status == 25174016) return false; + return true; + } + } + + public override bool Equals(object obj) { + DeviceNode other = obj as DeviceNode; + if (ReferenceEquals(other, null)) return false; + return DevInst == other.DevInst; + } + public override int GetHashCode() { + return (int)DevInst; + } + public static Boolean operator ==(DeviceNode x, DeviceNode y) { + if (ReferenceEquals(x, y)) return true; + if (ReferenceEquals(x, null)) return false; + if (ReferenceEquals(y, null)) return false; + return x.DevInst == y.DevInst; + } + public static Boolean operator !=(DeviceNode x, DeviceNode y) { + return !(x == y); + } + + public void SetEnabled(Boolean enabled) { + 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()); + SP_PROPCHANGE_PARAMS PropChangeParams = new SP_PROPCHANGE_PARAMS(); + PropChangeParams.ClassInstallHeader.cbSize = Marshal.SizeOf(PropChangeParams.ClassInstallHeader); + PropChangeParams.ClassInstallHeader.InstallFunction = UsbApi.DIF_PROPERTYCHANGE; + PropChangeParams.Scope = UsbApi.DICS_FLAG_GLOBAL; // or use DICS_FLAG_CONFIGSPECIFIC to limit to current HW profile + PropChangeParams.HwProfile = 0; //Current hardware profile + PropChangeParams.StateChange = enabled ? UsbApi.DICS_ENABLE : UsbApi.DICS_DISABLE; + if (!SetupApi.SetupDiSetClassInstallParams(dis, ref dd, ref PropChangeParams.ClassInstallHeader, Marshal.SizeOf(PropChangeParams))) + throw new Win32Exception(Marshal.GetLastWin32Error()); + if (!SetupApi.SetupDiCallClassInstaller(UsbApi.DIF_PROPERTYCHANGE, dis, ref dd)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + } +}