Передача указателей из неуправляемого кода - PullRequest
7 голосов
/ 07 мая 2009

У меня есть проект C #, который импортирует C DLL, DLL имеет эту функцию:

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

Я хочу получить доступ к серийному параметру. Я на самом деле получил его, чтобы вернуть один символ серийного параметра, но я не совсем уверен, что делаю, и хотел бы понять, что происходит, и, конечно, заставить его работать.

Итак, я очень уверен, что к dll обращаются, другие функции без указателей работают нормально. Как мне обращаться с указателями? Должен ли я это сделать? Может быть, я должен иметь фиксированное место для размещения данных?

Объяснение было бы замечательно.

Спасибо! Ричард

Ответы [ 3 ]

8 голосов
/ 07 мая 2009

Вам нужно будет использовать IntPtr и Marshal, который IntPtr, в любую структуру C #, в которую вы хотите ее вставить. В вашем случае вам придется преобразовать ее в int [].

Это делается в несколько шагов:

  • Выделите неуправляемую ручку
  • вызов функции с массивом без изменений
  • Преобразование массива в массив управляемых байтов
  • Преобразование байтового массива в массив 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);
}

Не забудьте попробовать-наконец, иначе вы рискуете вытечь неуправляемой ручкой.

2 голосов
/ 07 мая 2009

Если я понимаю, что вы пытаетесь сделать, это должно сработать для вас.

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 # выполнял сортировку для вас в фоновом режиме.

Надеюсь, это даст вам представление о том, что происходит на немного более низком уровне.

0 голосов
/ 07 мая 2009

При написании объявления 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 в аргументах, передаваемых по ссылке.

...