【问题标题】:How to use different resource files for different build targets in MFC如何在 MFC 中为不同的构建目标使用不同的资源文件
【发布时间】:2013-03-17 03:15:59
【问题描述】:

我有一些特定于目标的资源。就像目标 client 的不同对话框和目标 admin 的不同对话框一样。还有一些特定于每个目标的字符串。我不希望特定于管理应用程序的资源和代码出现在客户端构建中。

假设我可以有 3 个资源文件,adminclientcommon,并以某种方式告诉构建引擎使用 admin 和 common res 用于管理员构建,使用 clientcommon res 用于客户端构建。

我怎样才能做到这一点?

如何拥有多个资源文件并将资源文件用于特定目标构建?

【问题讨论】:

    标签: visual-studio visual-c++ build mfc target


    【解决方案1】:

    好的,这是我完全回答您的问题的尝试,只要获得赏金会很有趣(它们在 MFC 标记的问题中不会经常发生 :))。如果有的话,请说明您认为未解决的问题领域。这就是 VS 2008 的全部内容,对其他版本的更改应该是最小的。

    • 首先为每个不同的构建目标添加资源文件,例如“admin.rc”、“common.rc”等。在解决方案浏览器中,右键单击您的项目,“添加->新建项目->资源文件”。

    • 在解决方案浏览器中右键单击新添加的资源文件,选择“属性”并在“常规”下将“从构建中排除”设置为“是”。

    • 在资源视图中,您现在可以将所需的资源添加到相应的资源文件中。

    • 接下来,在资源视图中,右键单击“主”资源文件()并选择“资源包含”。

    • 在下面的框中,在所有内容的末尾,添加

    #ifdef ADMIN
    #include "admin.rc"
    #endif
    

    当然在预处理器中使用的符号你可以自己选择,并且文件名需要与你之前创建资源文件时选择的任何内容相匹配。

    • 然后,在您的“管理员”项目配置中(我假设您对每个目标使用不同的配置?)并在解决方案资源管理器中,右键单击您的项目并导航到“资源->常规” ”。在“预处理器定义”下,添加“ADMIN”(或您在上一步中选择的任何内容)。

    • 构建您的解决方案。您可以使用 http://www.wilsonc.demon.co.uk/d10resourceeditor.htmhttp://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 对资源文件及其格式有一个简洁但足够的解释,您可能想从壁橱中挖掘出来,并在掌握事情的窍门时将其放在手边。

    【讨论】:

      【解决方案2】:

      您可以在 .rc 文件中使用 #ifdef。但是,这会搞砸资源编辑器。处理此问题的“标准”方法是为每个目标设置单独的 .rc 文件,然后将它们中的每一个都包含在一个脚本中,您可以在其中执行 #ifdef,例如

      #ifdef CLIENT_1
      #include "client_1.rc"
      #endif
      #ifdef CLIENT_2
      #include "client_2.rc"
      #endif
      

      这样资源编辑器只需要解析“完整”的rc文件。尽管如此,这样工作还是很痛苦,因为编辑器很容易混淆。曾几何时,我还尝试为每个“目标”创建一个单独的项目,然后在我的“资源包含”部分中将它们与相对路径一起#include。我不记得为什么我最后没有使用这种方法。使用预处理器可以完成这项工作,但总感觉有点笨拙。也许最新版本的 VS 可以更好地处理它。

      【讨论】:

      • Visual Studio 2017 支持单个资源的条件...并且在幕后,它添加了 #if ... #endif 就像您指定的那样,但不会破坏编辑器。我的回答中还有更多细节。
      【解决方案3】:

      根据给定的描述,我认为不需要不同的 .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 文件,但这太麻烦了,并且在重新构建资源编译器时会重新编写 .RC 文件(和 resource.h)。如果多个目标是您的首要任务,我想使用纯资源 DLL。
      【解决方案4】:

      如果您只有少数特定于配置的资源,您可能会发现在配置之间共享 .rc 更容易且更易于维护,但让它们使用不同的资源子集。 VS(至少 2017 年)也支持它:为单个资源添加 Condition

      Solution Explorer 中,双击您的 .rc 以打开 Resource View。在资源树中,右键单击您希望依赖于配置的对话框、图标等,然后打开Properties

      在属性窗口中,您应该会看到 Condition

      现在,您应该已经为您的客户端、服务器、管理员构建专门定义了预处理器符号。 (如果您不这样做,现在就这样做!Property Pages -> C/C++ -> Preprocessor -> Preprocessor Definitions。)

      只需将此符号添加到条件。这具有在 .rc 文件中的代码块周围添加#ifdef ... #endif 的效果,但以VS 友好的方式 - 它不会破坏编辑器。

      注意:然而,我注意到这个过程似乎不适用于字符串表。无法判断这是 UI 错误还是根本不受支持。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多