What are the capitalized text identifiers for Win32 error codes called, and how can they be determined programmatically, given an error code?
Asked Answered
G

1

3

In listings of Win32 error codes, each error has three components:

  • The numeric error code
  • A descriptive message
  • An identifier consisting of capitalized words separated by underscores

According to the documentation, the term "message identifier" refers to the descriptive message, but it doesn't say what the term is for the capitalized error name, and I haven't been able to find that anywhere. These identifiers appear to be analogous to what's called the "Error Id" in a PowerShell ErrorRecord object, but googling for "win32 error id" and "win32 error identifier" didn't lead to an answer.

For example, in the following error:

ERROR_TOO_MANY_OPEN_FILES

4 (0x4)

The system cannot open the file.

  • 4 is the error code.
  • The system cannot open the file. is the message identifier.
  • ERROR_TOO_MANY_OPEN_FILES is the __________?

Also, how can this text value be determined, given an error code? I can easily determine the message identifier associated with a given error code like this:

string MessageIdentifier = new Win32Exception(ErrorCode).Message;

However, the Win32Exception class doesn't appear to have a property that corresponds to these capitalized error names (analogous to the ErrorRecord class's ErrorId property).

In some listings I've seen these kinds of identifiers referred to as "constants", but if they're constants, where are they defined/enumerated and how do you access them from a program?

Gadolinite answered 13/5, 2015 at 0:35 Comment(9)
pinvoke.net/default.aspx/Constants/WINERROR.htmlImmix
I'm pretty sure "The system cannot open the file" is the description and ERROR_TOO_MANY_OPEN_FILES is the message identifier.Nims
@Plutonix I've already seen that, but it doesn't answer either part of my question. It doesn't tell me what the proper term is, and it explicitly defines each one as a constant, one by one. That doesn't tell me how to programatically determine the text identifier that corresponds to a given error code, only allows you to refer to the numeric code using text names that you've already manually looked up and defined in your code, which misses the point.Gadolinite
@RonBeyer Intuitively it would sound that way, but the linked doc says that "message identifier" is the description.Gadolinite
@RonBeyer Actually, it looks like I misread that. In fact, "message identifier" is neither the description nor the capitalized name. The term refers to the numeric error code itself, when there is a descriptive message defined, i.e. the error code 4 is the "message identifier" of the descriptive message The system cannot open the file. But the term for ERROR_TOO_MANY_OPEN_FILES remains a mystery.Gadolinite
The error code is the "message identifier". The "capitalized name" is also the "message identifier", it is just a human-readable alias for the numeric error code. It doesn't really have any special term of its own beyond that. It is an alias used in documentation, and typically used in code to make it more readable. But it gets replaced with the numeric code during compiling.Selfexpression
You are not expected to show the ERROR_XXX names to the user. They are for use in your source code. Show the description to the user. That can be obtained by calling FormatMessage.Shrier
@DavidHeffernan Oh, I realize that it's just for code readability. What confused me is that these things look like some identifier defined by the API, rather than just descriptions used in the documentation, so I expected that they could be read from some object representing the error, or something like that. Remy's answer clears up where they come from. I'm not sure why the docs themselves don't.Gadolinite
"these things look like some identifier defined by the API" - they are, by the Win32 API itself. The ERROR_... names are logically defined by the Win32 API and used/documented all the other place. But how your compiler knows what they are is a different story. For C/C++, they are defined in the winerror.h file. In Delphi, they are defined in the Winapi.Windows unit. For other programming languages, they are defined other ways.Selfexpression
S
5

For example, in the following error:

ERROR_TOO_MANY_OPEN_FILES
4 (0x4)
The system cannot open the file.

4 is the error code.
The system cannot open the file. is the message identifier.
ERROR_TOO_MANY_OPEN_FILES is the __________?

You are wrong on the last two points. 4 is both the error code and the message identifier, per the same documentation you linked to:

All Win32 error codes MUST be in the range 0x0000 to 0xFFFF, although Win32 error codes can be used both in 16-bit fields (such as within the HRESULT type specified in section 2.1) as well as 32-bit fields. Most values also have a default message defined, which can be used to map the value to a human-readable text message; when this is done, the Win32 error code is also known as a message identifier.

The system cannot open the file. is the message text that belongs to message identifier 4. That text is reported by FormatMessage() and Win32Exception.Message.

ERROR_TOO_MANY_OPEN_FILES is just a human-readable #define in winerror.h in the Win32 SDK:

//
// MessageId: ERROR_TOO_MANY_OPEN_FILES
//
// MessageText:
//
// The system cannot open the file.
//
#define ERROR_TOO_MANY_OPEN_FILES        4L

There is no function in either the Win32 API or .NET to return the text ERROR_TOO_MANY_OPEN_FILES given the error code 4. You would have to write your own lookup code if you need that functionality, as demonstrated by this pinvoke.net example:

WINERROR (Constants)

int errorCode = 4; //Microsoft.Win32.Interop.ResultWin32.ERROR_TOO_MANY_OPEN_FILES
string identName = Microsoft.Win32.Interop.ResultWin32.GetErrorName(errorCode);
// returns "ERROR_TOO_MANY_OPEN_FILES"
Selfexpression answered 13/5, 2015 at 1:32 Comment(7)
Yes, I do see now that I misread how the doc is defining "message identifier". I thought it was saying that the descriptive message is called the message identifier, but it's actually saying that the error code is the message identifier for the message.Gadolinite
Anyway, it sounds like winerror.h is for C++. So, you're saying that the only way to have meaningful names for the errors is to define them yourself? In essence, then, these amount to nothing but suggested names to use when defining your own constants for the error codes? It seems strange that Microsoft uses these names all over their documentation when they're not defined by the API, and they don't even bother to explain that in the docs. :|Gadolinite
winerror.h is for C/C++, yes. Error handling in .NET is generally based on exceptions (where Win32-related errors are based on Win32Exception). You usually don't need the actual error code, but you can access it if needed, .NET usually has a different exception type for specific errors. But, if you use PInvoke to call a Win32 function directly, you have to do your own error handling, and define your own constants. You can set the DllImport.SetLastError property to true when appropriate (not all APIs use SetLastError()) so you can access the error code via Marshal.GetLastWin32Error()...Selfexpression
... or you can raise a Win32Exception() without providing an input value, so it calls Marshal.GetLastWin32Error() for you.Selfexpression
Indeed. Standard pattern is if (!SomeWin32Func()) throw new Win32Exception(); which could readily be wrapped in helper methodShrier
So essentially the answer to my question is that they refer to constants from a C++ #include file called winerror.h, and aren't defined by the API. I guess Microsoft reasonably assumed that anyone who would be interested in documentation of Win32 error codes would have background in C++ and would be familiar with winerror.h, so there's no need to mention that. It seems that it wouldn't be so hard to put them in a column with a heading that says something like "Constant name from winerror.h", but that would consume valuable real estate on the page, not leaving enough room for whitespace. ;)Gadolinite
winerror.h is part of the Windows SDK, but the error codes are part of the Win32 API itself. Just because .NET does not use winerror.h directly does not change that. Microsoft has Win32 error code documentation, winerror.h is not required for that. There are many programming languages that can access the Win32 API but not use winerror.h directly.Selfexpression

© 2022 - 2024 — McMap. All rights reserved.