4

我正在尝试使用 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);

非常感谢任何提示!谢谢!!!

4

3 回答 3

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 构建。如果这可能发生,它会CharSetDllImportAtribute某种程度上使情况复杂化 - 特别是如果您不使用TestA()/TestW()命名约定进行本机导出。

于 2009-02-28T06:14:46.563 回答
3

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

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

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

这应该适合你

于 2009-05-15T05:42:29.833 回答
0

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

一般来说,我建议不要使用TCHARs(或LPTSRs)。char他们使用宏魔法在(1 字节)和(2 字节)之间切换wchar_t,取决于是否_UNICODE#defined。我更喜欢显式使用chat并使wchar_t代码意图非常清晰。但是,您将需要调用任何使用TCHAR参数的 Win32 API 的 -A 或 -W 形式:例如MessageBoxA(),或MessageBoxW()代替MessageBox()(这是一个检查是否_UNICODE#defined 的宏。

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

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

于 2009-02-28T06:15:35.437 回答