15.5 Retrieve Unmanaged Error Information


Problem

You need to retrieve error information (either an error code or a text message) explaining why a Win32 API call failed.

Solution

On the declaration of the unmanaged method, set the SetLastError field of the DllImportAttribute to true . If an error occurs when you execute the method, call the static Marshal.GetLastWin32Error method to retrieve the error code. To get a text description for a specific error code, use the unmanaged FormatMessage function.

Discussion

You can't retrieve error information directly using the unmanaged GetLastError function. The problem is that the error code returned by GetLastError might not reflect the error caused by the unmanaged function you are using. Instead, it might be set by other .NET Framework classes or the CLR. Instead, you can retrieve the error information safely using the static Marshal.GetLastWin32Error method. This method should be called immediately after the unmanaged call, and it will return the error information only once. (Subsequent calls to GetLastWin32Error will simply return the error code 127.) In addition, you must specifically set the SetLastError field of the DllImportAttribute to true to indicate that errors from this function should be cached.

 [DllImport("user32.dll", SetLastError=true)] 

You can extract additional information from the Win32 error code using the unmanaged FormatMessage function from the Kernel32.dll file.

The following console application attempts to show a message box, but submits an invalid window handle. The error information is retrieved with Marshal.GetLastWin32Error , and the corresponding text information is retrieved using FormatMessage .

 using System; using System.Runtime.InteropServices; public class TestError {     [DllImport("kernel32.dll")]     private unsafe static extern int FormatMessage(int dwFlags, int lpSource,        int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize,       int Arguments);     [DllImport("user32.dll", SetLastError=true)]     public static extern int MessageBox(int hWnd, string pText,       string pCaption, int uType);     private static void Main() {         int badWindowHandle = 453;         MessageBox(badWindowHandle, "Message", "Caption", 0);         int errorCode = Marshal.GetLastWin32Error();         Console.WriteLine(errorCode);         Console.WriteLine(GetErrorMessage(errorCode));         Console.ReadLine();     }     // GetErrorMessage formats and returns an error message     // corresponding to the input errorCode.     public static string GetErrorMessage(int errorCode) {         int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;         int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;         int FORMAT_MESSAGE_FROM_SYSTEM  = 0x00001000;         int messageSize = 255;         string lpMsgBuf = "";         int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER            FORMAT_MESSAGE_FROM_SYSTEM  FORMAT_MESSAGE_IGNORE_INSERTS;                 int retVal = FormatMessage(dwFlags, 0, errorCode, 0,           ref lpMsgBuf, messageSize, 0);         if (0 == retVal) {               return null;         } else {             return lpMsgBuf;         }     } } 

Here's the output generated by the preceding program:

 1400 Invalid window handle. 



C# Programmer[ap]s Cookbook
C# Programmer[ap]s Cookbook
ISBN: 735619301
EAN: N/A
Year: 2006
Pages: 266

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net