potisanのプログラミングメモ

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

C++&Win32 API モジュールハンドル(HMODULE)は実行可能ファイルのメモリマップトファイルアドレス

公式ドキュメントは確認していませんが、Windows NT系列ではモジュールハンドルHMODULEは実行可能ファイルのメモリマップトファイルアドレスらしいです。なので、GetModuleHandleLoadLibraryで取得したモジュールハンドルをchar型文字列にキャストすると最初の2文字はMZIMAGE_DOS_HEADERの最初のメンバー変数)で、PSAPIGetMappedFileName関数で実行ファイル名を取得できます。

#include <bit>
#include <string>

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

constexpr std::wstring unpack_chars2_to_wstring_le(uint16_t x)
{
    return {
        static_cast<wchar_t>(x & 0xff),
        static_cast<wchar_t>((x >> 8) & 0xff)
    };
}

constexpr std::wstring unpack_chars4_to_wstring_le(uint32_t x)
{
    return {
        static_cast<wchar_t>(x & 0xff),
        static_cast<wchar_t>((x >> 8) & 0xff),
        static_cast<wchar_t>((x >> 16) & 0xff),
        static_cast<wchar_t>((x >> 24) & 0xff)
    };
}

#include <iostream>

int main()
{
    for (auto handle : {GetModuleHandleW(nullptr), LoadLibraryW(L"user32.dll")})
    {
        auto base{std::bit_cast<const PBYTE>(handle)};
        auto pimg_dos_hdr{std::bit_cast<const PIMAGE_DOS_HEADER>(base)};
        auto pimg_nt_hdrs_magic{std::bit_cast<const PDWORD>(base + pimg_dos_hdr->e_lfanew)};
        std::wcout << unpack_chars2_to_wstring_le(pimg_dos_hdr->e_magic).data() << std::endl; // MZ (IMAGE_DOS_SIGNATURE)
        std::wcout << unpack_chars4_to_wstring_le(*pimg_nt_hdrs_magic).data() << std::endl;   // PE\0\0 (IMAGE_NT_SIGNATURE)

        std::wstring sz(MAX_PATH - 1, '\0');
        ::GetMappedFileNameW(GetCurrentProcess(), handle, sz.data(), MAX_PATH);
        std::wcout << sz << std::endl;

        std::wcout << std::endl;
    }
}

constexprstd::bit_castを使わないコード

#include <string>
#include <iostream>

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

inline auto conv_uint16_into_chars(uint16_t x) {
    return std::string(reinterpret_cast<const char* const>(&x), sizeof x);
}

inline auto conv_uint32_into_chars(uint32_t x) {
    return std::string(reinterpret_cast<const char* const>(&x), sizeof x);
}

int main()
{
    for (auto handle : { ::GetModuleHandleW(nullptr), ::LoadLibraryW(L"user32.dll") })
    {
        auto base = reinterpret_cast<const PBYTE>(handle);

        auto pimg_dos_hdr = reinterpret_cast<PIMAGE_DOS_HEADER>(base);
        auto pimg_nt_hdrs_magic = reinterpret_cast<PDWORD>(base + pimg_dos_hdr->e_lfanew);

        std::cout.setf(std::ios_base::boolalpha);
        std::cout << conv_uint16_into_chars(pimg_dos_hdr->e_magic) << std::endl; // MZ (IMAGE_DOS_SIGNATURE)
        std::cout << conv_uint32_into_chars(*pimg_nt_hdrs_magic) << std::endl;   // PE\0\0 (IMAGE_NT_SIGNATURE)

        std::wstring sz(MAX_PATH - 1, '\0');
        ::GetMappedFileNameW(GetCurrentProcess(), handle, sz.data(), MAX_PATH);
        std::wcout << sz << std::endl;

        std::wcout << std::endl;
    }
}

出力例(システムディレクトリと実行ファイルProject1.exeがHarddiskVolume2にある場合)

MZ
PE
\Device\HarddiskVolume2\...\Project1.exe

MZ
PE
\Device\HarddiskVolume2\Windows\System32\user32.dll

参考