7

我有一个导入 C dll 的 C# 项目,该 dll 具有以下功能:

int primary_read_serial(int handle, int *return_code, int *serial, int length);

我想访问串行参数。我实际上已经让它返回串行参数的一个字符,但我不太确定我在做什么并且想了解发生了什么,当然让它工作。

所以,我非常确定正在访问 dll,其他没有指针的函数可以正常工作。如何处理指针?我必须编组它吗?也许我得有个固定的地方放数据呢?

一个解释会很棒。

谢谢!理查德

4

3 回答 3

8

您必须使用 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,否则您将面临泄漏非托管句柄的风险。

于 2009-05-07T14:47:11.443 回答
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# 在后台为您进行编组。

希望这能让您了解在稍低的水平上发生的事情。

于 2009-05-07T14:53:34.313 回答
0

在编写该函数的 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。

于 2009-05-07T14:51:55.737 回答