
Cで作ったdll内の関数を.NET(C#)のプログラムからPINVOKEを介して呼び出そうとしているのですが、構造体の配列を引数として渡すにはどうするべきかわかりません。データの流れる向きは、両方向 [In, Out] です。下記の方法を試してうまくいかないのですが、どこが悪いのでしょうか?下記サンプルはうまくいかないのですが、構造体の配列をメンバーに持った構造体を使ってデータを受け渡そうとしています。もしかして、IntPtrを使って自分でマーシャリングしないとできませんか?
助言いただきたく、おねがいいたします。
-- 呼び出し側 --
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace MarshalTest
{
[StructLayout(LayoutKind.Sequential)]
class Data
{
private const int buffersize = 256;
[MarshalAs(UnmanagedType.I4)]
public int count;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = buffersize)]
public Byte[] data;
public Data()
{
count = 0;
data = new Byte[buffersize];
}
}
[StructLayout(LayoutKind.Sequential)]
class DataBundle
{
private const int buffersize = 8;
[MarshalAs(UnmanagedType.I4)]
public int count;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStruct, SizeConst = buffersize)]
public Data[] data;
public DataBundle()
{
count = 0;
data = new Data[buffersize];
for (int idx = 0; idx < buffersize; idx++)
{
data[idx] = new Data();
}
}
}
class Program
{
[DllImport("NativeDll.dll")]
private static extern void test1([Out] Data data);
[DllImport("NativeDll.dll")]
private static extern void test2([Out] DataBundle data);
static void Main(string[] args)
{
#if false
// これはできます。
Data data = new Data();
test1(data);
System.Console.WriteLine(Encoding.ASCII.GetString(data.data, 0, data.count));
#else
// これができません。
DataBundle data = new DataBundle();
test2(data);
for (int idx = 0; idx < data.count; idx++)
{
System.Console.WriteLine(Encoding.ASCII.GetString(data.data[idx].data, 0, data.data[idx].count));
}
#endif
}
}
}
-- 呼ばれ側 --
#include <Windows.h>
extern "C" {
#define MAX_DATA 256
#define MAX_BUNDLE 8
struct Data
{
int count;
char data[MAX_DATA];
};
struct DataBundle
{
int count;
Data data[MAX_BUNDLE];
};
__declspec(dllexport) void __stdcall test1(Data *data);
__declspec(dllexport) void __stdcall test2(DataBundle *data);
};
void __stdcall test1(Data *data)
{
const char *text = "osite !! goo !!";
data->count = strlen(text);
strcpy(data->data, text);
data->data[strlen(text)] = '\0';
}
void __stdcall test2(DataBundle *data)
{
const char *text = "osite !! goo !!";
for (int idx = 0; idx < MAX_BUNDLE; idx++)
{
strcpy(data->data[idx].data, text);
data->data[idx].data[strlen(text)] = '\0';
}
}
以上です。
No.1ベストアンサー
- 回答日時:
自分でマーシャリングすればできます。
-- 呼び出し側 --
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace MarshalTest
{
[StructLayout(LayoutKind.Sequential)]
class Data
{
private const int buffersize = 256;
[MarshalAs(UnmanagedType.I4)]
public int count;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = buffersize)]
public Byte[] data;
public Data()
{
count = 0;
data = new Byte[buffersize];
}
}
class Program
{
[DllImport("NativeDll.dll")]
private static extern void test3([In, Out] IntPtr data);
static void Main(string[] args)
{
Data[] data = new Data[4];
for (int idx = 0; idx < 4; idx++)
{
data[idx] = new Data();
}
IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Data)) * 4);
IntPtr pos = new IntPtr(result.ToInt32());
for (int idx = 0; idx < 4; idx++)
{
Marshal.StructureToPtr(data[idx], pos, true);
pos = IntPtr.Add(pos, Marshal.SizeOf(typeof(Data)));
}
test3(result);
pos = new IntPtr(result.ToInt32());
for (int idx = 0; idx < 4; idx++)
{
data[idx] = (Data)Marshal.PtrToStructure(pos, typeof(Data));
pos = IntPtr.Add(pos, Marshal.SizeOf(typeof(Data)));
}
for (int idx = 0; idx < 4; idx++)
{
System.Console.WriteLine(Encoding.ASCII.GetString(data[idx].data, 0, data[idx].count));
}
Marshal.FreeHGlobal(result);
}
}
}
-- 呼ばれる側 --
#include <Windows.h>
extern "C" {
#define MAX_DATA 256
struct Data
{
int count;
char data[MAX_DATA];
};
__declspec(dllexport) void __stdcall test3(Data *data);
};
void __stdcall test3(Data *data)
{
const char *text = "osite !! goo !!";
for (int idx = 0; idx < 4; idx++)
{
strcpy(data[idx].data, text);
data[idx].data[strlen(text)] = '\0';
data[idx].count = strlen(text);
}
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
int型(2バイト)データの分割
-
C言語についてです! 同じ年の...
-
10個の実数に対する降順ソート...
-
printfの%eで指数部分の桁数を...
-
stable diffusionのエラー
-
C言語 構造体の名前欄?を小文...
-
ポインター引数の関数でコンパ...
-
UTF-8で5~6バイトになる文字コ...
-
COBOLのCOMP形式について
-
10Mバイトて文字数に すると何...
-
matlabで、平均値を求める方法...
-
DataGridViewの特定列に入力さ...
-
C++ Builderで文字列をバイトに...
-
char str[256]の256の意味は?
-
URLは最高何文字まで可能なので...
-
VB6.0でMSChartをタイマーを使...
-
Javaで日本語1文字のバイト数
-
文字列の最後の一字を削除
-
日付時刻を4バイトに
-
Excel VBA メール作成について ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
stable diffusionのエラー
-
printfの%eで指数部分の桁数を...
-
エクセルVBA:日付データの変換...
-
C#でのswitch文
-
C言語 ファイル内のデータと入...
-
int型(2バイト)データの分割
-
ポインター引数の関数でコンパ...
-
C言語でのLinuxとwindows共通の...
-
Excel VBA グラフ作成のとき...
-
【Excel VBA】10進数を2進数に...
-
データの値の近いものをグルー...
-
C言語の構造体にてバブルソート...
-
CreateProcessでの環境変数の設...
-
PINVOKEで構造体配列をマーシャ...
-
c言語 Bitについて
-
ビットデータのチェック方法
-
C++/CLIのオブジェクト型配列
-
RegQueryValueExでの2バイト文字
-
'dataType' 引数を Null にする...
-
System.Collections.ArrayList ...
おすすめ情報