How do I deal with placeholders for Win32 error messages?
Asked Answered
W

3

9

I would like to present meaningful error messages when my program encounters Win32 errors. I call GetLastError, and then FormatMessage. But some of the error messages contain placeholders. For instance, ERROR_BAD_EXE_FORMAT has the text:

%1 is not a valid Win32 application.

Presumably, the %1 is meant to be replaced by the name of the module which is not valid. How can I effect that replacement?

Note that I would ideally like a general solution because I note that there are many errors with placeholders. I can see the following messages in the documentation:

  • The wrong diskette is in the drive. Insert %2 (Volume Serial Number: %3) into drive %1.
  • The operating system cannot run %1.
  • This version of %1 is not compatible with the version of Windows you're running. Check your computer's system information and then contact the software publisher.
  • The image file %1 is signed, unable to modify.
  • The system cannot find message text for message number 0x%1 in the message file for %2.
  • ... and so on.
Wellappointed answered 22/1, 2014 at 11:14 Comment(2)
Related blogs.msdn.com/b/oldnewthing/archive/2007/11/28/6564257.aspxAvivah
@AlexK. It bugs me too that system error messages contain %1 insertions that you just have to "know" on a case-by-case basis. -Raymond Not very encouraging.Wellappointed
W
2

I think Raymond Chen effectively answers the question in a comment on his blog where he writes:

It bugs me too that system error messages contain %1 insertions that you just have to "know" on a case-by-case basis.

Wellappointed answered 1/2, 2014 at 12:7 Comment(0)
B
1

ERROR_BAD_EXE_FORMAT contains an insertion %1. You can replace that by using last parameter of FormatMessage(). This code a little sample.

LPWSTR pMessage = L"%1";
DWORD_PTR pArgs[] = {(DWORD_PTR)L"My_Test_App.exe" }; 

TCHAR buffer[1024];
DWORD dwError = ERROR_BAD_EXE_FORMAT;
DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY;
DWORD dwResult = FormatMessage(dwFlags, pMessage, dwError, 0, buffer, 1024,  (va_list*)pArgs);
if (dwResult) 
{
    //now, 'buffer' contains below message.

    //
    //My_Test_App.exe is not a valid Win32 application.
    //
}

I know that some sytem error codes have insertion. I think we can't supply relevant argument for all of them. So, if I were you, I would like to use just system error code, not FormatMessage(). Or, support argument list and FormatMessage()for only some frequently system error code.

Bryonbryony answered 22/1, 2014 at 12:53 Comment(4)
Are you suggesting that I have to do this on a case by case basis for each and every possible error code?Wellappointed
No, definitely not. It's impossible. I think a reason that almost windows application have their own error message format is because this case. I just want to show you how to replace place holder, if you don't know about that.Bryonbryony
@CodeDreamer: when using FORMAT_MESSAGE_FROM_SYSTEM, the lpSource parameter is not used and can be set to NULL instead of specifying "%1".Enchiridion
@DavidHeffernan: yes, you have to deal with insertions on a case by case basis, as different error codes expect different arguments, if any at all.Enchiridion
S
0

One possibility for such cases is to include the extra flag "FORMAT_MESSAGE_IGNORE_INSERTS" in the FormatMessage() call:

DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;

Then FormatMessage() will at least return the error text "as is", e.g. "%1 is not a valid Win32 application." in this case.

Spree answered 19/9, 2024 at 12:5 Comment(5)
Yes, we've known of The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flag for a decade. This doesn't attempt to answer the question.Abstain
Why doesn't it answer the question? The question is "how to deal with placeholders", and this is one way to do it, which hasn't been mentioned yet in the other answers. And it's an important way, as it prevents the problem that FormatMessage() errors out when you happen to get a Win32 error whose message contains placeholders! (Resulting in empty error message or even crashes in the worst case.)Spree
Straight from the question: "How can I effect that replacement?" How does this proposed answer address that?Abstain
You misunderstood the question then. The question is not, "how to effect the replacement", it is "how to deal with placeholders". -- And one way to deal with them, is to ignore them... :-) So in a complete treatment of this topic, this option should also be mentioned.Spree
I literally quoted the question asked and you turn around to respond: "No, no, no, that's not the question". That is beyond me. If you are having difficulty interpreting the question, the hint is in the very first sentence: "I would like to present meaningful error messages". "%1 is not a valid Win32 application." is the opposite of meaningful.Abstain

© 2022 - 2025 — McMap. All rights reserved.