返回从 c++ 到 c# 的指针数组

Return array of pointers from c++ to c#

本文关键字:指针 数组 c++ 返回      更新时间:2023-10-16

下面我有一个来自 c++ 的代码片段。我需要返回指针数组(到 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));            
} 

你做错了。

您正在混合指针类型。

通过使用new TempStruct(),您将创建一个指向TempStruct 的指针数组。我给你的例子创建了一个TempStruct数组。看到区别了吗?

现在。。。 TempStruct** outPtr应该是TempStruct*** outPtr的(因为你想返回(*(一个指针(*(的数组(*(...或者TempStruct**&如果你愿意:-(

更改此行

someData2[i] = (TempStruct)Marshal.PtrToStructure(Marshal.ReadIntPtr(wskptr), typeof(TempStruct));

因为您必须阅读单个指针。

我确实希望您TempStruct通过删除和使用

delete[] ptr;

运算符以删除结构数组。

完整示例:

C++:

struct TempStruct
{
    char* str;
    int num;
    // Note the strdup. You don't know the source of str.
    // For example if the source is "Foo", then you can't free it.
    // Using strdup solves this problem.
    TempStruct(const char *str, int num) 
        : str(strdup(str)), num(num)
    {
    }
    ~TempStruct()
    {
        free(str);
    }
};
extern "C"
{
    __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;
    }
    __declspec(dllexport) void FreeSomeData(TempStruct **ptr, int size)
    {
        for (int i = 0; i < size; i++)
        {
            delete ptr[i];
        }
        delete[] ptr;
    }
}

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);

请注意,不需要在 C# struct[Serializable]Pack=1

对于C++更正确:

__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;
}

它更正确,因为outPtrsize都不能NULL。请参阅 https://stackoverflow.com/a/620634/613130 。C# 签名是相同的。

C++代码是错误的。它返回一个指向结构的指针数组。您转换 new 返回的值这一事实应该提醒您您犯了一个错误。你想要返回一个结构数组。

它应该是:

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