USB 케이블이 플러그를 뽑아서 사라지는 직렬 포트를 캡처하는 방법
-
08-07-2019 - |
문제
AC# Winforms 프로그램이 있으며 직렬 포트를 열어줍니다. 최종 사용자가 USB 케이블을 풀고 장치가 사라지면 문제가 발생합니다. 그 후 프로그램이 충돌하여 오류를 Microsoft에보고하고 싶습니다.
이 이벤트를 포착하고 우아하게 종료하는 방법이 있습니까?
해결책
WMI (Windows Management Instrumentation)를 사용하여 USB 이벤트에 대한 알림을받을 수 있습니다. 2 년 전 특정 USB 장치의 막힘 및 플러그를 모니터링하면서 정확히 수행했습니다.
불행히도 코드는 전 고용주와 함께 있지만 한 가지 예를 찾았습니다. bytes.com:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Management;
class UsbWatcher
{
public static void Main()
{
WMIEvent wEvent = new WMIEvent();
ManagementEventWatcher watcher = null;
WqlEventQuery query;
ManagementOperationObserver observer = new ManagementOperationObserver();
ManagementScope scope = new ManagementScope("root\\CIMV2");
scope.Options.EnablePrivileges = true;
try
{
query = new WqlEventQuery();
query.EventClassName = "__InstanceCreationEvent";
query.WithinInterval = new TimeSpan(0,0,10);
query.Condition = @"TargetInstance ISA 'Win32_USBControllerDevice' ";
watcher = new ManagementEventWatcher(scope, query);
watcher.EventArrived
+= new EventArrivedEventHandler(wEvent.UsbEventArrived);
watcher.Start();
}
catch (Exception e)
{
//handle exception
}
}
E 특정 장치에 대해서만 이벤트를 수신하도록 쿼리를 수정했는지 또는 이벤트 핸들러의 다른 장치에서 이벤트를 걸러 냈는지 기억이 나지 않습니다. 자세한 내용은 MSDN WMI .NET 코드 디렉토리.
편집하다이벤트 핸들러에 대한 더 많은 정보를 찾았습니다. 대략적으로 다음과 같습니다.
protected virtual void OnUsbConnected(object Sender, EventArrivedEventArgs Arguments)
{
PropertyData TargetInstanceData = Arguments.NewEvent.Properties["TargetInstance"];
if (TargetInstanceData != null)
{
ManagementBaseObject TargetInstanceObject = (ManagementBaseObject)TargetInstanceData.Value;
if (TargetInstanceObject != null)
{
string dependent = TargetInstanceObject.Properties["Dependent"].Value.ToString();
string deviceId = dependent.Substring(dependent.IndexOf("DeviceID=") + 10);
// device id string taken from windows device manager
if (deviceId = "USB\\\\VID_0403&PID_6001\\\\12345678\"")
{
// Device is connected
}
}
}
}
그래도 예외 처리를 추가 할 수도 있습니다.
다른 팁
예, 이벤트를 포착하는 방법이 있습니다. 불행히도 장치가 제거 된 시간과 프로그램이 알림을받는 시간 사이에 긴 지연이 발생할 수 있습니다.
접근 방식은 ErrorReceived와 같은 COM 포트 이벤트를 트랩하고 WM_DEVICECHANGE 메시지를 포착하는 것입니다.
프로그램이 왜 충돌하는지 잘 모르겠습니다. 스택을 살펴보고 이것이 어디에서 일어나고 있는지 확인해야합니다.
레지스트리에서 :
hkey_local_machine Hardware devicemap serialcomm
실제 포트 목록입니다. 포트가 사라지면 플러그를 뽑았다는 것을 의미합니다.
Real example: (USB를 제거하고 레지스트리 편집기에서 F5를 누르십시오)
Windows Registry Editor Version 5.00
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM]
"Winachsf0"="COM10"
"\\Device\\mxuport0"="COM1"
"\\Device\\Serial2"="COM13"
COM10- 내 팩스 모뎀
com1- USB -MOXA USB 직렬 변환기
com13- USB- 프로파일 릭 직렬 변환기
문안 인사
이미 제공된 답변은 좋은 출발점을 제공하지만 .NET 4.5에 대한 몇 가지 작업 예제와 캡처의 예를 추가하고 싶습니다. 유형 USB 장치의.
Treb의 대답에서 그는 사용했습니다 'Win32_USBControllerDevice'
. 이는 달성하려는 내용에 따라 쿼리에 가장 적합한 조건이 될 수도 있고 아닐 수도 있습니다. Win32_usbControllerDevice의 장치 ID는 각 장치마다 고유합니다. 따라서 단일 장치를 식별하는 고유 한 ID를 찾고 있다면 바로 원하는 것입니다. 그러나 당신이 확실한 것을 찾고 있다면 유형 장치의 경우 사용할 수 있습니다 'Win32_PnPEntity'
그리고 액세스 Description
재산. 다음은 확실한 것을 얻는 예입니다 유형 설명에 의해 장치의 :
using System;
using System.ComponentModel.Composition;
using System.Management;
public class UsbDeviceMonitor
{
private ManagementEventWatcher plugInWatcher;
private ManagementEventWatcher unPlugWatcher;
private const string MyDeviceDescription = @"My Device Description";
~UsbDeviceMonitor()
{
Dispose();
}
public void Dispose()
{
if (plugInWatcher != null)
try
{
plugInWatcher.Dispose();
plugInWatcher = null;
}
catch (Exception) { }
if (unPlugWatcher == null) return;
try
{
unPlugWatcher.Dispose();
unPlugWatcher = null;
}
catch (Exception) { }
}
public void Start()
{
const string plugInSql = "SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_PnPEntity'";
const string unpluggedSql = "SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_PnPEntity'";
var scope = new ManagementScope("root\\CIMV2") {Options = {EnablePrivileges = true}};
var pluggedInQuery = new WqlEventQuery(plugInSql);
plugInWatcher = new ManagementEventWatcher(scope, pluggedInQuery);
plugInWatcher.EventArrived += HandlePluggedInEvent;
plugInWatcher.Start();
var unPluggedQuery = new WqlEventQuery(unpluggedSql);
unPlugWatcher = new ManagementEventWatcher(scope, unPluggedQuery);
unPlugWatcher.EventArrived += HandleUnPluggedEvent;
unPlugWatcher.Start();
}
private void HandleUnPluggedEvent(object sender, EventArrivedEventArgs e)
{
var description = GetDeviceDescription(e.NewEvent);
if (description.Equals(MyDeviceDescription))
// Take actions here when the device is unplugged
}
private void HandlePluggedInEvent(object sender, EventArrivedEventArgs e)
{
var description = GetDeviceDescription(e.NewEvent);
if (description.Equals(MyDeviceDescription))
// Take actions here when the device is plugged in
}
private static string GetDeviceDescription(ManagementBaseObject newEvent)
{
var targetInstanceData = newEvent.Properties["TargetInstance"];
var targetInstanceObject = (ManagementBaseObject) targetInstanceData.Value;
if (targetInstanceObject == null) return "";
var description = targetInstanceObject.Properties["Description"].Value.ToString();
return description;
}
}
SQL 문에서 사용할 수있는 클래스를 조사하는 데 유용 할 수있는 일부 링크 :
Win32 클래스 - 위의 예에서 'Win32_PnPEntity'
수업이 사용되었습니다.
WMI 시스템 클래스 - 위의 예에서 __InstanceCreationEvent
그리고 __InstanceDeletionEvent
수업이 사용되었습니다.
당신은 처리하려고 시도 할 수 있습니다 ErrorReceived
.
private void buttonStart_Click(object sender, EventArgs e)
{
port.ErrorReceived += new System.IO.Ports.SerialErrorReceivedEventHandler(port_ErrorReceived);
}
void port_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{
// TODO: handle the problem here
}
또한 진행하기 전에 포트가 존재하는지 확인할 수 있습니다. 읽기/쓰기 직전에 가끔 확인하고 싶을 수도 있습니다.
string[] ports = System.IO.Ports.SerialPort.GetPortNames();
if (ports.Contains("COM7:"))
{
// TODO: Can continue
}
else
{
// TODO: Cannot, terminate properly
}
당신은 또한 배치해야합니다 try-catch
모든 직렬 포트 작업에 대한 블록. 예상치 못한 종료를 방지하는 데 도움이됩니다.
IDE에서 디버그 모드에서 앱을 실행하고 오류를 시뮬레이션하려고 할 수 있습니다. 예외가 발생하면 문제가 가장 분명 해지는 위치를 식별 할 수 있습니다. 거기에서 아마도 더 구체적인 솔루션을 찾으려고 노력할 수 있습니다.
시도 명세서가 예외를 포착하지 않으면 Microsoft가 덤프를 검사하기를 바랍니다.
장치 도착 및 제거에 대한 조언을받을 수있는 Setupdi API가 있습니다 (시간이 오래 걸렸습니다). 그러나 제거 된 장치가 읽기 또는 읽기 중간에 있었기 때문에 이미 충돌 한 경우에는 도움이되지 않습니다. 작전을 작성하십시오.