【问题标题】:Why would C# mark all methods and types as System.Runtime.InteropServices.Charset.Ansi?为什么 C# 会将所有方法和类型标记为 System.Runtime.InteropServices.Charset.Ansi?
【发布时间】:2014-03-06 09:27:18
【问题描述】:

我今天在玩 Visual Studio,做一些 C# 来 PInvoke 来自 Win32 API 的一些东西。那是我注意到这个标题的时候(请在新标签中打开以查看完整尺寸)

上面写着:

虽然公共语言运行时默认值为 System.Runtime.InteropServices.CharSet.Auto,但语言可能会覆盖此默认值。例如,默认情况下,C# 将所有方法和类型标记为 System.Runtime.InteropServices.CharSet.Ansi。

为什么选择 ANSI?通过阅读 Mark Russinovich 的 Windows Internals, 我已经阅读:

由于许多应用程序处理 8 位(单字节)ANSI 字符串,许多 Windows 接受字符串参数的函数有两个入口点:Unicode(宽,16 位)版本和 ANSI(窄,8 位)版本。 如果调用窄版本的 Windows 函数,则会对性能产生轻微影响,因为输入字符串参数在处理之前会转换为 Unicode 由系统和输出参数在返回之前从 Unicode 转换为 ANSI 应用程序。

那么,我是否正确理解 C# 在 PInvoking 非托管代码时的默认设置是接受这种性能影响?

编辑:

所以如果我这样做:

[DllImport("kernel32.dll", Charset = CharSet.Auto]
public static extern bool Foo(IntPtr hHandle);

假设在 kernel32.dll 内部,存在一个 FooA 和一个 FooW ... C# 如何知道要使用哪个入口点? Visual Studio 中的帮助文本让我认为它会默认选择 ANSI 入口点,但如果可以避免性能影响(但可以忽略不计),我们更喜欢宽版本。

【问题讨论】:

    标签: c# windows winapi


    【解决方案1】:

    Pinvoke 不仅用于调用 winapi 函数。事实上,它的用途较少,因为 .NET Framework 已经封装了一大块 winapi。更常见的是它用于调用遗留的自定义 C 代码。从本网站上有关 pinvoke 的大多数问题中可以看出。 Charset.Ansi 的默认值只是简单匹配 C 语言中的默认字符类型,char 是 8 位类型。

    是的,如果您确实使用 pinvoke 调用未包装的 winapi 函数,那么使用 CharSet.Auto 对于避免数据损坏和转换开销非常重要。 pinvoke marshaller 完全不知道它是一个 winapi 函数,包含这些函数的 Windows DLL 与自定义 DLL 没有区别。请注意,Auto 本身不久前就不再相关了,您的代码将在今天启动 Windows 98 或 ME 的机器上运行的可能性微乎其微。


    请注意,您的 pinvoke 声明不是很有意义,而且通常是不明智的。只有采用字符串参数或指向包含字符串的结构的指针的 winapi 函数才需要 CharSet 属性。而且您几乎总是将参数实际声明为 String、StringBuffer 或结构类型,以允许 pinvoke 编组器正确处理。如果您使用 IntPtr,那么您的负担就是生成正确的字符串,您必须明确使用 Marshal.StringToHGlobalAnsi/Auto/Uni。或者 Marshal.StructureToPtr() 与适当的 [StructLayout] 如果它是一个结构,它也有一个 CharSet 属性。

    pinvoke marshaller 具有winapi 函数的内置知识,它们的名称后有额外的A 或W。它只是尝试首先找到没有额外字母的函数,然后尝试 A 或 W 版本。 EntryPoint 属性可用于禁用该探测。这只会发生一次,所以使用它没有多大意义。

    【讨论】:

    • 谢谢汉斯。这让我几乎到了那里,但我已经稍微编辑了我的问题,因为我还没有完全理解它。让我们忘记 95/98/ME,只假设 NT。
    • 对 - 编辑了我的字符串示例。谢谢,很有帮助。
    • 你一直让我的回答无效。请不要那样做。问题中的错误代码没有任何问题。
    猜你喜欢
    • 2012-02-24
    • 1970-01-01
    • 2015-05-10
    • 2020-02-28
    • 2018-01-22
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    • 2016-07-04
    相关资源
    最近更新 更多