P / Invoke与[Out] StringBuilder / LPTSTR和多字节字符:乱码文本?

时间:2009-02-28 05:32:56

标签: pinvoke stringbuilder multibyte lptstr


我正在尝试使用P / Invoke从非托管DLL中获取字符串(以及其他内容),但无论我尝试什么,字符串都会出现乱码。

我不是原生的Windows编码器,所以我不确定字符编码位。 DLL设置为使用“多字节字符集”,我无法更改(因为这会破坏其他项目)。我正在尝试添加一个包装函数来从一些现有的类中提取一些数据。有问题的字符串当前以CString的形式存在,我正在尝试将其复制到LPTSTR,希望将其转换为托管的StringBuilder。

这就是我所做的,我认为最接近正确(我已经删除了不相关的部分,显然):

// unmanaged function
DLLEXPORT void Test(LPTSTR result)
{
  // eval->result is a CString
  _tcscpy(result, (LPCTSTR)eval->result);
}

// in managed code
[DllImport("Test.dll", CharSet = CharSet.Auto)]
static extern void Test([Out] StringBuilder result);

// using it in managed code
StringBuilder result = new StringBuilder();
Test(result);
// contents in result garbled at this point

// just for comparison, this unmanaged consumer of the same function works
LPTSTR result = new TCHAR[100];
Test(result);

真的很感激任何提示!感谢!!!

3 个答案:

答案 0 :(得分:3)

一个问题是使用CharSet.Auto

在基于NT的系统上,这将假定本机DLL中的结果参数将使用Unicode。将其更改为CharSet.Ansi,看看您是否获得了更好的结果。

您还需要调整传入的StringBuilder的缓冲区大小:

StringBuilder result = new StringBuilder(100); // problem if more than 100 characters are returned

此外 - 本机C代码使用“TCHAR”类型和宏 - 这意味着它可以为Unicode构建。如果发生这种情况,则会使CharSet中的DllImportAtribute情况稍微复杂化 - 特别是如果您不对本机导出使用TestA() / TestW()命名约定。

答案 1 :(得分:3)

不要使用out参数,因为你没有在c函数中分配

[DllImport("Test.dll", CharSet = CharSet.Auto)]
static extern void Test(StringBuilder result);

StringBuilder result = new StringBuilder(100);
Test(result);

这应该对你有用

答案 2 :(得分:0)

你没有描述你的乱码字符串是什么样的。我怀疑你是在混合一些MBCS字符串和UCS-2字符串(使用2字节wchar_ts)。如果每隔一个字节为0,那么您正在查找UCS-2字符串(并且可能将其误用为MBCS字符串)。如果每个其他字节 0,那么您可能正在查看MBCS字符串(并可能将其误用为Unicode字符串)。

一般情况下,我建议不要使用TCHAR s(或LPTSR s)。他们使用宏魔法在char(1字节)和wchar_t(2字节)之间切换,具体取决于_UNICODE#define d。我更喜欢明确使用chatwchar_t来使代码意图非常明确。但是,您需要调用使用TCHAR参数的任何Win32 API的-A或-W形式:例如MessageBoxA()MessageBoxW()代替MessageBox()(这是一个检查_UNICODE是否为#define d的宏。

然后你应该将CharSet = CharSet.Auto更改为CharSet = CharSet.Ansi(如果调用者和被调用者都使用MBCS)或CharSet = CharSet.Unicode(如果调用者和被调用者都使用UCS-2 Unicode)。但听起来你的DLL使用的是MBCS,而不是Unicode。

pinvoke.net是一个很棒的wiki参考,包含许多Win32 API的P / Invoke函数签名示例: