どのように捉えるかというシリアルポートが消えるので、usbケーブルが抜

StackOverflow https://stackoverflow.com/questions/286184

  •  08-07-2019
  •  | 
  •  

質問

私c#などをサポートプログラムで、シリアルポートです。この問題の場合、エンドユーザー unplugsのusbケーブルおよびその装置が消えます。このプログラムがクラッシュしたい報告書のエラーがmicrosoft.

ですがこのイベントおよびシャットダウンしてく優雅に?

役に立ちましたか?

解決

利用できるWMI(Windows用)を通知を受け取りにUSBイベント。私はかなり異なるものでした二年前に、モニタリングのための差し込むと抜き差しで、特定の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.ネットコーディレクトリ.

編集 この詳細情報は、イベントハンドラで約ようになります:

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などのポートイベントをトラップし、WM_DEVICECHANGEメッセージをキャッチすることです。

プログラムがクラッシュする理由がわかりません。スタックを見て、これがどこで発生しているかを確認する必要があります。

レジストリ内:
HKEY_LOCAL_MACHINE \ HARDWARE \ DEVICEMAP \ SERIALCOMM
ポートの実際のリストです。ポートが消えた場合は、プラグが抜かれていることを意味します。

実際の例:(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デバイスの type をキャプチャする例を追加したいと思います。

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でデバッグモードでアプリを実行し、エラーをシミュレートすることができます。例外がスローされた場合、問題が最も顕著になる場所を特定できます。そこから、おそらくより具体的な解決策を見つけることができます。

tryステートメントが例外をキャッチしていない場合は、Microsoftがダンプを検査することを期待しましょう。

デバイスの到着と削除の通知を許可するSetupDi APIがいくつかあります(しばらくの間だと思いますが)読み取りまたは書き込み操作。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top