ここでちょっと触れたMSBuildの良いGUIが見つからなかったので、さくっと作った。
ダウンロードはこちらから。
https://github.com/sunnyone/MsbuildLauncher
MSBuildファイルを開くと、左側にターゲットのボタンができるので、クリックすれば実行される。
コマンドライン引数にも対応しているので、.msbuildを関連付けることも可能。
ページ
▼
2012-10-27
2012-10-25
C#の"ref"引数のMSIL的取り扱い(.NETと参照渡し)
C#でrefを使ったメソッドのMSIL的作り方/呼び出し方(参照渡しの方法)についてメモしておく。
これをコンパイルしたものを逆アセンブルしたものが以下。
(評価スタックのイメージを忘れてしまった場合は、この絵を思い出してほしい。)
まずメソッドの定義。
そしてtmp = x;の部分。
x = y;はいったん飛ばして、y = tmp;部分を見るとこう。
x = yは上記の組み合わせ。
ここでは、int32なので、ldind.i4/stind.i4だが、型によって使うべき命令は違う。ただし、
ldobj/stobjの例としては、ref int?を使うと、以下の感じで生成される。
&のついたref型で入っている。この元の型を得たいときは、こんな感じになる。
サマリ
- メソッドに渡す際は、アドレスを渡す。Cのポインタで言う&valのイメージ。
- 引数のpushには ldloca命令を使う。
- メソッド内では、アドレスの解決を行う。Cのポインタで言う*aのイメージ。
- 取得にはldind命令シリーズ(ldobj)、設定にはstind命令シリーズ(stobj)を使う。
- 型は、実際の型に&がついた「ref型」を利用する(例: System.Int32&)
- Type.MakeByRefTypeでref型化、Type.GetElementTypeで非ref型化できる。
- ref型かどうかは、Type.IsByRefで判断できる。
例
具体例として、参照を使うコードにありがちなSwapメソッドを作ってみる。C#コード
void Swap(ref int x, ref int y) { int tmp; tmp = x; x = y; y = tmp; } void SampleFunc() { int x = 10; int y = 20; Swap(ref x, ref y); System.Console.WriteLine("x, y: {0},{1}", x, y); }
これをコンパイルしたものを逆アセンブルしたものが以下。
.method private hidebysig instance void Swap(int32& x, int32& y) cil managed { .maxstack 2 .locals init ([0] int32 tmp) IL_0000: nop IL_0001: ldarg.1 IL_0002: ldind.i4 IL_0003: stloc.0 IL_0004: ldarg.1 IL_0005: ldarg.2 IL_0006: ldind.i4 IL_0007: stind.i4 IL_0008: ldarg.2 IL_0009: ldloc.0 IL_000a: stind.i4 IL_000b: ret } .method private hidebysig instance void SampleFunc() cil managed { .maxstack 3 .locals init ([0] int32 x, [1] int32 y) IL_0000: nop IL_0001: ldc.i4.s 10 IL_0003: stloc.0 IL_0004: ldc.i4.s 20 IL_0006: stloc.1 IL_0007: ldarg.0 IL_0008: ldloca.s x IL_000a: ldloca.s y IL_000c: call instance void ConsoleApplication1.Program::Swap(int32&, int32&) IL_0011: nop IL_0012: ldstr "x, y: {0},{1}" IL_0017: ldloc.0 IL_0018: box [mscorlib]System.Int32 IL_001d: ldloc.1 IL_001e: box [mscorlib]System.Int32 IL_0023: call void [mscorlib]System.Console::WriteLine(string, object, object) IL_0028: nop IL_0029: ret } // end of method Program::SampleFunc
呼ばれるSwapメソッド
適当に端折りながら、上から見ていく。(評価スタックのイメージを忘れてしまった場合は、この絵を思い出してほしい。)
まずメソッドの定義。
.method private hidebysig instance void Swap(int32& x, int32& y) cil managedint32ではなく、int32&型が使われている。これは、
Type t = typeof(Int32).MakeByRefType();てな感じで得られる。
そしてtmp = x;の部分。
IL_0001: ldarg.1 IL_0002: ldind.i4 IL_0003: stloc.0これは、
- 1番目の引数(ref x)を持ってくる
- 持ってきたアドレスからint32の値を持ってくる
- 0番目のローカル変数に格納する
x = y;はいったん飛ばして、y = tmp;部分を見るとこう。
IL_0008: ldarg.2 IL_0009: ldloc.0 IL_000a: stind.i4これは、
- 2番目の引数(ref y)を持ってくる
- 0番目のローカル変数からint32の値を持ってくる
- 持ってきたアドレスに持ってきた値を入れる
x = yは上記の組み合わせ。
IL_0004: ldarg.1 IL_0005: ldarg.2 IL_0006: ldind.i4 IL_0007: stind.i4
ここでは、int32なので、ldind.i4/stind.i4だが、型によって使うべき命令は違う。ただし、
すべての ldind 命令は、対応している組み込み値クラスを指定する Ldobj 命令のショートカットです。(OpCodes.Ldind_I4 フィールド)なので、ldobj [type]でもよい。
ldobj/stobjの例としては、ref int?を使うと、以下の感じで生成される。
IL_0008: stobj valuetype [mscorlib]System.Nullable`1
Swap()を呼ぶメソッド
こちらは実際に呼び出しているところだけ。IL_0001: ldc.i4.s 10 IL_0003: stloc.0 IL_0004: ldc.i4.s 20 IL_0006: stloc.1 IL_0007: ldarg.0 IL_0008: ldloca.s x IL_000a: ldloca.s y IL_000c: call instance void ConsoleApplication1.Program::Swap(int32&, int32&)10、20をそれぞれx、yに入れたあと、this、xのアドレス、yのアドレスの順に持ってきて、関数をコールしている。
リフレクションでの扱い
すでにあるメソッドのMethodInfoをGetMethod()で持ってきて、ParameterTypeを見ると、&のついたref型で入っている。この元の型を得たいときは、こんな感じになる。
if (parameterType.IsByRef) { Type valueType = parameterType.GetElementType(); }(Type.MakeByRefType メソッド)
2012-10-21
テキトーに使うWCF
WCFのちょっとした実験をしたいとか、ちょっとしたプロセス間通信をしたいといったときに、app.configだとかServiceReferenceだとかはわずらわしい。そんなときに使うコードサンプル。
2012-10-10
自炊向け本画像処理スクリプト群bkimgproc公開
前回のエントリで予告した、ImageMagickのwrapper script群を公開しました。
https://github.com/sunnyone/bkimgproc
git cloneするか、"ZIP"のボタンを押してzipを落として展開してください。
本1冊ごとにディレクトリを作って連番の素材を入れていき、最後にスクリプトを実行するとまとめてくれるツールです。詳しい使い方は、READMEに載せました。
Ubuntu/DebianであればREADMEの方法で使えますが、普通のshell scriptなので、もしかしたらCygwinでも動くかもしれません。
特徴としては、以下の通りです。
PDFの見開き方向指示は、こちらの方法を利用させていただいています。
ちなみにうちでは、convall.shの起動は、Jenkinsを使っています。
https://github.com/sunnyone/bkimgproc
git cloneするか、"ZIP"のボタンを押してzipを落として展開してください。
本1冊ごとにディレクトリを作って連番の素材を入れていき、最後にスクリプトを実行するとまとめてくれるツールです。詳しい使い方は、READMEに載せました。
Ubuntu/DebianであればREADMEの方法で使えますが、普通のshell scriptなので、もしかしたらCygwinでも動くかもしれません。
特徴としては、以下の通りです。
- pdf, cbz出力(PDFは見開き方向指示に対応)
- 横向きスキャンデータの回転
- 白レベル自動判定による白レベル調整
- kobo向けリサイズ(kobo plugin)
- 余白の自動カット(kobo plugin)
- テキストのボールド化(kobo plugin)
PDFの見開き方向指示は、こちらの方法を利用させていただいています。
ちなみにうちでは、convall.shの起動は、Jenkinsを使っています。