默认情况下,资源标识符的符号名称在头文件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 并让数字标识符随时可用。