0

我正在开发一个 MFC 应用程序,其中我在 .rc 文件中定义了菜单。我需要在运行时删除一些在 xml 文件中定义的菜单项。

菜单 ID 以字符串形式存储在 xml 中,如下所示

<exclusionmenu>ID_FILE_NEW</exclusionmenu>
<exclusionmenu>ID_FILE_OPEN</exclusionmenu>

从 xml 中检索菜单 ID 作为字符串,

RemoveMenu 函数需要 UINT(菜单 ID),

如何将xml中定义的菜单id字符串转换为uint菜单id

注意:这不是直接 cstring 到 uint 的转换,ID_FILE_NEW 是宏并且它具有 int 值。

4

3 回答 3

2

默认情况下,资源标识符的符号名称在头文件Resource.h中定义。在源代码和资源脚本中,符号名称被预处理器替换为它们各自的数值。当编译开始时,符号信息已经消失了。

要实现使用符号名称进行配置的方案,您必须提取并保留符号名称和资源标识符之间的映射以供以后在运行时使用,或者在部署之前将映射应用于配置文件。以下是潜在选项的列表:

使用关联容器并在应用程序启动时填充它:适当的容器将是std::map<std::string, unsigned int>. 使用 C++11 的列表初始化功能可以方便地填充此容器:

static std::map<std::string, unsigned int> IdMap = {
    {"ID_FILE_NEW", ID_FILE_NEW},
    {"ID_FILE_OPEN", ID_FILE_OPEN},
    // ...
}

在运行时,您可以使用此容器来检索给定其符号常量的资源标识符:

unsigned int GetId(const std::string& name) {
    if (IdMap.find(name) == IdMap.end())
        throw std::runtime_error("Unknown resource identifier.");
    return IdMap[name];
}

这种方法的缺点是您必须保持IdMap和资源同步。每当添加、修改或删除资源时,必须更新容器内容以说明所做的更改。

解析Resource.h并存储映射:包含符号标识符名称的头文件具有相当简单的结构。定义符号常量的代码行通常具有以下布局:

\s* '#' \s* 'define' \s+ <name> \s+ <value> <comment>?

提取映射的解析器并不像看起来那么难实现,并且应该在构建过程中的适当时间运行。提取映射后,可以将其存储在任意格式的文件中,例如INI 文件。该文件可以与应用程序一起部署,也可以作为资源编译到二进制映像中。在应用程序启动时,内容被读回,并用于构造上一段所述的映射。与之前的方案相比,解析Resource.h文件不需要在资源发生变化时手动更新代码。

解析Resource.h并转换配置 XML 文件:与之前的解决方案一样,此选项也需要解析Resource.h文件。使用此信息,然后可以转换配置 XML 文件,在部署之前用符号名称替换它们的数字对应项。这也需要额外的工作。但是,一旦完成此操作,该过程就可以自动化,并且可以验证结果以保持一致性。在运行时,您可以简单地读取 XML 并让数字标识符随时可用。

于 2014-08-13T20:52:39.890 回答
1

您的方案可行的唯一方法是当您将 Resoutce.h 与您的应用程序一起分发时,并且您有逻辑在启动时将 Resource.h 解析为包含 ID_* 名称及其值的表。

于 2014-08-13T12:15:51.797 回答
0

你不能,字符串形式在编译时“丢失”,它是一个预处理器标记。您可以存储菜单项的字符串变体:在代码中的某处,有 std::map 并用值填充它: menu_ids["ID_FILE_NEW"] = ID_FILE_NEW; 然后你调用 RemoveMenu(menu_ids[string_from_xml]);

于 2014-08-13T07:32:30.997 回答