2010-05-29 59 views
0

在外部(Delphi創建的)DLL中,我得到了以下函數,我需要從C#應用程序調用。C# - 調用分機。包含Delphi「變體記錄」參數的DLL函數

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

然後我使用「my9bytes」結構聲明瞭導入的「ReadMsg」函數。

[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不允許覆蓋字符串或數組成員,它將允許無限制地訪問垃圾收集堆。

這是一個函數的mutt,手動編組合適合這裏。

0

你試過System.Runtime.InteropServices.Marshal類嗎?它提供了很多Readxxx方法來訪問非託管內存。

1

由於您的記錄是可變的,您將按照所述進行一些手動編組。你可以通過創建具有明確佈局的目標類型來稍微簡化它,然後在打開TypeMsg字節後將它們傳送到這些目標類型。

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

,然後使用Marshal.PtrToStructure接收到的數據位塊傳輸到他們:使用顯式佈局

你可以佈置你的目標類型(類或結構)

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