Windows get error message

After a Windows API call, how can I get the last error message in a textual form? GetLastError() returns an integer value, not a text message.

i’ll leave this here since i will need to use it later. It’s a source for a small binary compatible tool that will work equally well in assembly, C and C++.

GetErrorMessageLib.c (compiled to GetErrorMessageLib.dll)

#include <Windows.h>

/***
 * returns 0 if there was enough space, size of buffer in bytes needed
 * to fit the result, if there wasn't enough space. -1 on error.
 */
__declspec(dllexport)
int GetErrorMessageA(DWORD dwErrorCode, LPSTR lpResult, DWORD dwBytes)
{    
    LPSTR tmp;
    DWORD result_len;

    result_len = FormatMessageA (
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        dwErrorCode,
        LANG_SYSTEM_DEFAULT,
        (LPSTR)&tmp,
        0,
        NULL
    );        

    if (result_len == 0) {
        return -1;
    }

    // FormatMessage's return is 1 character too short.
    ++result_len;

    strncpy(lpResult, tmp, dwBytes);

    lpResult[dwBytes - 1] = 0;
    LocalFree((HLOCAL)tmp);

    if (result_len <= dwBytes) {
        return 0;
    } else {
        return result_len;
    }
}

/***
 * returns 0 if there was enough space, size of buffer in bytes needed
 * to fit the result, if there wasn't enough space. -1 on error.
 */
__declspec(dllexport)
int GetErrorMessageW(DWORD dwErrorCode, LPWSTR lpResult, DWORD dwBytes)
{   
    LPWSTR tmp;
    DWORD nchars;
    DWORD result_bytes;

    nchars = dwBytes >> 1;

    result_bytes = 2 * FormatMessageW (
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        dwErrorCode,
        LANG_SYSTEM_DEFAULT,
        (LPWSTR)&tmp,
        0,
        NULL
    );    

    if (result_bytes == 0) {
        return -1;
    } 

    // FormatMessage's return is 1 character too short.
    result_bytes += 2;

    wcsncpy(lpResult, tmp, nchars);
    lpResult[nchars - 1] = 0;
    LocalFree((HLOCAL)tmp);

    if (result_bytes <= dwBytes) {
        return 0;
    } else {
        return result_bytes * 2;
    }
}

inline version(GetErrorMessage.h):

#ifndef GetErrorMessage_H 
#define GetErrorMessage_H 
#include <Windows.h>    

/***
 * returns 0 if there was enough space, size of buffer in bytes needed
 * to fit the result, if there wasn't enough space. -1 on error.
 */
static inline int GetErrorMessageA(DWORD dwErrorCode, LPSTR lpResult, DWORD dwBytes)
{    
    LPSTR tmp;
    DWORD result_len;

    result_len = FormatMessageA (
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        dwErrorCode,
        LANG_SYSTEM_DEFAULT,
        (LPSTR)&tmp,
        0,
        NULL
    );        

    if (result_len == 0) {
        return -1;
    }

    // FormatMessage's return is 1 character too short.
    ++result_len;

    strncpy(lpResult, tmp, dwBytes);

    lpResult[dwBytes - 1] = 0;
    LocalFree((HLOCAL)tmp);

    if (result_len <= dwBytes) {
        return 0;
    } else {
        return result_len;
    }
}

/***
 * returns 0 if there was enough space, size of buffer in bytes needed
 * to fit the result, if there wasn't enough space. -1 on error.
 */
static inline int GetErrorMessageW(DWORD dwErrorCode, LPWSTR lpResult, DWORD dwBytes)
{   
    LPWSTR tmp;
    DWORD nchars;
    DWORD result_bytes;

    nchars = dwBytes >> 1;

    result_bytes = 2 * FormatMessageW (
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        dwErrorCode,
        LANG_SYSTEM_DEFAULT,
        (LPWSTR)&tmp,
        0,
        NULL
    );    

    if (result_bytes == 0) {
        return -1;
    } 

    // FormatMessage's return is 1 character too short.
    result_bytes += 2;

    wcsncpy(lpResult, tmp, nchars);
    lpResult[nchars - 1] = 0;
    LocalFree((HLOCAL)tmp);

    if (result_bytes <= dwBytes) {
        return 0;
    } else {
        return result_bytes * 2;
    }
}

#endif /* GetErrorMessage_H */

dynamic usecase(assumed that error code is valid, otherwise a -1 check is needed):

#include <Windows.h>
#include <Winbase.h>
#include <assert.h>
#include <stdio.h>

int main(int argc, char **argv)
{   
    int (*GetErrorMessageA)(DWORD, LPSTR, DWORD);
    int (*GetErrorMessageW)(DWORD, LPWSTR, DWORD);
    char result1[260];
    wchar_t result2[260];

    assert(LoadLibraryA("GetErrorMessageLib.dll"));

    GetErrorMessageA = (int (*)(DWORD, LPSTR, DWORD))GetProcAddress (
        GetModuleHandle("GetErrorMessageLib.dll"),
        "GetErrorMessageA"
    );        
    GetErrorMessageW = (int (*)(DWORD, LPWSTR, DWORD))GetProcAddress (
        GetModuleHandle("GetErrorMessageLib.dll"),
        "GetErrorMessageW"
    );        

    GetErrorMessageA(33, result1, sizeof(result1));
    GetErrorMessageW(33, result2, sizeof(result2));

    puts(result1);
    _putws(result2);

    return 0;
}

regular use case(assumes error code is valid, otherwise -1 return check is needed):

#include <stdio.h>
#include "GetErrorMessage.h"
#include <stdio.h>

int main(int argc, char **argv)
{
    char result1[260];
    wchar_t result2[260];

    GetErrorMessageA(33, result1, sizeof(result1));
    puts(result1);

    GetErrorMessageW(33, result2, sizeof(result2));
    _putws(result2);

    return 0;
}

example using with assembly gnu as in MinGW32(again, assumed that error code is valid, otherwise -1 check is needed).

    .global _WinMain@16

    .section .text
_WinMain@16:
    // eax = LoadLibraryA("GetErrorMessageLib.dll")
    push $sz0
    call _LoadLibraryA@4 // stdcall, no cleanup needed

    // eax = GetProcAddress(eax, "GetErrorMessageW")
    push $sz1
    push %eax
    call _GetProcAddress@8 // stdcall, no cleanup needed

    // (*eax)(errorCode, szErrorMessage)
    push $200
    push $szErrorMessage
    push errorCode       
    call *%eax // cdecl, cleanup needed
    add $12, %esp

    push $szErrorMessage
    call __putws // cdecl, cleanup needed
    add $4, %esp

    ret $16

    .section .rodata
sz0: .asciz "GetErrorMessageLib.dll"    
sz1: .asciz "GetErrorMessageW"
errorCode: .long 33

    .section .data
szErrorMessage: .space 200

result: The process cannot access the file because another process has locked a portion of the file.

It is vital that you call GetLastError() IMMEDIATELY. The last error code can be overwritten by any other function, so if there’s an extra function call between the function that failed and the call to GetLastError() , the return from GetLastError() will no longer be reliable. Take extra caution when dealing with C++ constructors.

Once you get an error code, you will need to interpret it. You can get a comprehensive list of error codes on MSDN, at the System Error Codes (Windows) page. Alternatively, you can look in your system header files; the file with all the error code constants is winerror.h . (If you have Microsoft’s official SDK for Windows 8 or newer, this is in the shared subfolder of the include folder.)

Notes on calling GetLastError() in other programming languages

.net languages (C#, VB, etc.)

With .net, you should not P/Invoke to GetLastError() directly. This is because the .net runtime will make other Windows API calls on the same thread behind your back. For instance, the garbage collector might call VirtualFree() if it finds enough memory that it is no longer using, and this can happen between your intended function call and your call to GetLastError() .

Instead, .net provides the Marshal.GetLastWin32Error() function, which will retrieve the last error from the last P/Invoke call that you yourself made. Use this instead of calling GetLastError() directly.

(.net does not seem to stop you from importing GetLastError() anyway; I’m not sure why.)

The various facilities provided by Go for calling DLL functions (which reside in both package syscall and package golang.org/x/sys/windows ) return three values: r1 , r2 , and err . r2 is never used; you can use the blank identifier there. r1 is the function’s return value. err is the result of calling GetLastError() but converted into a type that implements error , so you can pass it up to calling functions to handle.

Because Go does not know when to call GetLastError() and when not to, it will always return a non- nil error. Therefore, the typical Go error-handling idiom

will not work. Instead, you must check r1 , exactly as you would in C, and only use err if that indicates the function returned an error:

Error reported with additional information on failure and success

Some API calls can succeed or fail in more than one way. The APIs commonly return additional information for both successful invocations as well as errors (e.g. CreateMutex).

Error reported as HRESULT value

HRESULTs are numeric 32-bit values, where bits or bit ranges encode well-defined information. The MSB is a failure/success flag, with the remaining bits storing additional information. Failure or success can be determined using the FAILED or SUCCEEDED macros. HRESULT s are commonly used with COM, but appear in non-COM implementations as well (e.g. StringCchPrintf).

Converting an error code into a message string

GetLastError returns a numerical error code. To obtain a descriptive error message (e.g., to display to a user), you can call FormatMessage :

In C++, you can simplify the interface considerably by using the std::string class:

NOTE: These functions also work for HRESULT values. Just change the first parameter from DWORD dwErrorCode to HRESULT hResult . The rest of the code can remain unchanged.

Источник

Win32 API
Сообщение об ошибках и обработка

замечания

Каждый поток будет иметь свой последний код ошибки. Windows API установит последний код ошибки в вызывающем потоке.

Вы всегда должны вызывать GetLastError сразу после проверки возвращаемого значения функции API Windows.

Большинство функций Windows API устанавливают последний код ошибки, когда они терпят неудачу. Некоторые также установят последний код ошибки, когда они преуспеют. Существует ряд функций, которые не устанавливают последний код ошибки. Всегда обращайтесь к документации по функциям Windows API.

Невозможно использовать FORMAT_MESSAGE_FROM_SYSTEM без FORMAT_MESSAGE_IGNORE_INSERTS при использовании функции FormatMessage для получения описания кода ошибки.

Вступление

API Windows предоставляется с помощью C-вызываемого интерфейса. Успех или сбой вызова API сообщаются строго через возвращаемые значения. Исключения не являются частью документированного контракта (хотя некоторые реализации API могут вызывать исключения SEH , например, при передаче аргумента lpCommandLine только для чтения в CreateProcess ).

Сообщение об ошибке грубо относится к одной из четырех категорий:

Документация для каждого вызова API явно вызывается, как сообщаются ошибки. Всегда обращайтесь к документации.

Ошибка, сообщенная только возвратным значением

Некоторые вызовы API возвращают единый флаг отказа / успеха без какой-либо дополнительной информации (например, GetObject ):

Сообщается об ошибке с сообщением об ошибке

В дополнение к возвращаемому значению отказа / успеха некоторые вызовы API также устанавливают последнюю ошибку при сбое (например, CreateWindow ). Документация обычно содержит следующую стандартную формулировку для этого случая:

Если функция завершается успешно, возвращаемое значение .
Если функция не работает, возвращаемое значение . Чтобы получить расширенную информацию об ошибке, вызовите GetLastError .

Очень важно, что вы вызываете GetLastError() НЕМЕДЛЕННО. Последний код ошибки может быть перезаписан любой другой функцией, поэтому, если есть дополнительная функция вызова между неудавшейся функцией и вызовом GetLastError() , возврат из GetLastError() больше не будет надежным. Будьте особенно осторожны при работе с конструкторами C ++.

Как только вы получите код ошибки, вам нужно будет его интерпретировать. Вы можете получить полный список кодов ошибок в MSDN на странице Системные коды ошибок (Windows) . Кроме того, вы можете посмотреть в своих файлах заголовков системы; файл со всеми константами кода ошибки — winerror.h . (Если у вас есть официальный SDK от Microsoft для Windows 8 или новее, это находится в shared папке с папкой include.)

Заметки о вызове GetLastError() на других языках программирования

.net (C #, VB и т. д.)

С .net вы не должны P / Invoke в GetLastError() напрямую. Это связано с тем, что среда выполнения .net сделает другие вызовы Windows API одним и тем же потоком за вашей спиной. Например, сборщик мусора может вызвать VirtualFree() если он найдет достаточно памяти, которую он больше не использует, и это может произойти между вашим назначенным вызовом функции и вашим вызовом GetLastError() .

Вместо этого .net предоставляет Marshal.GetLastWin32Error() , которая будет извлекать последнюю ошибку из последнего вызова P / Invoke, который вы сами сделали. Используйте это вместо прямого вызова GetLastError() .

(.net, похоже, не мешает вам импортировать GetLastError() любом случае, я не уверен, почему.)

Различные средства, предоставляемые Go для вызова DLL-функций (которые находятся как в syscall пакета, syscall и в пакете golang.org/x/sys/windows ), возвращают три значения: r1 , r2 и err . r2 никогда не используется; вы можете использовать пустой идентификатор. r1 — возвращаемое значение функции. err является результатом вызова GetLastError() но преобразуется в тип, реализующий error , поэтому вы можете передать его вызывающим функциям для обработки.

Поскольку Go не знает, когда вызывать GetLastError() а когда нет, он всегда будет возвращать ошибку nil . Поэтому типичная идиома обработки ошибок Go

не будет работать. Вместо этого вы должны проверить r1 точно так же, как и на C, и использовать только err если это указывает, что функция возвратила ошибку:

Сообщается об ошибке с дополнительной информацией о сбоях и успехах

Некоторые вызовы API могут преуспеть или сбой более чем одним способом. API обычно возвращают дополнительную информацию как для успешных вызовов, так и для ошибок (например, CreateMutex ).

Ошибка, сообщенная как значение HRESULT

HRESULT s — числовые 32-битные значения, где биты или диапазоны бит кодируют четко определенную информацию. MSB — это флаг отказа / успеха, а остальные бит хранят дополнительную информацию. Отказ или успех можно определить с помощью макросов FAILED или SUCCEEDED . HRESULT s обычно используются совместно с COM, но также отображаются в реализациях, отличных от COM (например, StringCchPrintf ).

Преобразование кода ошибки в строку сообщения

GetLastError возвращает числовой код ошибки. Чтобы получить описательное сообщение об ошибке ( например , для отображения пользователю), вы можете вызвать FormatMessage :

В C ++ вы можете значительно упростить интерфейс, используя класс std::string :

ПРИМЕЧАНИЕ. Эти функции также работают для значений HRESULT . Просто измените первый параметр из DWORD dwErrorCode на HRESULT hResult . Остальная часть кода может оставаться неизменной.

Источник

Win32 get error message

1. _com_error is just a wrapper around FormatMessage.

2. Higher versions of MS VS contain buggy implementation of _com_error.

See here for details. Sign In· View Thread

conversion error when compiling ehaerim 23-Dec-07 22:44
In an ATL COM project,

if (FAILED(hr))
<
::MessageBox(NULL, _com_error(hr).ErrorMessage, _T(«FinalConstruct»), MB_ICONSTOP);
>

cause the following error message and I couldn’t make it compile OK.

error C2664: ‘MessageBoxA’ : cannot convert parameter 2 from ‘const char *(void) const’ to ‘const char *’
There is no context in which this conversion is possible

How to fix this?

HaeRim

Sign In· View Thread
Can we use this with WSAGetLastError () for reporting WinSock errors? Siva Ranganeni 24-May-06 5:17
Hi,

This is a great article and very helpful.

Can we use the same with WSAGetLastError()? Will the following code give Winsock error message()?

_com_error( HRESULT_FROM_WIN32(WSAGetLastError() ).ErrorMessage()

Thanks in Advance.

Siva

Sign In· View Thread
Re: Can we use this with WSAGetLastError () for reporting WinSock errors? jwpfish 16-Jul-07 18:16

You can do that, e.g.:

puts(_com_error(WSAENOTSOCK).ErrorMessage());

Sign In· View Thread
That is great! Thank you! Ferne Li 8-May-06 16:32
That is great! Thank you!
Sign In· View Thread
Excellent. kimjim 20-Mar-06 18:11
Excellent article. I implemented this in my project. Thank you. A few words about passing GetLastError() as an argument.

As far as I know all the function’s arguments are evaluated before the actual function call is made. Let us take a case where some other win32 or other functions are called in the constructor of the _com_error or like class object. But we are passing the GetLastError as a parameter. So before even the constructor which is afterall a function, starts its execution. So I dont think this will be a problem. If at all the problem comes just make a workover. Create a function alike:

and put all your _com_error calls in that(using the ‘hr’ above). Pass GetLastError as a parameter to CallComErrMsgBox(). This should solve the problem.

Again excellent article. This kind of articles teaches again and again the time that can be saved by stopping «reinventing the wheel»

Thanks,
Jim

Sign In· View Thread
Very good Sam NG 20-Feb-06 17:02
Thank you I am not aware of the _com_error class. I do the error handling by my own macro, not a bad solution, but I think if the compiler already have it, better not «reinventing» the wheel.

Besides, I agree with ARB70 that display the «system» error message may not be the most difficult part, providing a more meaningful message specific to your application and your target user group is a even more challenging task. And I am always confused about what should be display in case of error

«Error initialize the program» seem good enough for general users but it won’t help in finding the reason why the program won’t start.

Sam

Sign In· View Thread
Re: Very good Brian C Hart 21-Feb-06 9:13

«Error initialize the program» seem good enough for general users but it won’t help in finding the reason why the program won’t start.

Perhaps. but all these strings are mapped to specific E_ or other constant values in code. and can be looked up in the docs. That’s the beauty of it. So just append, to the _com_error.ErrorMessage() output a string saying «nnEmail Tech support with the exact wording of this error string, and what you were doing when this happened.» Then you can work backwards from there as to what SDK calls you were making at that point, and from the error string you can work back to which error code the SDK call returned, and then you can look the SDK call up in the docs and work backward to figure out when said call returns that specific code.

Sincerely Yours,
Brian Hart
Department of Physics and Astronomy
University of California, Irvine

Sign In· View Thread
One problem this article does not solve. ARB70 3-Jan-06 12:43
The fact that both Win32 and COM error messages are frequently cryptic and unhelpful.

I have used _com_error a lot in the past for dealing with HRESULTS. If you import a COM type library in C++ and call methods on the generated smart pointers they always throw _com_error when something goes wrong, so having a catch handler that deals with them is nearly always mandatory. I was not aware that you could also use them for dealing with Win32 calls and that is very helpful and useful. Thanks.

However both Win32 and COM produce extremely «techie», unhelpful error messages and I nearly always find that they require massaging if they are going to be of any help to a «normal» user. In you example «The system cannot find the file specified» is not terribly helpful. 100 different files may have been specified! «Class not registered» is even more cryptic!

So unlike some other posters I won’t be changing all my code to use a one liner approach but will continue using support classes and other code to provide more meaningful error messages. Maybe this is not such a problem if all of your users are «propellor heads».

ARB70

Sign In· View Thread
Re: One problem this article does not solve. Brian C Hart 3-Jan-06 13:12

So unlike some other posters I won’t be changing all my code to use a one liner approach but will continue using support classes and other code to provide more meaningful error messages. Maybe this is not such a problem if all of your users are «propellor heads».

Conceded. You have to do what you think is best for your particular application, and the user base you will be serving.

Sincerely Yours,
Brian Hart
Department of Physics and Astronomy
University of California, Irvine

Sign In· View Thread
Re: One problem this article does not solve. Paul Sanders (the other one) 20-Oct-07 8:45

Nearly two years after the event is perhaps a little late to comment on this, but you never know, someone may read it.

I think that reporting ‘bare metal’ WIN32 errors is extremely important when something happens to your program that you did not anticipate when you wrote it. I do accept, though, that it is no substitute for handling error conditions that you know, when you are writing the program, might reasonably arise (such as ‘file not found’, to take a trivial example).

I guess what I am trying to say is that unexpected things ALWAYS happen to your software, and the more helpful *to the developer* the error message is in such circumstances, the more likely he/she is to be able to get to the bottom of it (and hence fix it in the next release). «The operation could not be completed» just doesn’t cut it. Encourage your users to copy cryptic error messages to the clipboard (provide a button that does it) and email them to you, perhaps.

Of course, the ultimate error message is ‘assert failed’

Sign In· View Thread
Re: One problem this article does not solve. Brian C Hart 21-Oct-07 16:38
Common Gotcha’s with GetLastError() Doug Schmidt 3-Jan-06 6:07
The article above is good, but readers should be cautioned not to embed a call to GetLastError() as an argument to another function. Resist the temptation to do everything in one line.

The only 100% reliable way of calling GetLastError() is on a line by itself, immediately after the WIN32 API call.

The reasoning is that GetLastError() retrieves the last error encountered by the last Win32 API call on each thread. Some C++ class contructors (like _bstr_t ) will make WIN32 API calls to allocate resources, and if the arguments to the error formatting function use these objects, GetLastError() may actually return 0 (SUCCESS).

So if your app formats every error with «ERROR DETECTED: %s», then you run the risk of displaying the embarassing «ERROR DETECTED: No error detected.», since «No error detected» is the message string for SUCCESS.

The rather large I am working on has hit this problem many times, and usually it is because a temporary string was construtcted in between the Win32 API call and the call to GetLastError() .

So you should prefer:

over this more terse equivalent of

Cheers,
Doug

Sign In· View Thread
Re: Common Gotcha’s with GetLastError() Brian C Hart 3-Jan-06 8:48

The above article is good, but readers should be cautioned not to embed a call to GetLastError() as an argument to another function. Resist the temptation to do everything in one line.

The only 100% reliable way of calling GetLastError() is on a line by itself, immediately after the WIN32 API call.

I concur that one should be careful; however, I have used this approach in multithreaded programs, with the _com_error class only, and have not had any problems. I assume that _com_error is somewhat thread-safe since it is designed to also be thrown as an exception type.

Sincerely Yours,
Brian Hart
Department of Physics and Astronomy
University of California, Irvine

Sign In· View Thread
Re: Common Gotcha’s with GetLastError() Karim AM 16-Jan-06 16:05

I disagree with Doug Schmidt on this one — I’d expect you to be fine passing GetLastError() on its own into a function call or constructor, as the first thing that will happen is that GetLastError()’s return result will be assigned (and therefore fixed) into the function/constructor parameter.

I would however be careful with macros, or fns/c’tors that have multiple parameters, where AFAIK it’s undefined in what order the parameters will be evaluated.

Karim

Sign In· View Thread
Nice article. However. W. Kleinschmit 1-Jan-06 22:40
Quote:
. to determine if it is anything other than the ‘success value,’ which is S_OK. .

Sorry, but this is wrong. By definition every negative HRESULT is an error. So the FAILED(. ) macro only tests for bit 31 of the HRESULT set.
There are other possible return values (S_FALSE for example), that are sometimes used to indicate special situations but are not considered an error.
FAILED(S_FALSE) returns FALSE.

Anyway. Your article is one of the more usefull ones I have seen on CodeProject lately.

Hang on.

Sign In· View Thread
Re: Nice article. However. Brian C Hart 2-Jan-06 9:23

Sorry, but this is wrong. By definition every negative HRESULT is an error. So the FAILED(. ) macro only tests for bit 31 of the HRESULT set.
There are other possible return values (S_FALSE for example), that are sometimes used to indicate special situations but are not considered an error.
FAILED(S_FALSE) returns FALSE.

I stand corrected.

Sincerely Yours,
Brian Hart
Department of Physics and Astronomy
University of California, Irvine

Sign In· View Thread
How do you correct this AlexEvans 2-Jan-06 15:33

Nice work Brian

Do intend to post a fix? Or maybe a way to fix this issue?

Thanks for sharing
Alex

Sign In· View Thread
Re: How do you correct this Brian C Hart 2-Jan-06 15:39

As you can see, I have revised the article. This invites readers to look up FAILED and SUCCEEDED macros in the docs. The way you check for whether your COM calls have succeeded or fails really depends on your particular application.

Sincerely Yours,
Brian Hart
Department of Physics and Astronomy
University of California, Irvine

Sign In· View Thread
Immediate usage Randor 1-Jan-06 16:23
There are some articles I read here on codeproject that have an immediate effect on my active projects, and motivate me to update older projects. This article is one of them.

Many thanks.

Sign In· View Thread
Re: Immediate usage Brian C Hart 1-Jan-06 18:23

I am humbled by your compliment. Thank you.

Sincerely Yours,
Brian Hart
Department of Physics and Astronomy
University of California, Irvine

Sign In· View Thread
Re: Immediate usage JPaulson 3-Jan-06 8:39

I agree. I immediately went through and updated the project I was working on as well. This is why I subscribe to the CodeProject newsletter.

Sign In· View Thread
Two words for you Rob Manderson 1-Jan-06 10:33
Bloody brilliant!

And exactly what I needed for a COM object I’m writing. You got my 5.

I’m working on a version for Visual Lisp++

My blog http://blogs.wdevs.com/ultramaroon/[^]

Sign In· View Thread
Re: Two words for you Brian C Hart 1-Jan-06 19:50

And exactly what I needed for a COM object I’m writing. You got my 5.

Such a pleasure to receive such kind words. Thank you. Happy New Year!

Sincerely Yours,
Brian Hart
Department of Physics and Astronomy
University of California, Irvine

Sign In· View Thread
Last Visit: 31-Dec-99 19:00 Last Update: 15-Jan-23 23:43 Refresh 1 2 Next ᐅ

General News Suggestion Question Bug Answer Joke Praise Rant Admin

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Источник

When it comes to troubleshooting end-user PCs, you often have to deal with cryptic error messages with unknown error codes. Here you will learn how to translate these error codes into descriptive messages.

  • Author
  • Recent Posts

Sami Laiho has been a Microsoft Most Valuable Professional (MVP) since 2011 and one of the world’s leading IT experts for Windows and security. He has been teaching OS troubleshooting, management, and security since 1996. In 2019 TiVi-magazine chose Sami as one of the top 100 influencers in IT in Finland. For more info, go to https://samilaiho.com.

Here are a few examples I have gotten from my end users. The first one gives me no information (and has a normal comment in it about IT’s job being to break computers):

A message from an end user

A message from an end user

On the other hand, this piece of paper was once delivered to my desktop:

 A piece of paper on which an end user wrote down the entire blue screen

A piece of paper on which an end user wrote down the entire blue screen

Getting informative messages starts with making it easier for the end user to capture the error messages returned by the system. Here, I offer some easy-to-teach tips on doing just that.

Every error message in Windows includes copy/paste functionality. When you get an error message such as this one, just press Ctrl+C. This copies the text from the error message to the clipboard.

You can press Ctrl+C to copy the error text to the clipboard

You can press Ctrl+C to copy the error text to the clipboard

You can then open an email and paste it there. I’ll just use Notepad here.

You can paste the text to any text editor

You can paste the text to any text editor

If the error is not from Windows or for some reason doesn’t allow copy/paste, you can use OneNote. Just capture the message with any screen capturing tool (Snipping tool, Snagit, etc.). I’ll do that from OneNote in this example.

Starting a screen capture from OneNote

Starting a screen capture from OneNote

Capturing an error message from OneNote

Capturing an error message from OneNote

If you used a tool other than OneNote itself, paste the picture into OneNote. Now right-click the picture, and choose Copy Text from Picture. Then just paste it out again. It uses optical character recognition (OCR), so it works on anything; on the other hand, it is not perfect.

Using OCR to interpret the error message

Using OCR to interpret the error message

Now that you have the error in text format it’s also easy to paste it to a search engine. I’ll just paste it right back to OneNote.

Pasting the output of the OCR

Pasting the output of the OCR

Our users often think we know all the error codes by heart. But there are 32,768 error messages in Windows, so we really don’t. This is a common conversation I have, as people honestly think they are doing a good job as they took note of the error number.

Customer: «Sami, I had error 1617.»

Me: «What did it say?»

Customer: «No idea but I wrote down the number.»

Luckily, we can translate these. This is a skill I use myself all the time, as event logs often show only the number. As do error messages.

There is an older tool that takes in decimal values and it’s in NET.exe. Here is an example:

NET HELPMSG 1617

Using NET HELPMSG to translate an error number (in decimal) to text

Using NET HELPMSG to translate an error number (in decimal) to text

If you have a hex value, you can use the newer version in WinRM.exe like this:

WINRM HELPMSG 0x651

Using WINRM HELPMSG to translate an error number (in hex) to text

Using WINRM HELPMSG to translate an error number (in hex) to text

Some error messages are quite funny. Try my favorite one out!

Subscribe to 4sysops newsletter!

«When you are married and you go to a company party, you need to remember NET HELPMSG 4006.«

avataravatar

  • Remove From My Forums
  • Question

  • Hi All,

    I have created MSI Installer for my application.

    I have used MsiSetExternalUI().

    And used MsiInstallProduct() to install my package silently.

    But, I need to show error messages whenever MsiInstallProduct() failed.

    How can I get the appropriate message string for the error code returned by MsiInstallProduct()?

    If anyone have idea about it then please reply.

    Thanks & Regards,

    Pariksheet.

Answers

  • Hi,

    Error Codes: returned by Windows Installer functions MsiExec.exe and InstMsi.exe

    Windows Installer Error Messages: returned by Windows Installer

    It is because of the error is returned by the Windows Installer rather than the functions, so it will show you the windows installer error messages, instead of the error description in «Error Codes» table.

    That is dependent on the error.

        public string GetDescriptionFromErrCode(uint errCode) 
        {
          string libPath = "msimsg.dll";
          IntPtr hModuleInstance = LoadLibraryEx(libPath, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE);
    
          StringBuilder sb = new StringBuilder(255);
          LoadString(hModuleInstance, errCode, sb, sb.Capacity + 1);
    
          return sb.ToString();
        }
    
        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, LoadLibraryFlags dwFlags);
    
        enum LoadLibraryFlags : uint
        {
    
          DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
          LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
          LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
          LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
          LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
          LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
        }
    
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax);
    

    Have a nice weekend!


    Mike [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by

      Wednesday, May 18, 2011 10:41 AM

RRS feed

  • Remove From My Forums
  • Question

  • Hi all,

    How can I get, writing in a file for instance, the error messages from WSH like this one:

    In alternative is there a way to get the text from this window with vbscript

    Thanks


    Joao Simplicio Rodrigues

Answers

  • To log errors:

    cscript //NoLogo myscript.vbs > output.txt 2>errors.txt


    _(ツ)_/

    • Marked as answer by
      João Simplicio Rodrigues
      Wednesday, August 23, 2017 8:25 PM

All replies

  • Have a look at

    https://social.technet.microsoft.com/Forums/lync/en-US/c0a814b8-7887-4acb-8653-766e174d7161/write-error-to-text-file?forum=winserverpowershell

  • Run script with «cscript» an output to  file:

    cscript yourscript.vbs > output.txt


    _(ツ)_/

    • Proposed as answer by
      Richard MuellerMVP
      Monday, August 7, 2017 1:35 PM
    • Marked as answer by
      Richard MuellerMVP
      Monday, August 14, 2017 4:44 PM
    • Unmarked as answer by
      João Simplicio Rodrigues
      Wednesday, August 23, 2017 8:25 PM

  • jrv

    I start my script in the Windows sheduler task and the information I get in output.txt isn’t quite the same I get in the textbox…

    In a cmd I wrote

    cscript myscript.vbs > output.txt

    Just get this:

    Microsoft (R) Windows Script Host Version 5.8
    Copyright (C) Microsoft Corporation. All rights reserved.


    Joao Simplicio Rodrigues

    • Edited by
      João Simplicio Rodrigues
      Tuesday, August 22, 2017 7:15 PM

  • That means there was no error.

    Do it like this:

    cscript //NoLogo myscript.vbs > output.txt


    _(ツ)_/

  • Start to going nuts…

    What you wrote makes perfect sense but it is not working.
    So I did a test that was append pause to the cmd and then I noticed that character 1 appears before the redirection character >

    I forced the error in the vbs for test..

    I also try to change from cmd to bat the is the same … I wrote the cmd/bat with notepad !!

    Tried the command line directly:

    The file aioc.txt just show:

    Microsoft (R) Windows Script Host Version 5.8
    Copyright (C) Microsoft Corporation. All rights reserved

    The aa.txt file has the traditional help message.

    With time I have to dig deeper…

    Thanks for your help


    Joao Simplicio Rodrigues

  • To log errors:

    cscript //NoLogo myscript.vbs > output.txt 2>errors.txt


    _(ツ)_/

    • Marked as answer by
      João Simplicio Rodrigues
      Wednesday, August 23, 2017 8:25 PM

  • OK !!

    You are the greatest. :)

    Thanks again.


    Joao Simplicio Rodrigues

    • Edited by
      João Simplicio Rodrigues
      Wednesday, August 23, 2017 8:28 PM

Понравилась статья? Поделить с друзьями:
  • Windows ftp error 530
  • Windows found drivers for your device but encountered an error while attempting to install them
  • Windows found driver software for your device but encountered an error
  • Windows fix disk error
  • Windows failed to start windows boot manager error 0xc000000e