在下面的示例中,如果将C ++中定义的dataArray
定义为数组而不是指针,则可以正常工作(仅产生垃圾数据)。是否还有另一种方法来封送C#数组,以便它以数组形式读取指针?
C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CSharpFoo{
int alpha;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5]
public int[] dataArray;
int beta;
}
C ++
struct CPPFoo{
int alpha;
//int* dataArray; //Doesn't work, even though initialized to an array elsewhere
int dataArray[5];
int beta;
}
通过这样的函数
C#
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public extern static bool InitializeDLL([MarshalAs(UnmanagedType.FunctionPtr)] ResultCallback callbackPointer);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void ResultCallback(CSharpFoo value);
C ++
//Callback
typedef void(__stdcall * ResultCallback)(CPPFoo);
__declspec(dllexport) bool InitializeDLL(ResultCallback callback);
谢谢!
编辑:: 因为尚不清楚“初始化为其他位置的数组”:
CPPFoo(int dummy){ //Constructor
alpha = 32;
dataArray = new int[5];
for (int i = 0; i < 5; i++){
dataArray[i] = i;
}
beta = 13;
}
//dataArray C++ {0,1,2,3,4}
//alpha C# 32
//dataArray C# {Total random garbage} (dataArray[3] is 13!)
//beta C# 0
PS,CPPFoo结构是来自DLL的复杂结构,因此我无法更改它。现在,为了使工作正常,我将其复制到更合适的数组中,如NonCreature0714的答案,但这导致所有数据被复制两次。我想避免的就是这个双重副本。
另一个编辑: 对于包含单个数组的结构,似乎可以正确传递值,而对于复杂的结构,则可能会抛出垃圾。 我已经更新了代码以反映更复杂的结构!
答案 0 :(得分:1)
据我了解您的代码,我在本地计算机上进行了一些测试。我的以下代码没有问题
c#侧
struct Foo
{
public int alpha;
public IntPtr Data;
public int beta;
public void GetData(ref int[] buffer,int length)
{
Marshal.Copy(Data,buffer,0,length);
}
}
班计划 {
[DllImport("MyPtr.dll",EntryPoint = "InitializeDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern bool InitializeDLL([MarshalAs(UnmanagedType.FunctionPtr)]ResultCallback callbackPointer);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void ResultCallback(ref Foo value);
static void CallBackMe(ref Foo value)
{
var buffer = new int[5];
value.GetData(ref buffer,buffer.Length);
}
static void Main(string[] args)
{
InitializeDLL(CallBackMe);
}
}
C ++方面
struct CPPFoo {
int* dataArrayPtr;
CPPFoo()
{
dataArrayPtr = new int[5];
for (int i = 0; i < 5; i++) {
dataArrayPtr[i] = i;
}
}
};
typedef void(__stdcall * ResultCallback)(CPPFoo);
extern "C" __declspec(dllexport) bool InitializeDLL(ResultCallback callback)
{
CPPFoo f;
callback(f);
return true;
}
答案 1 :(得分:0)
我在C#中的经验非常有限,但似乎可以与 int dataArray [5]; 一起使用,因为代码与CSharpFoo和CPPFoo的类型一致。两者的大小均为5个整数。当您将类型更改为指针时,一个是五个整数的大小,另一个是单个指针,该大小小于五个整数。
最有可能传递一个动态大小的数组将需要一个大小,并且要获取一个指针,您可能需要使用不安全的代码来做一些事情,但是我不是用C#编写的,所以这只是一个猜测。
struct CPPFoo {
int* dataArray = nullptr;
int size = 0;
}
答案 2 :(得分:0)
使用向量。
#include <vector>
struct CPPFoo {
std::vector<int> dataArray;
};
向量更易读且更安全。它只是轻微会增加代码的大小,并且只比使用原始数组慢一点。您也不必担心保持变量的大小,并在每次更改时对其进行更新。