我对下面的测试问题的可能答案有一些疑问:
问题:您编写以下代码段以使用平台调用从Win32应用程序编程接口(API)调用函数。
string personName = "N?el";
string msg = "Welcome" + personName + "to club"!";
bool rc = User32API.MessageBox(0, msg, personName, 0);
您需要定义一个最能编组字符串数据的方法原型。你应该使用哪个代码段?
// A.
[DllImport("user32", CharSet = CharSet.Ansi)]
public static extern bool MessageBox(int hWnd, string text, string caption, uint type);
}
// B.
[DllImport("user32", EntryPoint = "MessageBoxA", CharSet = CharSet.Ansi)]
public static extern bool MessageBox(int hWnd,
[MarshalAs(UnmanagedType.LPWStr)]string text,
[MarshalAs(UnmanagedType.LPWStr)]string caption, uint type);
}
// C. - Correct answer
[DllImport("user32", CharSet = CharSet.Unicode)]
public static extern bool MessageBox(int hWnd, string text, string caption, uint type);
}
// D.
[DllImport("user32", EntryPoint = "MessageBoxA", CharSet = CharSet.Unicode)]
public static extern bool MessageBox(int hWnd,
[MarshalAs(UnmanagedType.LPWStr)]string text,
[MarshalAs(UnmanagedType.LPWStr)]string caption,
uint type);
}
为什么正确答案是C?不可能它也是A?唯一的区别是它将是ANSI而不是Unicode。
据我所知,它不能是D,因为我们选择Unicode作为字符集,然后将ANSI函数作为入口点。
B为什么不工作?
答案 0 :(得分:10)
string personName = "N?el";
这个字符串因此问题所引发的确切问题而出现乱码。毫无疑问,它原来看起来像这样:
string personName = "Nöel";
ö往往是个问题,它的字符代码不是ASCII字符集,默认系统代码页不支持 。这是当你pinvoke ANSI版本的MessageBox,也就是MessageBoxA时使用的。真正的函数是MessageBoxW,它采用utf-16编码的Unicode字符串。
MessageBoxA是旧版本Windows中使用的遗留函数,早在程序仍然使用8位字符串时。它还没有完全消失,许多C和C ++程序仍然倾向于使用8位编码。 MessagBoxA通过将8位编码字符串转换为Unicode然后调用MessageBoxW来实现。如果您首先使用Unicode字符串,那么速度很快且有损耗。
评价4个版本:
答:使用MessageBoxA + 8位编码,风险很大
B:使用MessageBoxA + Unicode,失败。
C:使用MessageBoxW + Unicode,好用
D:使用MessageBoxA + Unicode,失败。
答案 1 :(得分:2)
CharSet.Ansi
告诉编组人员将编组为ANSI。同样,CharSet.Unicode
是指示以UTF-16编组的指令,除非另有说明。
由于选项B和D确实以其他方式指示,因此覆盖CharSet
参数,因此选项B和D实际上是等效的。它们都是不正确的,因为您要求名为MessageBoxA
的函数需要ANSI文本。
留下A和C.选项A调用函数MessageBoxA
的ANSI变体,选项C调用Unicode变体MessageBoxW
。在幕后,p / invoke marshaller使用CharSet
参数的值选择适当的入口点。
现在,您可以使用A或C,但区别在于选项A,您将传递ANSI编码文本。如果您传递的文本包含无法用ANSI编码的字符,则会丢失信息。这就是C首选的原因。它将始终接收.net调用代码中存在的完全相同的文本。
答案 2 :(得分:0)
我怀疑答案在personName
。
我认为它没有正确地复制粘贴到您的问题中。
string personName = "N?el";
请注意?
字符。我认为这表明原始字符串在那里有一个非ANSI字符。如果这是真的,你可以正确地看到它,那么它表明你必须使用Unicode而不是ANSI(因此答案必须是C
)。
在任何情况下,Unicode都可以使用比ANSI更多的格式,因此它是更好的默认选择。