備註
自第一次包含在在線文件中以來,尚未更新下列技術附注。 因此,某些程式和主題可能已過期或不正確。 如需最新信息,建議您搜尋在線檔索引中感興趣的主題。
此附註說明 Visual C++ 資源編輯器如何支援在單一項目中共用或跨多個專案共用的多個資源檔和頭檔,以及如何利用該支援。 此附注會回答下列問題:
何時可能想要將專案分割成多個資源檔及/或標頭檔,以及其執行方式
如何在兩個
.H
檔案間共享一個通用頭.RC
檔呢如何將項目資源分割成多個
.RC
檔案您和工具如何管理
.RC
、.CPP
和.H
檔案之間的組建相依性
您應該注意,如果您將額外的資源檔新增至專案,ClassWizard 將無法辨識新增檔案中的資源。
此附注的結構是用來回答上述問題,如下所示:
Visual C++如何管理資源文件和標頭檔 的概觀,概述Visual C++ 中的 Resource Set Includes 命令如何讓您在同一個專案中使用多個資源檔和標頭檔。
分析由 AppWizard 建立的
.RC
和.H
檔案 會查看 AppWizard 所建立應用程式的多個資源和頭檔。 這些檔案可作為您想要新增至專案之其他資源檔和標頭檔的良好模型。包含其他頭檔 描述您可能想要包含多個頭檔的位置,並提供如何執行此動作的詳細數據。
在兩
.RC
個檔案之間共用頭文件 說明如何在不同專案中的多個.RC
檔案之間共用一個頭檔,或可能在同一個項目中共用。在相同的專案中使用多個資源檔 描述您可能想要將專案分解成多個
.RC
檔案的位置,並提供如何執行此動作的詳細數據。強制執行不可編輯的 Visual C++ 檔案 說明如何確定 Visual C++不會編輯和無意中重新格式化自定義資源。
管理多個 Visual C++編輯
.RC
檔案共用的符號 說明如何跨多個.RC
檔案共用相同的符號,以及如何避免指派重複的標識子數值。管理、
.RC
和.CPP
檔案之間的.H
相依性說明 Visual C++如何避免不必要的重新編譯.CPP
相依於資源符號檔的檔案。Visual C++ 如何管理設置包含訊息,提供有關 Visual C++ 如何追蹤多個(巢狀)
.RC
檔案,以及由.RC
檔案所包含的多個標頭檔的技術詳細資料。
Visual C++如何管理資源文件和標頭檔的概觀
Visual C++會將單 .RC
一資源文件和對應的 .H
頭文件作為緊密結合的檔案組來管理。 當您在檔案中 .RC
編輯和儲存資源時,會間接編輯並儲存對應 .H
檔案中的符號。 雖然您可以一次開啟和編輯多個 .RC
檔案(使用 Visual C++ 的 MDI 使用者介面),但對於任何給定的 .RC
檔案,您會間接編輯一個對應的標頭檔案。
資源視圖的資源包含對話框
若要存取 [資源包含],請開啟 [資源檢視 ],然後以滑鼠右鍵按兩下 .RC
檔案,然後選取 [ 資源包含]。
符號頭檔
根據預設,Visual C++一律會命名對應的頭檔,不論資源文件 RESOURCE.H
的名稱為何(例如, MYAPP.RC
)。 Visual C++ [資源包含] 對話方塊中的 [符號頭檔:] 區段可讓您變更此頭文件的名稱。 在區段的編輯方塊中輸入新的檔名。
備註
資源檔未位於與 .RC
檔案相同的目錄時,必須在相對路徑前加上逃脫的 '\',才能正確地被讀取。
Read-Only 符號指令
雖然 Visual C++ 只會編輯任意指定 .RC
檔案的一個標頭檔,但 Visual C++ 支援引用在其他唯讀標頭檔中定義的符號。 在 [資源包含] 對話框中,[Read-Only 符號指令:] 區段可讓您將任意數量的其他唯讀標頭檔指定為 Read-Only 符號指令。 「唯讀」限制表示當您在檔案中 .RC
新增資源時,可以使用唯讀頭檔中定義的符號。 不過,如果您刪除資源,符號仍會保留在唯讀頭檔中作為定義。 您無法變更指派給唯讀符號的數值。
Compile-Time 指令
Visual C++也支援資源檔的巢狀結構,其中一個 .RC
檔案會使用 #include
指示詞包含在另一個檔案內。 當您使用 Visual C++ 編輯指定的 .RC
檔案時,不會顯示內含檔案中的任何資源。 但是當您編譯檔案 .RC
時,也會編譯包含的檔案。 [資源包含] 對話框中的 [Compile-Time 指示詞:] 區段可讓您指定要包含為 Compile-Time 指示詞的任何.RC
數目檔案。
請注意,如果您將一個 .RC
檔案讀入 Visual C++,並且該檔案包含了另一個 .RC
檔案,但未指定為 Compile-Time 指示詞,會發生什麼事。 當您將一個先前以文字編輯器手動維護的檔案帶入 Visual C++ 時,可能會發生這種情況。 當 Visual C++讀取包含 .RC
的檔案時,它會將包含的資源合併到父 .RC
檔案中。 當您儲存父 .RC
檔案時, #include
語句實際上會由包含的資源取代。 如果您不希望進行此合併,您應該先從父#include
檔案中移除.RC
語句,然後用 Visual C++ 將其讀入;接下來使用 Visual C++,以 Compile-Time 指令形式新增回相同的語句。
Visual C++會將上述三種集合包含資訊(符號頭檔、Read-Only 指示詞,以及 Compile-Time 指示詞)儲存在.RC
檔案中#include
指示詞和資源TEXTINCLUDE
中。 在TEXTINCLUDE
中解釋了資源,這是您通常不需要處理的實作細節。
分析 AppWizard 建立 .RC
和 .H
檔案
檢查 AppWizard 所產生的應用程式程式碼,可讓您深入瞭解 Visual C++如何管理多個資源檔和頭檔。 以下所檢查的程式代碼摘錄來自 MYAPP
使用預設選項由 AppWizard 所產生的應用程式。
AppWizard 建立的應用程式會使用多個資源檔和多個頭檔,如下圖所示:
RESOURCE.H AFXRES.H
\ /
\ /
MYAPP.RC
|
|
RES\MYAPP.RC2
AFXRES.RC
AFXPRINT.RC
您可以使用 Visual C++ File/Set Includes 命令來檢視這些多個檔案關聯性。
MYAPP.RC
您使用 Visual C++ 編輯的應用程式資源檔案。
RESOURCE.H
是應用程式特定的頭檔。 它一律由 AppWizard 命名 RESOURCE.H
,與 Visual C++頭文件的預設命名一致。
#include
此標頭檔案在資源檔案(MYAPP.RC
)中的首個陳述式:
//Microsoft Visual C++ generated resource script
//
#include "resource.h"
RES\MYAPP.RC2
包含 Visual C++ 不會編輯的資源,但會包含在最終編譯 .EXE
的檔案中。 AppWizard 預設不會建立這類資源,因為Visual C++可以編輯所有標準資源,包括版本資源(此版本中的新功能)。 如果您想要將自己的自定義格式化資源新增至此檔案,AppWizard 會產生空白檔案。
如果您使用自訂格式化的資源,您可以使用 Visual C++ 文字編輯器來新增 RES\MYAPP.RC2
和編輯它們。
AFXRES.RC
和 AFXPRINT.RC
包含架構特定功能所需的標準資源。 如 RES\MYAPP.RC2
,這兩個由框架提供的資源檔案會包含在 MYAPP.RC
的結尾,並且會在 [集合包含] 對話框中指定 [Compile-Time 指令]。 因此,當您在 Visual C++ 中編輯 MYAPP.RC
時,您不會直接檢視或編輯這些架構資源,但它們會編譯成應用程式的二進位 .RES
檔和最終 .EXE
檔案。 如需標準架構資源的詳細資訊,包括修改它們的程式,請參閱 技術附註 23。
AFXRES.H
定義標準符號,例如 ID_FILE_NEW
架構所使用的 ,並特別用於 AFXRES.RC
。
AFXRES.H
也會使用 #include
來包含 WINRES.H
,其中包含 WINDOWS.H
的子集,這些子集是 Visual C++ 產生的 .RC
檔案和 AFXRES.RC
所需的。 當您編輯應用程式資源檔案 (AFXRES.H
) 時,可以使用 中MYAPP.RC
定義的符號。 例如, ID_FILE_NEW
是用於 File
檔案功能表資源中的 New
MYAPP.RC
功能表項。 您無法變更或刪除這些架構定義的符號。
包含其他標頭檔案
AppWizard 建立的應用程式只包含兩個標頭檔: RESOURCE.H
和 AFXRES.H
。 只有 RESOURCE.H
應用程式專屬。 在下列情況下,您可能需要包含其他唯讀標頭檔案:
頭檔是由外部來源提供,或者您想要在多個專案或相同專案的多個部分之間共用頭檔。
標頭檔案具有您不希望Visual C++在儲存檔案時變更或篩選掉的格式和批註。 例如,您可能想要保留使用符號算術的 #define,例如:
#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)
您可以使用 Resource Includes 命令,將語句 #include
指定為 Read-Only 符號指令的第二項,以包含其他只讀頭檔,如下列所示:
#include "afxres.h"
#include "second.h"
現在新的檔案關聯圖看起來像這樣:
AFXRES.H
RESOURCE.H SECOND.H
\ /
\ /
MYAPP.RC
|
|
RES\MYAPP.RC2
AFXRES.RC
AFXPRINT.RC
在兩個 .RC
檔案之間共享標頭檔案
您可能想要在不同專案的兩個 .RC
檔案之間共用頭檔,或者在相同專案中共用。 若要這樣做,請將上述的 Read-Only 指示詞技術套用至這兩個 .RC
檔案。 在兩 .RC
個檔案適用於不同應用程式(不同項目)的情況下,下圖說明結果:
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
下面將討論第二個頭檔由相同應用程式 (專案) 中的兩個 .RC
檔案共享的情況。
在相同的專案中使用多個資源檔
Visual C++ 和資源編譯程式透過.RC
指示詞支援相同專案中的多個#include
檔案,這些指示詞包含另一個.RC
檔案。 允許多重嵌套。 有各種理由將項目的資源分割成多個 .RC
檔案:
如果您將資源分割成多個
.RC
檔案,就能更輕鬆地管理多個專案小組成員之間的大量資源。 如果您使用原始檔控制管理套件來簽出檔案和簽入變更,請將資源分割成多個.RC
檔案,可讓您更精細地控制管理資源的變更。如果您要針對資源部分使用預處理器指示詞,例如
#ifdef
、#endif
和#define
,您必須將它們隔離在資源編譯程式所編譯的唯讀資源中。元件
.RC
檔案會在 Visual C++中載入並儲存速度比一個複合.RC
檔案更快。如果您希望以人類可讀的形式,使用文本編輯器維護資源,您應該將其保存在一個與 Visual C++ 編輯的檔案分開的
.RC
檔案中。如果您需要將使用者定義資源保留在另一個特製化數據編輯器可解譯的二進位或文字窗體中,則您應該將它保留在個別
.RC
的檔案中,讓 Visual C++不會將格式變更為十六進位數據。.WAV
MFC 進階概念範例 SPEAKN 中的 (sound) 檔案資源是很好的範例。
您可以在 [設定包含] 對話框中的 [Compile-Time 指示詞] 中加入 SECOND.RC
。
#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
下圖說明結果:
RESOURCE.H AFXRES.H
\ /
\ /
MYAPP.RC
|
|
RES\MYAPP.RC2
SECOND.RC
AFXRES.RC
AFXPRINT.RC
使用 Compile-Time 指示詞,您可以將 Visual C++可編輯和不可編輯的資源組織成多個 .RC
檔案,其中 main MYAPP.RC
不會 #include
執行其他 .RC
檔案。 如果您使用 Visual Studio C++項目 .MAK
檔,則您應該在專案中包含主要 .RC
檔案,讓所有內含的資源都與您的應用程式一起編譯。
強制執行不可編輯的 Visual C++ 檔案
AppWizard 所建立的 RES\MYAPP.RC2
檔案是您不想不小心讀入 Visual C++ 並且在格式資訊遺失的情況下寫回的資源檔案範例。 若要防範此問題,請將下列幾行放在檔案開頭 RES\MYAPP.RC2
:
#ifdef APSTUDIO_INVOKED
#error this file is not editable by Visual C++
#endif //APSTUDIO_INVOKED
當 Visual C++編譯 .RC
檔案時,它會同時定義 APSTUDIO_INVOKED
和 RC_INVOKED
。 如果 AppWizard 建立的檔案結構已損毀,且 Visual C++會讀取上述 #error 行,則會報告嚴重錯誤並中止讀取 .RC
檔案。
管理多個 Visual C++編輯 .RC
檔案共用的符號
當您將資源分割成 .RC
多個您想要在 Visual C++中個別編輯的檔案時,就會發生兩個問題:
您可能想要跨多個
.RC
檔案共用相同的符號。您需要協助 Visual C++避免將相同的識別子數值指派給不同的資源(符號)。
下圖說明 .RC
和 .H
檔案的組織,以解決第一個問題:
MYAPP.RC
/ \
/ \
MYSTRS.H / MYSHARED.H \ MYMENUS.H
\ / / \ \ \
\ / / \ \ \
MYSTRS.RC MYMENUS.RC
在這裡範例中,字串資源會保留在一個資源檔案中,MYSTRS.RC
而選單則保留在另一個 資源檔案中。 MYMENUS.RC
某些符號,例如命令,可能需要在兩個檔案之間共用。 例如,ID_TOOLS_SPELL
可能是工具功能表中拼字項目的命令標識符;它也可能是應用程式主視窗狀態欄中架構顯示的指令提示的字串標識碼。
符號ID_TOOLS_SPELL
會保留在共享頭檔中。 MYSHARED.H
您可以使用文字編輯器手動維護此共享頭檔;Visual C++不會直接編輯它。 在先前提到過的 Read-Only 指令中,使用 MYSTRS.RC
命令為 MYMENUS.RC
指定 #include "MYSHARED.H"
,包含在兩個資源檔案MYAPP.RC
和中。
在您嘗試使用符號來識別任何資源之前,最好先預想您要共享的符號。 將符號新增至共享頭檔,且如果您尚未在.RC
檔案的Read-Only指令中包含共享頭檔,請在使用符號之前執行此動作。 如果您未預期以這種方式共享符號,則必須手動(使用文字編輯器)將符號的 #define 語句從 MYMENUS.H
MYSHARED.H
移至 ,再將其用於 MYSTRS.RC
。
當您管理多個 .RC
檔案中的符號時,也必須協助Visual C++避免將相同的標識碼數值指派給不同的資源(符號)。 對於任意的 .RC
檔案,Visual C++ 會逐步在四個標識符領域中指派標識符。 在編輯會話期間,Visual C++ 會追蹤 .RC
文件符號標頭檔案中各個網域指派的最後一個標識符。 以下是空的(新的)APS_NEXT
檔案的 .RC
值:
#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
是下一個符號值,將用於對話框資源、功能表資源等等。 資源符號值的有效範圍是 1 到 0x6FFF。
_APS_NEXT_COMMAND_VALUE
是下一個將用於命令識別的符號值。 命令符號值的有效範圍是0x8000至0xDFFF。
_APS_NEXT_CONTROL_VALUE
是下一個將用於對話框控件的符號值。 對話框控件符號值的有效範圍是8到 0xDFFF。
_APS_NEXT_SYMED_VALUE
是當您使用 [符號瀏覽器] 中的 [新增] 命令手動指派符號值時,將會發出的下一個符號值。
建立新 .RC
檔案時,Visual C++會從略高於最低合法值的值開始。 AppWizard 也會將這些值初始化為更適合 MFC 應用程式的值。 如需標識碼值範圍的詳細資訊,請參閱 技術附註 20。
現在,每次您建立新的資源檔,即使在相同的專案中,Visual C++也會定義相同的 _APS_NEXT_
值。 這表示,如果您在兩個不同的 .RC
檔案中新增多個對話框,很可能將相同的 #define 值指派給不同的對話。 例如,IDD_MY_DLG1
在第一個.RC
檔案中,可能會被指派與第二個IDD_MY_DLG2
檔案中的.RC
相同的編號 101。
若要避免此問題,您應該針對個別 .RC
檔案中的四個標識元定義域,保留個別的數值範圍。 在您開始新增資源_APS_NEXT
,請手動更新每個.RC
檔案中的值,以設定範圍。 例如,如果第一個 .RC
檔案使用預設值 _APS_NEXT
,您可能會想要將下列 _APS_NEXT
值指派給第二個 .RC
檔案:
#define _APS_NEXT_RESOURCE_VALUE 2000
#define _APS_NEXT_COMMAND_VALUE 42000
#define _APS_NEXT_CONTROL_VALUE 2000
#define _APS_NEXT_SYMED_VALUE 2000
當然,Visual C++仍可能會在第一個 .RC
檔案中指派過多的標識符,使得數值開始與保留給第二個 .RC
檔案的標識符重疊。 您應該保留足夠大的範圍,以免發生此衝突。
管理.RC
、.CPP
和 .H
檔案之間的相依性
當 Visual C++ 儲存 .RC
檔案時,也會將符號變更儲存至對應的 RESOURCE.H
檔案。 參考.CPP
檔案中資源的任何.RC
檔案都必須使用#include
來包含RESOURCE.H
檔案,這通常是在專案的主要標頭檔案中進行。 因為開發環境的內部專案管理會掃描原始程序檔中的標頭相依性,因此這種包含會導致不良副作用。 每次在 Visual C++中新增符號時,都必須重新編譯具有 .CPP
指示詞的所有#include "RESOURCE.H"
檔案。
Visual C++,透過將下列註解納入為檔案RESOURCE.H
的第一行來規避對RESOURCE.H
的相依性。
//{{NO_DEPENDENCIES}}
開發環境通過忽略對 RESOURCE.H
的更改來解釋此註釋,以便相依的 .CPP
檔案不需要重新編譯。
Visual C++儲存檔案時,會一律將//{{NO_DEPENDENCIES}}
批注行新增至.RC
檔案。 在某些情況下,規避對RESOURCE.H
的編譯依賴可能會導致在連結時未被偵測到的執行時錯誤。 例如,如果您使用符號瀏覽器來變更指派給資源符號的數值,則如果 .CPP
參考資源的檔案未重新編譯,將無法正確找到資源,並在應用程式運行時間載入資源。 在這種情況下,您應明確重新編譯您知道會受到符號變更 .CPP
影響的任何 RESOURCE.H
檔案,或選擇 全部重建。 如果您需要經常變更特定資源組的符號值,您可能會發現,將這些符號分隔到一個單獨的只讀標頭檔案中,更為方便且安全,如上述章節< c0>新增標頭檔案中所述。
Visual C++如何管理集合包含資訊
如上所述,[檔案] 選單 [包括] 命令可讓您指定三種類型的資訊:
符號頭檔
Read-Only 符號指令
Compile-Time 指令
下表說明 Visual C++ 如何在 .RC
檔案中維護這項資訊。 您不需要此資訊來使用 Visual C++,但可能會增強您的瞭解,以便更自信地使用 [設定包含] 功能。
上述三種類型的 Set Include 資訊會以兩種形式儲存在檔案中 .RC
:(1) 作為 #include
或資源編譯程式可解譯的其他指示詞,而 (2) 則為只有 Visual C++ 可解譯的特殊 TEXTINCLUDE
資源。
資源的目的是TEXTINCLUDE
在 Visual C++ 的 Set Includes 對話框中安全地儲存集合包含資訊,使其可隨時展示。
TEXTINCLUDE
是 Visual C++所定義的 資源類型 。 Visual C++可辨識具有資源標識符 1、2 和 3 的三個特定 TEXTINCLUDE
資源:
TEXTINCLUDE 資源標識碼 |
集合類型包含資訊 |
---|---|
1 | 符號頭檔 |
2 | Read-Only 符號指令 |
3 | Compile-Time 指令 |
這三種類型的 Set Includes 資訊都說明 AppWizard 所建立的預設 MYAPP.RC
和 RESOURCE.H
檔案,如下所述。 RC 語法需要在 \0
和 ""
區塊之間的額外 BEGIN
和 END
標記,才能分別指定零結束字元串和雙引號字元。
符號頭檔
資源編譯程式解譯的符號頭文件資訊形式只是語句 #include
:
#include "resource.h"
對應的 TEXTINCLUDE
資源為:
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
Read-Only 符號指令
在下面的形式中,Read-Only 符號指示詞被包含在資源編譯程式可解譯的最上方 MYAPP.RC
。
#include "afxres.h"
對應的 TEXTINCLUDE
資源為:
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
Compile-Time 指令
Compile-Time 指令被包括在 MYAPP.RC
的結尾部分,以下格式由資源編譯器可解譯:
#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
#ifndef APSTUDIO_INVOKED
指令會指示 Visual C++ 略過 Compile-Time 指令。
對應的 TEXTINCLUDE
資源為:
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