2012-07-16 103 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