从 C# 到 C++ 的编组

Posted

技术标签:

【中文标题】从 C# 到 C++ 的编组【英文标题】:Marshaling from C# to C++ 【发布时间】:2009-07-31 14:02:47 【问题描述】:

我必须将 C# 应用程序中的 InParameter 传递给 VC++ DLL 中的导出函数。该函数接受 2 个参数:

int func_name (FILE* fp, BYTE& by);

fp 是 In,by 是 Out 参数。

我正在考虑对FILE* 使用IntPtr 进行编组,对BYTE 使用字节。这是正确的吗?如果我用 C# 编写以下内容

[DllImport("name_of_project.dll", CharSet = CharSet.Ansi)] public static extern int      func_name(IntPtr FilePointer, [MarshalAs(UnmanagedType.BYTE&)] byte by);

它会起作用吗?我认为它会给编组语句中的“&”符号带来错误。如何通过引用传递out参数?

非常感谢您的帮助。

谢谢,维伦

【问题讨论】:

【参考方案1】:

不,这不会像写的那样工作。

    在 C# 程序中,您将在哪里获得 FILE*?除非您的非托管 dll 中的某些其他函数为您提供此指针,否则您就有麻烦了。顺便说一句,我强烈建议将此FILE* 包装在SafeHandle 中;那么您的 p/invoke 签名将使用 SafeFilePointer 而不是裸露的 IntPtr。 您要编组多少字节?如果只有一个,请将 out byte by 放入托管签名中(不需要属性)。 您不需要指定字符集,因为您没有编组任何chars 或strings。

【讨论】:

我只编组 1 个字节。那么,您能否建议对 FILE* 进行编组的声明。我是 .NET 编程的新手,不知道用 SafeHandle 包装 FILE*。谢谢,维伦 我再重复一遍——你从哪里得到那个文件*?你需要打开一个文件,还是什么? 我在 C# 应用程序中导入的 C++ DLL 中导出了 int func_name(FILE* fp, BYTE& by)。在我的 C# 应用程序中,我打算打开一个二进制文件并将句柄传递给导入的函数。我还不确定如何在 C# 中获取句柄。我假设我们可以在 C# 中打开一个二进制文件并获取它的句柄,就像我们在 C++ 中使用 File* fp = _tfopen(path, mode) 一样。 你不能那样做。您的非托管函数想要的FILE* 属于与您的非托管dll 链接的C++ 运行时库,它不一定与链接到CLR 的C++ 运行时库相同。无论如何,.NET 内部并不使用FILE*,它在本机HANDLEs 之上构建I/O。您是否可以控制非托管 dll 的源? 我可以访问它,但它是只读访问。我不允许对其进行修改,并且无论如何都不应修改它,因为它是在实时(生产)系统上。【参考方案2】:

如果本机函数需要引用,您可以使用它 ref/out 对其进行编组。因此,在您的情况下,您可以使用: out byte by。我已经检查过了,它对我有用。

再次编辑:我刚想到,我给你的建议是行不通的,因为 FILE 是一个结构,你不能那么容易地从 c# 编组。因此,从头开始,如果您将 SafeFileHandle 威胁为非托管库中的 HANDLE 对象,则可以使用此方法。如果您无法修改此 dll,一种解决方案是创建自己的包装器以使用 stdio 创建文件,它可能如下所示:

    创建公开 fopen、fclose 等功能的库。Fe。 (在 C++ 中):
    FILE* CreateFile(char* name);
    Marhall 这个函数,在这个例子中你将使用 (c#):
    public static extern IntPtr CreateMyFile([MarshalAs(UnmanagedType.LPStr)] 字符串名称);
    将所有 FILE* 参数编组到 IntPtr,然后将函数 CreateMyFile 的结果作为 FILE* 传递。

【讨论】:

感谢 Ravadre。但我仍然坚持使用 FILE * 类型编组。您能否提出一个相同的声明:我应该使用 4 字节无符号整数吗?我现在没有要测试的代码。我很快就会得到它,并会尽快在这里更新。现在我正在考虑以下内容: DllImport("name_of_project.dll", CharSet = CharSet.Ansi)] public static extern int func_name(U4 FilePointer, out byte by); Uf,对所有这些编辑感到抱歉,我已经检查过这个解决方案,它工作得很好。 一点:确保两个非托管 dll 链接到相同的 C++ 运行时 dll,或相同版本的静态 C++ 运行时库。

以上是关于从 C# 到 C++ 的编组的主要内容,如果未能解决你的问题,请参考以下文章

将字符串从 c# 编组到 c++

将非 Blittable 结构从 C# 编组到 C++

从 C++ 编组到 C# 时 CLR 崩溃

如何将指向 char[256] 数组的指针从 C++ 编组到 C#

将包含 int 和 int[] 的结构从 C# 编组到 C++

将安全数组的安全数组从 C++ 中的 VARIANT 编组到 C#