libpowrprof.a とかリンクのこと

以前、スリープ状態にする EXE を自作したが、LoadLibrary で powrprof.dll を呼び出してから SetSuspendState を実行するという処理をしていた。

#include <windows.h>
int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) {
  HMODULE lib = LoadLibrary(TEXT("powrprof.dll"));
  FARPROC SetSuspendState = GetProcAddress(lib, "SetSuspendState");
  SetSuspendState(FALSE, FALSE, FALSE);
  FreeLibrary(lib);
  return 0;
}

それというのも、SetSuspendState 関数のプロトタイプ宣言がある powrprof.h というヘッダファイルをインクルードしても、直で SetSuspendState することができなかったためだ。理想としては、LoadLibrary をすることなく、WinMain 関数の先頭でいきなり SetSuspendState が現れるようなコードにしたかった。

調べたり、試したりしているうちに、それをやる方法がわかった。

#include <windows.h>
#include <powrprof.h>
#pragma comment(lib, "powrprof.lib")
int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) {
  SetSuspendState(FALSE, FALSE, FALSE);
  return 0;
}

powrprof.h をインクルードするだけではだめで、powrprof.lib という名前のライブラリのリンクという処理を行わなければならなかったのだ。powrprof.lib は、Visual Studio Express 2012 (VSE) に入っており、VSE でビルドする場合は、コード中に #pragma comment(lib, "powrprof.lib") という記述を入れておけば、リンク時に、powrprof.lib をリンクしてくれる。ただし、この方法は、VSE 限定である。

本命の gcc でやる場合、#pragma comment は使えない。ではどうするかというと、gcc のコマンドラインオプションで指定する。具体的には -lpowrprof というオプションを付け加えることでリンクしてくれる。このオプションは、本質的には、libpowrprof.a をリンクしろという命令を意味している。libpowrprof.a というライブラリをリンクしたければ -lpowrprof だし、libhoge.a をリンクするならば -lhoge だし、libx.a なら -lx だ。

この、ライブラリのリンクという行程は、なくてはならないものであることを最近、知った。VSE もそうだが、gcc は、暗黙に、libuser32.a や libkernel32.a などの、多くの場合なくてはならないライブラリをリンクする。これらのライブラリは、user32.dll や kernel32.dll から、ExitProcess 関数や MessageBox 関数などの実体を呼び出す役割を担っている。ヘッダファイルには、たとえば MessageBox 関数のプロトタイプ宣言が書かれているが、それが実際に、どういう処理なのかは書かれていない。そのため、libuser32.a をリンクして、教えてあげる必要がある。

しかしながら、関数の実体が書かれているライブラリが一体どれなのかは自明ではない。powrprof.h の場合は powrprof.lib や libpowrprof.a という、似た名前のライブラリがあるので、きっとこれだろうという推測のもと、実際にリンクを試してみるのであるが、全然ちがう名前だったら、どうすればいいのだろう。まあ、たいていは、Microsoft のサイトを参照すれば、だいたいわかるのだが。