从非托管代码传递指针
Posted
技术标签:
【中文标题】从非托管代码传递指针【英文标题】:Passing pointers from unmanaged code 【发布时间】:2009-05-07 14:42:44 【问题描述】:我有一个导入C dll的C#项目,该dll有这个功能:
int primary_read_serial(int handle, int *return_code, int *serial, int length);
我想访问串行参数。我实际上已经让它返回串行参数的一个字符,但我不太确定我在做什么,想了解发生了什么,当然要让它工作。
所以,我非常确定 dll 正在被访问,其他没有指针的函数可以正常工作。如何处理指针?我必须编组它吗?也许我得有个固定的地方放数据吧?
解释一下就好了。
谢谢! 理查德
【问题讨论】:
【参考方案1】:您必须使用 IntPtr 并将该 IntPtr 编组到您想要放入的任何 C# 结构中。在您的情况下,您必须将其编组为 int[]。
这分几个步骤完成:
分配非托管句柄 使用未管理的数组调用函数 将数组转换为托管字节数组 将字节数组转换为整数数组 释放非托管句柄该代码应该会给你一个想法:
// The import declaration
[DllImport("Library.dll")]
public static extern int primary_read_serial(int, ref int, IntPtr, int) ;
// Allocate unmanaged buffer
IntPtr serial_ptr = Marshal.AllocHGlobal(length * sizeof(int));
try
// Call unmanaged function
int return_code;
int result = primary_read_serial(handle, ref return_code, serial_ptr, length);
// Safely marshal unmanaged buffer to byte[]
byte[] bytes = new byte[length * sizeof(int)];
Marshal.Copy(serial_ptr, bytes, 0, length);
// Converter to int[]
int[] ints = new int[length];
for (int i = 0; i < length; i++)
ints[i] = BitConverter.ToInt32(bytes, i * sizeof(int));
finally
Marshal.FreeHGlobal(serial_ptr);
不要忘记 try-finally,否则您将面临泄露非托管句柄的风险。
【讨论】:
具体来说,分配一个非托管数组和一个托管 int[] 和 Marshal。将您的 IntPtr 从非托管数组复制到托管数组。【参考方案2】:如果我理解你想要做什么,这应该对你有用。
unsafe
int length = 1024; // Length of data to read.
fixed (byte* data = new byte[length]) // Pins array to stack so a pointer can be retrieved.
int returnCode;
int retValue = primary_read_serial(0, &returnCode, data, length);
// At this point, `data` should contain all the read data.
JaredPar 为您提供了一种简单的方法,只需更改您的外部函数声明,以便 C# 在后台为您进行编组。
希望这能让您对正在发生的事情有所了解。
【讨论】:
【参考方案3】:在编写该函数的 P/invoke 声明时,请尝试对指针参数使用关键字 ref,如下所示:
[DllImport("YouDll.dll", EntryPoint = "primary_read_serial")]
public static extern int primary_read_serial(int, ref int, ref int, int) ;
我不确定您是否需要在 C# 中指定参数的名称。请记住,在调用该方法时,您还必须在通过引用传递的参数中使用 ref。
【讨论】:
如果它应该是一个数组,他需要确保作为 IntPtr 和 Marshal.Copy 传递给托管数组。以上是关于从非托管代码传递指针的主要内容,如果未能解决你的问题,请参考以下文章
将 HBITMAP 句柄从非托管代码传递到托管代码以创建 System.Drawing.Bitmap 的安全性