Can I use C headers for protocol in C#

7
我正在开发一个新的C#程序,遇到了技术问题。在这个项目中,我需要在TCP/IP网络上与另一个非Windows系统进行通信。另一个系统上的所有软件都是用C编写的,未来的任何开发也将采用C/C++。协议都是由另一位工程师用C编写的,并且使用C typedef struct定义了所有变量并使用memcpy提取/放置数据包,这对于C来说非常好用。我的所有协议都以C头文件的形式提供,其中包含所有typedef和struct,并且未来对协议所做的任何更改都将以同样的方式完成。
我的问题是,是否有办法在C#中使用它们?
我尝试将它们编译为DLL库中的类,但不起作用,因为C#只能使用托管的C DLL。如果我尝试将其编译为托管的C类,由于协议中有许多数组,并且由于C代码必须符合一堆规格,许多变量已被typedef。现在,我可以在C#中重新做所有结构,但那将花费很多时间,而且每次更改或添加协议时都必须重新做。更不用说每次这样做时出现错误的风险。
在我的C项目中,其他工程师只需向我提供更新后的头文件即可。
那么,有没有办法直接在C#中使用这些头文件,或者每次更新协议时都可以进行自动转换?实际上,我需要使用这个头文件从TCP/IP连接中提取数据流中的数据(无法使用memcpy)。
使用C#的原因是因为我在WPF中使用了很多图形,而Visual C++不支持WPF。
非常感谢您提供任何帮助或建议!

2
Protobuf可能会证明其有用,但可能需要重写现有代码。 - CodeCaster
很遗憾他们不做C#... - gerharddvs
他们在这里:http://code.google.com/p/protobuf-net/。 - CodeCaster
3个回答

1

我曾经不得不在C#中使用C头文件来获取通过TCP/IP发送的结构体定义。我们采用的方法是通过T4文本模板解析头文件。虽然这是一项相当繁琐的任务,但你必须编写足够好的C解析器以生成.cs文件,因此会有很多字符串混乱。对我们来说,这是一个足够好的解决方案,所以它可能也能帮助到你。

在这里查看T4:http://msdn.microsoft.com/en-us/library/bb126445.aspx


如果我正确理解了这个 T4 方法,那么我可以做的就是编写一些代码/函数,将头文件中的结构转换为等效的类/结构体,并将数据包从 TCP/IP 数据流中转储到 cs 文件中。 - gerharddvs
是的,您可以使用它生成一个包含与C头文件中定义相同结构定义的C#代码文件。然后,您可以使用任何序列化方式将该结构发送到TCP流中。在我的情况下,我只在客户端上工作,因此无法控制协议。就像你所说的那样,它会将二进制数据转储到流中。但是,如果您对协议有任何控制权,我建议使用另一种格式,例如XML、YAML甚至JSON。这样,如果需要,您将有一个解耦服务器和客户端的选项。 - Honza Brestan
我可能经常需要进行这种转换,因为我的主要编程语言实际上是C/C++,而且我的大多数项目都是用这些语言编写的。只有在需要使用花哨的GUI时才会使用C#。变量typedef与MIL规范和安全标准有关,这是公司政策,所以我无法改变它。因此,我想制作一种转换器来进行转换,然后将来可以使用它。更改头文件是不可能的,因为它们仍然必须在原始的C编译器上工作... - gerharddvs

1

不是一个真正的答案,更像是一种可能的好解决方案:

创建一个包含现在在C头文件中的信息的定义文件。然后使用它来生成.h头文件和适当的C#源代码。

如果数据相对简单,则可以使用简单的键值文件格式,甚至是csv文件。但如果它更复杂,则最好使用XML,这样在编程上更容易解析。

如果有抵制使用独立于语言的定义文件的情况,那么您可以尝试让.c头文件遵循一些字符串格式规则,以便您可以简单地解析它并从中生成C#代码(只需确保编写.h的人理解,它不再是C,实际上是您自己的类似C的定义语言,并且任何额外的C内容都必须放到另一个文件中)。


这让事情变得非常复杂的是几乎每种变量类型都被typedef了(例如:unsigned char是UINT8_t),然后有结构体内部的typedef,而且其中一些结构体在数组中,所以它变得混乱不堪...(你可以将一个结构体扩展成10个其他数组和结构体)。 - gerharddvs
@gerharddvs 在这种情况下,我强烈建议您将定义移入XML文件,并从中生成任何需要的特定语言文件...也就是说,“要求”(在您的情况下可能意味着什么),您可以获得协议定义的相关部分,以语言无关、易于机器解析的格式(即XML)。 - hyde
我可能经常需要进行这种转换,因为我的主要编程语言实际上是C/C++,而且我的大多数项目都是用这些语言编写的。只有在需要使用花哨的GUI时才会使用C#。变量typedef与MIL规范和安全标准有关,这是公司政策,所以我无法改变它。因此,我想制作一种转换器来进行转换,然后将来可以使用它。更改头文件是不可能的,因为它们仍然必须在原始的C编译器上工作... - gerharddvs

0

在C#中您不可以使用头文件,也无法使用头文件。您需要将其编译成dll文件,并从C#引用。

在C文件中,您需要定义#define DLLAPI __declspec(dllexport),并像下面的示例一样定义方法:DLLAPI *返回值数据类型 函数名称*。然后在C#中调用它:

[DllImport(@"*dll-path*")]
        public static extern *return-value-datatype function-name*

如果需要,您可以对以下数据类型进行编组

[DllImport(@"*dll-path*")]
        public static extern void InitParam([MarshalAs(UnmanagedType.LPWStr)] string inputFile,
            [MarshalAs(UnmanagedType.LPWStr)] string outputFile,
            [MarshalAs(UnmanagedType.LPWStr)] string templateFile,
            [MarshalAs(UnmanagedType.LPWStr)] string userName,
            [MarshalAs(UnmanagedType.LPWStr)] string manifestFilePath,
            [MarshalAs(UnmanagedType.LPWStr)] string usersRightList);

        [DllImport(@"*dll-path*")]
        public static extern Int32 ProtectDocument(
            [MarshalAs(UnmanagedType.LPStr)]string validToDate);

        [DllImport(@"*dll-path*")]
        public static extern void DebugGeneratedFiles(
            [MarshalAs(UnmanagedType.LPWStr)] string singedIssuenceLicenseFilePath,
            [MarshalAs(UnmanagedType.LPWStr)] string encryptedContentOutputFilePath);

我知道在C#中不能使用头文件,这就是问题所在...你的方法看起来可能行得通,但每次协议修改后我都必须重新做一遍,而这正是我想要避免的... - gerharddvs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接