potisanのプログラミングメモ

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

C++20&Win API デバイス情報要素のGUID、不透明ハンドル、概要を列挙する

バイス情報要素のGUID、不透明ハンドル(Opaque Handle)、概要を列挙するサンプルコードです。

#include <memory>
#include <string>
#include <format>
#include <numeric>
#include <iostream>
#include <list>

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

struct HDEVINFO_deleter {
    void operator() (HDEVINFO handle) const noexcept {
        ::SetupDiDestroyDeviceInfoList(handle);
    }
};
using unique_HDEVINFO = std::unique_ptr<std::remove_pointer_t<HDEVINFO>, HDEVINFO_deleter>;

unique_HDEVINFO unique_SetupDiGetClassDevsW(
    const GUID* ClassGuid,
    LPCWSTR Enumerator,
    HWND hWndParent,
    DWORD Flags) noexcept
{
    return unique_HDEVINFO(::SetupDiGetClassDevsW(ClassGuid, Enumerator, hWndParent, Flags));
}

std::wstring GUIDToWString(const GUID& guid)
{
    std::wstring s(38, L'\0');
    if (FAILED(::StringFromGUID2(guid, s.data(), 38)))
        return {};
    return std::move(s);
}

std::list<SP_DEVINFO_DATA> SetupDiEnumDeviceInfo_list(HDEVINFO DeviceInfoSet) noexcept
{
    std::list<SP_DEVINFO_DATA> list;
    for (DWORD i = 0; i < std::numeric_limits<DWORD>::max(); i++)
    {
        SP_DEVINFO_DATA data{ sizeof(data) };
        if (!::SetupDiEnumDeviceInfo(DeviceInfoSet, i, &data))
            break;
        list.emplace_back(data);
    }
    return std::move(list);
}

int main()
{
    std::wcout.imbue(std::locale("", std::locale::ctype));

    auto devinfo_handle{ unique_SetupDiGetClassDevsW(
        nullptr,
        nullptr,
        nullptr,
        DIGCF_ALLCLASSES) };
    auto devinfos{ SetupDiEnumDeviceInfo_list(devinfo_handle.get()) };

    std::wcout << L"ClassGuid, DevInst, Class Description" << std::endl;
    std::wstring class_des(LINE_LEN - 1, L'\0');
    for (const auto& devinfo : devinfos)
    {
        ::SetupDiGetClassDescriptionExW(&devinfo.ClassGuid,
            class_des.data(), class_des.size(), nullptr, nullptr, nullptr);
        std::wcout
            << std::format(L"{}, {}, {}",
                GUIDToWString(devinfo.ClassGuid), devinfo.DevInst, class_des.data())
            << std::endl;
    }
}

C++20&Win API ドロップされたOLEデータオブジェクトのクリップボード形式を列挙する

エクスプローラーやブラウザからドロップされたデータのデータ形式を列挙するサンプルコードです。Windowsプロジェクトでのウィンドウクラスの登録、ウィンドウの表示、複数行テキストボックスだけ持つウィンドウの実装、IUnknownクラスの実装サンプルとしても使えるかもしれません。

#define STRICT
#include <Windows.h>

#include <bit>
#include <format>
#include <vector>
#include <string>

auto MY_WINDOW_CLASS_NAME{ L"Project1" };
auto MY_WINDOW_WINDOW_NAME{ L"Project1" };

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int nCmdShow)
{
    if (HRESULT hr = OleInitialize(nullptr); FAILED(hr))
        return hr;

    WNDCLASSEX wce{
        sizeof(wce),
        0,
        MyWndProc,
        0,
        0,
        nullptr,
        LoadIcon(nullptr, IDI_APPLICATION),
        LoadCursor(nullptr, IDC_ARROW),
        reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1),
        nullptr,
        MY_WINDOW_CLASS_NAME,
        LoadIcon(nullptr, IDI_APPLICATION) };
    if (!RegisterClassEx(&wce))
        return 0;

    auto hWnd{ CreateWindowEx(
        WS_EX_OVERLAPPEDWINDOW,
        MY_WINDOW_CLASS_NAME,
        MY_WINDOW_WINDOW_NAME,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        nullptr,
        nullptr,
        nullptr,
        nullptr) };
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    OleUninitialize();

    return static_cast<int>(msg.wParam);
}

template<DWORD INIT = 256, DWORD EXPANDING = 256>
std::wstring GetClipboardFormatNameW(CLIPFORMAT cf)
{
    std::wstring buffer;
    for (DWORD size = INIT;; size += EXPANDING)
    {
        buffer.resize(size);
        auto copied{ GetClipboardFormatNameW(cf, buffer.data(), size) };
        if (copied != buffer.size() - 1)
        {
            buffer.resize(copied);
            buffer.shrink_to_fit();
            return std::move(buffer);
        }
    }
}

// https://docs.microsoft.com/ja-jp/windows/desktop/api/oleidl/nn-oleidl-idroptarget
class CMyDropTarget : public IDropTarget
{
private:
    ULONG m_ref;
    HWND m_hwndEdit;

    CMyDropTarget() {}

public:
    CMyDropTarget(HWND hwndEdit)
        : m_ref(1), m_hwndEdit(hwndEdit)
    {
    }

    HRESULT QueryInterface(
        REFIID riid,
        void** ppvObject)
    {
        if (IsEqualIID(riid, __uuidof(IUnknown)))
        {
            *ppvObject = static_cast<IUnknown*>(this);
        }
        else if (IsEqualIID(riid, __uuidof(IDropTarget)))
        {
            *ppvObject = static_cast<IDropTarget*>(this);
        }
        else
        {
            return E_NOINTERFACE;
        }
        AddRef();
        return S_OK;
    }

    ULONG AddRef()
    {
        return InterlockedIncrement(&m_ref);
    }

    ULONG Release(void)
    {
        if (InterlockedDecrement(&m_ref) == 0)
        {
            delete this;
            return 0;
        }
        return m_ref;
    }

    HRESULT STDMETHODCALLTYPE DragEnter(
        IDataObject* pDataObj,
        DWORD grfKeyState,
        POINTL pt,
        DWORD* pdwEffect)
    {
        *pdwEffect = DROPEFFECT_LINK;
        return S_OK;
    }

    HRESULT DragOver(
        DWORD grfKeyState,
        POINTL pt,
        DWORD* pdwEffect)
    {
        return S_OK;
    }

    HRESULT DragLeave()
    {
        return S_OK;
    }

    HRESULT Drop(
        IDataObject* pDataObj,
        DWORD grfKeyState,
        POINTL pt,
        DWORD* pdwEffect)
    {
        std::vector<CLIPFORMAT> cfs;

        IEnumFORMATETC* pEnumFormatEtc{ nullptr };
        if (SUCCEEDED(pDataObj->EnumFormatEtc(DATADIR::DATADIR_GET, &pEnumFormatEtc)))
        {
            FORMATETC fmtetc;
            while (pEnumFormatEtc->Next(1, &fmtetc, nullptr) == S_OK)
            {
                cfs.push_back(fmtetc.cfFormat);
            }
            pEnumFormatEtc->Release();
        }

        std::wstring buffer;
        for (auto& cf : cfs)
        {
            auto name = GetClipboardFormatNameW(cf);
            buffer.append(std::format(L"{:04X} ({})\r\n", cf, name));
        }
        SetWindowText(m_hwndEdit, buffer.c_str());

        *pdwEffect = DROPEFFECT_LINK;
        return S_OK;
    }

    HWND GetEditWindowHandle() const
    {
        return m_hwndEdit;
    }
};

CMyDropTarget* pDropTarget{ nullptr };

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uiMsg)
    {
    case WM_CREATE:
        {
            // データ表示用のテキストボックス作成
            auto hwndEdit1{ CreateWindowExW(
                WS_EX_CLIENTEDGE,
                L"edit",
                L"ファイルやURLをドロップしてください。",
                WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_MULTILINE,
                0, 0, 0, 0,
                hWnd,
                nullptr,
                nullptr,
                nullptr) };
            SendMessage(hwndEdit1, WM_SETFONT,
                std::bit_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)),
                MAKELPARAM(FALSE, 0));
            // ドロップ対象として登録
            pDropTarget = new CMyDropTarget(hwndEdit1);
            RegisterDragDrop(hWnd, pDropTarget);
            pDropTarget->Release();
            return 0;
        }
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_QUIT:
        RevokeDragDrop(hWnd);
        return 0;
    case WM_SIZE:
        MoveWindow(
            pDropTarget->GetEditWindowHandle(),
            0, 0,
            LOWORD(lParam), HIWORD(lParam),
            TRUE);
        return 0;
    }

    return DefWindowProc(hWnd, uiMsg, wParam, lParam);
}

C++20&Win API ドロップされたOLEデータオブジェクトに含まれるShellItemを列挙する

ドロップされたOLEデータオブジェクトに含まれるShellItem(ファイル、フォルダ、特殊フォルダ等)を列挙するサンプルコードです。

#define STRICT
#include <Windows.h>
#include <ShlObj.h>
#include <ShObjIdl.h>

#include <bit>
#include <format>
#include <string>
#include <vector>

auto MY_WINDOW_CLASS_NAME{ L"Project1" };
auto MY_WINDOW_WINDOW_NAME{ L"Project1" };

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int nCmdShow)
{
    if (HRESULT hr = OleInitialize(nullptr); FAILED(hr))
        return hr;

    WNDCLASSEX wce{
        sizeof(wce),
        0,
        MyWndProc,
        0,
        0,
        nullptr,
        LoadIcon(nullptr, IDI_APPLICATION),
        LoadCursor(nullptr, IDC_ARROW),
        reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1),
        nullptr,
        MY_WINDOW_CLASS_NAME,
        LoadIcon(nullptr, IDI_APPLICATION) };
    if (!RegisterClassEx(&wce))
        return 0;

    auto hWnd{ CreateWindowEx(
        WS_EX_OVERLAPPEDWINDOW,
        MY_WINDOW_CLASS_NAME,
        MY_WINDOW_WINDOW_NAME,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        nullptr,
        nullptr,
        nullptr,
        nullptr) };
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    OleUninitialize();

    return static_cast<int>(msg.wParam);
}

template<DWORD INIT = 256, DWORD EXPANDING = 256>
std::wstring GetClipboardFormatNameW(CLIPFORMAT cf)
{
    std::wstring buffer;
    for (DWORD size = INIT;; size += EXPANDING)
    {
        buffer.resize(size);
        auto copied{ GetClipboardFormatNameW(cf, buffer.data(), size) };
        if (copied != buffer.size() - 1)
        {
            buffer.resize(copied);
            buffer.shrink_to_fit();
            return std::move(buffer);
        }
    }
}

std::wstring GetShellItemDisplayName(IShellItem* pShellItem, SIGDN sigdnName)
{
    LPWSTR pszName;
    if (SUCCEEDED(pShellItem->GetDisplayName(sigdnName, &pszName)))
    {
        std::wstring s{ pszName };
        ::CoTaskMemFree(pszName);
        return std::move(s);
    }
    return {};
}

// https://docs.microsoft.com/ja-jp/windows/desktop/api/oleidl/nn-oleidl-idroptarget
class CMyDropTarget : public IDropTarget
{
private:
    ULONG m_ref;
    HWND m_hwndEdit;

    CMyDropTarget() {}

public:
    constexpr CMyDropTarget(HWND hwndEdit)
        : m_ref(1), m_hwndEdit(hwndEdit)
    {
    }

    HRESULT QueryInterface(REFIID riid, void** ppvObject)
    {
        if (IsEqualIID(riid, __uuidof(IUnknown)))
        {
            *ppvObject = static_cast<IUnknown*>(this);
        }
        else if (IsEqualIID(riid, __uuidof(IDropTarget)))
        {
            *ppvObject = static_cast<IDropTarget*>(this);
        }
        else
        {
            return E_NOINTERFACE;
        }
        AddRef();
        return S_OK;
    }

    ULONG AddRef()
    {
        return InterlockedIncrement(&m_ref);
    }

    ULONG Release(void)
    {
        if (InterlockedDecrement(&m_ref) == 0)
        {
            delete this;
            return 0;
        }
        return m_ref;
    }

    HRESULT STDMETHODCALLTYPE DragEnter(
        IDataObject* pDataObj,
        DWORD grfKeyState,
        POINTL pt,
        DWORD* pdwEffect)
    {
        *pdwEffect = DROPEFFECT_LINK;
        return S_OK;
    }

    HRESULT DragOver(
        DWORD grfKeyState,
        POINTL pt,
        DWORD* pdwEffect)
    {
        return S_OK;
    }

    HRESULT DragLeave()
    {
        return S_OK;
    }

    HRESULT Drop(
        IDataObject* pDataObj,
        DWORD grfKeyState,
        POINTL pt,
        DWORD* pdwEffect)
    {
        std::vector<CLIPFORMAT> cfs;

        FORMATETC fmtetc{ static_cast<FORMATETC>(RegisterClipboardFormat(CFSTR_SHELLIDLIST)) };
        if (!pDataObj->QueryGetData(&fmtetc))
            return S_OK;

        IShellItemArray* pShellItems{ nullptr };
        if (SUCCEEDED(SHCreateShellItemArrayFromDataObject(pDataObj,
            IID_IShellItemArray, (void**)&pShellItems)))
        {
            DWORD c;
            if (SUCCEEDED(pShellItems->GetCount(&c)))
            {
                std::wstring ss;
                ss.append(std::format(
                    L"SIGDN_NORMALDISPLAY, "
                    "SIGDN_PARENTRELATIVEPARSING,"
                    "SIGDN_DESKTOPABSOLUTEPARSING, "
                    "SIGDN_PARENTRELATIVEEDITING, "
                    "SIGDN_DESKTOPABSOLUTEEDITING, "
                    "SIGDN_FILESYSPATH, "
                    "SIGDN_URL, "
                    "SIGDN_PARENTRELATIVEFORADDRESSBAR, "
                    "SIGDN_PARENTRELATIVE, "
                    "SIGDN_PARENTRELATIVEFORUI\r\n"));

                for (UINT i = 0; i < c; i++)
                {
                    IShellItem* pShellItem{ nullptr };
                    if (SUCCEEDED(pShellItems->GetItemAt(i, &pShellItem)))
                    {
                        ss.append(std::format(L"{}, {}, {}, {}, {}, {}, {}, {}, {}, {}\r\n",
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_NORMALDISPLAY),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVEPARSING),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_DESKTOPABSOLUTEPARSING),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVEEDITING),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_DESKTOPABSOLUTEEDITING),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_FILESYSPATH),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_URL),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVEFORADDRESSBAR),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVE),
                            GetShellItemDisplayName(pShellItem, SIGDN::SIGDN_PARENTRELATIVEFORUI)));
                    }
                    pShellItem->Release();
                }
                SetWindowText(m_hwndEdit, ss.c_str());
            }
            pShellItems->Release();
        }

        *pdwEffect = DROPEFFECT_LINK;
        return S_OK;
    }

    constexpr HWND GetEditWindowHandle() const
    {
        return m_hwndEdit;
    }
};

CMyDropTarget* pDropTarget{ nullptr };

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uiMsg)
    {
    case WM_CREATE:
        {
            // データ表示用のテキストボックス作成
            auto hwndEdit1{ CreateWindowEx(
                WS_EX_CLIENTEDGE,
                L"edit",
                L"ファイルやURLをドロップしてください。",
                WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_MULTILINE,
                0, 0, 0, 0,
                hWnd,
                nullptr,
                nullptr,
                nullptr) };
            SendMessage(hwndEdit1, WM_SETFONT,
                std::bit_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)),
                MAKELPARAM(FALSE, 0));
            // ドロップ対象として登録
            pDropTarget = new CMyDropTarget(hwndEdit1);
            RegisterDragDrop(hWnd, pDropTarget);
            pDropTarget->Release();
            return 0;
        }
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_QUIT:
        RevokeDragDrop(hWnd);
        return 0;
    case WM_SIZE:
        MoveWindow(
            pDropTarget->GetEditWindowHandle(),
            0, 0,
            LOWORD(lParam), HIWORD(lParam),
            TRUE);
        return 0;
    }

    return DefWindowProc(hWnd, uiMsg, wParam, lParam);
}

C++20&Win API IMAGE_COR20_HEADERを取得する

概要

32ビット形式のPEファイルを生データとして解析してIMAGE_COR20_HEADER構造体を取得するサンプルコードのC++20版です。実際にはIMAGE_COR20_HEADER構造体のメインであろうメタデータは今後の拡張に備えてフォーマット非公開なのでCLSID_CorMetaDataDispenserで公開されるクラスを使うべきだと思います。

C++11版はこちらです

コード

#include <utility>
#include <format>
#include <span>
#include <memory>

#define STRICT
#include <Windows.h>
#include <CorHdr.h>

// PEファイルのRVAからRVAを含むセクションのIMAGE_SECTION_HEADERを返します。
const PIMAGE_SECTION_HEADER ImageSectionHeaderContainingRVA(
    LPCVOID Base,
    const IMAGE_NT_HEADERS32* NTHeaders,
    DWORD RVA) noexcept
{
    // IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTORを含むセクションの探索
    const auto p{ IMAGE_FIRST_SECTION(NTHeaders) };
    for (auto& SectionHeader : std::span{ p, p + NTHeaders->FileHeader.NumberOfSections })
    {
        if (SectionHeader.VirtualAddress <= RVA
            && RVA <= SectionHeader.VirtualAddress + SectionHeader.SizeOfRawData)
        {
            return &SectionHeader;
        }
    }
    return nullptr;
}

// PEファイルのRVAをVAに変換します。
LPCVOID ImageRVAToVA32(LPCVOID Base, const IMAGE_NT_HEADERS32* NTHeaders, DWORD RVA) noexcept
{
    auto SectionHeader{ ImageSectionHeaderContainingRVA(Base, NTHeaders, RVA) };
    if (SectionHeader == nullptr)
        return nullptr;
    return (std::bit_cast<LPCBYTE>(Base) + SectionHeader->PointerToRawData)
        + (RVA - SectionHeader->VirtualAddress);
}

// ファイルが32ビットPE形式であればIMAGE_NT_HEADERS32のポインタを返します。
const PIMAGE_NT_HEADERS32 GetPointerToImageNTHeaders32(LPCVOID Base) noexcept
{
    auto DOSHeader{ std::bit_cast<const PIMAGE_DOS_HEADER>(Base) };
    if (DOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
        return nullptr;

    auto Signature{ std::bit_cast<const PDWORD>(std::bit_cast<LPCBYTE>(Base) + DOSHeader->e_lfanew) };
    if (*Signature != IMAGE_NT_SIGNATURE)
        return nullptr;

    auto FileHeader{ std::bit_cast<const PIMAGE_FILE_HEADER>(Signature + 1) };
    if (FileHeader->SizeOfOptionalHeader != sizeof IMAGE_OPTIONAL_HEADER32)
        return nullptr;

    auto OptionalHeader{ std::bit_cast<const PIMAGE_OPTIONAL_HEADER32>(FileHeader + 1) };
    if (OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
        return nullptr;

    return std::bit_cast<const PIMAGE_NT_HEADERS32>(Signature);
}

const PIMAGE_COR20_HEADER GetPointerToCorHeader20(LPCVOID Base) noexcept
{
    auto NTHeaders{ GetPointerToImageNTHeaders32(Base) };
    if (NTHeaders == nullptr)
        return nullptr;

    // IMAGE_COR2_HEADERはIMAGE_DIRECTORY_ENTRY_COM_DESCRIPTORに配置されます
    auto ComDescDir{ &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] };
    return std::bit_cast<const PIMAGE_COR20_HEADER>(
        ImageRVAToVA32(Base, NTHeaders, ComDescDir->VirtualAddress));
}

#include <iostream>

struct HANDLE_deleter {
    void operator() (HANDLE handle) const noexcept {
        ::CloseHandle(handle);
    }
};
using unique_HANDLE = std::unique_ptr<std::remove_pointer_t<HANDLE>, HANDLE_deleter>;

struct MapViewOfFilePointer_deleter {
    void operator() (LPCVOID handle) const noexcept {
        ::UnmapViewOfFile(handle);
    }
};
using unique_MapViewOfFilePointer = std::unique_ptr<std::remove_pointer_t<HANDLE>, MapViewOfFilePointer_deleter>;

// 32ビットPEファイルのCLIヘッダー情報を表示します。
int main()
{
    std::wcout.imbue(std::locale("", std::locale::ctype));

    // CLIヘッダーを確認する実行ファイルの場所
    auto path{ <ファイル名を指定して下さい> };

    unique_HANDLE FileHandle{ CreateFileW(path, GENERIC_READ,
        FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr) };
    if (FileHandle.get() == INVALID_HANDLE_VALUE)
    {
        std::wcout << L"ファイルハンドルが開けませんでした。" << std::endl;
        return -1;
    }
    unique_HANDLE FileMapHandle{ CreateFileMappingW(FileHandle.get(), nullptr, PAGE_READONLY, 0, 0, nullptr) };
    if (FileMapHandle == nullptr)
    {
        std::wcout << L"ファイルマッピングオブジェクトが作成できませんでした。" << std::endl;
        return -1;
    }
    unique_MapViewOfFilePointer mapViewOfFile{ MapViewOfFile(FileMapHandle.get(), FILE_MAP_READ, 0, 0, 0) };
    auto Base{ std::bit_cast<LPCBYTE>(mapViewOfFile.get()) };
    if (Base == nullptr)
    {
        std::wcout << L"ファイルマッピングオブジェクトのビューが作成できませんでした。" << std::endl;
        return -1;
    }

    auto CorHeader{ GetPointerToCorHeader20(Base) };
    if (CorHeader == nullptr)
    {
        std::wcout << L"ファイルはNTヘッダーまたはCLIヘッダーを含みません。" << std::endl;
        return -1;
    }

    // CLIヘッダー情報の出力
    auto entryPointType{ (CorHeader->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) ? L"Native" : L"Managed" };
    std::wcout
        << std::format(
            L"IMAGE_COR20_HEADER\n"
            "ランタイムのバージョン: {}.{}\n"
            "メタデータのサイズ: {}\n"
            "フラグ: 0x{:08X}\n"
            "エントリーポイント: 0x{:08X} ({})",
            CorHeader->MajorRuntimeVersion, CorHeader->MinorRuntimeVersion,
            CorHeader->MetaData.Size,
            CorHeader->Flags,
            CorHeader->EntryPointRVA, entryPointType)
        << std::endl;

    return 0;
}

C++20&Win API ファイルのセキュリティユーザーの名前を列挙する

ファイルセキュリティ記述子→DACL→ACEと取得してセキュリティユーザーの名前を列挙するサンプルです。

#include <bit>
#include <string>
#include <span>
#include <memory>
#include <vector>

#define STRICT
#define NOMINMAX
#include <Windows.h>
#include <AclAPI.h>

// ファイルのセキュリティ情報をバイト配列として返します。
std::vector<BYTE> GetFileSecurityW(std::wstring_view Path, SECURITY_INFORMATION RequestedInformation)
{
    DWORD needed{ 0 };
    if (!::GetFileSecurityW(Path.data(), RequestedInformation, nullptr, 0, &needed)
        && ::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    {
        return {};
    }

    std::vector<BYTE> buffer(needed);
    if (!::GetFileSecurityW(Path.data(), RequestedInformation,
        static_cast<PSECURITY_DESCRIPTOR>(buffer.data()), needed, &needed))
    {
        return {};
    }
    return std::move(buffer);
}

// SIDの名前・参照ドメイン名・名前の使い方を返します。
// auto [name, refDomainName, use] = LookupAccountSidW(SystemName, Sid);
std::tuple<std::wstring, std::wstring, SID_NAME_USE> LookupAccountSidW(
    std::wstring_view SystemName,
    PSID Sid)
{
    DWORD cchName{ 0 };
    DWORD cchRefDomainName{ 0 };
    SID_NAME_USE use;
    if (!::LookupAccountSidW(nullptr, Sid, 0,
        &cchName, nullptr, &cchRefDomainName, &use)
        && ::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    {
        return {};
    }

    std::wstring name(cchName, L'\0');
    std::wstring refDomainName(cchRefDomainName, L'\0');
    if (!::LookupAccountSidW(nullptr, Sid,
        name.data(), &cchName, refDomainName.data(), &cchRefDomainName, &use))
    {
        return {};
    }

    return std::make_tuple(std::move(name), std::move(refDomainName), use);
}

struct HLOCAL_deleter {
    void operator() (void* p) const noexcept {
        ::LocalFree(p);
    }
};
template <typename T>
using unique_hlocal_ptr = std::unique_ptr<T, HLOCAL_deleter>;

using unique_EXPLICIT_ACCESS_W = unique_hlocal_ptr<EXPLICIT_ACCESS_W>;

// ACLのACE記述構造体配列を取得します。
// auto [p, entryCount, explicitEntries] = GetExplicitEntriesFromAclWInUniquePtr(pDacl);
std::tuple<unique_EXPLICIT_ACCESS_W, ULONG, std::span<EXPLICIT_ACCESS_W>> GetExplicitEntriesFromAclWInUniquePtr(
    PACL pAcl)
{
    ULONG entryCount;
    PEXPLICIT_ACCESS_W pExplicitEntries;
    if (::GetExplicitEntriesFromAclW(pAcl, &entryCount, &pExplicitEntries) != ERROR_SUCCESS)
    {
        return {};
    }

    return std::make_tuple(
        unique_EXPLICIT_ACCESS_W(pExplicitEntries),
        entryCount,
        std::span{ pExplicitEntries, pExplicitEntries + entryCount });
}

// TRUSTEE_W構造体から名前を取得します。
std::wstring GetTrusteeName(const TRUSTEE_W& Trustee)
{
    // https://docs.microsoft.com/en-us/windows/win32/api/accctrl/ns-accctrl-trustee_a
    // TRUSTEE_IS_NAME/TRUSTEE_IS_OBJECTS_AND_NAME/TRUSTEE_IS_OBJECTS_AND_SID/TRUSTEE_IS_SID
    switch (Trustee.TrusteeForm)
    {
    case TRUSTEE_IS_NAME:
        return Trustee.ptstrName;
    case TRUSTEE_IS_OBJECTS_AND_NAME:
        return std::bit_cast<OBJECTS_AND_NAME_W*>(Trustee.ptstrName)->ptstrName;
    case TRUSTEE_IS_OBJECTS_AND_SID:
        {
            auto [name, refDomainName, use] = LookupAccountSidW(
                {}, std::bit_cast<OBJECTS_AND_SID*>(Trustee.ptstrName)->pSid);
            return std::move(name);
        }
        break;
    case TRUSTEE_IS_SID:
        {
            auto [name, refDomainName, use] = LookupAccountSidW(
                {}, std::bit_cast<PSID>(Trustee.ptstrName));
            return std::move(name);
        }
    default:
        return {};
    }
}

#include <iostream>

int main()
{
    std::wstring_view path{ L"C:\\Windows" };

    // ファイルのDACLセキュリティ情報を取得します。
    auto secDescBuffer = GetFileSecurityW(path, DACL_SECURITY_INFORMATION);
    auto pSecDesc = static_cast<PSECURITY_DESCRIPTOR>(secDescBuffer.data());

    // ファイルのDACLの存在・ポインタ・既定かどうかを取得します。
    BOOL daclPresent;
    PACL pDacl;
    BOOL daclDefaulted;
    if (!::GetSecurityDescriptorDacl(pSecDesc, &daclPresent, &pDacl, &daclDefaulted))
    {
        return 0;
    }

    // DACLのエントリを取得します。
    auto [p, entryCount, explicitEntries] = GetExplicitEntriesFromAclWInUniquePtr(pDacl);
    for (auto& explicitEntry : explicitEntries)
    {
        std::wcout << GetTrusteeName(explicitEntry.Trustee) << std::endl;
    }

    return 0;
}