从c+;返回指针数组+;到c# 下面我有一个C++代码片段。 我需要返回指针数组(到TempStruct)

从c+;返回指针数组+;到c# 下面我有一个C++代码片段。 我需要返回指针数组(到TempStruct),c#,c++,pinvoke,C#,C++,Pinvoke,问题是在c端我只得到一个元素。另一方面,我得到AV **C++** extern "C" __declspec(dllexport) void GetResult(TempStruct** outPtr, long *size) { *outPtr = (TempStruct*)new TempStruct*[2]; outPtr[0] = new TempStruct("sdf", 123); outPtr[1] = new TempStruct("

问题是在c端我只得到一个元素。另一方面,我得到AV

**C++**
extern "C" __declspec(dllexport) void GetResult(TempStruct** outPtr, long *size)
{       
    *outPtr = (TempStruct*)new TempStruct*[2];

     outPtr[0] = new TempStruct("sdf", 123);
     outPtr[1] = new TempStruct("abc", 456);

    *size = 2;      
}

**C#**    
[DllImport("test.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void GetResult(out IntPtr outPtr, out int size);

IntPtr ptr = IntPtr.Zero;
int length;        
GetResult(out ptr, out length);

int size = Marshal.SizeOf(typeof(TempStruct));
TempStruct[] someData2 = new TempStruct[length];

for (int i = 0; i < length; i++)
{
   IntPtr wskptr = (IntPtr)(ptr.ToInt64() + (size * i));
   someData2[i] = (TempStruct)Marshal.PtrToStructure(wskptr, typeof(TempStruct));            
} 
**C++**
外部“C”uu declspec(dllexport)void GetResult(TempStruct**outPtr,long*size)
{       
*outPtr=(TempStruct*)新的TempStruct*[2];
outPtr[0]=新的临时结构(“sdf”,123);
outPtr[1]=新的临时结构(“abc”,456);
*尺寸=2;
}
**C#**
[DllImport(“test.dll”,CallingConvention=CallingConvention.Cdecl,CharSet=CharSet.Ansi)]
公共静态外部void GetResult(out IntPtr outPtr,out int size);
IntPtr ptr=IntPtr.0;
整数长度;
GetResult(输出ptr、输出长度);
int size=Marshal.SizeOf(typeof(TempStruct));
TempStruct[]someData2=新的TempStruct[length];
for(int i=0;i
你做错了

您正在混合指针类型

通过使用
new TempStruct()
可以创建指向
TempStruct
的指针数组。我给出的示例创建了一个
TempStruct
数组。看到区别了吗

现在
TempStruct**outPtr
应该是
TempStruct***outPtr
(因为您希望返回(
*
)指针数组(
*
)……或者
TempStruct**
,如果您愿意的话:-)

换行

someData2[i] = (TempStruct)Marshal.PtrToStructure(Marshal.ReadIntPtr(wskptr), typeof(TempStruct));
因为你必须读单指针

我希望您使用delete删除各种
TempStruct
,并使用

delete[] ptr;
运算符删除结构数组

完整示例:

C++:


它更正确,因为
outPtr
size
都不能为
NULL
。看见C签名是相同的。

< P> C++代码是错误的。它将返回指向struct的指针数组。您对
new
返回的值进行强制转换的事实应该提醒您犯了错误。您希望返回一个struct数组

应该是:

*outPtr = new TempStruct[2];
(*outPtr)[0].str = "sdf";
(*outPtr)[0].i = 123;
(*outPtr)[1].str = "abc";
(*outPtr)[1].i = 456;
*size = 2;      

你的意思是不是例如
(*outPtr)[0]
?既然您分配了一个指针数组,那么
outPtr
参数不应该是一个三重指针(即
TempStruct***outPtr
)吗?分配内存时所做的强制转换是为了掩盖最后一个错误,千万不要强制转换
new
的结果。你的意思是不是例如
(*outPtr)[0]
?:)@约阿希姆皮勒堡是的。非常感谢。我只是垃圾在C++!DavidHeffernan唯一的问题是,您不能轻松地使用具有该语法的参数化构造函数。有人问过这个问题,以及解决方案。可以使用,但我更愿意去看牙医…:-)@xanatos是的,但我更喜欢它,而不是那些额外的分配和间接的方式。如果调用方知道需要多少元素,那么整个过程就可以由p/invoke封送器完成,而无需显式分配。在C++代码中,我只需生成一个返回新值的函数:<代码> TempStruct MakeNewStruct(const char * STR,const int i)< /> >,我仍然只能读取第一个项。我将参数更改为三个指针,并按照您上面所写的那样更改了c代码
delete[]ptr
是不够的。问题中的代码也要求删除每个项目。这就是为什么我认为C++代码是错误的。@ DavidHeffernan…更正。@John请参阅完整示例。@John示例中的
outPtr
通常不是
NULL
。如果你从C++中使用了这个方法,你会:<代码> TimStutt**PTR;整数大小;GetResult(&ptr,&size),因此您将为
outPtr
传递一个值:
&ptr
。在C#中也一样,使用
out ptr
。显然,您可以添加一个
NULL
检查,因为有人可以执行
GetResult(NULL,NULL)
。从技术上讲,C++中“正确”的方式是<代码>无效的GETREST(TestSufft *&OutpTR,int和size)< /C>,因为两者都是<代码> OutpTr> /Cuff>和<代码> size <代码>不能是代码> null < /C> >(参见)
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1), Serializable]
internal struct TempStruct
{
    public string str;
    public int num;
}

[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void GetResult(out IntPtr outPtr, out int numPtr);

[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void FreeSomeData(IntPtr ptr, int num);

// C++ will return its TempStruct array in ptr
IntPtr ptr;
int size;

GetResult(out ptr, out size);

TempStruct[] someData2 = new TempStruct[size];

for (int i = 0; i < size; i++)
{
    IntPtr ptr2 = Marshal.ReadIntPtr(ptr, i * IntPtr.Size);
    someData2[i] = (TempStruct)Marshal.PtrToStructure(ptr2, typeof(TempStruct));
}

// Important! We free the TempStruct allocated by C++. We let the
// C++ do it, because it knows how to do it.
FreeSomeData(ptr, size);
__declspec(dllexport) void GetResult(TempStruct **&outPtr, int &size)
{
    outPtr = new TempStruct*[2];

    outPtr[0] = new TempStruct("sdf", 123);
    outPtr[1] = new TempStruct("abc", 456);

    size = 2;
}
*outPtr = new TempStruct[2];
(*outPtr)[0].str = "sdf";
(*outPtr)[0].i = 123;
(*outPtr)[1].str = "abc";
(*outPtr)[1].i = 456;
*size = 2;