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);
透過回傳值值卻沒有更改。 嘗試改成ref和out都不行,ref直接封包指標錯誤,而out則函數呼叫失敗。
後來想起C#中對string的處理類似於C,都是把它當作一個
常數來處理,修改一個字符串的值實際上是拋棄該字符串而聲明一個新字串,顯然這裡不能把輸出參數定義為字串。 最後改為StringBuilder,並以[Out]
屬性