vs2015 C#实现usb虚拟串口自动识别和重新连接
2016-08-19 14:02
651 查看
主要接口
GetPortNum 获取虚拟串口所在的COM端口号
DeletePort 删除指定的虚拟串口
Rescan 重新扫描硬件(在DeletePort之后调用)
主要问题
1 在做DeletePort的时候,SetupDiCallClassInstaller返回false,使用GetLastError发现错误码为E0000235
已解决,将PlatformTarget改成x64.
2 DeletePort 后Rescan,COM端口号会增加,怀疑是删除不彻底
已解决,使用SetupDiCallClassInstaller代替SetupDiRemoveDevice.
public static bool Remove(int SelectedItem, IntPtr DevInfo) { bool result = false; SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA(); ; devInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); if (true == SetupDiEnumDeviceInfo(DevInfo, SelectedItem,
devInfoData)) { if (true == SetupDiCallClassInstaller(Win32.DIF_REMOVE,DevInfo, devInfoData)) { result = true; } else { uint ret = (uint)Win32.GetLastError(); Log.Show(Log.Level.Operation, "Remove Device failed(" + ret.ToString() + ")"); } } return result;
} public static bool StateChange(bool Enable, int SelectedItem, IntPtr DevInfo) { bool result = false; SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA(); ; devInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); if (true == SetupDiEnumDeviceInfo(DevInfo,
SelectedItem, devInfoData)) { SP_PROPCHANGE_PARAMS pcp = new SP_PROPCHANGE_PARAMS(); ; pcp.ClassInstallHeader.cbSize = Marshal.SizeOf(typeof(SP_CLASSINSTALL_HEADER)); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
pcp.StateChange = (Enable ? DICS_ENABLE : DICS_DISABLE); if (true == SetupDiSetClassInstallParams(DevInfo, devInfoData, pcp, Marshal.SizeOf(pcp))) { if (true == SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, devInfoData)) { result = true; } else {
uint ret = (uint)Win32.GetLastError(); Log.Show(Log.Level.Operation, "Disable Device failed(" + ret.ToString() + ")"); } } } return result; } public static String GetClassNameFromGuid(Guid guid) { String result = String.Empty; StringBuilder className = new
StringBuilder(); Int32 iRequiredSize = 0; Int32 iSize = 0; bool b = SetupDiClassNameFromGuid(ref guid, className, iSize, ref iRequiredSize); className = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = SetupDiClassNameFromGuid(ref guid, className,
iSize, ref iRequiredSize); if (true == b) { result = className.ToString(); } return result; } public static String GetClassDescriptionFromGuid(Guid guid) { String result = String.Empty; StringBuilder classDesc = new StringBuilder(0); Int32 iRequiredSize =
0; Int32 iSize = 0; bool b = SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize); classDesc = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize); if (true
== b) { result = classDesc.ToString(); } return result; } public static String GetDeviceInstanceId(IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData) { String result = String.Empty; StringBuilder id = new StringBuilder(0); Int32 iRequiredSize = 0; Int32
iSize = 0; bool b = SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfoData, id, iSize, ref iRequiredSize); id = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfoData, id, iSize, ref iRequiredSize);
if (true == b) { result = id.ToString(); } return result; } } #endregion #region setupapi.dll elements used by Rescan [DllImport("setupapi.dll", SetLastError = true)] static extern int CM_Locate_DevNode_Ex(ref UInt32 pdnDevInst, string pDeviceID, int ulFlags,
IntPtr hMachine); [DllImport("setupapi.dll")] static extern UInt32 CM_Reenumerate_DevNode_Ex(UInt32 dnDevInst, UInt32 ulFlags, IntPtr hMachine); const uint CR_SUCCESS = 0x00000000; #endregion }
GetPortNum 获取虚拟串口所在的COM端口号
DeletePort 删除指定的虚拟串口
Rescan 重新扫描硬件(在DeletePort之后调用)
主要问题
1 在做DeletePort的时候,SetupDiCallClassInstaller返回false,使用GetLastError发现错误码为E0000235
已解决,将PlatformTarget改成x64.
2 DeletePort 后Rescan,COM端口号会增加,怀疑是删除不彻底
已解决,使用SetupDiCallClassInstaller代替SetupDiRemoveDevice.
public class DevManager { /* 自动查找VID/PID匹配的USB设备当作Virutal COM Port口 输入值: 字符串,如VID_0483&PID_5740 返回值: 0 - 没有找到对应设备 */ public static int GetPortNum(String vid_pid) { ManagementObjectCollection USBControllerDeviceCollection = new ManagementObjectSearcher("SELECT * FROM Win32_USBControllerDevice").Get(); if (USBControllerDeviceCollection != null) { foreach (ManagementObject USBControllerDevice in USBControllerDeviceCollection) { String Dependent = (USBControllerDevice["Dependent"] as String).Split(new Char[] { '=' })[1]; if (Dependent.Contains(vid_pid)) { ManagementObjectCollection PnPEntityCollection = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE DeviceID=" + Dependent).Get(); if (PnPEntityCollection != null) { foreach (ManagementObject Entity in PnPEntityCollection) { String DevName = Entity["Name"] as String;// 设备名称 String PortNum = Regex.Replace(DevName, @"[^\d.\d]", ""); return Convert.ToInt32(PortNum); } } } } } return -1; } /* 删除指定的usb虚拟串口 输入值: 设备管理器下的设备名称,不包括后面的(COMXX) 返回值: 成功/失败 */ /*!!!BUG: 删除port后重新扫描,port number会加一;插拔或者通过设备管理器Uninstall port没有这个问题。!!!*/ public static bool DeletePort(String portName = null) { bool ret = false; Guid classGuid = Guid.Empty; IntPtr hDevInfo = Win32.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, Win32.DIGCF_ALLCLASSES | Win32.DIGCF_PRESENT); if (hDevInfo.ToInt32() == Win32.INVALID_HANDLE_VALUE) { Console.WriteLine("访问硬件设备失败"); } else { int i = 0; int selected = 0; StringBuilder deviceName = new StringBuilder(); deviceName.Capacity = Win32.MAX_DEV_LEN; do { SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA(); StringBuilder _DeviceName = new StringBuilder(""); _DeviceName.Capacity = 1000; devInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); devInfoData.classGuid = Guid.Empty; devInfoData.devInst = 0; devInfoData.reserved = IntPtr.Zero; bool result = Win32.SetupDiEnumDeviceInfo(hDevInfo, i, devInfoData); if (false == result) { break; } Win32.SetupDiGetDeviceRegistryProperty(hDevInfo, devInfoData, 0, 0, _DeviceName, (uint)_DeviceName.Capacity, IntPtr.Zero); if (_DeviceName.ToString().Equals(portName)) { Log.Show(Log.Level.Operation, _DeviceName.ToString() + ":" + Win32.GetDeviceInstanceId(hDevInfo, devInfoData).ToString()); selected = i; } ++i; } while (true); ret = Win32.Remove(selected, hDevInfo); } Win32.SetupDiDestroyDeviceInfoList(hDevInfo); return ret; } /* 重新扫描硬件 输入值: 无 返回值: 成功/失败 */ public static bool Rescan() { UInt32 devRoot = 0; if (CM_Locate_DevNode_Ex(ref devRoot, null, 0, IntPtr.Zero) != CR_SUCCESS) { return false; } if (CM_Reenumerate_DevNode_Ex(devRoot, 0, IntPtr.Zero) != CR_SUCCESS) { return false; } return true; } public static bool DisablePort(String portName = null) { bool ret = false; Guid classGuid = Guid.Empty; IntPtr hDevInfo = Win32.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, Win32.DIGCF_ALLCLASSES | Win32.DIGCF_PRESENT); if (hDevInfo.ToInt32() == Win32.INVALID_HANDLE_VALUE) { Console.WriteLine("访问硬件设备失败"); } else { int i = 0; int selected = 0; StringBuilder deviceName = new StringBuilder(); deviceName.Capacity = Win32.MAX_DEV_LEN; do { SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA(); StringBuilder _DeviceName = new StringBuilder(""); _DeviceName.Capacity = 1000; devInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); devInfoData.classGuid = Guid.Empty; devInfoData.devInst = 0; devInfoData.reserved = IntPtr.Zero; bool result = Win32.SetupDiEnumDeviceInfo(hDevInfo, i, devInfoData); if (false == result) { break; } Win32.SetupDiGetDeviceRegistryProperty(hDevInfo, devInfoData, 0, 0, _DeviceName, (uint)_DeviceName.Capacity, IntPtr.Zero); if (_DeviceName.ToString().Equals("USB Serial Port")) { Log.Show(Log.Level.Operation, _DeviceName.ToString()); selected = i; } ++i; } while (true); ret = Win32.StateChange(false, selected, hDevInfo); } Win32.SetupDiDestroyDeviceInfoList(hDevInfo); return ret; } #region setupapi.dll elements [StructLayout(LayoutKind.Sequential)] public struct SP_BROADCAST_HANDLE { public int dbch_size; public int dbch_devicetype; public int dbch_reserved; public IntPtr dbch_handle; public IntPtr dbch_hdevnotify; public Guid dbch_eventguid; public long dbch_nameoffset; public byte dbch_data; public byte dbch_data1; } [StructLayout(LayoutKind.Sequential)] public class DEV_BROADCAST_DEVICEINTERFACE { public int dbcc_size; public int dbcc_devicetype; public int dbcc_reserved; } [StructLayout(LayoutKind.Sequential)] public class SP_DEVINFO_DATA { public int cbSize; public Guid classGuid; public int devInst; public IntPtr reserved; }; [StructLayout(LayoutKind.Sequential)] public class SP_DEVINSTALL_PARAMS { public int cbSize; public int Flags; public int FlagsEx; public IntPtr hwndParent; public IntPtr InstallMsgHandler; public IntPtr InstallMsgHandlerContext; public IntPtr FileQueue; public IntPtr ClassInstallReserved; public int Reserved; [MarshalAs(UnmanagedType.LPTStr)] public string DriverPath; }; [StructLayout(LayoutKind.Sequential)] public class SP_PROPCHANGE_PARAMS { public SP_CLASSINSTALL_HEADER ClassInstallHeader = new SP_CLASSINSTALL_HEADER(); public int StateChange; public int Scope; public int HwProfile; }; [StructLayout(LayoutKind.Sequential)] public class SP_CLASSINSTALL_HEADER { public int cbSize; public int InstallFunction; }; public class Win32 { [DllImport("kernel32.dll")] public static extern uint GetLastError(); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, DEV_BROADCAST_DEVICEINTERFACE NotificationFilter, UInt32 Flags); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern UInt32 UnregisterDeviceNotification(IntPtr hHandle); [DllImport("setupapi.dll", SetLastError = true)] public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPStr)]String Enumerator, IntPtr hwndParent, Int32 Flags); [DllImport("setupapi.dll")] public static extern IntPtr SetupDiGetClassDevsEx(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPStr)]String Enumerator, IntPtr hwndParent, Int32 Flags, IntPtr DeviceInfoSet, [MarshalAs(UnmanagedType.LPStr)]String MachineName, IntPtr Reserved); [DllImport("setupapi.dll", SetLastError = true)] public static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr lpInfoSet); [DllImport("setupapi.dll", SetLastError = true)] public static extern Boolean SetupDiEnumDeviceInfo(IntPtr lpInfoSet, Int32 dwIndex, SP_DEVINFO_DATA devInfoData); [DllImport("setupapi.dll", SetLastError = true)] public static extern Boolean SetupDiGetDeviceRegistryProperty(IntPtr lpInfoSet, SP_DEVINFO_DATA DeviceInfoData, UInt32 Property, UInt32 PropertyRegDataType, StringBuilder PropertyBuffer, UInt32 PropertyBufferSize, IntPtr RequiredSize); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern Boolean SetupDiSetClassInstallParams(IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData, SP_PROPCHANGE_PARAMS ClassInstallParams, int ClassInstallParamsSize); [DllImport("setupapi.dll", CharSet = CharSet.Auto)] public static extern Boolean SetupDiCallClassInstaller(UInt32 InstallFunction, IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData); [DllImport("setupapi.dll", CharSet = CharSet.Auto)] public static extern Boolean SetupDiRemoveDevice(IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData); [DllImport("setupapi.dll", CharSet = CharSet.Auto)] public static extern Boolean SetupDiClassNameFromGuid(ref Guid ClassGuid, StringBuilder className, Int32 ClassNameSize, ref Int32 RequiredSize); [DllImport("setupapi.dll", CharSet = CharSet.Auto)] public static extern Boolean SetupDiGetClassDescription(ref Guid ClassGuid, StringBuilder classDescription, Int32 ClassDescriptionSize, ref Int32 RequiredSize); [DllImport("setupapi.dll", CharSet = CharSet.Auto)] public static extern Boolean SetupDiGetDeviceInstanceId(IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData, StringBuilder DeviceInstanceId, Int32 DeviceInstanceIdSize, ref Int32 RequiredSize); [DllImport("setupapi.dll", SetLastError = true)] public static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData, int Property, uint PropertyRegDataType, StringBuilder PropertyBuffer, uint PropertyBufferSize, IntPtr RequiredSize); public const int DIGCF_ALLCLASSES = (0x00000004); public const int DIGCF_PRESENT = (0x00000002); public const int INVALID_HANDLE_VALUE = -1; public const int SPDRP_DEVICEDESC = (0x00000000); public const int MAX_DEV_LEN = 200; public const int DEVICE_NOTIFY_WINDOW_HANDLE = (0x00000000); public const int DEVICE_NOTIFY_SERVICE_HANDLE = (0x00000001); public const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = (0x00000004); public const int DBT_DEVTYP_DEVICEINTERFACE = (0x00000005); public const int DBT_DEVNODES_CHANGED = (0x0007); public const int WM_DEVICECHANGE = (0x0219); <pre code_snippet_id="1839989" snippet_file_name="blog_20160819_1_8546058" name="code" class="csharp"> public const int DIF_REMOVE = (0x00000005);public const int DIF_PROPERTYCHANGE = (0x00000012); public const int DICS_FLAG_GLOBAL = (0x00000001); public const int DICS_FLAG_CONFIGSPECIFIC = (0x00000002); public const int DICS_ENABLE = (0x00000001); public const int DICS_DISABLE = (0x00000002);
public static bool Remove(int SelectedItem, IntPtr DevInfo) { bool result = false; SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA(); ; devInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); if (true == SetupDiEnumDeviceInfo(DevInfo, SelectedItem,
devInfoData)) { if (true == SetupDiCallClassInstaller(Win32.DIF_REMOVE,DevInfo, devInfoData)) { result = true; } else { uint ret = (uint)Win32.GetLastError(); Log.Show(Log.Level.Operation, "Remove Device failed(" + ret.ToString() + ")"); } } return result;
} public static bool StateChange(bool Enable, int SelectedItem, IntPtr DevInfo) { bool result = false; SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA(); ; devInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); if (true == SetupDiEnumDeviceInfo(DevInfo,
SelectedItem, devInfoData)) { SP_PROPCHANGE_PARAMS pcp = new SP_PROPCHANGE_PARAMS(); ; pcp.ClassInstallHeader.cbSize = Marshal.SizeOf(typeof(SP_CLASSINSTALL_HEADER)); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
pcp.StateChange = (Enable ? DICS_ENABLE : DICS_DISABLE); if (true == SetupDiSetClassInstallParams(DevInfo, devInfoData, pcp, Marshal.SizeOf(pcp))) { if (true == SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, devInfoData)) { result = true; } else {
uint ret = (uint)Win32.GetLastError(); Log.Show(Log.Level.Operation, "Disable Device failed(" + ret.ToString() + ")"); } } } return result; } public static String GetClassNameFromGuid(Guid guid) { String result = String.Empty; StringBuilder className = new
StringBuilder(); Int32 iRequiredSize = 0; Int32 iSize = 0; bool b = SetupDiClassNameFromGuid(ref guid, className, iSize, ref iRequiredSize); className = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = SetupDiClassNameFromGuid(ref guid, className,
iSize, ref iRequiredSize); if (true == b) { result = className.ToString(); } return result; } public static String GetClassDescriptionFromGuid(Guid guid) { String result = String.Empty; StringBuilder classDesc = new StringBuilder(0); Int32 iRequiredSize =
0; Int32 iSize = 0; bool b = SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize); classDesc = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize); if (true
== b) { result = classDesc.ToString(); } return result; } public static String GetDeviceInstanceId(IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData) { String result = String.Empty; StringBuilder id = new StringBuilder(0); Int32 iRequiredSize = 0; Int32
iSize = 0; bool b = SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfoData, id, iSize, ref iRequiredSize); id = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfoData, id, iSize, ref iRequiredSize);
if (true == b) { result = id.ToString(); } return result; } } #endregion #region setupapi.dll elements used by Rescan [DllImport("setupapi.dll", SetLastError = true)] static extern int CM_Locate_DevNode_Ex(ref UInt32 pdnDevInst, string pDeviceID, int ulFlags,
IntPtr hMachine); [DllImport("setupapi.dll")] static extern UInt32 CM_Reenumerate_DevNode_Ex(UInt32 dnDevInst, UInt32 ulFlags, IntPtr hMachine); const uint CR_SUCCESS = 0x00000000; #endregion }
public const int DIF_PROPERTYCHANGE = (0x00000012);
相关文章推荐
- C#winform treeview连接数据库后自动识别主键并显示出来
- VS2015 C#6.0 中的没有实现/支持的特性
- C#实现自动识别URL网址的方法
- C#(VS10)调用HALCON12----实现数字识别
- 在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
- 用C#和vs2015编写了一个简单音乐播放器,实现功能,多条音乐导入,播放、暂停、上下曲。采用vs2105自带的一个播放器控件
- vs2015 C#连接mysql
- 自动识别USB端口连接信息
- 在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
- C#实现软件关闭后重新自动启动
- 【vs2015】Windows NT实现系统版本识别
- 在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
- C#中重新定义Console实现自动保存输出到文件
- 在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
- VS2015中C#连接Oracle数据库
- 在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
- C# Winform应用程序调用Microsoft RDP client control实现远程连接(VS2013)
- VMware无法识别USB设备的解决方法 以及 从虚拟机中断开USB设备,使其重新连接到windows主机上
- 【VS2015】c++实现windows系统版本、类型、语言识别
- C#实现web信息自动抓取