【问题标题】:Correct usage of DllImport正确使用 DllImport
【发布时间】:2010-07-13 14:47:20
【问题描述】:

假设在 Native.dll 中有一个 c++ 方法int NativeMethod(double, double *)。我第一次尝试从托管代码调用此方法是(假设我不需要指定入口点)

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, IntPtr outD);

然后使用我做的DLL

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
NativeMethod(2.0, x);

//do stuff with x

Marshal.FreeHGlobal(x);  //crash

我想了解为什么这里会崩溃。我的第一个猜测是这是一个堆问题,因为 DLL 和我的应用程序可能使用不同的 CRT。但如果是这种情况,为什么对 NativeMethod 的调用不会崩溃呢?该方法返回一个 x,我可以从中成功提取双精度。

我可以通过引用传递双精度来使导入工作

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, IntPtr outD);

为什么 FreeHGlobal 在第一次尝试时会崩溃,将指针传递给本机方法的推荐方法是什么? out 关键字在这种情况下可能工作得很好,但是如果我需要编组一个字符串怎么办?我认为我无法绕过 AllocH 和 FreeH...

【问题讨论】:

  • 它给你的错误信息是什么?
  • 当然,这应该是typeof(double)。但我认为 SizeOf(typeof(InpPtr)) 总是 >= SizeOf(typeof(double)),所以它可能以某种方式起作用。有趣的是,什么是“do stuff with x”部分?

标签: c# dll pinvoke marshalling unmanaged


【解决方案1】:

我可能误解了您的目标,但您似乎使目标变得比必要的复杂。只需通过引用传递它,让下面的编组处理它。

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, ref double outD);

double x;

x = 1;
NativeMethod( 2.0, ref x );

【讨论】:

  • +1 最有代表性的是用 out 代替 ref。 OP 从未初始化指针。
  • @JaredPar,这是真的。我不确定 OP 是否想要 ref 或 out 行为,但我未能识别出明显的线索(他没有在示例中初始化它的事实)。
  • 究竟使用 out/ref 与 AllocHGlobal 来获取未管理的内存有什么影响? GC可以在方法/函数返回之前重新排列内存和更改指针引用吗?
  • @thomask,有一个关于here的讨论
  • @thomask - 关于它的另一点。我相信对blittable 使用out/ref 会更有效率。我认为简单变量的地址会直接传递给非托管DLL进行修改,所以不涉及额外分配。
【解决方案2】:

问题在于该方法采用double*,它是一个指向双精度的指针。您正在传递一个指向IntPtr 的指针。这一点很重要,因为double(8 个字节)和IntPtr 之间的大小差异是可变大小(4 个或 8 个字节)。您需要将指针分配给double

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double));

【讨论】:

  • 啊,非常感谢.. 我错过了 msdn 参考中有关平台特定大小的部分。
【解决方案3】:

我不是专家,但不应该这样:

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double)));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-28
    • 1970-01-01
    • 1970-01-01
    • 2011-06-04
    相关资源
    最近更新 更多