トップ回答者
共用体を含んだ構造体を引数にとるDLL関数の処理方法について

質問
-
アンマネージDLL関数の引数に、下記のような、共用体を含んだ構造体をとるものがあるのですが、
このような場合の構造体のマーシャリング方法がわかりません。
typedef struct {
int a;
union {
int b;
char *c;
} value;
} KYOUYOU;下記のようにしてみましたが、実行時に例外となってしまいます。
(System.TypeLoadException はハンドルされませんでした。
Message="アセンブリ 'kyouyoutai, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' からの型 'kyouyoutai.KYOUYOU' を読み込めませんでした。 オフセット 4 に不適切に整列されたか、オブジェクト以外のフィールドでオーバーラップされたオブジェクト フィールドが含まれています。")
<StructLayout(LayoutKind.Explicit)> _
Private Structure KYOUYOU
<FieldOffset(0)> Dim a As Integer
<FieldOffset(4)> Dim b As Integer
<FieldOffset(4)> Dim c As String
End StructureInteger型とString型を同じ境界に配置することはできないのでしょうか。
このような構造体を引数にとるDLL関数を適切に処理するにはどのようにすればよいのでしょうか。
ご存知の方がいらっしゃればアドバイスお願いいたします。
回答
-
Hongliangさん、お答えありがとうございます。
こんな便利なメソッドがあるんですね。
下記のようにして、RtlMoveMemoryを使わずに文字列を取り出すことができました。Dim str As String = Marshal.PtrToStringAnsi(c)
呼び出し先でのメモリ確保に関してですが、Hongliangさんのおっしゃるとおり、
呼び出し側でメモリ確保が行われている模様です。
使用しているDLLに、メモリ開放用関数が用意されていて
値取得後はその関数でメモリの解放を行うというというのが作法のようです。アドバイスいただき、どうもありがとうございました。
すべての返信
-
Hongliangさん、回答ありがとうございます。
Hongliangさんのアドバイスをもとに上記構造体のメンバcを
下記のようにString型からIntPtr型へ変更することで、例外とならなくなりました。<StructLayout(LayoutKind.Explicit)> _
Private Structure KYOUYOU
<FieldOffset(0)> Dim a As Integer
<FieldOffset(4)> Dim b As Integer
<FieldOffset(4)> Dim c As IntPtr
End Structureこの後、取得したcの先の文字列を取り出したい場合は、下記のようにRtlMoveMemoryを用いて
確保したByte型配列へコピーを行うことで解決できました。ありがとうございました。
Dim str(1023) As Byte
RtlMoveMemory(str(0), c, ...)ただ、もっと直感的に下記のようなイメージでString型へ変換できるようにも思えるのですが、
よい手段が見つかりません。もしRtlMoveMemoryを用いずにIntPtrをString型へ変換する方法をご存知でしたら
お教えください。このような方法では実現できないのでしょうか。Dim str As String = CType(c, String)
※これだとstrはcの内容(アドレス)がそのまま文字列として表現されてしまう
目的はそのアドレスに格納されている文字列をstrが指すようにしたい -
Hongliangさん、お答えありがとうございます。
こんな便利なメソッドがあるんですね。
下記のようにして、RtlMoveMemoryを使わずに文字列を取り出すことができました。Dim str As String = Marshal.PtrToStringAnsi(c)
呼び出し先でのメモリ確保に関してですが、Hongliangさんのおっしゃるとおり、
呼び出し側でメモリ確保が行われている模様です。
使用しているDLLに、メモリ開放用関数が用意されていて
値取得後はその関数でメモリの解放を行うというというのが作法のようです。アドバイスいただき、どうもありがとうございました。