在不同的返回类型上将字符串从 C# 传递到 C++ DLL 不同的文本编码

Posted

技术标签:

【中文标题】在不同的返回类型上将字符串从 C# 传递到 C++ DLL 不同的文本编码【英文标题】:Passing String from C# to C++ DLL different Text Encoding on different return Types 【发布时间】:2018-08-30 06:46:02 【问题描述】:

我希望有人能解释一下到底有什么区别:

在我的 C# 程序中,我想将字符串传递给 C++ 方法。 我的 C# 代码如下所示:

    [DllImport("Test.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
    public static extern String DoIt(String filename);

我的 C++ DLL 内部如下所示:

__declspec(dllexport) CString DoIt(char* szFilename)

....

如果我传递字符串(如:C:\temp\my.txt),它会变成格式错误 =>“Ôœ&°8é-”。

现在是我无法理解的令人困惑的部分。如果我将返回类型从 CString 更改为 char* 一切都很好。

__declspec( dllexport ) char* DoIt(char* filename)

为什么会这样? C# 中的 CharSet 已设置为 Ansi 以将字符串编组为正确的类型。我无法弄清楚返回类型和我传递的字符串之间的连接在哪里。

如果您需要更多信息,请告诉我。

【问题讨论】:

哪里有问题?输出窗口、日志文件、监视窗口? 我在调试 DLL 时发现了异常。当我将鼠标悬停在参数“文件名”上或使用 AfxMessageBox() 时,它显示为格式错误。 CString 是一个 C++ 类,pinvoke 根本不支持 C++ 特定类型。 char* 是一种解决方法,但仍然存在内存管理问题。考虑返回 BSTR。您需要 C++ 代码中的 SysAllocString() 和 [return: MarshalAs(UnmanagedType.BStr)] 让 CLR 知道它。 嘿汉斯,我会试一试并测试它。但为什么它会影响争论呢? 函数按值返回 CString 对象。这要求调用者为该值保留空间,它传递一个指向该空间的指针。当从 C# 进行调用时,这些都不会发生,指针丢失并且也会抛出参数。 【参考方案1】:

您的代码的两个版本都是错误的。您当然不能将 CString 作为互操作类型传递。您可以将简单类型用于互操作,而不是 C++ 类。

使用char* 时的错误更加微妙。在这种情况下,有两个问题。

首先,在 C# 端使用 string 返回类型,pinvoke marshaller 假定返回的字符串是用CoTaskMemAlloc 分配的,并在复制后调用CoTaskMemFree 将其释放。

其次,虽然我们看不到它,但您的 C++ 代码几乎肯定会返回指向 C++ 函数中的局部变量所拥有的缓冲区的指针。显然,当函数返回时,这个局部变量超出了范围,因此指针变得无效。

一些选项:

    让调用者找到字符串缓冲区并让被调用者填充它。 使用CoTaskMemAlloc分配返回的char*,从而满足C#代码的期望。 使用 pinvoke marshaller 可以理解的 COM BSTR 类型。

【讨论】:

简而言之,由于在 C# 中错误地将字符串用作返回类型,pinvoke marshaller 导致内存中的参数格式错误?我主要不关心返回类型,但更关心我从 C# 传递到 C++ 的参数。 没有。格式错误的文本来自使用 CString 与 C# 端的 string 不匹配 那么 C++ 中的 CString 和 C# 中的 string 导致从 C# 到 C++ 的传递字符串格式错误?即使参数类型仍然相同? Pinvoke 编组器根本无法编组像 CString 这样的 C++ 类型。这是我回答的第一段。不知道你说的“参数类型还是一样”是什么意思 带有参数的意思是filename 参数我给方法做某事。从一开始,类型仍然是 char*。但这就是畸形的价值。

以上是关于在不同的返回类型上将字符串从 C# 传递到 C++ DLL 不同的文本编码的主要内容,如果未能解决你的问题,请参考以下文章

将字节数组从 c++ 传递到 c# 程序集都有哪些不同的方法?

将字符串值从 C# 返回到 c++

如何将结构数组从 c++ 传递到 c#?

如何将对象列表从 C++ 传递到 C#?

如何安全地将字符串引用从 c# 传递到 c++?

如何使用 DLLImport 将字符串从 C# 传递到 C++(以及从 C++ 到 C#)?