次の方法で共有


デバイスと対話する Win32 サービス

INF AddService を介してインストールされ、デバイスと対話する理想的な Win32 サービスは、ドライバーデバイスと対話するのと同様に動作します。 ドライバーはデバイスの存在に応じて読み込まれ、アンロードされます。デバイスと対話する Win32 サービスは、デバイスの存在に応じて、この同じパターンの 開始停止 に従う必要があります。

サービスは、デバイス インターフェイスが存在し、対話できるときにのみ開始し、デバイス インターフェイスが有効でなくなったときに停止する必要があります。 この設計パターンにより、望ましくない動作と未定義の動作を最小限に抑える堅牢なサービスが確保されます。 このパターンに従うようにサービスを設計する方法について説明します。

サービスのインストール

サービスをインストールするには、INF AddService ディレクティブを使用します。 これにより、サービスを作成して開始できます。

サービスをデマンド スタートする設定を追加します。 これは、StartType=0x3 (サービスをトリガー スタートする) を設定することによって達成できます。

このセクションの最後の手順では、AddTrigger ディレクティブを使用して、デバイス インターフェイスが到着したときにサービスを開始します (AddTrigger の詳細については、AddService を参照してください)。 AddTrigger の使用方法の例を次に示します。

[UserSvc_Install]
ServiceType   = 0x10 ; SERVICE_WIN32_OWN_PROCESS
StartType     = 3    ; SERVICE_DEMAND_START
ErrorControl  = 0    ; SERVICE_ERROR_IGNORE
ServiceBinary = %13%\oemsvc.exe
AddTrigger    = UserSvc_AddTrigger

[UserSvc_AddTrigger]
TriggerType = 1                           ; SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL
Action      = 1                           ; SERVICE_TRIGGER_ACTION_SERVICE_START
SubType     = %GUID_DEVINTERFACE_OSRFX2%  ; Interface class GUID
DataItem    = 2, "USB\VID_0547&PID_1002"  ; SERVICE_TRIGGER_DATA_TYPE_STRING

DataItem で指定される HardwareId は省略可能であり、通常は、ジェネリック クラス インターフェイスを使用してトリガーをより具体的なデバイスにスコープ設定する場合にのみ必要であることに注意してください。

サービス ランタイム

ランタイムの観点から、サービスの最初の手順は、デバイス インターフェイス通知の登録です。 これを実現する方法に関する規範的なガイダンスについては、「デバイス インターフェイスの到着とデバイスの削除の通知の登録」のページを参照してください。

特に、CM_Register_NotificationCM_NOTIFY_FILTERY_TYPE_DEVICEINTERFACE フラグと共に使用して、デバイス インターフェイス通知の適切な登録を達成する必要があります。

Note

サービスの開始時には、到着通知が既に通過している可能性があるため、デバイス インターフェイス通知を受信するという事実に依存することはできません。特に、デバイス インターフェイスの到着がサービスの開始の原因である場合です。 代わりに、既にインターフェイスが存在する場合は、チェックするデバイス インターフェイスの一覧を取得する必要があります。

デバイス インターフェイスの通知を登録すると、新しいデバイス インターフェイスが有効になっているか、既存のデバイス インターフェイスが無効になっているかどうかが通知されます。 通知コールバックからデバイス インターフェイス パスを検出できます。 既存のデバイス インターフェイスのリストをクエリして、サービス開始前に存在し、通知が登録されていたデバイス インターフェイスを調べるには、CM_Get_Device_Interface_List などの API を通じて、デバイス インターフェイスのリストを取得できます。

Note

通知を登録してから、システムに既に存在するデバイス インターフェイスのリストを取得するまでの間に、デバイス インターフェイスが到着する可能性があります。 その場合、デバイス インターフェイスは、通知コールバックとデバイス インターフェイスの一覧の両方に一覧表示されます。

I/O API でデバイス インターフェイスと対話する場合、目的のデバイス インターフェイスを見つけたら、CreateFile を介してインターフェイスへのハンドルを開きます。

次の手順では、セカンダリのハンドルごとの通知を登録して、デバイスの削除や削除されるデバイスに関するクエリの試行など、デバイスの状態変更の通知を受け取ります。 これは、CM_Register_NotificationCM_NOTIFY_FILTER_TYPE_DEVICEHANDLE フラグと共に使用して行うことができます。 「デバイス インターフェイスの到着とデバイスの削除の通知の登録」に記載されているガイダンスに従うと、デバイスが削除されるとき、それに応じてハンドルを解放できます。

デバイス インターフェイスの到着と削除を追跡する必要があり、サービスが対話する最後のデバイス インターフェイスを削除すると、サービスを停止できることを意味します。 最後のインターフェイスが削除されたら、サービスを停止します (詳細については、このページを参照してください)。 これを行うには、次の手順に従います。

  1. SERVICE_STOP_PENDING 状態を SCM にポストして、サービスがダウンすることを示します

  2. サービスで使用されていたすべてを初期化解除/クリーンアップします

  3. SERVICE_STOP 状態を SCM にポストして、停止操作を完了します

サービスが停止している場合は、既存のすべての開いているハンドルをチェックし、デバイス インターフェイスに移動し (存在しない場合もあります)、クリーンアップします。

デバイス インターフェイスは、デバイスのインストール中、デバイスの有効化/無効化、デバイスの再列挙、システムの再起動中、または一覧にないその他のシナリオの間に戻ることができます。 デバイス インターフェイスが戻ると、トリガーの開始登録に基づいてサービスがトリガー開始されます。

このフローにより、サービスはデバイス インターフェイスの到着時に開始し、最後のデバイス インターフェイスが存在しなくなったときに停止します。

GitHub には、サービスがこのイベント フローを活用する方法を説明するサンプルがあります。 サンプルは、Win32 Service Sample にあります。

さらに、AddTrigger に関する有用なドキュメントが AddService ページにあります。