ゆなこんブログ

ゆなこんぴゅーたー (Yuna Computer) の公式ブログ

Windowsのシステムエラーコードからエラーメッセージを取得する方法

GetLastError() 関数から返されるシステムエラーコードに対応するエラーメッセージ文字列を取得するために、SystemMessageクラスを書きました。 定番の処理なので車輪の再発明なのは分かっていますが、新しい C++ で書きたいよね。string_view 大好き! ってなわけで、このSystemMessageクラスは単純で安全なリソース管理をします。

// SystemMessage.hpp
#ifndef SYSTEM_MESSAGE_HPP
#define SYSTEM_MESSAGE_HPP

#include <Windows.h>
#include <string_view>
#include <stdexcept>

template <typename = void>
class SystemMessageImpl {
    LPWSTR str = nullptr;
    std::size_t len = 0;

public:
    explicit SystemMessageImpl(DWORD dwMessageId, DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)) {
        constexpr DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;
        len = ::FormatMessageW(flags, nullptr, dwMessageId, dwLanguageId, reinterpret_cast<LPWSTR>(&str), 0, nullptr);
        if (!len) {
            throw std::runtime_error("エラーメッセージの取得に失敗しました。");
        }
    }

    ~SystemMessageImpl() {
        ::LocalFree(str);
    }

    SystemMessageImpl(const SystemMessageImpl&) = delete;
    SystemMessageImpl& operator=(const SystemMessageImpl&) = delete;
    SystemMessageImpl(SystemMessageImpl&&) = delete;
    SystemMessageImpl& operator=(SystemMessageImpl&&) = delete;

    std::wstring_view view() const {
        return std::wstring_view(str, len);
    }
};

using SystemMessage = SystemMessageImpl<>;

#endif // SYSTEM_MESSAGE_HPP

クラステンプレートとして実装されているので、ヘッダーオンリーのライブラリとして使えます。 これにより、複数の翻訳単位での #include ができますし、リンケージの問題を避けられます。たぶん。 また、エラーメッセージの取得に失敗した場合には例外を投げます。

Windowsのシステムエラーコードからエラーメッセージを取得する上でおそらく問題となるのは、訳が分からない FormatMessageW() / FormatMessage() の仕様と、FORMAT_MESSAGE_ALLOCATE_BUFFER の指定で確保されたバッファをどう管理するかだと思うのですが、その辺はクラスに閉じ込めてます。 本質となるエラーメッセージは、 view() メンバ関数呼び出して wstring_view として使ってねって設計です。

ムーブ周りまで = delete してますが、必要であれば正しく定義してください。 ここでは不要ですし、実装するのも面倒なので、楽に安全側に倒しています。

以下の例は、SystemMessageクラスを使って、現在のスレッドの最後のエラーコードに対応するメッセージを取得して表示する例です。 システムエラーメッセージを正しく表示するために setlocale() でロケールを日本語に設定しています。

#include <clocale>
#include <iostream>
#include "SystemMessage.hpp"

int main()
{
    std::setlocale(LC_CTYPE, "ja_JP.UTF-8");
    try {
        SystemMessage message{ ::GetLastError() };
        std::wcout << message.view();
    } catch (const std::runtime_error& e) {
        std::wcerr << L"エラーメッセージの取得に失敗: " << e.what() << std::endl;
    }
}

実行結果は以下の通り。GetLastError() が返す値によってメッセージが変わります。

この操作を正しく終了しました。

連載「技術的負債とダンスを」の目次

面白かった記事・連載を見つけたのですが、目次が見当たらず不便だったので目次を作りました。

連載「技術的負債とダンスを」の目次

純正カバーからサビが出てApple Storeコールセンターに電話したけどダメだった

純正カバーから出たサビのせいでiPad Airに傷がつく

お客様用に購入した純正カバーからサビが出て、そのサビのせいでカバーを取り付けていたiPad Airに傷がついてしまいました。 交換できるかApple Storeコールセンターに電話をしたのですが、カバーは交換できずiPad Airは交換できるかもという微妙な話で終わってしまいました。

電話の内容と結果について書きたいと思います。

続きを読む

.NET 5.0 と VB の今後

.NET 5.0 と Visual Basic の今後

これから Visual Basic がどうなっていくのか公式の発表がありました。

devblogs.microsoft.com

以前こんな記事を書きました。

blog.yuna-computer.com

その時に VB のデスクトップ開発に力が入れられる と書きましたが、実際そうなりました。

今は .NET Core 3.1 の時代ですが、今後 .NET 5 の開発が行われていきます。 その .NET 5 では 以下の Visual Basic の開発がサポートされます。

  • Class Library
  • Console
  • Windows Forms
  • WPF
  • Worker Service
  • ASP.NET Core Web API

広い範囲で Visual Basic での開発がサポートされるようです。

その一方で、Visual Basic 言語そのものは今後バージョンアップされないようです。 それを「フェードアウト」とする見方もあるようですね。

www.softantenna.com

個人的には非常に残念なのですが、VB を使う層がそもそも保守的で、言語を改良されることを好まない、改良されるとついていけない(ついて来ない)ような人たちが多かったようです。

C++最近の記事

C++に関するリンク

まとめる時間がないので一覧のみで

無限アラート事件

Coinhive事件の最終弁論があったことを以前書きました。

blog.yuna-computer.com

今度は「無限ループの中でアラート表示する」だけのJavaScriptで逮捕される事件(?)が起きました。

続きを読む

C++に関するリンク

C++に関するリンク

最近はブログの更新が滞っていました。

C++20 仕様がほぼ固まるということで、最近は C++ のブログ記事も多く出ていますね。 C++20 に限らず、C++に関する記事を紹介します。

続きを読む