private static string GetMessageFromModule( string modulePath, int errorNumber, CultureInfo culture) { const uint LOAD_LIBRARY_AS_DATAFILE = 2; const int RT_RCDATA = 10; IntPtr msgModule = NativeMethods.LoadLibraryEx( modulePath, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); if (msgModule == IntPtr.Zero) { return(null); } try { // On pre-Vista systems, the messages are stored as RCDATA resources. int lcid = 0; IntPtr resourceInfo = NativeMethods.FindResourceEx( msgModule, new IntPtr(RT_RCDATA), new IntPtr(errorNumber), (ushort)lcid); if (resourceInfo != IntPtr.Zero) { IntPtr resourceData = NativeMethods.LoadResource( msgModule, resourceInfo); IntPtr resourcePtr = NativeMethods.LockResource(resourceData); if (lcid == 0) { string msg = Marshal.PtrToStringAnsi(resourcePtr); return(msg); } else { int len = 0; while (Marshal.ReadByte(resourcePtr, len) != 0) { len++; } byte[] msgBytes = new byte[len + 1]; Marshal.Copy(resourcePtr, msgBytes, 0, msgBytes.Length); Encoding encoding = Encoding.ASCII; string msg = encoding.GetString(msgBytes); return(msg); } } else { // On Vista (and above?), the messages are stored in the module message table. // They're actually in MUI files, and the redirection happens automatically here. const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800; const uint MESSAGE_OFFSET = 20000; // Not documented, but observed on Vista StringBuilder buf = new StringBuilder(1024); uint formatCount = NativeMethods.FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, msgModule, (uint)errorNumber + MESSAGE_OFFSET, (ushort)lcid, buf, (uint)buf.Capacity, IntPtr.Zero); return(formatCount != 0 ? buf.ToString().Trim() : null); } } finally { NativeMethods.FreeLibrary(msgModule); } }