meideru blog

meideruが書いているブログです。主に電子工作・プログラミング・ガジェット類などを中心に記事を書いています。

【Windows API】リソースをバイナリで出力する方法

      2016/08/03

Windows向けにプログラムを書いているときに、とあるやりたいことに出くわしました。

内容は以下のようなことです。

やりたいこと

実行ファイルAを実行すると、デスクトップに実行ファイルBを作成する。

ただし、作成する実行ファイルBは、元の実行ファイルAがリソースとして保持していなければならない。

@イメージ図
実行ファイルのリソースから取り出す。

結論から言うと、この問題は解決できました!

なかなかピンポイントかつマニアックな内容ですが、この記事で解説しようと思います(^o^)

方針

まず、実行ファイルBを実行ファイルAにリソースとして保持させます。

実行ファイルAは内部リソースの実行ファイルBを、バイナリ形式で読み取り、新しくファイルを作り、その中にfwriteで書き込みます。

これで、解決できました(・o・)

解説

具体的に解説していこうと思います。

実行ファイルBを作成

まず、サンプルとして実行ファイルBを作成します。

ファイルの内容は以下の通りです。

実行ファイルBは、クリックすると「実行ファイルBです!」というメッセージボックスが現れるという単純なプログラムです。

実行ファイルAを作成

次に、本題の実行ファイルAの作成に取り掛かります。

まずは、リソースに実行ファイルBを持たせましょう。リソースファイルとリソースヘッダに以下の記述を追加します。(リソースファイルとリソースヘッダの書き方がわからない方は調べてみてください!)

 

リソースファイルに以下の記述を追加します。

リソースの名前(ID)はIDR_EXE1、リソースの種類はEXEにします。最後に、実行ファイルBの名前はexeB.exeなので、”exeB.exe”と記述します。

 

リソースヘッダに以下の記述を追加します。

IDR_EXE1の値は101と定義します。

 

最後に、main関数の記述を書きます!

 

上のソースを用いて少し、具体的に説明します。

 

初めに、リソースヘッダをインクルードしてください。忘れると実行できません^^;

 

リソースハンドルを取得します。これは、リソースの場所を特定しているのに等しいです。

モジュール(リソース)のハンドルは、winmain関数の引数と同じものでよいです。

それと、本来ならば、MAKEINTRESOURCE(IDR_EXE1)の代わりにL”IDR_EXE1″としても良いはずなのですが、これをやると何故か上手く動作しませんでした。デバッグして確認したところ、リソースのハンドルの場所がNULLで返ってきてしまいました。原因は不明です^^;

もし知っている方がいれば、是非ともコメントで教えてください^^;

 

リソースを読み出します。

リソースに関連付けられたデータのハンドルを取得しています。

 

リソースデータのポインタを取得します。

これで、pvResDataにリソースデータのポインタ変数が格納されます。

 

以上で完成です!

ビルドして実行ファイルA実行すると、無事、デスクトップに実行ファイルBが作成されるはずです。

 

最後に・・・

ちょっと話は変わります。勘の良い方はあることに、気づかれたかと思います。それは、「メモリの開放」についてです。

LoadResourceでリソースを読みだし、LockResourceでリソースデータへのポインタを取得した時点で、メモリを動的に確保していることになりますよね。

動的にメモリを確保したときは、プログラマがメモリを開放しなければいけません。なのに、上のプログラムだと開放していません。

結論から言うと、win32apiでは開放しなくて良いそうです。自動でやってくれるとMSDNに書いてありました。

以下はコピペです。

Win32 アプリケーションでは、LoadResource 関数でロードしたリソースを解放する必要がありません。LoadResource 関数で取得したリソースは、それをロードしたモジュールがアンロードされると自動的に解放されます。

出典:https://msdn.microsoft.com/ja-jp/library/cc364598.aspx

 

ノシ

 - プログラミング