FormatMessage是WINDOWS提供的一個API,用來擷取調用Windows API時返回的錯誤碼對應的文字資訊,以前在VB下用過,但是在C#中還沒用到,主要是不太瞭解Windows API在C#中調用的一些規則。
最近對VC++ WIN32開發手機程式突然有了極大的興趣,撿起N久不用的C++,當然也就需要頻繁和Windows API打交道了,寫C#寫多了,再用VB又有點不習慣,於是在C#下調用此方法。為什麼不直接在C++中使用呢?嗯,手機調試比較煩,不想寫太多代碼,C#用起來還是要方便快捷得多。
DWORD WINAPI FormatMessage( in DWORD dwFlags, in LPCVOID lpSource, in DWORD dwMessageId, in DWORD dwLanguageId, out LPTSTR lpBuffer, in DWORD nSize, in va_list* Arguments );
const int FORMAT_MESSAGE_FROM_SYSTEM = 0x1000; const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x200; [DllImport("Kernel32.dll")] private static extern int FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out]StringBuilder lpBuffer, uint nSize, IntPtr arguments);
這是FormatMessage API原型和在C#中的定義,其中第2個和最後一個參數因為用不上,定義成IntPtr或int都可以,如果是int,調用時傳入0,IntPtr的話,則傳入IntPtr.Zero。
比較惱火的是lpBuffer這個參數,用來接收返回的文字資訊,在VB中,這種類型的參數都是定義成ByVal String,然後用Space(長度)來初始化(把字串初始化為指定長度的空格),調用時為nSize指定長度值即可。
在C#中我用類似的方法,參數定義為 string lpBuffer,調用時:
uint dwFlags= FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ; string lpBuffer=new string(' ',260); int count=FormatMessage(dwFlags,IntPtr.Zero,1439,0,lpBuffer,260,IntPtr.Zero);
通過傳回值count可以知道函數調用成功,但lpBuffer的值卻沒有更改。
嘗試改成ref和out都不行,ref直接報指標錯誤,out則函數調用失敗。
後來想起C#中對string的處理類似於C,都是把它當作一個常量來處理,修改一個字串的值實際上是拋棄該字串而聲明一個新字串,顯然這裡不能把輸出參數定義為字串。
最後改成StringBuilder,並用[Out]屬性修飾,調用時:
StringBuilder lpBuffer=new StringBuilder(260); //聲明StringBuilder的初始大小 int count=FormatMessage(dwFlags,IntPtr.Zero,1439,0,lpBuffer,260,IntPtr.Zero);
成功!