読者です 読者をやめる 読者になる 読者になる

ゆとりーなの日記

日記的な事を書いて行くと思はれる

標準ライブラリに入つたライブラリでもBoostの方がお得感あるライブラリ

std::system_errorとboost::system::system_error

MSVCのstd::system_errorはGetLastErrorを渡してもFormatMessage相當のメッセージをwhatで返󠄁してくれない(VS2015 Previwの時點)。
試しに以下のコードを實行してみても、

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
  try {
    WNDCLASSEX wc = {}; // 初期化󠄁はテキトー
    wc.cbSize = sizeof(wc);
    wc.lpszClassName = L"TEST";
    if (!RegisterClassEx(&wc)) {
      throw std::system_error{static_cast<int>(GetLastError()), std::system_category()};
    }
    // 同名のクラスは既󠄀に登錄されてゐる!
    if (!RegisterClassEx(&wc)) {
      throw std::system_error{static_cast<int>(GetLastError()), std::system_category()};
    }
  } catch (const std::exception &err) {
    OutputDebugStringA(err.what());
  }
  return 0;
}
unknown error

としか言つてくれない。
代はりにboost::system::system_errorを使󠄁ふと、

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
  try {
    WNDCLASSEX wc = {}; // 初期化󠄁はテキトー
    wc.cbSize = sizeof(wc);
    wc.lpszClassName = L"TEST";
    if (!RegisterClassEx(&wc)) {
      throw boost::system::system_error{static_cast<int>(GetLastError()), boost::system::system_category()};
    }
    if (!RegisterClassEx(&wc)) {
      throw boost::system::system_error{static_cast<int>(GetLastError()), boost::system::system_category()};
    }
  } catch (const std::exception &err) {
    OutputDebugStringA(err.what());
  }
  return 0;
}
そのクラスは既にあります。

FormatMessage相當のローカライズされたメッセージが返󠄁つてくるのでお得である。最近のFormatMessageはHRESULT値にもある程󠄁度は對應してゐるらしいので、DirectXAPIの戾り値を入れて投げてみると案外幸せになれるかもしれない。

std::tr2::sys::pathとboost::filesystem::path

最近󠄁のMSVCにはtr2としてbasic_pathが入つてゐる。これはどうもboost::filesystemで云ふ處のv2仕樣らしく、C++1yに提案されてゐるのはv3仕樣との事なので嚴密には標準ライブラリに入つたと云ふにはあれなのだがtr2のpathよりもboostのpathの方がWin環󠄁境でも壓倒的にお得なのでここでさらつと。
tr2のpathはbasic_pathなんでマルチバイト文󠄁字列のファイルパスとワイド文󠄁字列のファイルパスを扱ふクラスはpathとwpathと完全󠄁にテンプレートで分󠄁かれてゐる。要󠄁するにマルチバイト文󠄁字列のファイル名とワイド文󠄁字列のファイルパスは手前󠄁で變換しないといけない。これの何が不便󠄁かと云ふと、ファイル名を受け取るCOM APIにはワイド文󠄁字列を受け取るAPIしかないもの(例へばWIC)があり、3Dモデルデータが使󠄁ふテクスチャファイル名はマルチバイト文󠄁字列で保持されてゐると云ふ場合が儘ある事である。

void Read3DModel(const std::tr2::sys::path &modelPath/* "test/model.dat "*/) {
  std::ifstream fin(modelPath, std::ios::in | std::ios::binary);
  ...
  char textureFileName[21];
  fin.read(textureFileName, 21);
  const std::tr2::sys::path texturePath = modelPath.parent_path() / textureFileName;
  Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
  wicFactory->CreateDecoderFromFilename(/* ワイド文󠄁字列から取るのが面倒 */,
                                        nullptr,
                                        GENERIC_READ,
                                        WICDecodeMetadataCacheOnLoad,
                                        &decoder)
}

texturePathからワイド文󠄁字列ポインタを取る手段がないのでMultiByteToWideCharなりを使󠄁つて變換しないといけない。今更󠄁こんなCつぽいAPIを使󠄁ふ氣にはなかなかなれない。
一方でWin環󠄁境のboost::filesystem::path(v3)は、c_str()メンバ函數でワイド文󠄁字列ポインタを返󠄁してくれる。因つて單純に

void Read3DModel(const std::tr2::sys::path &modelPath/* "test/model.dat "*/) {
  boost::filesystem::ifstream fin(modelPath, std::ios::in | std::ios::binary);
  ...
  char textureFileName[21];
  fin.read(textureFileName, 21);
  const boost::filesystem::path texturePath = modelPath.parent_path() / textureFileName;
  Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
  wicFactory->CreateDecoderFromFilename(texturePath.c_str(),
                                        nullptr,
                                        GENERIC_READ,
                                        WICDecodeMetadataCacheOnLoad,
                                        &decoder)
}

で濟む。實にWindowsAPIと相性が良い。