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

时间:2010-02-25 22:27:32

标签: c# pinvoke marshalling

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

SomeData* test();

我们假设SomeData为:

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

现在我想从C#代码中调用此函数。我开始定义像这样自定义编组所需的C#Struture:

[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 ANSWER之后编辑------------------- -

事实上,我在将代码复制到我的问题时犯了一个错误。我使用的真实托管签名是:

  

[DllImport(“DynamicLibrary.dll”,CharSet = CharSet.Auto)]
      [返回:MarshalAs(UnmanagedType.LPStruct)]
      public static extern IntPtr test();

JaredPar的回答仍然相关。为了获得正确的行为,我有两个选择:

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

2)使用'public static extern SomeData test();' (使用MarshalAs属性)然后只需使用SomeData sd = test();

1 个答案:

答案 0 :(得分:10)

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

[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
  }
}