Windows Programming/資源腳本參考

維基教科書,自由的教學讀本

本篇附錄介紹資源腳本文件(Resource script file)。[1]

一般結構[編輯]

資源腳本文件是人可讀的文本文件,用ANSI或UTF-16小端序帶字節掩碼「BOM」格式。

為支持多語種國際化,對ASNI格式,使用#pragma切換代碼頁。對Unicode格式使用#pragma 切換,而LANGUAGE僅支持Win32。

典型的小文件例子:

#include <windows.h>
#define IDC_STATIC -1

100 ICON "ProgIcon.ico"

10 MENU
{		// or BEGIN
 POPUP "&File"
 {
  MENUITEM "&Exit",IDCANCEL
 }
}		// or END

使用花括號或BEGIN/END都行。Visual Studio資源編輯器總是產生BEGIN/END對。

各種資源的格式為:

id_of_resource  resource_type  [memory management flags]  "filename"

id_of_resource  resource_type  [memory management flags]
BEGIN
 subsequent data
END

上述規則的例外情形:

  • LANGUAGE語句可以放在任何位置(僅限Win32)
  • DIALOGVERSIONINFO資源,在頭行與BEGIN之間還有別的語句。
  • STRINGTABLE資源在關鍵字之前不需要資源ID,但每個資源需要ID前綴

id_of_resourceresource_type可以是字符串或數。這裏不需要引號。數是更好的辨識資源的方法。所有預定的資源的類型都是數。

支持條件預編譯指令 #if / #ifdef / #endif

用於ID的表達式限於非常簡單的數學,不允許布爾運算符。

內部機制[編輯]

資源被編譯為三級目錄結構:

  1. 資源類型 (MENU, DIALOG 等)
  2. 資源ID
  3. 資源所用的語言

讀二進制資源的API函數使用順序示例:

FindResource()		// get a handle
LoadResource()		// get the binary size
LockResource()		// get a pointer; Win32: This is a simple macro 
…			// do something
UnlockResource()	// Win32: This is a do-nothing macro 
FreeResource()		// release

由於bitmap, icon, cursor, dialog, string table, menu資源沒有官方文檔,分析時有點費解,編程者應該使用專門的資源類型的加載函數。詳見下述。

標識符[編輯]

建議以ID為開頭,第三個字母表示資源類型:

  • IDS: A string resource
  • IDM: A menu resource
  • IDC: A command identifier
  • IDD: A dialog box resource
  • IDA: An Accelerator table resource
  • IDI: An Icon or bitmap resource
  • IDB: A Bitmap resource
  • ID: A custom resource, or an uncommon resource type.

有時,菜單中的命令的標識符使用前綴"IDM_",以區分其它資源的命令。

ID允許範圍為0..65535,建議範圍1..32767

LANGUAGE[編輯]

關鍵詞LANGUAGE有不同的作用域:

  • 本地(用於一個資源)如果在資源行之下,例如:
21 MENU
LANGUAGE 7,1 // or, LANG_GERMAN, SUBLANG_GERMAN
{
 POPUP "&Datei"  // = "&File"
 …
  • 全局(適用於所有之下的資源)如果出現在別處:

語言中立資源,如無文化局限的icons, VersionInfo, Manifests 應當設置LANGUAGE 0,0 (或更繁瑣一點 LANG_NETUTRAL,SUBLANG_NEUTRAL)

在一份RC文件中,同一個資源ID在不同語言下可出現多次。

內存管理標誌[編輯]

Win16時代留下了一些內存管理標誌,如MOVEABLE, FIXED等。詳見LocalAlloc()

DISCARDABLE[編輯]

關鍵字DISCARDABLE在32位Windows上被忽略。用於向後兼容。[1]

Icons[編輯]

作業系統使用icon在用戶界面種表示對象如文件、文件夾、快捷、應用程式、文檔等。 作業系統提供了一套標準的icon,在SDK頭文件種以IDI_為前綴定義了其標識符。

Icons在資源文件中用ICON關鍵字聲明。例如:

IDI_ICON<n> ICON [DISCARDABLE] "iconfile.ico"

Windows Explorer使用資源腳本中第一個icon顯示二進制可執行文件。例如,如果有2各icon:

IDI_ICON1 ICON DISCARDABLE "icon1.ico"
IDI_ICON2 ICON DISCARDABLE "icon2.ico"

在對應的resource.h中定義宏:

#define IDI_ICON1 1
#define IDI_ICON2 2

那麼可執行文件以icon1.ico作為icon。

為可執行模塊加載一個icon,假定我們有該實例的句柄(下例hInst),可以得到icon的句柄:

HICON hIcon;
hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));

Icon辨識符一般前綴為"IDI_"表示"ID for an Icon"。

LoadIcon()函數的第二個參數是一個字符串指針。如果該指針的高16位是零,Windows把它當作一個資源數的值,而不是一個字符串。Microsoft提供了宏MAKEINTRESOURCE把16位無符號數轉為字符串指針。當然也可以用字符串來定義一個Icon:

MYICON1 ICON DISCARDABLE "icon1.ico"

可以用名字加載icon:

HICON hIcon;
hIcon = LoadIcon(hInst, "MYICON1");

資源的字符串標識符是大小寫敏感的。

WNDCLASSEX有2個句柄值用於表示2個icon:大icon與小icon。小icon用於應用程式左上角,一般是16個像素正方形。大icon是32個像素正方形。如果不提供小icon,自動從大icon產生小icon。

LoadIcon()函數如果使用NULL實例句柄,則Windows提供缺省icon。

Win32 API已經允許用LoadImage函數加載icon、bitmap、鼠標光標。

二進制可執行文件內部用數值資源類型RT_ICON == 3存儲只有單一圖片的icon,用RT_GROUP_ICON == 14存儲有一組圖片的icon。

Windows使用4種icon尺寸:system small、system large、shell small、shell large。

  1. system small icon:在窗口標題條上顯示。 int cx = GetSystemMetrics(SM_CXSMICON ); int cy = GetSystemMetrics(SM_CYSMICON ); 可獲取其值。一般是16X16。
  2. system large icon:主要用於應用程式,也在Alt+Tab對話框顯示。其尺寸不可更改。 int cx = GetSystemMetrics(SM_CXICON ); int cy = GetSystemMetrics(SM_CYICON ); 可獲取其值。一般是32X32。
  3. shell small icon:用於Windows Explorer與common dialog。默認為system small的尺寸。用 SHGetFileInfo函數與ImageList_GetIconSize函數查詢其尺寸。
  4. shell large icon:用於桌面。用 SHGetFileInfo函數與ImageList_GetIconSize函數查詢其尺寸。

開始菜單使用shell small icons或shell large icons,取決於是否「Use large icons check box」被選中。

應用程式應該在資源中提供下述尺寸的icon:

  • 48x48, 256 color
  • 32x32, 16 color
  • 16x16 pixels, 16 color

位圖[編輯]

資源文件中,位圖定義為:

(bitmap ID or name) BITMAP [DISCARDABLE] "bitmapfile.bmp"

加載位圖使用LoadBitmap函數(也可以用LoadImage函數):

HBITMAP hBmp;
hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));

或者加載用字符串來命名的位圖資源:

hBmp = LoadBitmap(hInst, "MyBitmapRes");

位圖是大型資源,如果加載到內存失敗或者ID或名字值無效,該函數返回值為NULL。因此,使用前應該檢查其句柄是否為空。

卸載位圖用函數DeleteObject函數。

位圖標識符一般以"IDB_"為前綴。

可執行模塊內部,位圖的數值資源類型為RT_BITMAP == 2。

鼠標光標[編輯]

加載鼠標光標使用LoadCursor函數。

可執行模塊內部,鼠標光標的資源數值類型,當為單獨圖像為 RT_CURSOR == 1,一組圖像時為 RT_GROUP_CURSOR == 12。

除了明確指出外部的二進制資源的文件,資源編譯器允許資源文件內聯的二進制數據。例如:

42 ICON
{
 123,4567,0x89AB,0xCDEF
 '\x01','\x23',"ajx"
}

源自Win16的遺產:

  • 十進制或十六進制的數作為未對齊的16位小尾值。
  • 字符作為8位值存儲。

字符串表[編輯]

一個資源腳本文件中可以有多個字符串表。編譯時會自動合併為一個。例子:

STRINGTABLE DISCARDABLE
BEGIN
   IDS_STRING1, "This is my first string"
   IDS_STRING2, "This is my second string"
   ...
END

使用LoadString函數裝入字符串:

int LoadString(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax);

注意該函數可能會返回豐富的警告信息。msdn Windows會在返回的字符串自動以0位元組結尾。

加速鍵[編輯]

菜單[編輯]

版本信息[編輯]

StringFileInfo預定義名稱
名稱 描述
CompanyName 生成文件的公司,例如 "Microsoft Corporation" 或 "Standard Microsystems Corporation,Inc." 此字符串是必需的。
FileDescription 要向用戶顯示的文件說明。 當用戶選擇要安裝的文件時,此字符串可能會顯示在列表框中,例如 "AT-Style 鍵盤的鍵盤驅動程序"。 此字符串是必需的。
FileVersion 文件的版本號,例如 "3.10" 或 "5.00. RC2"。 此字符串是必需的。
InternalName 文件的內部名稱(如果存在)(例如,如果文件為動態連結庫,則為模塊名稱)。 如果該文件沒有內部名稱,則此字符串應為原始文件名,而不包含擴展名。 此字符串是必需的。
LegalCopyright 適用於該文件的版權聲明。 這應包括所有聲明的完整文本、合法符號、版權日期等。 此字符串是可選的。
LegalTrademarks 適用於該文件的商標和註冊商標。 這應包括所有聲明的完整文本、合法符號、商標號等。 此字符串是可選的。
OriginalFilename 文件的原始名稱,不包括路徑。 此信息使應用程式能夠確定文件是否已被用戶重命名。 名稱的格式取決於為其創建該文件的文件系統。 此字符串是必需的。
PrivateBuild 有關文件私有版本的信息(例如,"由 TESTER1 在 TESTBED 上生成 \ ")。 僅當在根塊的 fileflags 參數中指定 VS _ FF _ PRIVATEBUILD 時,才應提供此字符串。
ProductName 用於分發文件的產品的名稱。 此字符串是必需的。
ProductVersion 用於分發該文件的產品的版本,例如 "3.10" 或 "5.00. RC2"。 此字符串是必需的。
SpecialBuild 指示此版本的文件與標準版本的不同之處的文本,例如 "用於 TESTER1 的專用生成解決 M250 和 M250E 計算機上的鼠標問題"。 僅當在根塊的 fileflags 參數中指定 VS _ FF _ SPECIALBUILD 時,才應提供此字符串。
Comments 出於診斷目的應顯示的其他信息

例如:

BLOCK "StringFileInfo"
  BEGIN
      BLOCK "040904E4"
      BEGIN
          VALUE "CompanyName",      "My Company.\0"
          VALUE "FileDescription",  "A Win32 program."
          VALUE "FileVersion",      "1.0.0.0\0"
          VALUE "ProductName",      "The product name.\0"
          VALUE "ProductVersion",   "1.0\0"
          VALUE "LegalCopyright",   "My Company.\0"
      END
  END
  BLOCK "VarFileInfo"
  BEGIN 
      /* 只能有一行,但可以包含一对或多对WORD */
      VALUE "Translation", 0x409, 1252
  END

對話框[編輯]

對話框資源的通用模式:

(Dialog ID or name) DIALOG [DISCARDABLE] x, y, width, height
TITLE "(dialog box title)"
[CLASS "(class name)"]
FONT "(font name)"
BEGIN
   ...
END

如果一個對話框沒有關聯一個CLASS,那麼CLASS域不需要填寫。所有字符串必須用雙引號包含。

一般控件[編輯]

CONTROL classname,windowname,id,left,top,width,height,windowflags

特殊按鈕[編輯]

編輯框[編輯]

Manifests[編輯]

Manifest資源包含UTF-8編碼的XML描述信息,關於作業系統與DLL依賴。

FONT[編輯]

FONTDIR[編輯]

RCDATA[編輯]

MESSAGETABLE[編輯]

定義應用程式的消息表資源的ID與文件。消息表是特殊的字符串資源用於event logging以及FormatMessage函數。文件中包含消息編譯器MC.EXE產生的二進制消息表。[2]

輸入給消息編譯器MC.EXE的message text (.mc) 文件採用語法見[3],例子:

; // ***** Sample.mc *****
; // This is the header section.

MessageIdTypedef=DWORD

SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
Warning=0x2:STATUS_SEVERITY_WARNING
Error=0x3:STATUS_SEVERITY_ERROR
)

FacilityNames=(System=0x0:FACILITY_SYSTEM
Runtime=0x2:FACILITY_RUNTIME
Stubs=0x3:FACILITY_STUBS
Io=0x4:FACILITY_IO_ERROR_CODE
)

LanguageNames=(English=0x409:MSG00409)
LanguageNames=(Japanese=0x411:MSG00411)

; // The following are message definitions.

MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=MSG_BAD_COMMAND
Language=English
You have chosen an incorrect command.
.

Language=Japanese
<Japanese message string goes here>
.

MessageId=0x2
Severity=Warning
Facility=Io
SymbolicName=MSG_BAD_PARM1
Language=English
Cannot reconnect to the server.
.

Language=Japanese
<Japanese message string goes here>
.

MessageId=0x3
Severity=Success
Facility=System
SymbolicName=MSG_STRIKE_ANY_KEY
Language=English
Press any key to continue . . . %0
.

Language=Japanese
<Japanese message string goes here>
.

MessageId=0x4
Severity=Error
Facility=System
SymbolicName=MSG_CMD_DELETE
Language=English
File %1 contains %2 which is in error.
.

Language=Japanese
<Japanese message string goes here>
.

MessageId=0x5
Severity=Informational
Facility=System
SymbolicName=MSG_RETRYS
Language=English
There have been %1!d! attempts with %2!d!%% success%! Disconnect from 
the server and try again later.
.

Language=Japanese
<Japanese message string goes here>
.

TEXTINCLUDE[編輯]

TEXTINCLUDE是一種資源類型。目的是安全地存儲Set Include information,使Visual C++的Set Includes對話框可以表達它們。[4]

Visual C++識別3種特定的TEXTINCLUDE資源,其起源標識數分別是1, 2, 3:

Visual C++識別3種特定的TEXTINCLUDE資源
TEXTINCLUDE resource ID Type of Set Includes information
1 Symbol Header File
2 Read-Only Symbol Directives
3 Compile-Time Directives

用戶定義資源[編輯]

用戶定義資源應當使用更大的資源類型標識符,如RT_RCDATA == 10.

DLGINCLUDE[編輯]

包含菜單、對話框的#define語句的頭文件。資源編輯器使用。

多語言的資源[編輯]

在單個exe文件中可嵌入多種語言的資源。但Visual Studio資源編輯器不支持,所以必須手工編輯。

使用.rc2文件定義資源,因為Visual Studio資源編輯器不會修改它。需要把.rc2存為UTF-16 LE編碼並且以空行結束。

一個MFC項目創建時就有了一個空的.rc2文件。我們稱它為"main" .rc2文件。在main .rc2文件中,對每種語言增加一行#include該語言的.rc2文件:

   #include "lang_en.rc2"
   #include "lang_de.rc2"
   // Restore default language for resources included after current file
   LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL

創建語言相關的.rc2文件。每個文件以該語言的聲明 LANGUAGE <LANGID>, <SUBLANGID> 開始,如lang_en.rc2文件中:

   LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
   STRINGTABLE
   BEGIN
       IDS_STRING1 "Stack Overflow"
       IDS_STRING2 "Stack Overflow is a privately held website, the flagship site of the Stack Exchange Network, created in 2008 by Jeff Atwood and Joel Spolsky."
   END

在文件lang_de.rc2中:

   LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
   STRINGTABLE
   BEGIN
       IDS_STRING1 "Stapelüberlauf"
       IDS_STRING2 "Stack Overflow (englisch für Stapelüberlauf) ist eine Internetplattform, auf der angemeldete Benutzer Fragen zum Thema Softwareentwicklung stellen können."
   END

編譯可執行文件並在資源編輯器中檢查已經包括了多種語言。也可以在Visual Studio打開.exe程序,查看它的資源。

在原始碼中,可以正常加載資源,Windows自動根據當前用戶locale加載對應語言的資源。如果沒有匹配的資源,它會加載英語資源。

也可以用FindResourceEx函數加載明確給出的某種語言的資源,包括標準MFC資源 afxres.h 。

標準MFC資源 如afxres,可以包含在特點語言的.rc2文件中,如:

LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
#ifdef __AFXRES_RC__
   #undef __AFXRES_RC__    // To be able to include multiple language versions of afxres.rc
#endif
#include "l.deu\afxres.rc"  // Standard MFC resources
STRINGTABLE
BEGIN
   IDS_STRING1 "Stapelüberlauf"
   IDS_STRING2 "Stack Overflow (englisch für Stapelüberlauf) ist eine Internetplattform, auf der angemeldete Benutzer Fragen zum Thema Softwareentwicklung stellen können."
END

參考文獻[編輯]

  1. MSDN:Working with Resource Files
  2. MSDN:Message Compiler (MC.exe)
  3. MSDN:Message Text Files
  4. TN035: Using Multiple Resource Files and Header Files with Visual C++