potisanのプログラミングメモ

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

WIL GitHub Wiki Win32ヘルパーの和訳・改変

MicrosoftがGitHubでMITライセンス公開しているWILのGitHub Wikiの記事を和訳・改変したものです。素人による翻訳なので、誤訳や著作権上の問題などありましたらご連絡いただけますと幸いです。

Win32ヘルパー(原題:Win32 helpers)

Brian Gianforcaro、2020/10/6、リビジョン9個

WILのWin32ヘルパーはWin32で使われる多様な関数とデータ型を補助します。

使い方

Win32ヘルパーは適切なヘッダーファイルをインクルードして使用できます。

#include <wil/win32_helpers.h>

文字列長定数

すべての文字列長定数はwil名前空間にありsize_t型です。

名前 意味
max_path_segment_length 254 ディレクトリ名やファイル名の最大長。終端のnullは含みません。
max_path_length 259 MAX_PATHパスの最大長。終端のnullは含みません。
max_extended_path_length 32743 拡張パス(extended path)の最大長。終端のnullは含みません。
guid_string_buffer_length 39 GUIDを保持するバッファーのサイズ。前後の中括弧と終端のnullを含みます。
guid_string_length 38 GUID文字列の長さ。前後の中括弧は含みますが、終端のnullは含みません。

max_extended_path_lengthの一般的ではない値はシステム制限の0x7FFFから24を引いた数です。24は\Device\HardDiskVolume#プレフィックスの長さです。パスが10~99番目のハードディスクボリュームを指す場合、このプレフィックスは25文字に増え、対応する最大長は1だけ減ります。

ファイルタイム定数

ファイルタイム定数はwil::filetime_duration名前空間にあります。これらはlomg long型であり、よく知られた期間を持つFILETIME単位(100 ns)の数を表します。

名前
one_millisecond 10000
one_second 10000000
one_minute 600000000
one_hour 36000000000
one_day 864000000000

ファイルタイムヘルパー

ファイルタイムヘルパーはwil::filetime名前空間にあります。

  • unsigned long long to_int64(const FILETIME &ft)
  • FILETIME from_int64(unsigned long long i64)
    • FILETIME構造体(2つの32ビット整数)と64ビット符号なし整数の変換関数。
  • FILETIME add(_In_ FILETIME const &ft, long long delta)
    • 既存のFILETIME構造体の値を特定の刻み(tick)で調整します。
  • bool is_empty(const FILETIME &ft)
    • FILETIME全体が0ならtrueを返します。
  • FILETIME get_system_time()
    • システム日時をFILETIMEとして返します。

可変長文字列を返す関数

多くのWin32関数は呼び出し側の提供するバッファーに可変長文字列を返します。AdaptFixedSizeToAllocatedResultテンプレート関数は文字列のバッファーを要求し、必要に応じてより大きなバッファーで再試行する共通パターンを実装します。

template<typename string_type, size_t stackBufferLength = 256>
HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, wistd::function<HRESULT(PWSTR, size_t, size_t*)> callback);

求める文字列を生産するまで、バッファーを大きくしながら繰り返しcallbackを呼び出します。バッファーはstring_type形式で返されます。失敗時はCOMエラーコードを返し、resultは変更されません。

  • string_typestring_maker(原文リンク)のサポートする任意の型です。
  • stackBufferLengthは初期クエリで使用されるスタックバッファーのサイズです。ほとんどの使用ケースで十分だろう値を選ぶことで、リトライが不要なより短い実行パスを提供できます。
  • callbackは提供したバッファーに文字列を取得し、実際あるいは必要なサイズを返します。一般的にラムダ式が渡されます。
HRESULT callback(PWSTR value, size_t valueLength, size_t* valueLengthNeededWithNul);
  • valueは書き込まれるバッファーのポインタです。
  • valueLengthはバッファーのサイズです。null終端を含めます。
  • valueLengthNeededWithNul はバッファーに要求されるサイズを取得します。null終端を含めます。

コールバックが文字列全体を読み込めた場合、valueLengthNeededWithNulは返される文字列(null終端を含む)の正確なサイズを返し、コールバックはS_OKを返します。

バッファーのサイズが小さすぎてコールバックが文字列全体を読み込めない場合、valueLengthNeededWithNulは次の反復で使うバッファーのサイズを返し、コールバックはS_OKを返します。多くの場合、ラップしたいWin32関数は次の反復の提案サイズを提供するでしょう。その他の場合、(std::max)(40, valueLength * 2)のようなヒューリスティックを使う必要があり、整数のオーバーフロー回避に注意が必要です。

コールバックは文字列を取得できない場合にCOMエラーコードを返し、それはAdaptFixedSizeToAllocatedResultの戻り値に伝播されます。この場合、valueLengthNeededWithNulの値は使用されません。

ノートAdaptFixedSizeToAllocatedResultで使われる引数は一般的な文脈の命名規則Lengthはnull終端を除いた長さ、Sizeはnull終端を含む長さ)に従いません。私達はこれを認識しています。

可変長文字列を返す関数の定義済みアダプター

HRESULTを返す非throw版アダプターが常に用意されています。throw版はしばしば返された文字列をそのまま返します。

template<typename string_type, size_t stackBufferLength = 256>
HRESULT ExpandEnvironmentStringsW(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT;

template<typename string_type = wil::unique_cotaskmem_string, size_t stackBufferLength = 256>
string_type ExpandEnvironmentStringsW(_In_ PCWSTR input);

ExpandEnvironmentStringsW(input, buffer, bufferSize)のラッパー。

template<typename string_type, size_t stackBufferLength = 256>
HRESULT SearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, _In_opt_ PCWSTR extension, string_type& result) WI_NOEXCEPT;

template<typename string_type = unique_cotaskmem_string, size_t stackBufferLength = 256>
string_type TrySearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, PCWSTR _In_opt_ extension);

SearchPathW(path, fileName, extension, bufferSize, buffer, nullptr)のラッパー。

TrySearchPathW版はERROR_FILE_NOT_FOUNDを成功として扱い、空文字列を作成します。

template<typename string_type, size_t stackBufferLength = 256>
HRESULT QueryFullProcessImageNameW(HANDLE processHandle, _In_ DWORD flags, string_type& result) WI_NOEXCEPT;

QueryFullProcessImageNameW(processHandle, flags, buffer, &bufferSize)のラッパー。

template<typename string_type>
HRESULT GetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT;

template<typename string_type = unique_cotaskmem_string>
string_type GetEnvironmentVariableW(_In_ PCWSTR key);

template<typename string_type>
HRESULT TryGetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT;

template<typename string_type = unique_cotaskmem_string>
string_type TryGetEnvironmentVariableW(_In_ PCWSTR key);

GetEnvironmentVariableW(key, buffer, bufferSize)のラッパー。

TryGetEnvironmentVariableW版はERROR_ENVVAR_NOT_FOUNDを成功として扱い、空文字列を作成します。

template<typename string_type, size_t initialBufferLength = 128>
HRESULT GetModuleFileNameExW(_In_opt_ HANDLE process, _In_opt_ HMODULE module, string_type& path);

template <typename string_type = unique_cotaskmem_string>
string_type GetModuleFileNameExW(HANDLE process, HMODULE module);

GetModuleFileNameExW(process, module, buffer, bufferSize)のラッパー。

template<typename string_type, size_t initialBufferLength = 128>
HRESULT GetModuleFileNameW(HMODULE module, string_type& path);

template<typename string_type = unique_cotaskmem_string>
string_type GetModuleFileNameW(HMODULE module);

template<typename string_type = unique_cotaskmem_string>
string_type GetModuleFileNameW(HMODULE module);

GetModuleFileNameExW(nullptr, module, buffer, bufferSize)のラッパー。

template<typename string_type, size_t stackBufferLength = 256>
HRESULT GetSystemDirectoryW(string_type& result) WI_NOEXCEPT;

GetSystemDirectoryW(buffer, bufferSize)のラッパー。

ワンタイム初期化(One-time initialization)

ワンタイム初期化(one-time-initialization)ヘルパー関数は最初に呼び出されたときだけ実行され、その後の呼び出しでは何もしません。

template<typename T>
HRESULT init_once_nothrow(_Inout_ INIT_ONCE& initOnce, T func, _Out_opt_ bool* callerCompleted = nullptr) WI_NOEXCEPT;
  • initOnceINIT_ONCE構造体であり、初期化が既に実行されたかを記録します。
  • funcHRESULT operator()メソッドを持つ関数(原文:functor)です。
  • callerCompletedはオプション引数です。提供された場合、funcの実行が成功した場合はtruefuncが実行されないか失敗した場合はfalseを設定されます。

funcがCOM失敗コードを返した場合、失敗コードはinit_one_nothrowの戻り値となり、initOneは未初期化のままになります。同じinitOneを与えたその後のinit_one_nothrow呼び出しでは初期化が再試行されます。

使用例:

INIT_ONCE g_init{};
ComPtr<IFoo> g_foo;

HRESULT MyMethod()
{
    bool winner = false;
    RETURN_IF_FAILED(wil::init_once_nothrow(g_init, []
    {
        ComPtr<IFoo> foo;
        RETURN_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo));
        RETURN_IF_FAILED(foo->Startup());
        g_foo = foo;
    }, &winner);
    if (winner)
    {
        RETURN_IF_FAILED(g_foo->Another());
    }
    return S_OK;
}

詳細はInitOnceExecuteOnce on MSDNを参照してください。

template<typename T> bool init_once_failfast(_Inout_  INIT_ONCE& initOnce, T&& func) WI_NOEXCEPT;

_failfast版はcallerCompletedの値を返し、初期化関数の失敗時はフェイルファストします。

template<typename T> bool init_once(_Inout_  INIT_ONCE& initOnce, T func);

例外ベース版のため、funcvoid operator()を持つべきです。これは例外のthrowにより失敗を報告します。

使用例:

INIT_ONCE g_init{};
ComPtr<IFoo> g_foo;
void MyMethod()
{
    bool winner = wil::init_once(g_init, []
    {
        ComPtr<IFoo> foo;
        THROW_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo));
        THROW_IF_FAILED(foo->Startup());
        g_foo = foo;
    });
    if (winner)
    {
        THROW_IF_FAILED(g_foo->Another());
    }
}
bool init_once_initialized(_Inout_  INIT_ONCE& initOnce) WI_NOEXCEPT;

initOne構造体が初期化成功で完了した場合、trueが返されます。

その他のヘルパー関数

template<typename string_type, size_t stackBufferLength = 256>
HRESULT ExpandEnvAndSearchPath(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT;

ExpandEnvironmentStringsWと続くSearchPathWの組み合わせです。

HINSTANCE GetModuleInstanceHandle();

現在のモジュールのハンドルを返します。__ImageBase特殊リンカーシンボルを使います。

auto GetProcAddressByFunctionDeclaration(hinst, FunctionName)

GetProcAddressByFunctionDeclaration マクロは提供した関数の関数プロトタイプに合うように戻り値をキャストする型安全なGetProcAddressです。

使用例:

auto sendMail = GetProcAddressByFunctionDeclaration(hinstMAPI, MAPISendMailW);
if (sendMail)
{
    sendMail(0, 0, pmm, MAPI_USE_DEFAULT, 0);
}

著作権表示

この記事は以下の著作物を使用しています。

Copyright (c) Microsoft Corporation. All rights reserved. https://github.com/microsoft/wil/blob/master/LICENSE