TN035: Using Multiple Resource Files and Header Files with Visual C++

This note describes how the Visual C++ resource editor supports multiple resource files and header files shared in a single project or shared across multiple projects and how you can take advantage of that support. This note answers these questions:

  • When might you want to split a project into multiple resource files and/or header files, and how you do it?
  • How do you share a common header .H file between two .RC files?
  • How do you divide project resources into multiple .RC files?
  • How do you (and the tools) manage build dependencies between .RC, .CPP, and .H files?

You should be aware that if you add an additional resource file to your project, ClassWizard will not recognize the resources in the added file.

This note is structured to answer the above questions as follows:

Overview of How Visual C++ Manages Resource Files and Header Files

Visual C++ manages a single .RC resource file and a corresponding .H header file as a tightly coupled pair of files. When you edit and save resources in an .RC file, you indirectly edit and save symbols in the corresponding .H file. Although you can open and edit multiple .RC files at a time (using Visual C++'s MDI user interface) for any given .RC file you indirectly edit exactly one corresponding header file.

Symbol Header File

By default, Visual C++ always names the corresponding header file RESOURCE.H, regardless of the name of the resource file (e.g., MYAPP.RC). Using the File Set Includes command in Visual C++, you can change the name of this header file by updating the Symbol Header File file in the Set Includes dialog.

Read-Only Symbol Directives

Although Visual C++ only edits one header file for any given .RC file, Visual C++ supports references to symbols defined in additional read-only header files. Using the File Set Includes command in Visual C++, you can specify any number of additional read-only header files as Read-Only Symbol Directives. The "read-only" restriction means that when you add a new resource in the .RC file, you can use a symbol defined in the read-only header file; but if you delete the resource, the symbol still remains defined in the read-only header file. You cannot change the numeric value assigned to a read-only symbol.

Compile-Time Directives

Visual C++ also supports nesting of resource files, where one .RC file is #include'd within another. When you edit a given .RC file using Visual C++, any resources in the #include'd files are not visible. But when you compile the .RC file, the #include'd files are also compiled. Using the File Set Includes command in Visual C++, you can specify any number of #include'd .RC files as Compile-Time Directives.

Note what happens if you read into Visual C++ an .RC file that #include's another .RC file that is not specified as a Compile-Time Directive. This situation might arise when you bring to Visual C++ an .RC file that you had been previously maintaining manually with a text editor. When Visual C++ reads the #include'd .RC file, it merges the #include'd resources into the parent .RC file. When you save the parent .RC file, the #include statement, in effect, will be replaced by the #include'd resources. If you do not want this merge to happen, you should remove the #include statement from the parent .RC file prior to reading it into Visual C++; then using Visual C++, add back the same #include statement as a Compile-Time Directive.

Visual C++ saves in an .RC file the three kinds of above Set Includes information (Symbol Header File, Read-Only Symbol Directives, and Compile-Time Directives) in #include directives and in TEXTINCLUDE resources. The TEXTINCLUDE resources, an implementation detail that you do not normally need to deal with, are explained in How Visual C++ Manages Set Includes Information.

Analysis of AppWizard-Created .RC and .H Files

Examining the application code produced by AppWizard provides insight into how Visual C++'s manages multiple resource files and header files. The code excerpts examined below are from a MYAPP application produced by AppWizard using the default options.

An AppWizard-created application uses multiple resource files and multiple header files, as summarized in the diagram below:

   RESOURCE.H     AFXRES.H                   
         \       /                             
          \     /                               
         MYAPP.RC                              
             |                               
             |                             
       RES\MYAPP.RC2 
       AFXRES.RC                  
       AFXPRINT.RC                

You can view these multiple file relationships using the Visual C++ File/Set Includes command.

MYAPP.RC

The application resource file that you edit using Visual C++.

RESOURCE.H is the application-specific header file. It is always named RESOURCE.H by AppWizard, consistent with Visual C++'s default naming of the header file. The #include for this header file is the first statement in the resource file (MYAPP.RC):

//Microsoft Visual C++ generated resource script
//
#include "resource.h"

RES\MYAPP.RC2

Contains resources that will not be edited by Visual C++ but will be included in the final compiled .EXE file. AppWizard creates no such resources by default, since Visual C++ can edit all of the standard resources, including the version resource (a new feature in this release). An empty file is generated by AppWizard in case you wish to add your own custom formatted resources to this file.

If you use custom formatted resources, you can add them to RES\MYAPP.RC2 and edit them using the Visual C++ text editor.

AFXRES.RC and AFXPRINT.RC contain standard resources required by certain features of the framework. Like RES\MYAPP.RC2, these two framework-provided resource files are #include'd at the end of MYAPP.RC, and they are specified in the Compile-Time Directives of the Set Includes dialog box. Thus, you do not directly view or edit these framework resources while you edit MYAPP.RC in Visual C++, but they are compiled into the application's binary .RES file and final .EXE file. For more information on the standard framework resources, including procedures for modifying them, see Technical Note 23.

AFXRES.H defines standard symbols, such as ID_FILE_NEW, used by the framework and specifically used in AFXRES.RC. AFXRES.H also #include's WINRES.H, which contains a subset of WINDOWS.H that are needed by Visual C++ generated .RC files as well as AFXRES.RC. The symbols defined in AFXRES.H are available as you edit the application resource file (MYAPP.RC). For example, ID_FILE_NEW is used for the File New menu item in MYAPP.RC's menu resource. You cannot change or delete these framework-defined symbols.

Including Additional Header Files

The AppWizard-created application includes only two header files: RESOURCE.H and AFXRES.H. Only RESOURCE.H is application-specific. You may need to include additional read-only header files in the following cases:

The header file is provided by an external source, or you want to share the header file among multiple projects or multiple parts of the same project.

The header file has formatting and comments that you do not want Visual C++ to change or filter out when it saves the file. For example, maybe you want to preserve #define's that use symbolic arithmetic such as:

#define RED 0
#define BLUE 1
#define GREEN 2
#define ID_COLOR_BUTTON 1001
#define ID_RED_BUTTON (ID_COLOR_BUTTON + RED)
#define ID_BLUE_BUTTON (ID_COLOR_BUTTON + BLUE)
#define ID_GREEN_BUTTON (ID_COLOR_BUTTON + GREEN)

You can include additional read-only header files by using the File Set Includes command to specify the #include statement as a second Read-Only Symbol Directive, as in:

#include "afxres.h"
#include "second.h"

The new file relationship diagram now looks like this:

                   AFXRES.H      
   RESOURCE.H     SECOND.H                   
         \       /                             
          \     /                               
         MYAPP.RC  
             |                               
             |                             
       RES\MYAPP.RC2 
       AFXRES.RC                  
       AFXPRINT.RC                

Sharing a Header File Between Two .RC Files

You may want to share a header file between two .RC files that are in different projects, or possibly the same project. To do so, simply apply the Read-Only Directives technique described above to both .RC files. In the case where the two .RC files are for different applications (different projects), the result is illustrated in the following diagram:

     RESOURCE.H   AFXRES.H   RESOURCE.H 
   (for MYAPP1)  SECOND.H   (for MYAPP2)            
         \       /     \       /          
          \     /       \     /            
         MYAPP1.RC      MYAPP2.RC                
          /    \        /     \                  
         /      \      /       \           
RES\MYAPP1.RC2  AFXRES.RC     RES\MYAPP2.RC2             
               AFXPRINT.RC                

The case where the second header file is shared by two .RC files in the same application (project) is discussed below.

Using Multiple Resource Files in the Same Project

Visual C++ and the Resource Compiler support multiple .RC files in the same project through #include's of one .RC file within another. Multiple nesting is allowed. There are various reasons to split your project's resources into multiple .RC files:

  • It is easier to manage a large number of resources among multiple project team members if you split the resources into multiple .RC files. If you use a source control management package for checking out files and checking in changes, splitting the resources into multiple .RC files will give you finer control over managing changes to resources.
  • If you want to use preprocessor directives, such as #ifdef, #endif, and #define, for portions of your resources, you must isolate them in read-only resources that will be compiled by the Resource Compiler.
  • Component .RC files will load and save faster in Visual C++ than one composite .RC file.
  • If you want to maintain a resource with a text editor in a human-readable form, you should keep it in a .RC file separate from the one Visual C++ edits.
  • If you need to keep a user-defined resource in a binary or text form that is interpretable by another specialized data editor, then you should keep it in a separate .RC file so Visual C++ does not change the format to hexadecimal data. The .WAV (sound) file resources in the MFC Advanced Concepts sample SPEAKN are a good example.

You can #include a SECOND.RC in the Compile-Time Directives in the Set Includes dialog box:

#include "res\myapp.rc2"  // non-Visual C++ edited resources
#include "second.rc"  // THE SECOND .RC FILE #include "afxres.rc"  // Standard components
#include "afxprint.rc"  // printing/print preview resources

The result is illustrated in the following diagram:

   RESOURCE.H     AFXRES.H                   
         \       /                             
          \     /                               
         MYAPP.RC
             |                               
             |                             
       RES\MYAPP.RC2
       SECOND.RC 
       AFXRES.RC                  
       AFXPRINT.RC                

Using Compile-Time Directives, you can organize your Visual C++-editable and non-editable resources into multiple .RC files, where the "master" MYAPP.RC does nothing but #include the other .RC files. If you are using a Visual C++ project .MAK file, then you should include the "master" .RC file in the project so that all the #include'd resources are compiled with your application.

Enforcement of Non-Editable Visual C++ Files

The AppWizard-created RES\MYAPP.RC2 file is an example of a file that contains resources that you do not want to accidentally read into Visual C++ and then write it back out with loss of formatting information. To protect against this, we place the following lines in the beginning of the RES\MYAPP.RC2 file:

#ifdef APSTUDIO_INVOKED
   #error this file is not editable by Visual C++
#endif //APSTUDIO_INVOKED

When Visual C++ compiles the .RC file, it defines APSTUDIO_INVOKED as well as RC_INVOKED. If the AppWizard-created file structure is corrupted and Visual C++ reads the #error line above, it reports a fatal error and abort the reading of the .RC file.

Managing Symbols Shared by Multiple Visual C++-Edited .RC Files

Two issues arise when you split up your resources into multiple .RC files that you want to edit separately in Visual C++:

  • You might want to share the same symbols across multiple .RC files.
  • You need to help Visual C++ avoid assigning the same ID numeric values to distinct resources (symbols).

The following diagram illustrates an organization of .RC and .H files that deals with the first issue:

              MYAPP.RC
            /         \
           /           \
MYSTRS.H   / MYSHARED.H  \  MYMENUS.H
    \    /    /      \   \    \
     \  /    /        \   \    \
  MYSTRS.RC           MYMENUS.RC

In this example, string resources are kept in one resource file, MYSTRS.RC, and menus are kept in another, MYMENUS.RC. Some symbols, such as for commands, may need to be shared between the two files. For example, a ID_TOOLS_SPELL may be the menu command ID for the Spell item in a Tools menu; and it may also be the string ID of the command prompt displayed by the framework in the application's main window status bar.

The ID_TOOLS_SPELL symbol is kept in the shared header file, MYSHARED.H. You maintain this shared header file manually with a text editor; Visual C++ does not directly edit it. In the two resource files MYSTRS.RC and MYMENUS.RC, you specify #include MYSHARED.H in the Read-Only Directives for MYAPP.RC, using the File Set Includes command, as described earlier.

It is most convenient to anticipate a symbol you will share before you attempt use it to identify any resource. Add the symbol to the shared header file and, if you have not already #include'd the shared header file in the Read-Only Directives for the .RC file, do so before using the symbol. If you did not anticipate sharing the symbol in this way, then you will have to manually (using a text editor) move the #define statement for the symbol from, say, MYMENUS.H to MYSHARED.H before using it in MYSTRS.RC.

When you manage symbols in multiple .RC files, you also must help Visual C++ avoid assigning the same ID numeric values to distinct resources (symbols). For any given .RC file, Visual C++ incrementally assigns IDs in each of four ID domains. Between editing sessions, Visual C++ keeps track of the last ID it assigned in each of the domains in the symbol header file for the .RC file. Here is what the APS_NEXT values are for an empty (new) .RC file:

#define _APS_NEXT_RESOURCE_VALUE  101
#define _APS_NEXT_COMMAND_VALUE   40001
#define _APS_NEXT_CONTROL_VALUE   1000
#define _APS_NEXT_SYMED_VALUE     101

_APS_NEXT_RESOURCE_VALUE is the next symbol value that will be used for a dialog resource, menu resource, and so on. The valid range for resource symbol values is 1 to 0x6FFF.

_APS_NEXT_COMMAND_VALUE is the next symbol value that will be used for a command identification. The valid range for command symbol values is 0x8000 to 0xDFFF.

_APS_NEXT_CONTROL_VALUE is the next symbol value that will be used for a dialog control. The valid range for dialog control symbol values is 8 to 0xDFFF.

_APS_NEXT_SYMED_VALUE is the next symbol value that will be issued when you manually assign a symbol value using the New command in the Symbol Browser.

Visual C++ starts with slightly higher values that the lowest legal value when creating a new .RC file. AppWizard will also initialize these values to something more appropriate for MFC applications. For more information about ID value ranges, see Technical Note 20.

Now every time you create a new resource file, even in the same project, Visual C++ defines the same _APS_NEXT_ values. This means that if you add, say, multiple dialogs in two different .RC files, it is highly likely that the same #define value will be assigned to different dialogs. For example, IDD_MY_DLG1 in the first .RC file might be assigned the same number, 101, as IDD_MY_DLG2 in a second .RC file.

To avoid this, you should reserve a separate numeric range for each of the four domains of IDs in the respective .RC files. Do this by manually updating the _APS_NEXT values in each of the .RC files before you start adding resources. For example, if the first .RC file uses the default _APS_NEXT values, then you might want to assign the following _APS_NEXT values to the second .RC file:

#define _APS_NEXT_RESOURCE_VALUE  2000
#define _APS_NEXT_COMMAND_VALUE   42000
#define _APS_NEXT_CONTROL_VALUE   2000
#define _APS_NEXT_SYMED_VALUE     2000

Of course, it is still possible that Visual C++ will assign so many IDs in the first .RC file that the numeric values start to overlap those reserved for the second .RC file. You should reserve sufficiently large ranges so that this does not happen.

Managing Dependencies Between .RC, .CPP, and .H Files

When Visual C++ saves an .RC file, it also saves symbol changes to the corresponding RESOURCE.H file. Any of your .CPP files that refer to resources in the .RC file must #include the RESOURCE.H file, usually from within your project's master header file. This leads to an undesirable side-effect due to the development environment's internal project management which scans source files for header dependencies. Every time you add a new symbol in Visual C++, all the .CPP file that #include RESOURCE.H would need to be recompiled.

Visual C++, circumvents the dependency on RESOURCE.H by including the following comment as the first line of the RESOURCE.H file:

//{{NO_DEPENDENCIES}}

The development environment interprets this comment by ignoring the changes to RESOURCE.H so that dependent .CPP files will not need to be recompiled.

Visual C++ always adds the //{{NO_DEPENDENCIES}} comment line to a .RC file when it saves the file. In some cases, circumventing of the build dependency on RESOURCE.H may lead to run-time errors undetected at link time. For example, if you use the Symbol Browser to change the numeric value assigned to a symbol for a resource, the resource will not be correctly found and loaded at application run-time if the .CPP file referring to the resource is not recompiled. In such cases, you should explicitly recompile any .CPP files that you know are affected by the symbol changes in RESOURCE.H or select Rebuild All. If you have the need to frequently change symbol values for a certain group of resources, you will probably find it more convenient and safer to break out these symbols into a separate read-only header file, as described in the above section Including Additional Header Files.

How Visual C++ Manages Set Includes Information

As discussed above, the File menu Set Includes command lets you specify three types of information:

  • Symbol Header File
  • Read-Only Symbol Directives
  • Compile-Time Directives

The following describes how Visual C++ maintains this information in a .RC file. You do not need this information to use Visual C++, but it may enhance your understanding so that you can more confidently use the Set Includes feature.

Each of the above three types of Set Includes information is stored in the .RC file in two forms: (1) as #include or other directives interpretable by the Resource Compiler, and (2) as special TEXTINCLUDE resources interpretable only by Visual C++.

The purpose of the TEXTINCLUDE resource is to safely store Set Include information in a form that is readily presentable in Visual C++'s Set Includes dialog box. TEXTINCLUDE is a resource type defined by Visual C++. Visual C++ recognizes three specific TEXTINCLUDE resources that have the resource identification numbers 1, 2 and 3:

TEXTINCLUDE resource i.d. Type of Set Includes information
1 Symbol Header File
2 Read-Only Symbol Directives
3 Compile-Time Directives

Each of the three types of Set Includes information is illustrated by the default MYAPP.RC and RESOURCE.H files created by AppWizard, as described below. The extra \0 and "" tokens between BEGIN and END blocks are required by the RC syntax to specify zero terminated strings and the double quote character respectively.

Symbol Header File

The form of the Symbol Header File information interpreted by the Resource Compiler is simply a #include statement:

#include "resource.h"

The corresponding TEXTINCLUDE resource is:

1 TEXTINCLUDE DISCARDABLE
BEGIN
#resource.h\0"
END

Read-Only Symbol Directives

Read-Only Symbol Directives are included at the top of MYAPP.RC in the following form interpretable by the Resource Compiler:

#include "afxres.h"

The corresponding TEXTINCLUDE resource is:

2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END

Compile-Time Directives

Compile-Time Directives are included at the end of MYAPP.RC in the following form interpretable by the Resource Compiler:

#ifndef APSTUDIO_INVOKED
///////////////////////
//
// From TEXTINCLUDE 3
//
#include "res\myapp.rc2"  // non-Visual C++ edited resources #include "afxres.rc"  // Standard components
#include "afxprint.rc"  // printing/print preview resources
#endif  // not APSTUDIO_INVOKED

The #ifndef APSTUDIO_INVOKED directive instructs Visual C++ to skip over Compile-Time Directives.

The corresponding TEXTINCLUDE resource is:

3 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""res\myapp.rc2""  // non-Visual C++ edited resources\r\n"
"\r\n"
"#include ""afxres.rc""  // Standard components\r\n"
"#include ""afxprint.rc""  // printing/print preview resources\r\n"
"\0"
END

Technical Notes by NumberTechnical Notes by Category



Send feedback to MSDN. Look here for MSDN Online resources.

TN035: Using Multiple Resource Files and Header Files with Visual C++的更多相关文章

  1. VC中Source Files, Header Files, Resource Files,External Dependencies的区别

    VC中Source Files, Header Files, Resource Files,External Dependencies的区别 区别: Source Files 放源文件(.c..cpp ...

  2. 解决Cannot find MySQL header files under /usr/include/mysql的错误

    按照下面的步骤能成功,亲测.转帖,做笔记 编译php-5.5-6的mysql支持,出现Cannot find MySQL header files under /usr/include/mysql. ...

  3. 编译安装php Cannot find MySQL header files under /usr/include/mysql.

    编译php-5.5-6的mysql支持,出现Cannot find MySQL header files under /usr/include/mysql. Note that the MySQL c ...

  4. Unable to find the ncurses libraries or the required header files解决

    问题: 解决方法: sudo apt-get install ncurses-dev 参考:Unable to find the ncurses libraries or the required h ...

  5. 编译安装php时提示Cannot find MySQL header files的解决方法

    php的配置文件中有一行--with-mysql=/usr/local/mysql ,安装的时候提示:configure: error: Cannot find MySQL header files ...

  6. [转载]C header files matching your running 

    原文地址:C header files matching your running kernel were not found.作者:[Opser]小默 c header files matching ...

  7. 【linux】安裝 PHP时出现error: Cannot find MySQL header files

    checking for specified location of the MySQL UNIX socket... no checking for MySQL UNIX socket locati ...

  8. Vmware由于centos升级内核不可运行(C header files matching your running kernel were not found)的解决方案

    C header files matching your running kernel were not found. Refer to your distribution's documentati ...

  9. why inline functions must be put in header files?

    [why inline functions must be put in header files?] 编译中有2个过程:compile.link.先进行compile,compile中把源代码编译成 ...

随机推荐

  1. Python爬虫 -- 抓取电影天堂8分以上电影

    看了几天的python语法,还是应该写个东西练练手.刚好假期里面看电影,找不到很好的影片,于是有个想法,何不搞个爬虫把电影天堂里面8分以上的电影爬出来.做完花了两三个小时,撸了这么一个程序.反正蛮简单 ...

  2. 拒绝低调,国内首家推出微软WP8.1移动开发全套免费课程

    活动类型:公开课 开始时间:2014-10-20 20:00 活动地点:YY频道:85155393 课程简介:学习本次公开课你将收获和体会到:      Windwos Phone8.1的推出正是微软 ...

  3. Windows Azure 使用体验

    本文只是对Windows Azure的肤浅使用做个记录,算是简单入门吧. 一.门户网站 Windows Azure其实有两个版本,我们在国内所说的或者说所用的就是有别于国际版的,主要原因我想各位也是知 ...

  4. DOM操作(Window.document对象)

    间隔与延迟: 间隔一段代码: window.setInterval("代码",间隔执行秒数) 延迟一段时间后执行一段代码: window.setTimeout("执行代码 ...

  5. 记一次https访问握手失败(handshake failure)

    文章作者:luxianghao 文章来源:http://www.cnblogs.com/luxianghao/p/6239518.html  转载请注明,谢谢合作. 免责声明:文章内容仅代表个人观点, ...

  6. ucos操作系统的内核有哪些调度方法

    1)时间片轮番调度法 假设系统中有5个任务,T1,T2,T3,T4,T5,这个时候,操作系统为每一个任务分配时间,比如说我们为T1任务分配10毫秒,为T2任务分配20毫秒,为T3任务分配5毫秒,为T4 ...

  7. 转:电子取证中AVI文件的文件雕复

    电子取证中AVI文件的文件雕复 收藏本文 分享 1引言在电子取证工作中,恢复数字设备中被删除的数据是极为重要的工作之一,恢复数据又分依赖系统元信息的传统数据恢复技术和不依赖系统元信息的文件雕刻.文件雕 ...

  8. 【Android开发坑系列】如何让Service尽可能存活

    流行的思路如下[2015-11-20更新]: 1.让Service杀不死.Service的onStartCommand返回START_STICKY,同时onDestroy里面调用startServic ...

  9. Java 模板引擎 jetbrick-template

    jetbrick-template 是一个新一代 Java 模板引擎,具有高性能和高扩展性. 适合于动态 HTML 页面输出或者代码生成,可替代 JSP 页面或者 Velocity 等模板. 指令和 ...

  10. Python的列表推导式

    1.列表推导式书写形式: [表达式 for 变量 in 列表]    或者  [表达式 for 变量 in 列表 if 条件] 2.举例说明: #!/usr/bin/python # -*- codi ...