2010-05-29 3 views
0

Во внешней (Delphi-created) DLL У меня есть следующая функция, которую мне нужно вызвать из приложения C#.C# - вызов ext. DLL-функция, содержащая параметр «вариант записи Delphi»

function ReadMsg(handle: longword; var Msg: TRxMsg): longword; stdcall; external 'MyDll.dll' name 'ReadMsg'; 

типа «TRxMsg» является вариант записи, определяется следующим образом:

TRxMsg = record 
    case TypeMsg: byte of 
     1: (accept, mask: longword); 
     2: (SN: string[6]); 
     3: (rx_rate, tx_rate: word); 
     4: (rx_status, tx_status, ctl0, ctl1, rflg: byte); 
end; 

Для того, чтобы вызвать функцию из C#, я объявил вспомогательную структуру «my9Bytes», содержащий массив байтов и определил, что он должен быть упорядочен как массив длиной 9 байтов (который точно соответствует размеру записи Delphi).

private struct my9Bytes { 
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 9)] 
    public byte[] data; 
} 

Затем я объявил импортированную функцию «ReadMsg», используя структуру «my9bytes».

[DllImport("MyDll.dll")] 
private static extern uint ReadMsg(uint handle, ref my9Bytes myMsg); 

Я могу вызвать функцию без проблем ... Тогда мне нужно создать структуру, соответствующую исходной «TRxMsg» вариант записи и преобразовать свою вспомогательную «myMsg» массив в эту структуру.

Я не знаю ни одного эквивалентного варианта C# для Delphi, поэтому я использовал наследование и создал следующие классы.

public abstract class TRxMsg { 
    public byte typeMsg; 
} 
public class TRxMsgAcceptMask:TRxMsg { 
    public uint accept, mask; 
    //... 
} 
public class TRxMsgSN:TRxMsg { 
    public string SN; 
    //... 
} 
public class TRxMsgMRate:TRxMsg { 
    public ushort rx_rate, tx_rate; 
    //... 
} 
public class TRxMsgStatus:TRxMsg { 
    public byte rx_status, tx_status, ctl0, ctl1, rflg; 
    //... 
} 

Наконец создать соответствующий объект и инициализировать его значение вручную преобразуется из «myMsg» массива (я использовал BitConverter для этого).

Это прекрасно работает, это решение кажется мне слишком сложным и что это должно быть возможно сделать как можно более прямо, без вспомогательных структур «my9bytes» или наследования и ручной конвертации отдельных значений. Поэтому я хотел бы попросить у вас предложения по наилучшему способу сделать это.

Большое спасибо!

ответ

1

Обычно вы обрабатываете это с помощью атрибута [StructLayout (LayoutKind.Explicit)] в объявлении структуры. В этом случае отдельные объявления структуры для членов профсоюза. Который бы почти работал, если бы не член SN. CLR не позволит вам наложить элемент строки или массива, что позволит неограниченный доступ к собранной кучей мусора.

Это мутант функции, ручное маршалинг здесь подходит.

0

Вы пробовали System.Runtime.InteropServices.Marshal class? Он предоставляет множество методов Readxxx для доступа к неуправляемой памяти.

1

Поскольку ваша запись является переменной, вы собираетесь выполнить ручную сортировку, как описано. Вы можете немного упростить его, создав целевые типы с явным макетом, а затем blitting на них после включения вашего байта TypeMsg.

Вы можете макет вашего типов целевых (классы или структуры) с использованием явной раскладку:

http://en.csharp-online.net/Common_Type_System%E2%80%94Explicit_Layout_Example

А затем Blit полученные данные на них с помощью Marshal.PtrToStructure:

http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx

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

  • Нет связанных вопросов^_^