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

酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Windows Media Player用の視覚エフェクト(Visualizer)を作ってみるテスト(2.5) DLLは自分自身のリソースを使う事が出来ない?

エフェクト名も難なく変える事が出来たので、次は絵を表示させてみたいです。リソースからのBMPをロードした事が無いので調べながらやっていきたいと思います。

疑問編

Googleの検索でひっかかったサンプルコードを参考に、CSample::Render()にリソースID「IDB_BITMAP1」の画像をロードするようなコードを書きました。

  HINSTANCE hInstance = ::GetModuleHandle(NULL);
  HBITMAP hBmp= LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
  if(!hBmp)
  {
    // hBmpがNULLであればエラーメッセージを出力する
    OutputMessage(GetLastError());
  }

これで取得したhBmpを素直に描画してやればいいやなんて思ってましたが、実際実行してみるとhBmpはNULLで返ってきてしまうのが分かりました。

覚えたてのエラーメッセージ取得技を使ってみると、エラーメッセージは「指定されたリソースの種類がイメージファイルに見つかりません。」との事です。Σ('д';)な、なんやってー!?


ちゃんと指定しているはずだと調べてみても、プロジェクト内に「IDB_BITMAP1」の定義はきちんとありました。

#define IDB_BITMAP1                     201  
IDB_BITMAP1             BITMAP  DISCARDABLE     "bitmap1.bmp"  

リソースエディタでBITMAPを追加して、ビルドが走ってるのも確認してるのでリソースには問題は無いと思うんだけど……何がおかしいのでしょうか?教えて偉い人!!

解答編

しばらく考えていて、ざっくりと見返していたら、「何故GetModuleHandle()の引数はNULLなの?」と疑問を感じて、MSDNを紐解いてみました。

GetModuleHandle
呼び出し側プロセスのアドレス空間に該当ファイルがマップされている場合、指定されたモジュール名のモジュールハンドルを返します。


HMODULE GetModuleHandle(
LPCTSTR lpModuleName // モジュール名
);
lpModuleName
NULL を指定すると、呼び出し側プロセスの作成に使われたファイルのハンドルが返ります。

GetModuleHandle 関数

゜ ゜ ( д )ポカーン ……呼び出し側プロセスって、Windows Media Playerじゃまいか。


GetModuleHandle()の引数に、自前のDLL名を指定すれば良さそうです。拡張子を略した場合「.dll」が付与されるらしいので、"sample"とだけ指定しておきます。

//  HINSTANCE hInstance = ::GetModuleHandle(NULL);
  HINSTANCE hInstance = ::GetModuleHandle("sample");
  HBITMAP hBmp= LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
  if(!hBmp)
  {
    //hBmpがNULLであればエラーメッセージを出力する
    OutputMessage(GetLastError());
  }

これでようやくhBmpの値を取得する事が出来ました!!かれこれ1週間位これで悩んでいましたよ(´;ω;`)

解答編その2

その後、とっちゃんに自分のモジュール(や自分でロードしたDLL)のリソースにアクセスする場合は、WinMain()やDllMain()のhInstをグローバルに保持しておいて、それを利用するのがセオリーだよと、教えてもらいました。