首先如果您看下面代碼有些費解的話,推薦先閱讀以下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