Safe / flexible facade for Windows FormatMessage
I need to use FormatMessage () for a project, but I don't like its ugly interface. Does anyone know of a facade that picks it up while still keeping the replacement options?
I just read the second part of FastFormat introduction and I am considering making an extension for FormatMessage () (or ask the FastFormat command if they have one in the works) but I really want to get something ASAP, so if there is anything - anything else worthy, I would probably use it.
I want to write some code like:
HINSTANCE netevent = ::LoadLibrary("netevent.dll");
std::string msg = LookupError(netevent, EVENT_SERVICE_START_FAILED_II,
"child-svr", "parent-svr", "ship happens");
::puts(msg.c_str());
Which will give the result:
The child-svr service depends on the parent-svr service which failed to start be cause of the following error:
ship happens
The current shell I created has an interface:
std::string LookupError(HINSTANCE hinst, DWORD id, ...);
There are two problems with this:
- This is not a safety type, since it is easy to transfer any type -
int
,std::string
,void*
- is notconst char*
- Easily match the number of arguments with the number required by the format string representing the error
Given FastFormat 's type safety capabilities , I want to know if there is a way to follow its mechanisms, refer to FormatMessage () .
a source to share
Since the number of parameters to be inserted in the format string cannot be checked by the compiler, it is impossible to make this truly type-safe at compile time.
You can get the most of this way by simply having multiple overloads for different numbers of inserted parameters and then specifying the inserted values with something flexible like boost::any
. So the overload for two parameters would be:
std::string FormatMessage(HINSTANCE hinst, DWORD id, const boost::any &arg1, const boost::any &arg2);
When you retrieve a value from arg1
, boost will throw if you try to get the wrong type, so you just have to examine the format string and try to get the type you want from each argument.
Alternatively, you can use templates and std :: ostringstream (or boost :: lexical_cast) for a very flexible version; overloads will occur again to change the number of arguments, so here's the single argument version:
template <class TArg1>
std::string FormatMessage(HINSTANCE hinst, DWORD id, const TArg1 &arg1)
{
std::ostringstream arg1Stream;
arg1Stream << arg1;
std::string arg1String = arg1Stream.str();
DWORD_PTR argArray = reinterpret_cast<DWORD_PTR>(arg1String.c_str());
// ... etc
}
This way you can get a string from each argument if the type being passed can be streaming and nothing needs to be required if the format strings are expecting only strings to be inserted.
a source to share
The C ++ Format Library allows you to format native Windows error messages that match the error codes returned GetLastError()
and POSIX error messages that match those given errno
. For instance:
// This throws a WindowsError with the description
// cannot open file 'madeup': The system cannot find the file specified.
// or similar (system message may vary).
const char *filename = "madeup";
LPOFSTRUCT of = LPOFSTRUCT();
HFILE file = OpenFile(filename, &of, OF_READ);
if (file == HFILE_ERROR)
throw fmt::WindowsError(GetLastError(), "cannot open file '{}'", filename);
Windows error message received using FormatMessage
API function . You can also format the error message with fmt::format_windows_error
, which does not throw an exception. See System Errors for details .
Disclaimer: I am the author of C ++ Format
a source to share