Passing pointers from unmanaged code

此生再无相见时 提交于 2019-12-04 21:54:58

问题


I have a C# project that imports a C dll, the dll has this function:

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

I want to get access to the serial parameter. I've actually got it to return one character of the serial parameter, but I'm not really sure what I'm doing and would like to understand what is going, and of course get it working.

So, I'm very sure that the dll is being accessed, other functions without pointers work fine. How do I handle pointers? Do I have to marshal it? Maybe I have to have a fixed place to put the data it?

An explanation would be great.

Thanks! Richard


回答1:


You will have to use an IntPtr and Marshal that IntPtr into whatever C# structure you want to put it in. In your case you will have to marshal it to an int[].

This is done in several steps:

  • Allocate an unmanaged handle
  • Call the function with the unamanged array
  • Convert the array to managed byte array
  • Convert byte array to int array
  • Release unmanaged handle

That code should give you an idea:

// 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);
}

Don't forget the try-finally, or you will risk leaking the unmanaged handle.




回答2:


If I understand what you're trying to do, this should work for you.

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 gives you the easy way to do it however, which is just to change your external function declaration so that C# does the marshalling for you in the background.

Hopefully this gives you an idea of what's happening at a slightly lower level anyway.




回答3:


When writing your P/invoke declaration of that function, try using keyword ref for the pointer parameters like this:

[DllImport("YouDll.dll", EntryPoint = "primary_read_serial")]
public static extern int primary_read_serial(int, ref int, ref int, int) ;

I'm not sure if you need to specify the parameters' name in C#. And remember, when calling that method, you will also have to use ref in the arguments you're passing by reference.



来源:https://stackoverflow.com/questions/835072/passing-pointers-from-unmanaged-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!