c# - 将指针从非托管代码返回到托管代码

标签 c# pinvoke marshalling

我有一个导出以下函数的非托管 dll:

SomeData* test();

让我们假设 SomeData 为:

typedef struct _Data Data;  
struct _Data{  
    int a;  
    int b;  
}

现在我想从 C# 代码调用这个函数。我开始像这样定义自定义编码(marshal)处理所需的 C# 结构:

[StructLayout(LayoutKind.Sequential)]  
public class SomeData  
{  
    public Int32 a;  
    public Int32 b;  
}  

现在,我声明托管函数:

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)]  
[return: MarshalAs(UnmanagedType.LPStruct)]  
public static extern SomeData test();  

在主要功能中我有:

IntPtr ptr = test();  

这样做,我得到了 MarchalDirectiveException:“无法编码‘返回值’:无效的托管/非托管类型组合(Int/UInt 必须与 SysInt 或 SysUInt 配对)。”

我没有在 C# 中为 SomeData 分配内存,因为我希望这个内存是在 C 函数中分配的,我会使用 Marshal.Copy 将其传递给托管内存。

有什么想法吗?谢谢

------------------------ JaredPar 回答后编辑-------------------- -

事实上,我在针对我的问题编写代码时犯了一个错误。我使用的真正托管签名是:

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)]
[return: MarshalAs(UnmanagedType.LPStruct)]
public static extern IntPtr test();

JaredPar 的回答仍然有意义。为了获得正确的行为,我有 2 个选择:

1) 使用 'public static extern IntPtr test();' (没有 MarshalAs 属性)签名,然后像 JaredPar 建议的那样访问返回的指针。

2) 使用 'public static extern SomeData test();' (使用 MarshalAs 属性)然后简单地使用 SomeData sd = test();

最佳答案

在声明托管函数时,您需要将指针类型与引用值或 IntPtr 值相匹配。在这种情况下,LPStruct 修饰符将无济于事。最简单的解决方案是将 test 的返回值转换为 IntPtr 而不是 SomeData,因为 native 方法返回的是指针值。然后您可以编写以下包装器

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)]
public static extern IntPtr test();

public static SomeData testWrapper() {
  var ptr = test();
  try {
    return (SomeData)Marshal.PtrToStructure(ptr, typeof(SomeData));
  } finally {
    // Free the pointer here if it's allocated memory
  }
}

关于c# - 将指针从非托管代码返回到托管代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2338146/

相关文章:

c# - MarshalAsAttribute 字符串数组

c# - 在 VBA 的 C# dll 中返回字符串 []

c# - 将 c 字符数组 [128] 编码到 c#

c# - 是否有将 "YYYYMMDDHHMMSS.UUUUUU-TZO"格式转换为 C# DateTime 的 API?

c# - 删除 Azure 表存储中的所有表

c# - 如何将 IntPtr 获取为 bool 值

c# - 从 C++ DLL 在 C# 中触发事件

c# - C# 中的无限数字

c# - 尽管 64 位操作系统上有 AnyCPU,IntPtr.Size 始终为 4

c# - 如何从 C# 调用具有 char[] 作为 OUT 参数的非托管函数?