kkamegawa's weblog

Visual Studio,TFS,ALM,VSTS,DevOps関係のことについていろいろと書いていきます。Google Analyticsで解析を行っています

動的ロード疲れたよ

Windowsに限らないけれど、あるバージョンでは入っているDLLのあるAPIが、以前のバージョンのOSには存在しないってことがざらにあります。身近な例では統合アーカイバ関係でしょうか。あれもlzh,zip,arc,etc,etc...と、圧縮ツールが起動時の環境をチェックして使える圧縮形式をチェックしています。
ある製品が入っていれば、そのDLLのこの関数を呼び出す〜というのは、Windows登場時点からこんな感じのコードを書くように、と書かれているのを一度や二度見たことがあるでしょう。

  typedef int (WINAPI *PDLLProc)(int, int);

  PDLLProc pFunction;
  FARPROC pf;
  int iRet;

  HMODULE hMod = LoadLibarary("hoge.dll");
  pf = GetProcAddress( hMod, "foo_function" );
  if (pf) {
     pFunction = reinterpret_cast<PDLLProc>(pf);
  } 

  iRet = (*pFunction)(1, 2);
  ...

これが一つや二つならまだしも、60個位同じよーな処理(しかも引数違うからこぴぺもなかなか大変)を書くとなったら、それだけで気がめいってしまいます。みんないやだと思ったのか、VC4.0のあたりかな?から、遅延ロード(delay load)という考えが導入されました。上記のようにhoge.dll(必ずあるとは限らないdll)のfoo_function()を呼び出す場合でも下のようにかけます。

  foo_function(1,2);

これはリンカに

  /DELAYLOAD:hoge.dll /implib:Delayimp.lib

というオプションを渡しておけばいいのですが*1、なんとなく好きじゃなくて、今までずーっと自分で書いていました。でもさすがに60個もGetProcAddress()とそのエラー処理を書くのは心がくじけそうで、/DELAYLOADに逃げそうな私がいます(笑)。もちろんDLLの存在判定はプログラム起動時にやるんですけどね。
「なかったら「DLLがありません」ってメッセージが出るじゃないか」って?サーバプロセスでそんなことやったら、トランザクションがタイムアウトでとまってしまいます(メッセージボックス押す人がいないから)。つらくてもチェックだけはやるしかないのです。

*1:独自の遅延ロードヘルパ関数を呼び出すのもアリ。昔MSDN Magagineに載っていたような…