从非托管代码传递指针

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 的安全性

gcServer 设置未从非托管 exe 传递到托管 dll

在托管代码和非托管代码之间传递非托管结构的安全数组

将托管类中包含的非托管指针字段传递给非托管代码

调试从非托管 C++ 调用的托管 .NET 代码

将数组从非托管 C++ 传递到 C#