我有一些特定于目标的资源。就像目标客户端的不同对话框和目标管理员的不同对话框一样。还有一些特定于每个目标的字符串。我不希望特定于管理应用程序的资源和代码出现在客户端构建中。
假设我可以有 3 个资源文件,admin、client和common,并以某种方式告诉构建引擎使用admin和common res 进行 admin 构建,并使用client和common res 进行客户端构建。
我怎样才能做到这一点?
如何拥有多个资源文件并将资源文件用于特定目标构建。?
我有一些特定于目标的资源。就像目标客户端的不同对话框和目标管理员的不同对话框一样。还有一些特定于每个目标的字符串。我不希望特定于管理应用程序的资源和代码出现在客户端构建中。
假设我可以有 3 个资源文件,admin、client和common,并以某种方式告诉构建引擎使用admin和common res 进行 admin 构建,并使用client和common res 进行客户端构建。
我怎样才能做到这一点?
如何拥有多个资源文件并将资源文件用于特定目标构建。?
好的,这是我完全回答您的问题的尝试,只要获得赏金会很有趣(它们在 MFC 标记的问题中不会经常发生 :) )。如果有的话,请说明您认为未解决的问题领域。这就是 VS 2008 的全部内容,对其他版本的更改应该是最小的。
首先为每个不同的构建目标添加资源文件,例如“admin.rc”、“common.rc”等。在解决方案浏览器中,右键单击您的项目,“添加->新建项目->资源文件”。
在解决方案浏览器中右键单击新添加的资源文件,选择“属性”并在“常规”下将“从构建中排除”设置为“是”。
在资源视图中,您现在可以将所需的资源添加到相应的资源文件中。
接下来,在资源视图中,右键单击“主”资源文件()并选择“资源包含”。
在下面的框中,在任何内容的末尾,添加
#ifdef ADMIN #include "admin.rc" #endif
当然,在预处理器中使用的符号您可以自己选择,并且文件名需要与您之前创建资源文件时选择的任何内容相匹配。
然后,在您的“管理员”项目配置中(我假设您对每个目标使用不同的配置?)并在解决方案资源管理器中,右键单击您的项目并导航到“资源->常规”。在“预处理器定义”下,添加“ADMIN”(或您在上一步中选择的任何内容)。
构建您的解决方案。您可以使用类似http://www.wilsonc.demon.co.uk/d10resourceeditor.htm或http://melander.dk/reseditor/的方式验证二进制文件中包含哪些资源。
请注意,显然您必须考虑各种构建中不可用的资源;因此,您必须确保不显示将在其构造函数中使用对话框 IDD 的对话框。您也可以通过预处理器执行此操作;只需将相同的标志添加到相应配置中的 C++ 预处理器即可。
另一个问题是每个 .rc 文件都有一个 resource.h,并且它们都将使用自己的编号。您可以通过仔细命名和编号来完成这项工作,但我会为每个分配一个不同的范围,以尝试在编译时捕获尽可能多的问题。为此,请打开您的“resource1.h”或您所称的任何名称,并将 _APS_NEXT__VALUE 定义更改为更高的数字。
或者,您可以将所有资源定义粘贴到一个 resource.h 中并编辑所有 .rc 文件以包含该一个 resource.h。只需在解决方案资源管理器中右键单击 rc 文件,然后选择“打开方式”并单击“源代码编辑器”。如果您要走“复杂的资源构建”路线,无论如何您都必须熟悉 rc 文件的格式(至少对于基础知识而言)。这并不难,只要确保您对链接器、资源编译器、.rc 文件、.cpp 文件和 resource.h 文件之间的关系有一个大致的了解。此外,特定于 MFC 的预处理器值一开始看起来很吓人,但它们大多是不言自明的,无论如何您大部分时间都可以忽略它们。
Petzold 对资源文件及其格式有一个简洁但充分的解释,您可能想从壁橱中挖掘出来,并在掌握事情的窍门时将其放在手边。
您可以在 .rc 文件中使用 #ifdef。但是,这会搞砸资源编辑器。处理此问题的“标准”方法是为每个目标设置单独的 .rc 文件,然后将它们中的每一个都包含在一个执行 #ifdef 的脚本中,例如
#ifdef CLIENT_1
#include "client_1.rc"
#endif
#ifdef CLIENT_2
#include "client_2.rc"
#endif
这样资源编辑器只需要解析“完整”的 rc 文件。尽管如此,这样工作还是很痛苦,因为编辑器很容易混淆。曾几何时,我还尝试为每个“目标”设置一个单独的项目,然后在我的“资源包含”部分中将它们与相对路径一起#include。我不记得为什么我最后没有使用这种方法。使用预处理器可以完成这项工作,但总感觉有点笨拙。也许最新版本的 VS 可以更好地处理它。
根据给定的描述,我认为不需要不同的 .RC 文件。您可以有一个字符串表,其中包含两个(或多个目标)的字符串。在启动时,您将拥有指向其中任何一个的 UINT 变量。例如:
UINT nUserConfirmationId;
UINT nAcessDeiniedMsgId;
if(target1)
{
nUserConfirmationId = IDD_ENG_STRING_ID_FOR_CONFIRM;
..
}
else
{
nUserConfirmationId = IDD_FRE_STRING_ID_FOR_CONFIRM;
...
}
然后使用nUserConfirmationId
等变量。类似地,您可以拥有对话框资源(我不明白为什么需要不同的对话框,只应替换字符串)。是的,当您添加资源时,它存在维护问题。
或者,您可以拥有包含目标特定资源的纯资源 DLL。
如果您只有少数特定于配置的资源,您可能会发现在配置之间共享.rc更容易且更易于维护,但让它们使用不同的资源子集。VS(至少 2017 年)也支持它:为单个资源添加条件。
在解决方案资源管理器中,双击您的.rc以打开资源视图。在资源树中,右键单击您希望依赖于配置的对话框、图标等,然后打开Properties。
在属性窗口中,您应该看到Condition。
现在,您应该已经为您的客户端、服务器、管理员构建专门定义了预处理器符号。(如果你不这样做,现在就这样做!属性页 -> C/C++ -> 预处理器 -> 预处理器定义。)
只需将此符号添加到Condition中。这具有在.rc文件中的代码块周围添加#ifdef
...的效果,但是以 VS 友好的方式 - 它不会破坏编辑器。#endif
注意:但是,我注意到此过程似乎不适用于 String Tables。无法判断它是 UI 错误还是根本不受支持。