困っていること
C言語で書かれたDLLがあり、C#からここに定義された関数を呼び出したいと思っています。
しかし、P/Invoke時に関数に渡すべきクラスをどう作れば良いのか分からず困っています。
C#から関数を呼び出す際は以下のように定義したものを呼んでいます。
cs
1[DllImport("test.dll", EntryPoint="TestFunction")] 2public static extern int TestFunction([Out]ResultInfo result);
要するにTestFunction関数に ResultInfo
型の変数を渡すと そこに結果が入るだけなのですが、この ResultInfo
が厄介です。
C側で定義されたResultInfo
は構造体で、以下のように定義されています。
ResultInfo構造体 | |
---|---|
int | id |
Item[100] | items |
ResultInfo構造体の中に、Item
構造体の配列を含んでいます。
Item構造体は以下のように定義されています。
Item構造体 | |
---|---|
int | itemid |
char[64] | name |
このような場合、C#側ではResultInfo
とItem
をどう定義したら良いのでしょうか。
現状
以下のように定義しましたが、正しく動作しません。
cs
1/* ResultInfo.cs */ 2[StructLayout(LayoutKind.Sequential)] 3public class ResultInfo 4{ 5 public string id; 6 [MarshalAs(UnmanagedType.ByValArray, SizeConst=100)] 7 public Item[] items; 8} 9 10/* Item.cs */ 11[StructLayout(LayoutKind.Sequential)] 12public class Item 13{ 14 public int itemid; 15 [MarshalAs(UnmanagementType.ByValTStr, SizeConst=64)] 16 public string name; 17} 18 19/* 関数の呼び出し */ 20var resultInfo = new ResultInfo(); 21var resultCode = TestFunction(resultInfo);
この結果、DLLに定義されている関数自体は呼び出され、引数に渡したresultInfo
の中のresultInfo.id
には正しい値がセットされています。
しかし、resultInfo.items
の中身は全てnullとなってしまいます。
少なくとも呼び出しには成功しているようなので、items
が全てnullになってしまうのはC#側の定義が悪いのだろうと思っています。
どのように修正したら良いのでしょうか。
その他
ここで問題としているてtest.dllは仮の名前であり、実際はサードパーティ製のライブラリのためデバッグができません。
追記 (2017.08.27 20:00)
以下のように変更をしたら状況が進みました。
- ResultInfoクラスの定義をclassからstructに変更
- Itemクラスの定義をclassからstructに変更
- C#のTestMethodの引数を [Out]ResultInfo result → IntPtr result に変更
- 関数の呼び出し方を以下のように変更
cs
1var resultInfo = new ResultInfo(); 2// var resultCode = TestFunction(resultInfo); 3IntPtr p = Marshal.AllocCoTaskMem(Marshal.SizeOf(resultInfo)); 4Marshal.StructureToPtr(resultInfo, p, false); 5var resultCode = TaskFunction(p); 6ResultInfo res = (ResultInfo)Marshal.PtrToStructure(p, typeof(ResultInfo)); 7Marshal.FreeCoTaskMem(p);
この結果、ResultInfo.items
(ここでは変数res)の中身が全てnullという状態は改善し、中身は全てItem
型のオブジェクトになりました。
しかし、ResultInto.items[0].itemid
には値が入っている状態ですが、ResultInfo.items[0].name
はnullになってしまいます。
(本来はResultInfo.items[0].name
には空文字列またはSJISの文字列が入り、nullが入ることはありません)
回答2件
あなたの回答
tips
プレビュー