从跨平台 DLL 返回整数数组
我用 C++ 创建了一个跨平台 DLL,可以在 Windows 和 Mac OSX 上编译。在 Windows 上,我有一个使用 P/Invoke 调用 DLL 的 C# 应用程序,在 Mac OSX 上,有一个目标 C 应用程序调用 DLL。我有一个可以正常工作的简单函数,但我需要一个返回整数数组的新函数。
我能找到的最好的例子是 Marshal C++ int array to C# 和我能够让它发挥作用。但是,我想修改此示例以将整数数组作为引用参数传递回来。数组的大小必须在运行时设置。
这是我尝试过的。 pSize 正确返回,但列表为空。
在非托管 C++ 中:
bool GetList(__int32* list, __int32* pSize)
{
// Some dummy data
vector<int> ret;
ret.push_back(5);
ret.push_back(6);
list = (__int32*)malloc(ret.size());
for (unsigned int i = 0; i < ret.size(); i++)
{
list[i] = ret.at(i);
}
*pSize = ret.size();
return true;
}
在 C# 中:
[DllImport(@"MyDll.dll",
CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern bool GetList(out IntPtr arrayPtr, out int size);
public static int[] GetList() {
IntPtr arrayValue = IntPtr.Zero;
int size = 0;
bool b = GetFrames(out arrayValue, out size);
// arrayValue is 0 here
int[] result = new int[size];
Marshal.Copy(arrayValue, result, 0, size);
return result;
}
I created a cross-platform DLL in C++ that compiles on both Windows and Mac OSX. On Windows, I have a C# app that calls the DLL using P/Invoke and on Mac OSX, an objective C app calls the DLL. I have simple functions working just fine but I need a new function that returns an array of integers.
The best example I can find is at Marshal C++ int array to C# and I was able to make it work. However, I would like to modify this example to pass the integer array back as a reference argument instead. The size of the array has to be set at runtime.
Here's what I've tried. The pSize is coming back correctly but the list is empty.
In unmanaged c++:
bool GetList(__int32* list, __int32* pSize)
{
// Some dummy data
vector<int> ret;
ret.push_back(5);
ret.push_back(6);
list = (__int32*)malloc(ret.size());
for (unsigned int i = 0; i < ret.size(); i++)
{
list[i] = ret.at(i);
}
*pSize = ret.size();
return true;
}
In C#:
[DllImport(@"MyDll.dll",
CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern bool GetList(out IntPtr arrayPtr, out int size);
public static int[] GetList() {
IntPtr arrayValue = IntPtr.Zero;
int size = 0;
bool b = GetFrames(out arrayValue, out size);
// arrayValue is 0 here
int[] result = new int[size];
Marshal.Copy(arrayValue, result, 0, size);
return result;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
“调用者分配”是使代码可移植同时保持可维护性的唯一方法。您的代码不仅不会更改调用者的指针,而且 C# 代码也无法释放您分配的内存(
malloc
内存不会被垃圾回收清理)。如果快速找到大小(不需要生成所有输出数据),只需添加第二个函数来返回大小。
如果在生成数据之前无法获取大小,则让一个函数返回大小和指向内容的指针(
int**
,在 C# 端它将是ref IntPtr )。第二个函数将该数据复制到 C# 数组并释放本机缓冲区。
"Caller-allocates" is the only way to make code portable while keeping it maintainable. Not only does your code not change the caller's pointer, but the C# code has no way to free the memory you allocated (
malloc
-ed memory won't be cleaned up by garbage collection).If finding the size is quick (doesn't require generating all the output data), just add a second function to return the size.
If you can't get the size until you generate the data, then make one function return the size and a pointer to the content (
int**
, on the C# side it will beref IntPtr
). And a second function that copies that data to the C# array and frees the native buffer.您的问题是
list
的定义,它确实需要是__int32**
才能将分配的数组的地址传回。为了轻松解决指针到指针的互操作困难,您可以在失败时返回list
或null
的地址:通过对 C# 进行适当的修改:
Your problem is the definition of
list
, it really needs to be an__int32**
in order to pass back the address of the allocated array. To breeze through the interop difficulties of pointers-to-pointers, how about you instead return the address oflist
ornull
if it fails:With the appropriate modifications to your C#: