5

我对以下测试问题的可能答案有一些疑问:

问题:您编写以下代码段以使用平台调用从 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不工作?

4

3 回答 3

12
 string personName = "N?el";

这个字符串被这个问题所问的确切问题弄乱了。毫无疑问,它在原版中看起来像这样:

 string personName = "Nöel";

ö 往往是个问题,它的字符代码不在 ASCII 字符集中,并且可能不受默认系统代码页的支持。当您 P/Invoke MessageBox 的 ANSI 版本(即 MessageBoxA)时使用的是什么。真正的函数是 MessageBoxW,它采用 UTF-16 编码的 Unicode 字符串。

MessageBoxA 是旧版本的 Windows 中使用的遗留函数,早在过去程序仍然使用 8 位字符串的时候。它并没有完全消失,许多 C 和 C++ 程序仍然倾向于使用 8 位编码。MessageBoxA 是通过将 8 位编码字符串转换为 Unicode,然后调用 MessageBoxW 来实现的。如果你一开始就有一个 Unicode 字符串,这会很慢而且有损。

所以给4个版本打分:

A:使用MessageBoxA+8位编码,有风险。
B:使用 MessageBoxA + Unicode,失败。
C:使用 MessageBoxW + Unicode,不错。
D:使用 MessageBoxA + Unicode,失败。

于 2013-07-23T11:15:00.350 回答
4

CharSet.Ansi除非另有说明,否则告诉编组器以 ANSI 编组。除非另有说明,否则同样CharSet.Unicode是编组为 UTF-16 的指令。

由于选项 B 和 D 确实另有指示,因此CharSet参数被覆盖,因此选项 B 和 D 实际上是等价的。它们都是不正确的,因为您要求指定MessageBoxA需要 ANSI 文本的函数。

剩下 A 和 C。选项 A 调用函数的 ANSI 变体,MessageBoxA选项 C 调用 Unicode 变体MessageBoxW. 在幕后,p/invoke 编组器使用CharSet参数的值选择适当的入口点。

现在,您可以使用 A 或 C,但不同之处在于使用选项 A 您将传递 ANSI 编码的文本。如果您传递的文本包含无法以 ANSI 编码的字符,则会丢失信息。这就是为什么首选 C 的原因。它将始终收到与 .net 调用代码中存在的完全相同的文本。

于 2013-07-23T11:04:29.033 回答
0

我怀疑答案在personName.

我认为它没有正确复制粘贴到您的问题中。

string personName = "N?el";

注意?字符。我认为这表明原始字符串在那里有一个非 ANSI 字符。如果这是真的,并且您可以正确地看到,那么它表明您必须使用 Unicode 而不是 ANSI(因此答案必须是C)。

在任何情况下,Unicode 可以使用比 ANSI 更多的格式,因此它是更好的默认选择。

于 2013-07-23T10:55:14.823 回答