我正在尝试使用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);
真的很感激任何提示!感谢!!!
答案 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。我更喜欢明确使用chat
和wchar_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函数签名示例: