2015-07-29 4 views
2

Мне нужно экспортировать функцию из C DLL. Вот пример, который я написалКак правильно передать указатель struct из C# в C DLL

typedef struct tag_struct { 
    unsigned char first; 
    unsigned char second; 
} st_struct; 

__declspec(dllexport) unsigned char Func(st_struct *ptr) 
{ 
    return ptr->first + ptr->second; 
} 

Вот код C#, который я использую для импорта описанной выше функции.

using System; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace ImportTest 
{ 
    [Serializable] 
    [StructLayout(LayoutKind.Sequential)] 
    public class st_struct 
    { 
     public byte first; 
     public byte second; 
    } 

    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 

      st_struct x = new st_struct(); 

      x.first = 1; 
      x.second = 2; 

      byte result = Func(ref x); 
     } 

     [DllImport("MarshalTest.dll")] 
     protected static extern byte Func(ref st_struct inputs); 
    } 
} 

Моя проблема заключается в том, что возвращаемое значение Func не равно 3, как и должно быть (1 + 2).

Я использую отладчик, чтобы видеть значения внутри DLL - они разные (не 1 и 2, которые я предоставил).

Функция возвращает правильное значение Whan меняю C# код так:

public Form1() 
{ 
    InitializeComponent(); 

    st_struct x = new st_struct(); 

    x.first = 1; 
    x.second = 2; 

    byte result = Func(x); 
} 

[DllImport("MarshalTest.dll")] 
protected static extern byte Func(st_struct inputs); 

Проблема исчезает, когда я удаляю реф. Но я не понимаю, почему.

Не могли бы вы объяснить это?

+0

Что произойдет, если вы используете 'LayoutKind.Explicit' и украшаете поля' [FieldOffset (0)] 'и' [FieldOffset (1)] '? –

+0

@ Theodoros Chatzigiannakis: nothing :( – walruz

+0

Что делать, если вы пытаетесь передать указатель вместо этого? Https://msdn.microsoft.com/en-us/library/dn261468(v=vs.110).aspx –

ответ

1

Как @kennyzx упоминает, так как ваш st_struct является классом, он уже является ссылочным типом и будет передан как указатель. Я подозреваю, что вы выбрали ref, который даст вам двойной указатель, что не имеет большого смысла при смешивании управляемого и неуправляемого кода. Маршаллер может справиться с этим и создать для вас новый объект, если указатель изменится, но это похоже на отрывочную вещь.

Таким образом, при передаче класса без ref он работает как ожидается (код C получает указатель). Если вы измените его на struct, передав его без ref, он должен передать его в стек и передать его ref передаст его как указатель.

Использование struct кажется очевидным выбором в вашем случае, поскольку его можно передать напрямую (CLR просто нужно его закрепить и передать указатель). Использование class Я подозреваю, что будет задействован более маршаллинг.

2

Возможно, вы думаете, что ключевое слово ref необходимо для того, чтобы passing parameter by reference. Но так как st_struct определяется как ссылочный тип (класс является ссылочным типом), поэтому параметр передается по ссылке, а не по значению. Вам не нужно ключевое слово ref.

Если st_struct были определены как struct, вы можете найти его, когда используете ключевое слово ref.

Смежные вопросы