0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PCに接続されているデバイスを全部取得して表示する

Posted at

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

掲題の通り、PCに接続されているデバイスの名前とデバイスインスタンスパス、あとエラーがあるかどうかを表示したい。
というのをcopilotにお願いすると、まんま動くコードをくれたので、それ見ながら勉強する。

コード(by copilot)

#include <windows.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <iostream>
#include <vector>
#include <string>

#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "cfgmgr32.lib")

int main()
{
    std::setlocale(LC_ALL, "ja_JP.UTF-8");
    std::wcout.imbue(std::locale("ja_JP.UTF-8"));

    // すべてのデバイスを取得
    HDEVINFO hDevInfo = SetupDiGetClassDevsA(
        nullptr, // すべてのクラス
        nullptr,
        nullptr,
        DIGCF_ALLCLASSES | DIGCF_PRESENT
    );
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        std::cerr << "SetupDiGetClassDevsA failed." << std::endl;
        return 1;
    }

    DWORD index = 0;
    SP_DEVINFO_DATA devInfoData;
    devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

    while (SetupDiEnumDeviceInfo(hDevInfo, index, &devInfoData)) {
        ++index;

        // FriendlyName取得
        WCHAR friendlyName[256];
        DWORD requiredSize = 0;
        BOOL hasFriendlyName = SetupDiGetDeviceRegistryPropertyW(
            hDevInfo,
            &devInfoData,
            SPDRP_FRIENDLYNAME,
            nullptr,
            (PBYTE)friendlyName,
            sizeof(friendlyName),
            &requiredSize
        );

        if (!hasFriendlyName) {
            // FriendlyNameがない場合はDeviceDescを試す
            hasFriendlyName = SetupDiGetDeviceRegistryPropertyW(
                hDevInfo,
                &devInfoData,
                SPDRP_DEVICEDESC,
                nullptr,
                (PBYTE)friendlyName,
                sizeof(friendlyName),
                &requiredSize
            );
        }

        // Device Instance ID取得
        WCHAR deviceId[MAX_DEVICE_ID_LEN];
        if (CM_Get_Device_IDW(devInfoData.DevInst, deviceId, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) {
            wcscpy_s(deviceId, L"(取得失敗)");
        }

        // デバイスの状態取得
        ULONG status = 0, problem = 0;
        CONFIGRET cr = CM_Get_DevNode_Status(&status, &problem, devInfoData.DevInst, 0);
        
        // エラーのあるものだけ表示
        // エラーコード:https://support.microsoft.com/ja-jp/topic/windows-%E3%81%AE%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9-%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%BC%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC-%E3%82%B3%E3%83%BC%E3%83%89-524e9e89-4dee-8883-0afa-6bca0456324e
        /*if (!(status & DN_HAS_PROBLEM))
            continue;*/

        // 結果表示
        std::wcout << L"----------------------------------------" << std::endl;
        std::wcout << L"Device Instance ID: " << deviceId << std::endl;
        if (hasFriendlyName) {
            std::wcout << L"FriendlyName: " << friendlyName << std::endl;
        }
        else {
            std::wcout << L"FriendlyName: (取得不可)" << std::endl;
        }
        if (cr == CR_SUCCESS && (status & DN_HAS_PROBLEM)) {
            std::wcout << L"エラー: あり (Problem code: " << problem << L")" << std::endl;
        }
        else if (cr == CR_SUCCESS) {
            std::wcout << L"エラー: なし" << std::endl;
        }
        else {
            std::wcout << L"エラー状態取得失敗" << std::endl;
        }
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
    return 0;
}

エラーコードについて

👇のコードで取れる「プロブレムコード」の値がなにを表すかは、

ULONG status = 0, problem = 0;
CONFIGRET cr = CM_Get_DevNode_Status(&status, &problem, devInfoData.DevInst, 0);

👇のページで取れる。

知ったことメモ

デバイスインターフェースとは

  • 「デバイスインターフェース」というものがある。
    • デバイスがOSやアプリケーションとやり取りするために公開する“機能の入り口”
  • Windowsでは、1つの物理デバイスが複数の「デバイスインターフェース」を持つことがある。
    • USBメモリは、以下のような複数のインターフェースを持てる。
      • 「ストレージボリューム」としてのインターフェース(GUID_DEVINTERFACE_VOLUME)
      • USBデバイスとしてのインターフェース(GUID_DEVINTERFACE_USB_DEVICE)
  • 「デバイスインターフェース」は、アプリケーションやドライバがデバイスにアクセスするための論理的な窓口となるもの。
  • 物理デバイスそのものではなく、「この機能を持つデバイスの一覧がほしい」といった用途で使われる。

例:
SetupDiGetClassDevsA(&GUID_DEVINTERFACE_VOLUME, ...)
→ 「ボリューム(論理ドライブ)」としてアクセス可能なデバイスのインターフェース一覧を取得
SetupDiGetClassDevsA(&GUID_DEVINTERFACE_USB_DEVICE, ...)
→ 「USBデバイス」としてアクセス可能なインターフェース一覧を取得

つまり、

SetupDiGetClassDevsで、クラス(≒種類)ごとにデバイスをとるときに、ある機能を示すデバイスインターフェースを指定して取得すれば、その機能を持ったデバイスを取得できるということ。

つぎやりたいこと

デバマネの「デバイス(接続別)」で表示したツリー構造のように、
接続を改装で合わらすような情報を取得したい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?