初めて質問させていただきます。
HTMLヘルプの呼び出しを行うPlatformSDK(かな?)のHtmlHelpA()について、
単純に
DWORD dwCookie = NULL;
HtmlHelp(NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie);
HtmlHelp(NULL, NULL, HH_UNINITIALIZE, dwCookie);
としただけでもメモリリークが起きました。
検出ツールはHtmlHelp呼び出しの中でFreeLibrary()が呼ばれていないと言っていますが、
HtmlHelpの呼び出しというのは
HH_INITIALIZE~何かしらのヘルプ呼び出し処理~HH_UNINITIALIZE~
では何か不足があるのでしょうか?
詳しい方、よろしくお願いします。
Google で HtmlHelpA と入れて検索すると使い方がたくさんでてきますけど・・・。
すいません。質問の内容が不明瞭でした。
呼び出し方を知りたいのではなく、呼び出し時に発生するメモリリークを回避する方法が
もしあるようでしたら教えていただきたいと思います。
現状ですが、
http://msdn2.microsoft.com/ja-jp/library/ms644704.aspx
この辺を参考にしながら、簡単なTPで確認を行っています。
環境はVS2005SP1で、ウィザードで生成したダイアログベースのMFCプログラムにコードを
挿入してみて確認しています。
原因を絞り込むためにHTMLヘルプ呼び出しのコードを削っていってみたところ、
最初に呼び出すHH_INITIALIZEと、アプリケーション終了時に呼び出すHH_UNINITIALIZEだ
けでもすでにリークが出てくることが判ったところです。
(この二つはセットで呼び出すことになっているのでこれ以上は削れないという認識です)
検出ツールはDevPertnerStudio8SP2ですが、
HtmlHelpAが内部でLoadLibraryしていて、それをFreeLibraryしていないという結果を返
しています。
#LoadLibraryしているのは多分HHCtrl.ocxなんだろうなーと思っているのですが、
#たとえば、これは自力でなんとかして開放しなければならないとか?
VS2005なら直接HtmlHelpA を呼ばなくてもCWinApp::HtmlHelp
があるのでそれを使えばどうでしょうか?
(今ソースコードを見れないので)
予想でしかないのですが、EnableHtmlHelpを呼び出すと内部で
HH_INITIALIZEを呼び出してしまうため、別の箇所で、
HtmlHelp(NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie);
を行うと、2重にHH_INITIALIZEのコマンドが実行されてしまいうまくいっていないと
か。
CWinApp::EnableHtmlHelp
http://msdn2.microsoft.com/ja-jp/library/xb093wdb(VS.80).aspx
HH_INITIALIZE Command
http://msdn2.microsoft.com/ja-jp/library/ms670090.aspx
> You should call these commands once during the life of your application.
Blue様、回答ありがとうございました。
現状ではEnableHtmlHelp()は呼んでいませんのでその線はなさそうです。
(というか、HtmlHelpAを呼ぶときにEnableHtmlHelpは必要なのでしたっけ・・・?)
もう少し調査してみて、方法が見つからなければ
あきらめてCWinApp::HtmlHelp()を使おうと思いますが、
ひょっとしたらCWinApp::HtmlHelp()でもリークするのでは・・・
と考えると背筋が凍ります。
あるいは、これだけ調べて何もないとなると検出ツールのほうも疑ってみたほうがいい
か・・・という気もしてきます。
DevPartnerのバグだったら大事だなぁ・・・。
> (というか、HtmlHelpAを呼ぶときにEnableHtmlHelpは必要なのでしたっけ・・・?)
違います。
おそらくプロジェクトのウィザードで
HTMLヘルプ
のほうにチェックを入れると自動的にEnableHtmlHelpがInitInstanceあたりに
記述されるんじゃないかと思っています。
EnableHtmlHelpはCWinApp::HtmlHelpを使うときに必要で、
CWinApp::HtmlHelpからHH_INITIALIZE、HH_UNINITIALIZEのコマンドは使わない
んじゃないかと。
(ソースコード見てみないとなんともいえない)
m_bUseHtmlHelpでMFCのソースコード検索してみて
HH_INITIALIZE、HH_UNINITIALIZE
が出てきていれば、CWinAppクラスでHH_INITIALIZE、HH_UNINITIALIZEをやっている
ことなります。
よって、HH_INITIALIZEが2重に呼ばれている可能性があるんじゃないかと思っているわ
けで。
プロセスが死ねば勝手にDLLが開放されると言う前提のDLLがどこかに混ざって
いるだけという事はありませんかね?
IEエンジンがらみで変なDLLがロードされてしまうとかそういう可能性も無くは無い
ような気がします。
というか、FreeLibrary()が無いのはメモリリークではなく終了処理忘れだと思うの
でメモリリークと呼ばないほうがいいような気がします。
最悪、開放されないDLLをプログラムに直接ダイナミックリンクするとかそういう小
手先の方法で回避してしまうというわけには…行かないのでしょうね。
とりあえず開放されていないDLLを特定してみるというのはどうでしょうか。
LoadLibraryAとLoadLibraryW、同じくFreeLibraryをKernel32.dllの各プロシー
ジャ先頭で監視すれば手動で特定できるかもしれません。
いろいろ調べてみたら、MFC内部ではHH_INITIALIZEは呼ばれていないようでした。
ですので
>CWinApp::HtmlHelpからHH_INITIALIZE、HH_UNINITIALIZEのコマンドは使わない
>んじゃないかと。
は間違っていました。
ただ、CWnd::HtmlHelp(AfxHtmlHelp)では hhctrl.ocxをLoadLibrary&FreeLibrary
しているので自前でHtmlHelpを呼ばずに、MFCのメソッドを使えば、FreeLibraryされな
いということはないでしょう。
ただ、htmlhelp.libをリンクしてHtmlHelpを使っているのであればFreeLibraryされない
とかはありえないと思うけど(静的リンクなわけなので)、何でなんだろうかね。
麩様
> LoadLibraryAとLoadLibraryW、同じくFreeLibraryをKernel32.dllの各プロシー
> ジャ先頭で監視すれば手動で特定できるかもしれません。
よろしければ具体的な手順を教えていただけませんでしょうか?
場合によってはツールの不備を指摘するような形で本件はクローズになるかもしれないと
思っています。なのでこれをやってみようかと。
私が知ってるのはあんまりマトモな方法じゃないですけど…
LoadLibrary系とFreeLibraryを監視するのでいけるんですけど、取りこぼしがあ
るかもしれないのでちょっと違う方法書きます。
OllyDbg(日本語化しておく)使います。
起動したら「オプション」->「解析詳細設定」->「イベント」から(DLL)が付いた項
目をチェックしておきます。
調べる対象を読み込んで実行します。
そうすればDLLがロードされたりアンロードされるたびに実行が止まるので、「表
示」->「コールスタック」あたりで何処でLoad/Freeされたのか調べてから「解
析」->「実行」で次のDLLのイベントまで飛ぶ、を繰り返します。
DLLの終了処理が呼ばれないDLLはこれで調べが付きます。
詳しくやるなら、DLLがロードされた段階でDLLのエントリポイントまで追いかけて
から、そこにもブレークポイントを仕掛けたほうが確実です。
調べたいのはAPI呼び出しでの影響なので、API呼び出し寸前で止めてから「イ
ベント」のDLL関連項目を有効にするほうが効率がいいかと思います。
API呼び出し寸前でとめてからにする場合、「イベント」のDLL関連項目は切った
まま対象を読み込んで、APIの呼び出し位置を調べてブレークポイントを置
き、そこで止まってから「イベント」のDLL関連項目を有効にするという流れになり
ます。
APIの呼び出し位置を調べてのブレークポイント設置が面倒なら、実験用EXEを
作るときにAPI呼び出しの直前に「*(long*)0=0;」等と書いておけば勝手にエラー
で止まります。
操作方法はgoogleあたりで検索すれば出てきます。
逆アセンブリ表示なので、多少慣れがいります。
それと、DLLエントリポイントの書き方も知っておく必要があります。
ツールでどのDLLが問題なのか表示されない場合はこのようなアプローチもありっ
て程度で、あまりこういう手段には頼らないほうがいいと思います。
使い慣れないツールに悪戦苦闘中・・・
結果はもうちょっと遅くなるかもしれないです。
別件の仕事が回ってきて当面本件に手が回らなそうなので一旦クローズします。
あー・・・自宅用にVS2005あったらなー・・・