DLL呼び出しとマーシャリング

http://www.microsoft.com/japan/msdn/net/compactframework/netcfintrointerp.aspx
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpguide/html/cpcondefaultmarshalingforvaluetypes.asp

Felicaドライバを呼び出しIDを読み取る.NETプログラム VC++プログラムを以前作成したのだが、事前バインディングを使っていたため、Felica.dllがないと当然、EXE自体起動しない。
これを解決するため、遅延バインディングを使うやり方に変えたのだが、マネージドコードとアンマネージドコード間のマーシャリングの深い世界にどっぷりと嵌まった。
(今回、C#.NETにするのと正確には遅延ロードに変更する)
関数自体は[DllImport]で定義すればよいのだが(遅延ロード)、ポインタを含む構造体のリファレンスを渡すところでハマる...
最初、StringBuilderやStringでやろうとしてたのがそもそもの間違い。またunsafeキーワードやfixも最初使ってやってたが、必要なし。
構造体中のポインタはすべてIntPtrでやるのが正解。
また、Marshal.AllocCoTaskMemとMarshal.AllocHGlobalは、AllocCoTaskMemのほうを使う。
ということで、
typedef struct {
unsigned char* system_code;
unsigned char time_slot;
} structure_polling;

[StructLayout(LayoutKind.Sequential)]
private struct structure_polling {
public IntPtr system_code;
public char time_slot;
}
になる。(unsigned charは正しくはbyteになるが、とりうる値がcharの範囲なのでcharで定義)
typedef struct {
char* port_name;
unsigned long baud_rate;
unsigned char encryption_mode;
unsigned char* kar;
unsigned char* kbr;
} structure_reader_writer_mode;

[StructLayout(LayoutKind.Sequential)]
private struct structure_reader_writer_mode {
public IntPtr port_name;
public ulong baud_rate;
public char encryption_mode;
public IntPtr kar;
public IntPtr kbr;
}
に。
今回、Marshalクラスのをはじめて使ったが、このクラスを使えばマーシャリングはすべて対応可能。(理解すると結構簡単...)

一応IntPtrなので、64bitでも動くと思ったが、気になったのでVista x64で動作確認....
but、Felicaドライバ自体がそもそも64bit用がなし。一応ClickOnceで動いたので現時点でOKとする。


MEMO(25337)