Windows のエラー文字列の取得

今回は Windows の GetLastError() などが返すシステムエラーコードに対応するエラー文字列を返す関数を作成します.
エラー文字列は例えば C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include などにある WinError.h というファイルに書かれているのですが,開発中に見るのは面倒だったり,実行時にエラー文字列を画面に出力したい場合もあると思うので,一度エラーコードを文字列に変換する関数を作っておけば楽になるでしょう.

以下に,エラーコードをエラー文字列に変換する私の実装例を紹介します.

error.hpp

#ifndef ERROR_HPP_20100711_
#define ERROR_HPP_20100711_

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif


#include <string>
#include <windef.h>


namespace error {
    const std::wstring getErrorMessage(DWORD error);
    const std::wstring getLastErrorMessage();
}


#endif

error.cpp

#include <iomanip>
#include <sstream>
#include <windows.h>
#include "error.hpp"


namespace {
    class AutoLocal {
    public:
        explicit AutoLocal(HLOCAL local = nullptr) : local_(local) {}
        ~AutoLocal() { LocalFree(local_); }

        HLOCAL& get() { return local_; }

    private:
        HLOCAL local_;
    };
}


const std::wstring error::getErrorMessage(DWORD error)
{
    AutoLocal msg;

    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        nullptr, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&msg.get()), 0, nullptr)) {
            return std::wstring(static_cast<wchar_t*>(msg.get()));
    }
    else { // 失敗したら適当にエラーコードを付けて返す
        std::wostringstream ostr;

        ostr << L"0x" << std::hex << std::setw(8) << std::setfill(L'0') << error;

        return ostr.str();
    }
}


const std::wstring error::getLastErrorMessage()
{ return getErrorMessage(GetLastError()); }

error.cpp にシステムエラーコードを文字列に変換する関数 getErrorMessage() を実装しました.error.cpp をプロジェクトに加え(他のソースコードと一緒にコンパイル),error.hpp を include することにより getErrorMessage が使用可能になります.
getErrorMessage はエラーコードを受け取り,それを FormatMessage に渡すことによって文字列を取得します.FormatMessage に FORMAT_MESSAGE_ALLOCATE_BUFFER を指定した場合,バッファを LocalFree で解放する必要があることに注意して下さい(本サンプルではデストラクタで解放処理をしています).
また,getLastErrorMessage() は getErrorMessage() の引数に GetLastError() の戻り値を渡しているだけです.

以下のテストコードで getErrorMessage の動作を確認できます.

test.cpp

#include <windows.h>
#include "error.hpp"


int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
    MessageBox(nullptr, error::getErrorMessage(ERROR_OUTOFMEMORY).c_str(), L"ERROR_OUTOFMEMORY に対応するエラー文字列", MB_OK); // この操作を完了するのに十分な記憶域がありません。
    MessageBox(nullptr, error::getLastErrorMessage().c_str(), L"GetLastError() に対応するエラー文字列", MB_OK); // この操作を正しく終了しました。

    return 0;
}

nullptr でエラーが出る方は,nullptr をすべて 0 に置換して下さい.