(一)、Encoding和CharSet
為什麼先提這兩個,實屬問題之源。在C#中包裝DLL的時候,DllImportAttribute當中的選項CharSet著實讓我糊塗了很久,MSDN曰:規定封送字符串應使用何種字符集,其中枚舉值有Ansi和Unicode,我真不知道到底改選哪一個。於是乎, google一番,Encoding這棵救命草被我找到,同時也釋疑了不少疑惑。
首先,字符集不同於編碼,以前總將它們混為一談,CharSet是字符集,Encoding是編碼。字符集是字符的集合,規定這個集合裡有哪些字符,每個字符都有一個整數編號(只是編號不是編碼);而編碼是用來規定字符編號如何與二進制交互,每個“字符”分別用一個字節還是多個字節存儲。啊嗚,原來這樣,那我這裡接觸到的Ansi、Unicode、UTF8等等等等究竟是怎麼回事呢,借此機會,一探究竟!^_^
(二)、Ansi、Unicode、UTF8、bala bala
提到字符集,有ASCII、GB2312、GBK、GB18030、BIG5、JIS等等多種,與此相對應的編碼方式為ASCII、 GB2312、GBK、GB18030、BIG5、JIS(囧,難怪糊塗如我般的人如此多),但是Unicode字符集卻有多種編碼方式:UTF-8、 UTF-7、UTF-16、 UnicodeLittle、UnicodeBig。原來如此,字符集與編碼原來是這個樣子。ˇˍˇ|||
那Ansi又是什麼呢?
Ansi:系統編碼的發展經歷了三個階段,ASCIIàAnsi(不同國家語言本地化)àUnicode(標准化),原來Ansi編碼也好,Ansi字符集也好,都是指本地化的東西,在簡體中文系統下,ANSI 編碼代表 GB2312 編碼,Windows下自帶的記事本程序,默認的就是ANSI編碼。呵呵,那偶就去試試吧,輸入“anhui合肥”(不含引號),保存編碼方式選 “ANSI”,查看,哦,9個字節,明白了,原來Ansi編碼保留了對ASCII編碼的兼容,當遇到ASCII字符時,采用單字節存儲,當遇到非 ASCII編碼時,采用雙字節表示(GB2312編碼)。
(三)、DllImportAttribute中的CharSet枚舉值選擇
對字符集和編碼的概念清楚了以後,終於可以研究C#中調用非托管的DLL的方法咯。從托管應用程序去調用非托管代碼,如果 CharSet=Unicode,則DLL中的接口函數將出現的所有字符串(包括參數和返回值)視為Unicode字符集,Ansi一樣的道理。真不錯,了解到這裡總算有點撥雲見日的感覺了!O(∩_∩)O
好像目前需要了解的知識點都差不多了,終於可以開始來解決我的問題了, (*^__^*)。回顧整理一下,第一:我需要調用非托管代碼,第二:非托管代碼只處理UTF8編碼格式的字符,第三,萬惡的中文亂碼,接口函數簽名中,無論參數還是返回值,接收到或是發送出的字符串都含有中文。呵呵,看來上面的知識應該可以解決這個問題了:首先接收字符串,因為接收到的是UTF8編碼格式,CharSet屬性肯定要設置成Unicode了,接收後要正確顯示中文,在當前系統中,需要將編碼方式轉換成GB2312,即 Encoding.Default;另外關於發送字符數組,因為無論是C#中默認的Unicode編碼方式,還是DLL處理時規定的UTF8編碼方式,都是Unicode字符集的一種編碼方式,所以CharSet也要設置成Unicode,只是要在發送前需要將字符數組轉換一下編碼方式。以下附帶兩個簡單的函數實現。
以下是代碼片段:
// 轉換接收到的字符串
public string UTF8ToUnicode(string recvStr)
{
byte[] tempStr = Encoding.UTF8.GetBytes(recvNotify);
byte[] tempDef = Encoding.Convert(Encoding.UTF8, Encoding.Default, tempStr);
string msgBody = Encoding.Default.GetString(tempDef);
return msgBody;
}
// 轉換要發送的字符數組
public byte[] UnicodeToUTF8(string sendStr)
{
string tempStr = Encoding.UTF8.GetString(sendStr);
byte[] msgBody = Encoding.UTF8.GetBytes(tempUTF8);
return msgBody;
}
總結一下,本文因項目完成的需要,難免存在局限性,只討論了兩種情況:Unicode編碼的字符串轉UTF8格式的字符數組,以及UTF8格式的字符串轉Unicode格式的字符串,上面兩個方法均通過測試,至此總算解決了中文亂碼的問題。平台調用的知識點很多,只有真正掌握必需的基礎知識和平台調用的原理,才能做到活學活用。