potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

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;
}