2014-02-09 43 views
2

我今天在玩Visual Studio,做一些C#来PInvoke从Win32 API的一些东西。那是当我发现这个标题(请在新标签中打开查看原图)为什么C#将所有方法和类型标记为System.Runtime.InteropServices.Charset.Ansi?

Visual Studio

它读取:

尽管公共语言运行库默认为System.Runtime.InteropServices.CharSet .Auto,语言可以覆盖这个默认值。例如,默认情况下,C#将所有方法和类型标记为System.Runtime.InteropServices.CharSet.Ansi。

为什么选择ANSI?从阅读马克Russinovich的Windows内部,我已阅读:

因为许多应用程序处理8位(单字节)ANSI字符串,许多接受字符串参数有两个入口点的Windows 功能:a Unicode(宽16位)版本和ANSI(窄8位)版本。 如果您调用Windows函数的缩小版,有作为输入字符串参数轻微的性能影响正处理系统和输出参数 从Unicode转换返回到 应用程序之前为ANSI之前转换为Unicode。

所以,我在正确的理解是C#的默认时PInvoking非托管代码是接受性能的影响?

编辑:

所以,如果我这样做:

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

而且我们说这里面kernel32.dll中,存在FooAFooW ......请问C#知道哪些入门点使用? Visual Studio中的帮助文本使我认为默认情况下会选择ANSI入口点,但如果可以避免性能影响(尽管可以忽略),我们更喜欢宽版本。

回答

4

Pinvoke不仅用于调用winapi函数。事实上,它是较小的使用,因为.NET Framework已经包装了大量的winapi。它更常见的用于调用传统的自定义C代码。从大多数关于在本网站上进行销售的问题都可以看到。 Charset.Ansi的默认值只是简单地匹配C语言中的默认字符类型,char是一个8位类型。

是的,如果你使用的PInvoke调用然后使用CharSet.Auto展开的WINAPI功能是相当重要的,以避免数据损坏和转换开销。 pinvoke编组完全不知道它是一个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属性可用于禁用该探测。这只会发生一次,所以使用它没有多少意义。

+0

感谢Hans。这让我几乎在那里,但我已经编辑我的问题一点,因为我还没有得到它。让我们忘记95/98/ME,并假设只有NT。 –

+0

右键 - 编辑我的字符串示例。谢谢,非常有帮助。 –

+0

你继续使我的答案无效。请不要这样做。问题中的错误代码没有任何问题。 –

相关问题