/Fa"アセンブリファイル名"
と /Fm"マップファイル名"
をちょっとしたプログラムのコンパイル時に付けてみた。■アセンブリファイルは .obj と内容的に一致するものかな。ファイル名とか行数とか関数名がコメントとして付加されてるので、まずは関数のサイズが行数として把握できる。処理の内容はまあだいたいがスタックの上げ下げ、比較、ジャンプ、call, ret. こういう目立つ定型部分が高級言語の構成要素になるのでしょう。■マップファイルは .dll に対応するものだと思う。オプションを何もつけずにコンパイルしていたら一切の最適化がオフで(これをアセンブリファイル内のコメントで知った)、inline 指定していた関数の名前がすべてマップファイルの中に現れていてぎょっとした。そういうことがわかる。関数を単位とした .obj やアセンブリ(リスティング)ファイルの中身から、何が関数としてそのまま抜き出されたか、何がインライン化され無名のコードとして埋め込まれたかがわかる。インライン化はリンカの標準的な仕事とは違う気もするけどリンク時コード生成が有効だったのかも。並びとアドレスの差から関数のサイズもだいたいわかる。サイズ優先の最適化フラグを付けると、小さい関数間に最低限確保されていた間隔が短く詰められたんだけど、配置の間隔とその他の都合にどういう関係があるのか。■サイズ優先でコンパイルすると POD構造体のゼロ初期化(= {};
)に memset が使われるようになって、/NODEFAULTLIB を指定していたもんだからリンクエラーになる。自分が Cランタイムライブラリを使わないように気をつけていても、コンパイラが使ってしまう(ことがある)。どないせーと? 初期化しないでメンバのひとつひとつに代入したら memset を使わせないで済んだけど、なんだかなあ。memset だけ自作してリンクしたらよかったんか。自作せずにコンパイラの実装から memset だけ抜き出したりはできないのか。■@2018-10-29 GCC のドキュメントからそのものズバリ「The compiler may generate calls to memcmp, memset, memcpy and memmove. These entries are usually resolved by entries in libc. These entry points should be supplied through some other mechanism when this option is specified.」最終更新: 2018-06-06T13:48+0900
テキストエディタ Mery はシングルプロセス型のタブエディタだから、svn や git のコミットメッセージを編集するためには工夫が必要らしい。工夫でなんとかなるということである。
このプラグインは C# で書かれてる。秘訣がこれ>「.NETプラグイン開発キット - MeryWiki」 DotNetLib.dll のソースが読みたいよね、ていうかこれもユーザー投稿なの?
で、プラグインを Mery2.6 の 64ビット版で試してみたんだけど、動かないのはここに書かれていた通り>「【要望】Gitの編集」
再コンパイルするだけで動くんじゃないかという気もするんだけど C# はさっぱりなので、思いつきで名前付きパイプを使った方法を試してみた(プラグインもパイプも初めて!)。「プラグインソフトウェア開発キット」の C/Basic プラグインを骨組みにして必要なところだけ書き換える感じ。
.NET プラグインの方のヘルプには OnEvent を上書きするとアイドルイベントまで捕まえてしまうからできるだけ個別のイベントハンドラを実装するようにって書いてあるんだけど、C プラグインのスケルトンには OnEvent ハンドラしかなかった……。
こうなりました>MeryRelay2.zip(あとの方に新しいのがある)。64ビットコンパイラってただで手に入るのかな。Vista 時代の SDK には付属していて、それしか手元にないんだけど。
ポイントはただひとつ。PIPE_NOWAIT
は罠であるということ。PIPE_WAIT
と FILE_FLAG_OVERLAPPED
を指定すれば非同期に待てる。雰囲気で PIPE_NOWAIT
を指定すると待てども返ってこない。
あ、パスの区切り文字の置き換えを忘れてる(でも試したら Mery2.6は /
区切りに対応してるぽい)。それとタスクマネージャーでコマンドライン列を表示するとわかることだけど、Mery.exe のコマンドラインなのにその内容が「"MeryRelay2Exe.exe" "file.path"」みたいになってるはず。少なくとも Vista ではそう。Mery.exe が気にしてないみたいだからいいかなって、最大限に手を抜いた。そんなわけでコマンドラインは一切操作も解釈もしていないので複数ファイルのドロップもできるんだけど、どのファイルがひとつだけ選ばれて監視されるかは運です。最後にもうひとつ。短い時間で連続してリレイ経由でファイルを開くと監視が漏れるかもしれない。ていうかたぶん漏れる。バックアップ中とかウィルススキャン中だと短時間でなくても漏れるかもしれない。
結局ロックファイルでシリアライズしつつ中身で情報をやりとりするのが一石二鳥なのか? くやしいので Mutex にする。zip を差し替えておいた。これで次のようなバッチファイルにも対応する。
start "" "MeryRelay2Exe.exe" a.txt start "" "MeryRelay2Exe.exe" b.txt start "" "MeryRelay2Exe.exe" c.txt start "" "MeryRelay2Exe.exe" d.txt start "" "MeryRelay2Exe.exe" e.txt start "" "MeryRelay2Exe.exe" f.txt start "" "MeryRelay2Exe.exe" g.txt
無駄にクラス化するなど>MeryRelay2_class.zip<不細工な車輪を再発明してでもDLLサイズを縮めるなど。
依然こういうバッチファイルには対応しないはずだ。
start "" "Mery.exe" a.txt start "" "Mery.exe" b.txt start "" "Mery.exe" c.txt start "" "MeryRelay2Exe.exe" d.txt start "" "Mery.exe" e.txt start "" "Mery.exe" f.txt start "" "Mery.exe" g.txt
正しく d.txt を開いていたタブが閉じられるのを検知できるかは運次第。ここにはトレードオフがあって、これに対応しようとするとコマンドラインを解釈せざるをえないが、Mery が解釈するコマンドラインに対していかなる前提も置きたくないというのがある。それで今のように、最初に応答したタブと無差別に関係を結ぶようになってる。
ところで本家 MeryRelay.exe は最初のバッチには対応しないけど次のバッチには対応している。自分のと逆である。
最初に INVALID_HANDLE_VALUE があり、その次に NULL があったと。INVALID_HANDLE_VALUE が 0 でないから、0 が有効なハンドルになることがあるのかと疑っていたが、実際のところどうなのだろう。INVALID_HANDLE_VALUE を使う関数の方が古いらしいから、ないとは言えないよね。ハンドルクラスのデフォルト値・無効値の扱いに困るんだよ。ないと言って。
「INVALID_HANDLE_VALUE and NULL - Google グループ」
同じ疑問を持つ人が。そして、CloseHandle を実装する側から考えてみると値が NULL で有効なハンドルはありえないでしょって答える人と、これまでの経験で問題がなかったとしてもドキュメントに沿った慎重な振る舞いを勧める人と。
俺はもちろん、問題が生じるまで単純な対処法を選ぶ>20180308。
従来.netのDLLをアンマネージから呼び出すためにはCOMとしてレジストリ登録して、COM経由で呼び出すのが一般的ですが、当然Meryからはこのような呼ばれ方はしません。
これを解決するために、アンマネージのブリッジ用DLL(C++で書いてるみたいです)があって、これがMeryから呼ばれる。
ブリッジDLLにはMeryから呼ばれるインターフェイスがすべて実装されていて、呼ばれたらマネージDLLに転送して、そちらで目的の処理を実行。 という手順をとっているようです。
「再コンパイルするだけで動くんじゃないかという気もする」とは書いたけど .Net には CPU を限定しない AnyCPU ビルドというのがあるらしく、ks さん本人のものと思われるブログでもそれが言及されていた。なのにどうして 32ビット版限定プラグインになってしまうのかな、と。その種明かし。
MeryRelay プラグインには MeryRelay.dll (160 KB) と MeryRelay/MeryRelay.dll (6 KB) という2つの同名の DLL ファイルが含まれていて、たぶん大きい方がアンマネージドのブリッジであり、32 ビット版 Mery からプラグインとして見えるもの。
svn 連携、git 連携にしろプラグイン作成にしろ、いろいろ方法があるもんですね。