首先如果您看下面代码有些费解的话,推荐先阅读以下MSDN上关于平台调用的指定字符集文章:http://msdn.microsoft.com/zh-cn/library/7b93s42f.aspx
学习.NET(C#)的平台调用和对象封送,你会发现其实同样的系统API函数的平台调用定义可以有多种形式的,本文就拿WinAPI的MessageBox开涮。
首先通过DllImportAttribute.CharSet来自动指定名称探索(根据DllImportAttribute.ExactSpelling)和字符串封送,比如,这三个函数的平台调用最常用定义(来自上面MSDN的页面)
第一个是MessageBox的ANSI函数(MessageBoxA),而DllImportAttribute得CharSet字段默认值就是CharSet.Ansi枚举值。
第二个是MessageBox的Unicode函数(MessageBoxW)。
最后一个MessageBox使用自动觉察字符集编码,NT系统会调用MessageBoxW(Unicode),而98会调用MessageBoxA(ANSI)。
[DllImport("user32.dll")]
public static extern int MessageBoxA(int hWnd, String text, String caption, uint type);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBoxW(int hWnd, String text, String caption, uint type);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(int hWnd, String text, String caption, uint type);
//98调用MessageBoxA, NT调用MessageBoxW
接下来把CharSet全部去掉(值默认是CharSet.Ansi)。
然后为了使Unicode的MessageBox工作,手动加入MarshalAs特性把字符串封送成UnmanagedType.LPWStr(Unicode字符串)。
而最后的MessageBox实际上只会调用MessageBoxA(ANSI的MessageBox函数),因为DllImportAttribute.ExactSpelling会根据CharSet去搜索,而这里CharSet是Ansi(后面的Unicode也类似)。
//默认都是CharSet.Ansi
[DllImport("user32.dll")]
public static extern int MessageBoxA(int hWnd, String text, String caption, uint type);
//手动通过MarshalAs特性把字符串以Unicode形式封送
[DllImport("user32.dll")]
public static extern int MessageBoxW(int hWnd,
[MarshalAs(UnmanagedType.LPWStr)] String text,
[MarshalAs(UnmanagedType.LPWStr)]String caption,
uint type);
[DllImport("user32.dll")]
public static extern int MessageBox(int hWnd, String text, String caption, uint type);
//调用MessageBoxA
如果把CharSet全部改成Unicode,结果则是和上面相反。需要用MarshalAs特性特殊照顾一下MessageBoxA,而最后的MessageBox也只会调用MessageBoxW函数的。
//手动通过MarshalAs特性把字符串以ANSI形式封送
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBoxA(int hWnd,
[MarshalAs(UnmanagedType.LPStr)]String text,
[MarshalAs(UnmanagedType.LPStr)]String caption,
uint type);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBoxW(int hWnd, String text, String caption, uint type);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(int hWnd, String text, String caption, uint type);
//调用MessageBoxW
最后如果CharSet全部是Auto,那么为了确保所有函数能正常工作,必须为MessageBox的ANSI和Unicode编码都添加MarshalAs,因为此时字符串的封送形式是不定的,当然如果你确定程序会在某个特定的编码环境中运行,那么其对应的定义可以省略。最后MessageBox的TCHAR定义和最上面的一样,即98调用MessageBoxA, NT调用MessageBoxW。
//MarshalAs可以省略如果是98系统
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBoxA(int hWnd,
[MarshalAs(UnmanagedType.LPStr)]String text,
[MarshalAs(UnmanagedType.LPStr)]String caption,
uint type);
//MarshalAs可以省略如果是NT系统
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBoxW(int hWnd,
[MarshalAs(UnmanagedType.LPWStr)]String text,
[MarshalAs(UnmanagedType.LPWStr)]String caption, uint type);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(int hWnd, String text, String caption, uint type);
//98调用MessageBoxA, NT调用MessageBoxW