gpt4 book ai didi

c++ - 如何将指针函数从 C++ 导出到 C#?

转载 作者:搜寻专家 更新时间:2023-10-31 01:54:23 26 4
gpt4 key购买 nike

我正在使用 DllImport 从 C# 调用 C++ 的函数。

#if defined(__cplusplus)
extern "C" {
#endif

__declspec(dllexport) int __stdcall ABC(int i);

__declspec(dllexport) char* __stdcall C(int i);

#if defined(__cplusplus)
}
#endif

int __stdcall ABC(int i)

{
return i;
}

char* __stdcall C(int i)
{
char* n = new char[i];
memset(n, 9, i);
return n;
}

C# 中的代码是:

using System.Runtime.InteropServices;
using System;

namespace DepartmentStore
{
class Exercise
{
[DllImport("library.dll")]
public static extern int ABC(int i);

[DllImport("library.dll")]
public static extern char* C(int i);

static int Main()
{
int k = ABC(10);
byte[] b = C(1024);

return 0;
}
}
}

函数 ABC(int i) 没问题,但是函数 C(int i) 在构建时产生了以下错误:

"Pointers and fixed size buffers may only be used in an unsafe context"

我想我不明白如何导出函数的指针返回。

有人能告诉我 C# 以指针形式调用函数的正确方法吗?

最佳答案

后来的 P/Invoke 不知道如何将 C 风格的数组从非托管端编码到托管端;不像SAFEARRAY , 没有信息嵌入到 C 风格的数组中,P/Invoke 稍后可以使用这些信息来确定应该复制多少字节。

正因为如此,您需要声明您的C 函数以返回一个IntPtr。然后调用Marshal.PtrToStrAnsi method将指针转换为托管端的字符串,如下所示:

[DllImport("library.dll")]
public static extern IntPtr C(int i);

static int Main()
{
int k = ABC(10);
IntPtr b = C(1024);

string s = Marshal.PtrToStrAnsi(b);

// Problem: How do you release what is pointed to
// by IntPtr?

return 0;
}

此外,您必须将 IntPtr 传递回非托管端以释放您使用 new 分配的内存;如果不这样做,就会发生内存泄漏。

一个更简单的选择是在 C++ 中为您的非托管库创建一个托管包装器,它公开托管函数,这些函数进行调用并执行到 String^ 的转换(使用 marshal_as ),如下所示:

// compile with: /clr
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <msclr\marshal.h>

using namespace System;
using namespace msclr::interop;

String^ WrappedC(int i) {
// Make the call to the native function.
// Let's store in an auto_ptr to handle
// cleanup when the wrapper is exited.
auto_ptr<char> c(C(i));

// Convert to a managed string and
// return.
return marshal_as<String^>(c.get());
}

如果您不想编码回一个string,而是编码回一个byte 数组,那么我仍然推荐包装器方法(尽管在此在这种情况下,它需要您具备一些特定知识才能创建要返回的托管数组):

// compile with: /clr
#include <stdlib.h>
#include <memory>

using namespace System;
using namespace msclr::interop;

String^ WrappedC(int i) {
// Make the call to the native function.
// Let's store in an auto_ptr to handle
// cleanup when the wrapper is exited.
auto_ptr<char> c(C(i));

// Copy the pointer.
char* p = c.get();

// The byte array to return.
// i is the size of the array, as per the call
// to C.
array<byte>^ a = gcnew array<byte>(i);

// Populate.
for (int index = 0; index < i; ++index)
a[index] = (byte) *p++;

// Return the array.
return a;
}

这些是比完全在托管代码中处理它更好的选择,因为您不必担心在托管和非托管之间连续编码以处理指向在非托管空间中分配的内存的指针。

关于c++ - 如何将指针函数从 C++ 导出到 C#?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9678061/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com