2012-07-16 146 views
0

我正在編寫一個與舊的C DLL進行通信的C#應用​​程序。我看着C DLL的頭,看到2層的結構,我需要在C#創建:將C++結構轉換爲C#

typedef struct 
{ 
    char user_field_name[MAXLENGTH]; 
    WORD user_field_length; 
    char user_field_contents[80]; 
    char user_field_requested[1]; 
    char user_field_clear[1]; 
    char user_field_attribute[1]; 
} U_FIELD_STRUCT; 
typedef U_FIELD_STRUCT FAR * P_U_FIELD_STRUCT; 

typedef struct 
{ 
    char    user_begin_literal[7]; 
    char    user_screen_name[MNFRMSCRNAMELENGTH]; 
    char    key_to_be_sent[256]; 
    WORD    num_of_user_fields; 
    U_FIELD_STRUCT  user_field[MAXFIELDCOUNT]; 
    char    user_end_literal[7]; 
} USER_FIELD_STRUCT; 

在我的C#類,我寫了他們如下:

public const Int32 MAXLENGTH = 51; 
    public const Int32 MAXTAGLENGTH = 80; 
    public const Int32 MNFRMSCRNAMELENGTH = 5; 
    public const Int32 MAXFIELDCOUNT = 100; 
    public const Int32 MAXTAGCOUNT = 40; 
    public const Int32 MAXSCREENCOUNT = 150; 

    public const Int32 NO_SCREEN_DATA = 99; 

    [StructLayout(LayoutKind.Sequential, Pack=4, CharSet=CharSet.Ansi)] 
    public struct U_FIELD_STRUCT 
    { 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=MAXLENGTH)] 
     public char [] user_field_name; 
     public short user_field_length; 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=80)] 
     public char [] user_field_contents; 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=1)] 
     public char [] user_field_requested; 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=1)] 
     public char [] user_field_clear; 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=1)] 
     public char [] user_field_attribute; 
    }; 

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)] 
    public struct USER_FIELD_STRUCT 
    { 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=7)] 
     public char [] user_begin_literal; 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=MNFRMSCRNAMELENGTH)] 
     public char [] user_screen_name; 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] 
     public char [] key_to_be_sent; 
     public short num_of_user_fields; 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=MAXFIELDCOUNT)] 
     public U_FIELD_STRUCT [] user_field; 
     [ MarshalAs(UnmanagedType.ByValArray, SizeConst=7)] 
     public char [] user_end_literal; 
    }; 

當我初始化結構在C#中,我做如下:

 USER_FIELD_STRUCT UserFieldsData = new USER_FIELD_STRUCT(); 
     UserFieldsData.user_begin_literal = new char[7]; 
     UserFieldsData.user_screen_name = new char[MNFRMSCRNAMELENGTH]; 
     UserFieldsData.key_to_be_sent = new char[256]; 
     UserFieldsData.user_field = new U_FIELD_STRUCT[MAXFIELDCOUNT]; 
     UserFieldsData.user_end_literal = new char[7]; 
     for (int i = 0; i < MAXFIELDCOUNT; i++) 
     { 
      UserFieldsData.user_field[i].user_field_name = new char[MAXLENGTH]; 
      UserFieldsData.user_field[i].user_field_contents = new char[80]; 
      UserFieldsData.user_field[i].user_field_requested = new char[1]; 
      UserFieldsData.user_field[i].user_field_clear = new char[1]; 
      UserFieldsData.user_field[i].user_field_attribute = new char[1]; 
     } 

的問題是,當我的PInvoke我的方法,我收到一條錯誤消息(基本DLL具有驗證字符串,並將其發送一條消息,字符串不是什麼的y應該是)。所以我安裝了VS6,並以調試模式運行了DLL。我查看了我發送的結構,並且字符串確實有我放入其中的數據(某些char []沒有數據,其他字段有兩個字段的組合。)

例如如果我這樣設置字段的字段:

user_begin_literal=」T0k0a10」 
user_end_literal=」T0k0b10」 
user_screen_name=」SC00」 

當我看對象VS6:

user_begin_literal=」 T0k0a10」 
user_end_literal=」」 
user_screen_name=」SC00」 

難道我搞砸了我的結構設計?

+0

你是否試過對一些裝飾器進行備份?這可能也是你的問題的一部分。 – 2012-07-16 19:56:56

回答

2

在C中,char只有1個字節,但在C#中是2個字節。

在C#使用sbyte映射到一個C char(均符號的8位的值),和ushort映射到一個C WORD(都是無符號的16位值)。

如果你想爲一個字符串值分配給你的結構的緩衝器中的一個,你應該把它轉換爲ASCII(或者,如果本地代碼可以處理UTF8),然後將字節複製到外地:

void CopyStringToField(string value, sbyte[] field) 
{ 
    int maxLength = field.Length; // or field.Length - 1 if you need room for null terminator 

    byte[] fieldValue = Encoding.ASCII.GetBytes(value); 
    if (fieldValue.Length > maxLength) 
     throw new ArgumentException("string too long for field."); 

    int length = Math.Min(fieldValue.Length, maxLength); 
    Array.Copy(fieldValue, 0, field, 0, length); 

    // zero fill remaining bytes 
    for (int i = length; i < field.Length; i++) 
    { 
     field[i] = 0; 
    } 
} 
+0

是的。在C#中使用'byte'而不是'char'(但是我認爲編組也可以讓你直接指定固定大小的字節字符串)。 – Philipp 2012-07-16 19:46:45

+0

@ Philipp:是的,你可以做'公共固定字節名[24];'這是將'char'數組傳遞給C/C++ DLL的正確方法。 – 2012-07-16 19:54:20

+0

@ 0A0D'fixed'需要使用'unsafe'塊,不是嗎? – 2012-07-16 19:58:30

0

您需要將C#char重構爲byte。此外,您需要將byte數組聲明爲fixed byte,以便將其成功傳遞給您的DLL。

WORD應標記爲ushortC#

目前還不清楚你struct是如何在你的DLL命令,但你可能會確定與設定的順序爲

[StructLayout(LayoutKind.Sequential)]

我們從你個字節的填充任何信息。

另請參閱此question

+0

如何將字符串複製到固定字節上? – user889829 2012-07-16 21:07:36