Windows FormatMessage 的安全/灵活外观

发布于 2024-07-19 13:02:55 字数 1537 浏览 8 评论 0原文

我需要使用 FormatMessage() 来项目,但我不喜欢它可怕的界面。 有谁知道有一个外观可以整理它,同时仍然允许替换参数?

我刚刚阅读了 FastFormat 简介的第二部分,并且正在考虑编写一个FormatMessage() 的扩展名(或询问FastFormat 项目团队(如果他们正在开发中),但我我渴望尽快得到一些东西,所以如果有其他像样的东西,我可能会抓住它。

我想要的是能够编写如下代码:

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());

它将给出结果:

The child-svr service depends on the parent-svr service which failed to start be cause of the following error:
ship happens

我构建的当前包装器具有接口:

std::string LookupError(HINSTANCE hinst, DWORD id, ...);

这有两个问题:

  • 它不是类型安全的,因为它很容易传递任何类型- intstd::stringvoid* - 不是 const char*
  • 很容易与参数数量以及表示错误的格式字符串所需的数量

考虑到 FastFormat 在类型方面的能力-安全,我想知道是否有办法遵循其机制来处理 FormatMessage()

I need to use FormatMessage() for a project, but I don't like its scary interface. Does anyone know of a facade that tidies it up while still allowing for the replacement parameters?

I just read the second part of the FastFormat introduction, and am considering writing an extension for FormatMessage() (or asking the FastFormat project team if they've got one in the works), but I'm keen to get something asap, so if there's anything else decent out there I'd probably grab that instead.

What I want is to be able to write code such as:

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 would 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 wrapper I've built has the interface:

std::string LookupError(HINSTANCE hinst, DWORD id, ...);

There are two problems with this:

  • It's not type-safe, since it's easy to pass any type - int, std::string, void* - that is not const char*
  • It's easy to mismatch the number of arguments with the number required by the format string representing the error

Given the abilities of FastFormat in terms of type-safety, I want to know if there's a way to follow its mechanisms to deal with FormatMessage().

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

逆夏时光 2024-07-26 13:02:55

由于编译器无法检查要插入格式字符串的参数数量,因此不可能在编译时使其真正类型安全。

您只需对不同数量的插入参数进行一些重载,然后使用诸如 boost::any 等灵活的内容指定插入的值,就可以实现大部分目标。 因此,两个参数的重载将是:

std::string FormatMessage(HINSTANCE hinst, DWORD id, const boost::any &arg1, const boost::any &arg2);

当您从 arg1 检索值时,如果您尝试获取错误的类型,boost 将抛出异常,因此您只需要检查格式字符串并尝试获取每个参数所需的类型。

或者,您可以使用模板和 std::ostringstream (或 boost::lexical_cast)来获得非常灵活的版本; 再次,会有重载来允许参数数量变化,所以这里是单参数版本:

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
}

这样,只要可以流式传输传递的类型,您就可以从每个参数获取一个字符串,并且只要可以流式传输,就不需要其他任何东西因为格式字符串期望只插入字符串。

As the number of parameters to be inserted into the format string cannot be checked by the compiler, it is impossible to make this truly type-safe at compile time.

You can get most of the way there by just having a few 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 the value from arg1, boost will throw if you try to get the wrong type, so you just need to examine the format string and try to get the required type from each argument.

Alternatively you could use templates and std::ostringstream (or boost::lexical_cast) for a very flexible version; again there would be overloads to allow the number of arguments to vary, 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
}

That way you can get a string from each argument as long as the passed type can be streamed, and nothing else should be required as long as the format strings expect only strings to insert.

C++ 格式库 允许格式化与 GetLastError()< 返回的错误代码相对应的本机 Windows 错误消息/code> 和 POSIX 错误消息对应于 errno 给出的错误。 例如:

// 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);

使用FormatMessage API函数获取Windows错误消息。 您还可以使用 fmt::format_windows_error 格式化错误消息,这样不会引发异常。 有关更多详细信息,请参阅系统错误

免责声明:我是 C++ Format 的作者

The C++ Format library allows formatting native Windows error messages corresponding to error codes returned by GetLastError() and POSIX error messages corresponding to errors given by errno. For example:

// 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 is obtained using the FormatMessage API function. You can also format an error message with fmt::format_windows_error which doesn't throw an exception. See System Errors for more details.

Disclaimer: I'm the author of C++ Format

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文