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?

デバイスマネージャーの「デバイス(接続別)」のツリーを再現する

Posted at

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

やりたいこと

前回、PCに接続されているデバイスを全部取得して表示するということをした。

今回、デバマネの「デバイス(接続別)」と同じように、接続をツリー上に表示するようなコードにしたい。

image.png

👇こういうの
image.png

コード(ほぼby copilot)

今回も、ほぼcopilotに書いてもらった。

一度、うまく動かない部分があったので、そこは手で修正した。

#include <windows.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <locale>
#include <clocale>
#include <shlobj.h> // デスクトップパス取得用

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

// 指定したDevInstのFriendlyNameまたはDeviceDescを取得
std::wstring GetDeviceFriendlyName(HDEVINFO hDevInfo, SP_DEVINFO_DATA& devInfoData) {
    WCHAR buffer[256];
    DWORD requiredSize = 0;
    if (SetupDiGetDeviceRegistryPropertyW(
        hDevInfo,
        &devInfoData,
        SPDRP_FRIENDLYNAME,
        nullptr,
        (PBYTE)buffer,
        sizeof(buffer),
        &requiredSize
    )) {
        return buffer;
    }
    // FriendlyNameがない場合はDeviceDesc
    if (SetupDiGetDeviceRegistryPropertyW(
        hDevInfo,
        &devInfoData,
        SPDRP_DEVICEDESC,
        nullptr,
        (PBYTE)buffer,
        sizeof(buffer),
        &requiredSize
    )) {
        return buffer;
    }
    return L"(取得不可)";
}

// デバイスツリーを再帰的に表示(ファイル出力)
void PrintDeviceTree(HDEVINFO hDevInfo, DEVINST devInst, std::wofstream& ofs, int depth = 0) {
    SP_DEVINFO_DATA devInfoData = {};
    ULONG status = 0, problem = 0;
    devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    auto a = CM_Get_DevNode_Status(&status, &problem, devInst, 0);
    if (a == CR_SUCCESS) {
        // Device Instance ID取得
        WCHAR deviceId[MAX_DEVICE_ID_LEN];
        if (CM_Get_Device_IDW(devInst, deviceId, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) {
            wcscpy_s(deviceId, L"(取得失敗)");
        }

        // SP_DEVINFO_DATAを取得
        DWORD index = 0;
        bool found = false;
        while (SetupDiEnumDeviceInfo(hDevInfo, index, &devInfoData)) {
            ++index;
            WCHAR tmpId[MAX_DEVICE_ID_LEN];
            if (CM_Get_Device_IDW(devInfoData.DevInst, tmpId, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS) {
                if (wcscmp(tmpId, deviceId) == 0) {
                    found = true;
                    break;
                }
            }
        }
        // インデント
        for (int i = 0; i < depth; ++i) ofs << L"  ";
        ofs << L"[" << deviceId << L"] ";
        if (found) {
            ofs << GetDeviceFriendlyName(hDevInfo, devInfoData);
        }
        else {
            ofs << L"(FriendlyName取得不可)";
        }
        ofs << std::endl;
    }

    // 子デバイスを再帰的に表示
    DEVINST childDevInst;
    if (CM_Get_Child(&childDevInst, devInst, 0) == CR_SUCCESS) {
        PrintDeviceTree(hDevInfo, childDevInst, ofs, depth + 1);
        // 兄弟デバイスをたどる
        DEVINST siblingDevInst = childDevInst;
        while (CM_Get_Sibling(&siblingDevInst, siblingDevInst, 0) == CR_SUCCESS) {
            PrintDeviceTree(hDevInfo, siblingDevInst, ofs, depth + 1);
        }
    }
}

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

    // デスクトップパス取得
    WCHAR desktopPath[MAX_PATH];
    if (SHGetSpecialFolderPathW(nullptr, desktopPath, CSIDL_DESKTOPDIRECTORY, FALSE) == FALSE) {
        std::wcerr << L"デスクトップパスの取得に失敗しました。" << std::endl;
        return 1;
    }
    std::wstring filePath = desktopPath;
    filePath += L"\\device_tree.txt";

    // ファイル出力ストリームを開く
    std::wofstream ofs(filePath);
    if (!ofs) {
        std::wcerr << L"ファイルの作成に失敗しました: " << filePath << std::endl;
        return 1;
    }
    ofs.imbue(std::locale("ja_JP.UTF-8"));

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

    // ルートデバイスからツリー表示
    DEVINST rootDevInst;
    if (CM_Locate_DevNodeW(&rootDevInst, nullptr, 0) == CR_SUCCESS) {
        PrintDeviceTree(hDevInfo, rootDevInst, ofs, 0);
    }
    else {
        ofs << L"ルートデバイスの取得に失敗しました。" << std::endl;
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
    ofs.close();
    return 0;
}

動かして吐いたテキストファイル

こんな感じで出力された。

[HTREE\ROOT\0] (取得不可)
  [ROOT\JUNGO\0000] WinDriver
  [ROOT\VOLMGR\0000] ボリューム マネージャー
    [STORAGE\VOLUME\{9504634E-A3D5-11EC-89DE-806E6F6E6963}#0000000000004400] ボリューム
    [STORAGE\VOLUME\{9504634E-A3D5-11EC-89DE-806E6F6E6963}#0000000008100000] ボリューム
    [STORAGE\VOLUME\{9504634E-A3D5-11EC-89DE-806E6F6E6963}#000000000E500000] ボリューム
      [STORAGE\VOLUMESNAPSHOT\HARDDISKVOLUMESNAPSHOT1] 汎用ボリューム シャドウ コピー
      [STORAGE\VOLUMESNAPSHOT\HARDDISKVOLUMESNAPSHOT2] 汎用ボリューム シャドウ コピー
      [STORAGE\VOLUMESNAPSHOT\HARDDISKVOLUMESNAPSHOT3] 汎用ボリューム シャドウ コピー
      [STORAGE\VOLUMESNAPSHOT\HARDDISKVOLUMESNAPSHOT4] 汎用ボリューム シャドウ コピー
      [STORAGE\VOLUMESNAPSHOT\HARDDISKVOLUMESNAPSHOT5] 汎用ボリューム シャドウ コピー
    [STORAGE\VOLUME\{9504634E-A3D5-11EC-89DE-806E6F6E6963}#000000E7C2000000] ボリューム
    [STORAGE\VOLUME\{9504634E-A3D5-11EC-89DE-806E6F6E6963}#000000E7EF200000] ボリューム
  [ROOT\VMBUS\0000] Microsoft Hyper-V Virtual Machine Bus Provider
  [ROOT\BASICDISPLAY\0000] Microsoft 基本ディスプレイ ドライバー
  [ROOT\HVSERVICE\0000] Microsoft ハイパーバイザー サービス
  [ROOT\NET\0000] Fortinet Virtual Ethernet Adapter (NDIS 6.30)
  [ROOT\NET\0001] Fortinet SSL VPN Virtual Ethernet Adapter
  [ROOT\NET\0002] PPPoP WAN Adapter
  [ROOT\VID\0000] Microsoft Hyper-V 仮想化インフラストラクチャ ドライバー
  [ROOT\COMPOSITEBUS\0000] 複合バス列挙子
  [ROOT\VDRVROOT\0000] Microsoft 仮想ドライブ列挙子
  [ROOT\SPACEPORT\0000] Microsoft 記憶域コントローラー
  [ROOT\KDNIC\0000] Microsoft Kernel Debug Network Adapter #2
  [ROOT\UMBUS\0000] UMBus Root Bus Enumerator
    [UMB\UMB\1&841921D&0&TERMINPUT_BUS] UMBus Enumerator
  [ROOT\ACPI_HAL\0000] ACPI x64 ベース PC
    [ACPI_HAL\PNP0C08\0] Microsoft ACPI-Compliant System
      [ACPI\PNP0A08\0] PCI Express ルート コンプレックス
        [PCI\VEN_8086&DEV_9B63&SUBSYS_86941043&REV_03\3&11583659&0&00] PCI 標準ホスト CPU ブリッジ
        [PCI\VEN_8086&DEV_9BC8&SUBSYS_86941043&REV_03\3&11583659&0&10] Intel(R) UHD Graphics 630
          [SWD\DRIVERENUM\CUI&4&18929383&0] Intel(R) Graphics Control Panel
          [SWD\DRIVERENUM\IGCC&4&18929383&0] Intel(R) Graphics Command Center
          [DISPLAY\DEL42A2\4&18929383&0&UID200195] Dell P3223QE (DP)
        [PCI\VEN_8086&DEV_43ED&SUBSYS_86941043&REV_11\3&11583659&0&A0] Intel(R) USB 3.20 eXtensible Host Controller - 1.20 (Microsoft)
          [USB\ROOT_HUB30\4&1C1E67E3&0&0] USB ルート ハブ (USB 3.0)
            [USB\VID_0A12&PID_0001\5&153678D8&0&4] Generic Bluetooth Radio
              [BTH\MS_RFCOMM\6&190A23EC&0&0] Bluetooth Device (RFCOMM Protocol TDI)
              [BTH\MS_BTHBRB\6&190A23EC&0&1] Microsoft Bluetooth Enumerator
                [BTHENUM\{00000000-DECA-FADE-DECA-DEAFDECACAFE}_VID&0001004C_PID&740F\7&281E3D1F&0&B456E38ACECE_C00000000] Bluetooth 周辺デバイス
                [BTHENUM\{00001000-0000-1000-8000-00805F9B34FB}_VID&0001004C_PID&740F\7&281E3D1F&0&B456E38ACECE_C00000000] サービス検索サービス
                [BTHENUM\{0000110A-0000-1000-8000-00805F9B34FB}_VID&0001004C_PID&740F\7&281E3D1F&0&B456E38ACECE_C00000000] iPhone A2DP SNK
                [BTHENUM\{0000110B-0000-1000-8000-00805F9B34FB}_LOCALMFG&000A\7&281E3D1F&0&0CA694033D59_C00000000] HK Onyx Studio
                  [SWD\MMDEVAPI\{0.0.0.00000000}.{427A9F29-10B4-4302-A7B1-F6D4EE64CD7F}] スピーカー (3- HK Onyx Studio)
                [BTHENUM\{0000110C-0000-1000-8000-00805F9B34FB}_LOCALMFG&000A\7&281E3D1F&0&0CA694033D59_C00000000] HK Onyx Studio Avrcp トランスポート
                [BTHENUM\{0000110C-0000-1000-8000-00805F9B34FB}_VID&0001004C_PID&740F\7&281E3D1F&0&B456E38ACECE_C00000000] iPhone Avrcp トランスポート
                            ・
                            ・
                            ・
                            ・
                            ・
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?