potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

C++23Preview&Win API ローカルコンピューターのデバイス列挙子とデバイスIDリストの取得

CM系のAPIを使用してローカルコンピューターのデバイス列挙子とデバイスIDリストを取得するコードです。C++23で導入予定のstd::ranges::toを使用しています(MSVCのPreview版)。

#include <ranges>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#define STRICT
#define NOMINMAX
#include <Windows.h>
#include <Cfgmgr32.h>
#pragma comment(lib, "cfgmgr32.lib")

// ローカルコンピューターのデバイス列挙子をすべて取得します。
std::vector<std::wstring> GetConfigManagerEnumerators()
{
    std::vector<std::wstring> ss;
    std::wstring s(MAX_DEVICE_ID_LEN, L'\0');
    for (ULONG i = 0; i < ULONG_MAX; i++)
    {
        ULONG size = MAX_DEVICE_ID_LEN;
        auto cret = CM_Enumerate_EnumeratorsW(i, s.data(), &size, 0);
        if (cret == CR_NO_SUCH_VALUE)
            break;
        if (cret != CR_SUCCESS)
            return {};
        ss.emplace_back(s.data(), size);
    }
    return ss;
}


// デバイス列挙子からローカルコンピューターのデバイスIDリストを取得します。
std::wstring GetConfigManagerDeviceIDList(std::wstring_view filter, DWORD flags)
{
    ULONG len;
    if (CM_Get_Device_ID_List_SizeW(&len, filter.data(), flags) != CR_SUCCESS)
        return {};

    std::wstring s(len - 1, L'\0');
    if (CM_Get_Device_ID_ListW(filter.data(), s.data(), len, flags) != CR_SUCCESS)
        return {};
    s.resize(s.size() - 1);
    return s;
}

// 文字列を特定文字で区切った文字列のベクトルを作成します。
std::vector<std::wstring> SplitStringIntoVector(
    std::wstring_view sv, wchar_t delimiter)
{
    return std::views::lazy_split(sv, delimiter)
        | std::views::transform([](auto view) {
        return std::views::common(view) | std::ranges::to<std::wstring>();
    })
        | std::ranges::to<std::vector>();
}

int main()
{
    const auto enumerators = GetConfigManagerEnumerators();
    std::ranges::copy(
        enumerators,
        std::ostream_iterator<std::wstring, wchar_t>(std::wcout, L"\n"));

    const auto& enumerator = enumerators[0];
    std::wcout << std::endl << enumerator << std::endl;
    auto ids_raw = GetConfigManagerDeviceIDList(enumerator, CM_GETIDLIST_FILTER_ENUMERATOR);
    auto ids = SplitStringIntoVector(ids_raw, L'\0');
    std::ranges::copy(
        ids,
        std::ostream_iterator<std::wstring, wchar_t>(std::wcout, L"\n"));

    return 0;
}