2009年02月13日 [長年日記]
_ [TTBase] 倉庫(仮)さんとこの「TTBaseのソース」を読んで。
TTBase本体についていろいろ意見を頂いたので、ちょっと考えてみました。
InitでExecuteCommandを使う問題については、実際にコマンドを実行しているTPlugin.DoCommandでLoadしていなければLoadする(Initを行う)ということをしているので問題にならないはずです。 また、そもそも非常駐型のプラグインであれば、コマンド実行毎にInit→Execute→Unloadしているので、それも問題にならないです。 ただ、TTBase.datにまだ入っていない(新規にプラグインを追加した)場合、そもそもプラグインリストに追加されていない可能性があるわけで、そうなるとプラグインが見つからずに結局そのコマンドが実行されないだけ、ということが起こりえそうです。 それはそれで気付き辛い問題となりそうなので、プラグインの探索とInit処理は別タイミングにした方がいいかもしれませんね。一度プラグインリストを完成させてから、各プラグインのInit処理を呼び出す、と。
そういえば、今の話とはあまり関係ないけど、プラグインAのInitでプラグインBのコマンドを呼び出している場合に、プラグインBのInitでもプラグインAのコマンドを呼び出していたりすると(循環していると)無限ループに陥ってしまいそうです。 何らかの対処を考える必要があるかなぁ。。。 どうしたらいいかは思いつかないのだけれど。
とりあえずInitはこれでよいとしても、UnloadでExecuteCommandを使うと、せっかくUnloadした他のプラグインがまたLoadされてしまってリソースリークとか起こしてしまいそうですね。 Unload後に本当にUnloadされているかもう一度確かめた方がよいのかもしれません。 …それはそれで先に書いたように無限ループの可能性が残っちゃうのか。
なんか、いろいろと悩ましいです。
フックインストールとプラグインロードの順序については確かに指摘の通りですね。これは直すべきでしょう。
TTBEvent_FreePluginInfoについては、メモリを確保した人が解放すべき、という意味でも、このまま残しておきたいところです。 ただ、省略されたプラグインがあってもよいように拡張するのはありかもしれませんね。
_ [TTBase] プラグインのロードとフックインストールの順序。
以下の2つのテスト用プラグインを作成して検証してみました。
- Init時に5秒間だけ待機(Sleep)する、1st.StartWait.dll
- Init/Unload/Hookの各メソッドでログを出力するだけの、2nd.OutputLog.dll
こうすることで1st.StartWait.dllをロードしている間に2nd.OutputLog.dllのHookが呼ばれちゃうかなーと思ったのですが、結論としてはInit前にHookが呼ばれることは無かったです。 TTBase.datによるプラグイン情報のキャッシュがされている場合、されていない場合のそれぞれで確認しています。
で、改めてTTBaseのソースを確認したのですが、今のつくりのままでも問題なさそうなことが分かりました。 まず、フックしたメッセージがTTBaseに届くと、各プラグインのTPlugin.DoWindowHookが呼ばれます。この中ではTTBEvent_WindowsHookの関数アドレスを取得していれば(GetProcAddressしていれば)その関数を呼び出すようになっています。 では、TTBEvent_WindowsHookの関数アドレスを取得しているタイミングがどこかというと、TTBEvent_Initの呼出に成功した後(TPlugin.Load内)なんですね。んで、TTBEvent_Unloadしたら関数アドレスのクリア&DLLの解放をしています。 なので、InitしてからUnloadするまでの間しかTTBEvent_WindowsHookは呼ばれないようになっていました。
ということで、InitとHookの関係は今のままでも問題なし、という結論になります。
…が、プラグインがロードできていないタイミングでフックを開始するのは順序としてどーなの?という気はするので順番を入れ替えておいた方がよいですかねぇ。。。
_ [TTBase] メモリ使用量の削減。
TTBase.exeと同じ位置にTTBase.icoを配置するとそのアイコンを読み込む、という仕様があるのだけれど、このアイコンがあるかないかでメモリ使用量にかなり差があったので、いろいろ調べていました。 私の環境(WinXP + TTBase v1.1.0 beta1)でまったくプラグインがない状態で試したところ、TTBase.icoなしの場合は約8MB、TTBase.icoありの場合は約4.5MBほど使用しています。
TTBase.icoがない場合にデフォルトアイコンを取得するため、SHGetFileInfo APIを使用して自分自身のexeファイルからアイコンを読み込んでいるのですが、その処理があるとメモリ使用量が増えてしまうようです。
ということで、デフォルトアイコンの取得方法を変更した版を作ってみました。
他の環境でも有効であれば本体に取り込みたいので、試してもらえると嬉しいです。(→ttb10100b2pre.zip)
2009年02月14日 [長年日記]
_ [TTBase] Init/Unload中のExecuteCommandの呼び出し。
昨日想定した通り、やっぱりInit/Unload中にExecuteCommandを実行すると以下の問題が発生してしまいました。
- TTBEvent_Init中に常駐型プラグインのコマンドをTTBPlugin_ExecuteCommand APIで実行しようとすると、プラグインのロード順によってはコマンドが実行されないことがある。
- TTBEvent_Unload中に常駐型プラグインのコマンドをTTBPlugin_ExecuteCommand APIで実行しようとすると、エラーが発生する場合がある。
どちらも、プラグインリストが不完全な状態でTTBPlugin_ExecuteCommand APIを呼び出すことで、発生していました。 なので、プラグインリストを完成させてから各プラグインのTTBEvent_Initを呼び出すように、先に各プラグインのTTBEvent_Unloadを呼び出してからプラグインを解放するように修正することで対処しました。
TTBEvent_Unload内ですでにアンロード済みの常駐型プラグインのコマンドを実行しようとすると、もう一度TTBEvent_Initされてプラグインがロードされてしまいますが、最終的にもう一度アンロードを試みるので、基本的にはリソース等がリークすることはないはずです。 ただ、昨日も書いた通り、プラグイン間のコマンドの呼び出しが循環してしまっている場合(プラグインAがプラグインBのコマンドを実行し、プラグインBがプラグインAのコマンドを実行し…という場合)はどうしようもないです。 これは本体側ではなんとも対処しようがなさそうなので、そのまま放置しておくことにしちゃいます。 実際問題、そんなコマンド間の呼び出しが起こってしまうことはなさそうですので。
なんにせよ、これで指摘された部分で本質的にまずそうなところは対処できたのでbeta2としてリリースをしようと思います。 とりあえず、ソースはCVSにコミット済みです。 …ってゆーか、そろそろexeのバージョン管理がビルド番号Onlyなのが辛くなってきたのでいい加減1.1.0としてリリースしてしまって、以降のバグ改修はリビジョン番号をあげることで対処していきたいところですが、そうもいかないだろうな…。
2009年02月24日 [長年日記]
_ [TTBase] TTBase v.1.1.0リリース。
2008/7/22にv.1.0.17のα版がリリースされてから半年。 ようやく、α、βの文字を取り除いて正式版としてリリースしました。
本来なら、もうちょっと落ち着いてからリリースをすべきなんでしょうけど、いい加減ビルド番号でリソース管理するが面倒になっちゃったので断行しちゃいました。 本体に追加したい新機能があったので、一旦βの状態から脱しておきたい、ってのもあったし。 まだ潜在バグはありそうな気配なんですが、1.0.16以前からあったバグっぽいのでよいことにしてしまいました。
開発者都合でリリースしちゃってごめんなさいm(_ _)m
まぁ、言ってしまえば去年の夏、alpha2がリリースされてたころにちゃんと私の方でも検証していれば、その頃なら機能追加をしてくださったdrabornさんも居たでしょうしもっと早く正式版としてキチンとしたものをリリースできていたんでしょうけどね。。。 相変わらずいろいろ放置してしまってごめんなさいです。
とりあえず今後もTTBaseの中の人として活動は続けると思いますので、今後ともよろしゅうなのです。 …反応がものすごく遅い時があるかもしれませんが…。
_ [TTBase] TTBaseのCVSリポジトリ。
とりあえず、ずっと「release-1-0-17-alpha-1」ブランチで作業していたので、HEADにマージしてあります。 これで、ソースはHEAD一本に戻っている状態です。
今後のCVSの計画を忘れないようにメモ。
- 基本的には新機能の追加もHEADで作業する。
- 新機能追加中に、v.1.1.0のバグが発生して修正が必要になったら、その時点で「release-1-1-0」タグを起点にブランチを作成する。名前は…「release-1-1-x」とかでいいかなぁ。
- ブランチを作成するような状況になったら、HEADで作っていた新機能はv1.x.0としてリリースする。そうしないとタグの名前が訳分からないことになりそうなので。
_ U [はじめまして、Uです >コマンド実行毎にInit→Execute→Unloadしている ソースを改めて見たら、おっ..]
_ ももたろ [ツッコミありがとうです。 疑問が氷解したようでなによりです。 …とはいえ、指摘してくださった点で、直した方がよりよ..]