デバイスの有効・無効をプログラムから切り替える方法

みなさま、こんにちは。さなえすです。

デバイスマネージャから、特定のデバイスを有効にしたり、無効にすることができますね。では、このような操作を、プログラムから操作したいとしたら、どうすればよいでしょうか??

(デバイスを右クリックしたところ↓)

DevMgr

そのヒントは、 ”DevCon” にあります。

先の「デバイスを有効・無効にする API はありますか?」という質問の答えは、Yesです。ただ、単一の API では実現できませんので、複数の SetupDi API 関数などを組み合わせれば可能です、ということになります。(Vista以降のOSですと WMI などを使用しても実現できるようです。2012 年 7 月 30 日時点におきまして前述の方法は確認できておりませんことから訂正させていただきます。)今日は、SetupDi API関数を使った実現方法について DevCon サンプルを使って、” デバイスの有効・無効をプログラムから切り替える方法” としてご紹介します。DevCon やSetupDi APIについての詳しい説明は、以下のまさかたさんからの投稿を再度参照ください。今回の投稿と併せて読んでいただくことで、違う角度からさらに理解を深められることと思います!

DevCon と SetupDi API ~ DevCon の使い方編 ~

SetupDi API と DevCon ~ SetupDi API の使い方編 ~

1 .DevCon サンプルをビルド

さて、それでは早速 DevCon サンプルをビルドして、動かすところから始めましょう。(とりあえず、DevCon の操作方法だけ確認したいという方は、こちらからどうぞ。)C ドライブに Windows Driver Kit をインストールした場合、以下のフォルダに DevCon サンプルアプリケーションのソースコードがあります。

    C:\WinDDK\7600.16385.0\src\setup\devcon

ビルドしたプログラムを動作させるターゲットのオペレーティングシステムに応じて、ビルド環境を選択してください。そうすると、ビルドするための環境変数を読み込んだコマンドコンソールが起動されます。

    [スタート]

      -> [すべてのプログラム]

        -> [Windows Driver Kits]

          -> [WDK 7600.16385.0]

            -> [Build Environment]

ここでは例として [Windows 7]> [x86 Free Build Environment] を使用します。Devcon サンプルのフォルダへ移動し、 build コマンドで、サンプルをビルドしましょう。

    コマンド例:

    C:\WinDDK\7600.16385.0\src\setup\devcon>build

実行形式ファイル devcon.exe は、Free ビルドの場合、↓以下のフォルダに生成されます。

C:\WinDDK\7600.16385.0\src\setup\devcon\objfre_win7_x86\i386

2 .デバイスを列挙する

ビルドされた devcon.exe を使用して、“USB 大容量記憶装置デバイス” ( [USB Mass Storage Device] ) を無効化してみましょう。特定のデバイスを無効化するという判別作業には、インスタンス ID やデバイス名を使用して行います。DevCon では、hwids コマンドで、セットアップクラスを指定すると、該当するデバイスを列挙することができます。これで、デバイスのインスタンスIDが取得できます。

では実際に、USBクラスを例に、コマンドラインから以下を入力して、USB デバイスの ID を列挙してみます。この時、 = の後にスペースを入れずに入力してください。(※後でデバイスの有効・無効の切り替えを行う際に、管理者権限が必要となりますので、DevCon サンプルは管理者権限で動作させてください。)”USB” の他にも、”1394” や、”net” で、同様にそれぞれのクラスのデバイスが列挙できます。

    コマンド例:

devcon.exe hwids =usb

    出力例:

C:\Sample\DevCon>devcon.exe hwids =usb

PCI\VEN_8086&DEV_27C8&SUBSYS_01AD1028&REV_01\3&172E68DD&0&E8

    Name: Intel(R) 82801G (ICH7 Family) USB Universal Host Controller - 27C8

    Hardware IDs:

        PCI\VEN_8086&DEV_27C8&SUBSYS_01AD1028&REV_01

        PCI\VEN_8086&DEV_27C8&SUBSYS_01AD1028

        PCI\VEN_8086&DEV_27C8&CC_0C0300

        PCI\VEN_8086&DEV_27C8&CC_0C03

    Compatible IDs:

        PCI\VEN_8086&DEV_27C8&REV_01

        PCI\VEN_8086&DEV_27C8

        PCI\VEN_8086&CC_0C0300

        PCI\VEN_8086&CC_0C03

        PCI\VEN_8086

        PCI\CC_0C0300

        PCI\CC_0C03

PCI\VEN_8086&DEV_27C9&SUBSYS_01AD1028&REV_01\3&172E68DD&0&E9

    Name: Intel(R) 82801G (ICH7 Family) USB Universal Host Controller - 27C9

    Hardware IDs:

        PCI\VEN_8086&DEV_27C9&SUBSYS_01AD1028&REV_01

        PCI\VEN_8086&DEV_27C9&SUBSYS_01AD1028

        PCI\VEN_8086&DEV_27C9&CC_0C0300

        PCI\VEN_8086&DEV_27C9&CC_0C03

    Compatible IDs:

        PCI\VEN_8086&DEV_27C9&REV_01

        PCI\VEN_8086&DEV_27C9

        PCI\VEN_8086&CC_0C0300

        PCI\VEN_8086&CC_0C03

        PCI\VEN_8086

        PCI\CC_0C0300

        PCI\CC_0C03

PCI\VEN_8086&DEV_27CA&SUBSYS_01AD1028&REV_01\3&172E68DD&0&EA

    Name: Intel(R) 82801G (ICH7 Family) USB Universal Host Controller - 27CA

    Hardware IDs:

        PCI\VEN_8086&DEV_27CA&SUBSYS_01AD1028&REV_01

        PCI\VEN_8086&DEV_27CA&SUBSYS_01AD1028

        PCI\VEN_8086&DEV_27CA&CC_0C0300

        PCI\VEN_8086&DEV_27CA&CC_0C03

    Compatible IDs:

        PCI\VEN_8086&DEV_27CA&REV_01

        PCI\VEN_8086&DEV_27CA

        PCI\VEN_8086&CC_0C0300

        PCI\VEN_8086&CC_0C03

        PCI\VEN_8086

        PCI\CC_0C0300

        PCI\CC_0C03

USB\ROOT_HUB\4&19F1AF77&0

    Name: USB Root Hub

    Hardware IDs:

        USB\ROOT_HUB&VID8086&PID27CA&REV0001

        USB\ROOT_HUB&VID8086&PID27CA

        USB\ROOT_HUB

PCI\VEN_8086&DEV_27CB&SUBSYS_01AD1028&REV_01\3&172E68DD&0&EB

    Name: Intel(R) 82801G (ICH7 Family) USB Universal Host Controller - 27CB

    Hardware IDs:

        PCI\VEN_8086&DEV_27CB&SUBSYS_01AD1028&REV_01

        PCI\VEN_8086&DEV_27CB&SUBSYS_01AD1028

        PCI\VEN_8086&DEV_27CB&CC_0C0300

        PCI\VEN_8086&DEV_27CB&CC_0C03

    Compatible IDs:

        PCI\VEN_8086&DEV_27CB&REV_01

        PCI\VEN_8086&DEV_27CB

        PCI\VEN_8086&CC_0C0300

        PCI\VEN_8086&CC_0C03

        PCI\VEN_8086

        PCI\CC_0C0300

        PCI\CC_0C03

USB\ROOT_HUB\4&2F60F7EA&0

    Name: USB Root Hub

    Hardware IDs:

        USB\ROOT_HUB&VID8086&PID27CB&REV0001

        USB\ROOT_HUB&VID8086&PID27CB

        USB\ROOT_HUB

USB\ROOT_HUB\4&32C41A52&0

    Name: USB Root Hub

    Hardware IDs:

        USB\ROOT_HUB&VID8086&PID27C9&REV0001

        USB\ROOT_HUB&VID8086&PID27C9

        USB\ROOT_HUB

PCI\VEN_8086&DEV_27CC&SUBSYS_01AD1028&REV_01\3&172E68DD&0&EF

    Name: Intel(R) 82801G (ICH7 Family) USB2 Enhanced Host Controller - 27CC

    Hardware IDs:

        PCI\VEN_8086&DEV_27CC&SUBSYS_01AD1028&REV_01

        PCI\VEN_8086&DEV_27CC&SUBSYS_01AD1028

        PCI\VEN_8086&DEV_27CC&CC_0C0320

        PCI\VEN_8086&DEV_27CC&CC_0C03

    Compatible IDs:

        PCI\VEN_8086&DEV_27CC&REV_01

        PCI\VEN_8086&DEV_27CC

        PCI\VEN_8086&CC_0C0320

        PCI\VEN_8086&CC_0C03

        PCI\VEN_8086

        PCI\CC_0C0320

        PCI\CC_0C03

USB\ROOT_HUB\4&4FC3F26&0

    Name: USB Root Hub

    Hardware IDs:

        USB\ROOT_HUB&VID8086&PID27C8&REV0001

        USB\ROOT_HUB&VID8086&PID27C8

        USB\ROOT_HUB

USB\ROOT_HUB20\4&4F1A976&0

    Name: USB Root Hub

    Hardware IDs:

        USB\ROOT_HUB20&VID8086&PID27CC&REV0001

        USB\ROOT_HUB20&VID8086&PID27CC

        USB\ROOT_HUB20

USB\VID_054C&PID_0243\5A0903040021511←インスタンスID

    Name: USB Mass Storage Device ←デバイス名

    Hardware IDs:

        USB\VID_054C&PID_0243&REV_0200

        USB\VID_054C&PID_0243

    Compatible IDs:

        USB\Class_08&SubClass_06&Prot_50

        USB\Class_08&SubClass_06

        USB\Class_08

11 matching device(s) found.

USBクラスのデバイスがずらりと表示されました。このときの表示内容は、デバイスマネージャにてデバイスの種類別に表示した時と同じ内容になります。

この時デバイスマネージャはこんなかんじ↓

2 DevMgr

ハイ、どちらも USB クラスのデバイスについて同じインスタンス(11 個)が列挙されていますね。

ここで、日本語環境で検証中の方にちょっとだけ補足します。上記の図では、Windows 7 Build 7600 英語版環境で動作させていますので、気になりませんが、日本語表記のデバイス名は DevCon サンプルをコマンドプロンプトで動作させるとコマンドプロンプトが Unicode 文字を正しく表示できないため日本語が表示されません(残念..)。もちろん、文字列の文字コードデータ自体は正しくバッファに格納されていますので、プログラムで特定のデバイス名を比較する際の文字列操作は通常通り行うことができます。その点はご心配なく!

3 .デバイスを無効化・有効化する

次に、デバイスの無効化です。上記の手順で取得したインスタンス ID を指定して、 USB デバイスを無効化します。DevCon では、コマンドラインより devcon.exe disable <インスタンス ID> と入力して、指定した USB デバイスを無効化します。インスタンス ID を指定する場合は下記の例のように“@<インスタンス ID>” のようにダブルクウォートとアットマークを使用してインスタンス ID を指定してください。

    出力例:

C:\Sample\DevCon>devcon.exe disable "@USB\VID_054C&PID_0243\5A0903040021511"

USB\VID_054C&PID_0243\5A0903040021511 : Disabled

1 device(s) disabled.

というわけで、無事にデバイスが無効化されました。

この時デバイスマネージャはこんなかんじ↓ デバイスが無効化されていることが、デバイスマネージャからも確認できますね。

3 USB Disabled

今度は、先ほど無効化した USB デバイスを有効化してみます。上記同様、Devcon サンプルでは、有効にするデバイスのインスタンス ID を取得し、コマンドラインより devcon.exe enable <インスタンス ID> と入力して、指定したUSB デバイスを有効にします。

    出力例:

C:\Sample\DevCon>devcon.exe enable "@USB\VID_054C&PID_0243\5A0903040021511"

USB\VID_054C&PID_0243\5A0903040021511 : Enabled

1 device(s) are enabled.

実際、DevConでのデバイス列挙の部分でポイントとなる流れは、以下の SetupDi API 関数です。

⓪ SetupDiClassGuidsFromNameEx(クラスGUIDを取得)

① SetupDiGetClassDevsEx OR SetupDiCreateDeviceInfoListEx(Device Information Set の作成)

② SetupDiEnumDeviceInfo + CM_Get_Device_ID_Ex(デバイスの列挙)

③ SetupDiGetDeviceRegistryProperty(デバイス情報の取得)

これらは主に、EnumerateDevices() 関数で実装されていますので、詳しくはソースコードを参照ください。(まさかたさんのこちらの投稿でも “ Setup API の使い方” でポイントをまとめてくれています)以上の流れで、DevCon (=プログラム)を使って USB デバイスの有効・無効を切り替えが可能なことを確認できました。

4. その他 ~ネットワークアダプタの有効・無効~

上記は、USBクラスのデバイスについてでしたが、例えば、ネットワークアダプタの有効・無効を行う場合はどうでしょうか?先ほど同様、devcon.exe hwids =net で、デバイスを列挙することはできます。ただ、仮に複数のネットワークアダプタが存在している中で [ローカルエリア接続] に割り当てられているものを無効化したい、というような場合にちょっと困ってしまいます。DevCon サンプルのデバイス列挙は、デバイス単位で行われているため、どのネットワークアダプタが [ローカルエリア接続] に割り当てられているかまでを判別する処理は DevCon には含まれていないのです。

しかし、ここであきらめてはいけません! 逆を言えば、どのネットワークアダプタが 「ローカルエリア接続」 に割り当てられているかを判別する処理を別途組めばよいわけですから。そのアイディアを以下にご紹介します。(※なお、ここでご紹介する方法は、現行の OS におけるレジストリ構成に依存しています。そのため今後の OS の実装によっては同じロジックが使えなくなる可能性がありますので、その点にはご了承ください。)

試しに以下のレジストリをのぞいてみてください。

4 Registry

このような構成になっています。

    HKEY_LOCAL_MACHINE

     + SYSTEM

      + CurrentControlSet

        + Control

          + Network

           + {4D36E972-E325-11CE-BFC1-08002BE10318} <-- 1. ネットワーク アダプタのレジストリ

             + {6FF9F1D8-5A39-4A3F-B594-9759A9C8A7A} <-- 2. アダプタの GUID

               + Connection <-- 3. Connection キー

どのネットワークアダプタが「ローカルエリア接続」 に割り当てられているかは、このレジストリを検索して値の比較をして判別することによって実現できます。

1. ネットワーク アダプタのレジストリ

ネットワーク アダプタのレジストリにて 「ローカルエリア接続」 に使用しているネットワーク アダプタの関連付けを行っています。

2. アダプタの GUID

ネットワーク アダプタのレジストリの下に、各アダプタの GUID が列挙されています。GUID {6FF9F1D8-5A39-4A3F-B594-9759A9C8A7A} は、インストール時に割り当てられた値です。

3. Connection キー

Connection キーの中に [Name] の値として 「ローカル エリア接続」 の文字列と、[PnpInstanceID] の値としてインスタンス ID が格納されています。このインスタンス ID を使用すれば、DevCon サンプルで取得したデバイスのインスタンス ID と同様に使用できます。

判別のポイントとなるのは、3. Connection キーです。つまり、ここで登録されている ネットワークアダプタのレジストリの [Name] の  “ローカル エリア接続” の文字列を元に、 [PnpInstanceID] の ID と DevCon サンプルで取得したインスタンス ID と比較する処理を DevCon サンプルと組み合わせて実装すれば、特定のネットワークアダプタの有効・無効も可能になるというわけです。

いかがでしたでしょうか?

このようにプログラムからデバイスを無効・有効の切り替えを行いたい場合は、 SetupDi API をアプリケーションに組み込むことで実現できます。最後に、Devcon サンプルや、今回取り上げた SetupDi API 関数群に関してのヘルプドキュメント等をまとめておしまいにしたいと思います。DevCon は、沢山の機能が実装されているので、最初はとっつきにくいかもしれませんが、様々な場面で応用が効く、素晴らしいサンプルですので、みなさんも、DevCon サンプルの実装をもとにいろいろと試してみてください。 私も頑張りますJ

- DevCon

- SetupDiClassGuidsFromNameEx

- SetupDiGetClassDevsEx

- SetupDiCreateDeviceInfoListEx

- SetupDiEnumDeviceInfo

- CM_Get_Device_ID_Ex

- Device Management Functions

SetupDi を使用してハードウェア機器を列挙する方法

ではまた♪