メニュー、アイコン、バージョン情報の設定 ~ リソースファイルの作成
ここでは、プログラムにアイコン、メニュー及びバージョン情報を付けてみましょう。 出来上がりはこのようになります (赤枠は説明のために描いています。実際のプログラムには含まれません)。
図1. アイコン、メニューがついている
特定のファイルで使用するメニュー、アイコン、バージョン情報、ダイアログボックス等の情報は、 リソースファイル にそれを定義することができます。
後述のようにリソースファイルは、リソース・スクリプト (*.rc) と呼ばれるテキストファイルから作成されます。 アイコンやビットマップなど、バイナリファイルをリソースファイルとは別に用意する必要がある場合もありますが、 メニュー、ダイアログボックス、ストリングテーブルなどは、リソース・スクリプトというテキストファイルを用意し、 それをリソースコンパイラによってコンパイルすることによって作成できます。
手順は次の通りです。
- リソースを定義した リソース・スクリプト (*.rc) を記述する
* リソースファイルは後述の通り普通のテキストファイルです。
* リソースファイル内で使う定数はヘッダファイルにまとめて記述してください。そうすることによって C のコードから定数が参照できます。 - リソース・スクリプトを リソースコンパイラ でコンパイルする
- コンパイルの結果作られたコンパイル済みリソース・ファイル (*.res) をプログラムのビルド時にリンクする
では、まずプログラムを作りましょう。
次の内容を resource.rc として保存します。この例では日本語を扱いますので、ファイル形式を Unicode で保存 することに注意してください。 (Windows のメモ帳で保存するなら、保存ダイアログでファイル名を決めるときにファイル形式も指定することが出来ます. Unicode を選択してください)
#include <windows.h> #include "resource.h" // // Version Information // 1 VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_PRODUCTVERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS ( VER_DEBUG | VER_PRIVATE ) FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", VER_STR_COMMENTS VALUE "CompanyName", VER_STR_COMPANYNAME VALUE "FileDescription", VER_STR_FILEDESCRIPTION VALUE "FileVersion", VER_STR_FILEVERSION VALUE "InternalName", VER_STR_INTERNALNAME VALUE "OriginalFileName", VER_STR_ORIGINALFILENAME VALUE "LegalCopyright", VER_STR_LEGALCOPYRIGHT VALUE "ProductName", VER_STR_PRODUCTNAME VALUE "ProductVersion", VER_STR_PRODUCTVERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END // // Icon // IDI_APP ICON "app.ico" // // Menu // IDR_MENU_MAIN MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "開く(&O)...", IDM_FILE_OPEN MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_FILE_EXIT END POPUP "ヘルプ(&H)" BEGIN MENUITEM "バージョン情報(&A)...", IDM_HELP_ABOUT END END
次の内容を resource.h として保存します。
#pragma once // Application Data #ifdef DEBUG #define VER_DEBUG VS_FF_DEBUG #define VER_PRIVATE VS_FF_PRIVATEBUILD #else #define VER_DEBUG 0 #define VER_PRIVATE 0 #endif #define VER_STR_COMMENTS "Windows Programming Primer Sample Program" #define VER_STR_COMPANYNAME "keicode.com" #define VER_STR_FILEDESCRIPTION "Windows Programming Primer Sample Program" #define VER_FILEVERSION 1,0,0,1 #define VER_STR_FILEVERSION "1,0,0,1" #define VER_STR_INTERNALNAME "Sample Program - Simple" #define VER_STR_ORIGINALFILENAME "simple.exe" #define VER_STR_LEGALCOPYRIGHT "(C) 2008 Dadosan All Rights Reserved" #define VER_STR_PRODUCTNAME "Windows Programming Primer Samples" #define VER_PRODUCTVERSION 1,0,0,0 #define VER_STR_PRODUCTVERSION "1,0,0,0" // Icon ID #define IDI_APP 100 // Resource ID #define IDR_VERSION_INFO 1000 #define IDR_MENU_MAIN 1001 // Menu Item ID #define IDM_FILE_OPEN 2000 #define IDM_FILE_EXIT 2001 #define IDM_HELP_ABOUT 2100
また任意のアイコンファイル (*.ico) を同じディレクトリに app.ico という名前で保存してください。
アイコンファイルがない人は、こちらからダウンロードしてください。
前回作成した simple.cpp を次のように変更します。赤でマークしたところが変更点です。
#include <windows.h> #include "resource.h" #define WND_CLASS_NAME TEXT("My_Window") LRESULT CALLBACK WindowProc( HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam); HWND g_hWnd; int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { HWND hWnd; WNDCLASSEX wcl; wcl.cbSize = sizeof(WNDCLASSEX); wcl.hInstance = hInstance; wcl.lpszClassName = WND_CLASS_NAME; wcl.lpfnWndProc = WindowProc; wcl.style = NULL; wcl.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APP)); wcl.hIconSm = NULL; wcl.hCursor = LoadCursor(NULL, IDC_ARROW); wcl.lpszMenuName = MAKEINTRESOURCE (IDR_MENU_MAIN); wcl.cbClsExtra = 0; wcl.cbWndExtra = 0; wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); if(!RegisterClassEx(&wcl)) { return FALSE; } ...(以下全く同様のため省略)...
makefile は次の通りです。リソース・ファイルをコンパイル、リンクする箇所が追加されています。
LINK32=link.exe TARGETNAME=simple OUTDIR=.\chk ALL : "$(OUTDIR)\$(TARGETNAME).exe" "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" # compile CPPFLAGS=\ /nologo\ /MT\ /W3\ /Fo"$(OUTDIR)\\"\ /Fd"$(OUTDIR)\\"\ /c\ /Zi\ /DWIN32\ /DUNICODE\ /D_UNICODE\ #link LINK32_FLAGS=\ user32.lib\ gdi32.lib\ /nologo\ /subsystem:windows\ /pdb:"$(OUTDIR)\$(TARGETNAME).pdb"\ /machine:I386\ /out:"$(OUTDIR)\$(TARGETNAME).exe"\ /DEBUG\ /RELEASE LINK32_OBJS= \ "$(OUTDIR)\$(TARGETNAME).obj"\ "$(OUTDIR)\resource.res" #resource compiler RFLAGS=/l 0x411 /fo"$(OUTDIR)\resource.res" /d DEBUG "$(OUTDIR)\$(TARGETNAME).exe" : "$(OUTDIR)" $(LINK32_OBJS) $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS) .cpp{$(OUTDIR)}.obj: $(CPP) $(CPPFLAGS) $< .rc{$(OUTDIR)}.res: $(RC) $(RFLAGS) $<
上記のファイル (simple.cpp, resource.rc, resource.h, app.ico, makefile) をひとつのディレクトリに保存し、 Visual Studio コマンドプロンプトから nmake してください。これで実行可能なプログラムがビルドできるはずです。
> nmake -a Microsoft (R) Program Maintenance Utility Version 9.00.30729.01 Copyright (C) Microsoft Corporation. All rights reserved. if not exist ".\chk/" mkdir ".\chk" cl /nologo /MT /W3 /Fo".\chk\\" /Fd".\chk\\" /c /Zi /DWIN32 /DUNICODE /D_UNICODE "simple.cpp" simple.cpp rc /l 0x411 /fo".\chk\resource.res" /d DEBUG "resource.rc" Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1 Copyright (C) Microsoft Corporation. All rights reserved. link.exe user32.lib gdi32.lib /nologo /subsystem:windows /pdb:".\chk\simple.pdb" /machine:I386 /out:".\chk\simple.exe" /DEBUG /RELEASE ".\chk\simple.obj" ".\chk\resource.res"
上記、黄色でマークした箇所で、リソース・スクリプトがコンパイル・リンクされていることがわかります。
それでは、ここで新しく登場したリソーススクリプトを見て行きましょう。
よくある質問と答え
Q: 次のように「予期せずにファイルが終了した」というエラーが発生した。
resource.h(34) : fatal error RC1004: unexpected end of file found
A: ヘッダファイルの最後に一行空白行を入れるだけで、問題が解決することがあります。
リソースファイル
上で出てきた resource.rc を上から順にみていきます。
#include <windows.h> #include "resource.h"
まずはいつも通り windows.h ヘッダーをインクルードします。windows.h をインクルードすることで、 必要となる各種ヘッダファイルが取り込まれます。
resource.h は上に示したとおり、各種定数が define されているだけです。 各種リソースに ID を振る必要があるときは、数字を適当に決めて ID を決めてください。 会社名、製品名をあらわす文字列は適当に変更して使ってください。
次はバージョン情報です。バージョン情報は VERSIONINFO リソース に記載されています。 VERSIONINFO リソースは次のような構成になります。
// // Version Information // 1 VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_PRODUCTVERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS ( VER_DEBUG | VER_PRIVATE ) FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", VER_STR_COMMENTS VALUE "CompanyName", VER_STR_COMPANYNAME VALUE "FileDescription", VER_STR_FILEDESCRIPTION VALUE "FileVersion", VER_STR_FILEVERSION VALUE "InternalName", VER_STR_INTERNALNAME VALUE "OriginalFileName", VER_STR_ORIGINALFILENAME VALUE "LegalCopyright", VER_STR_LEGALCOPYRIGHT VALUE "ProductName", VER_STR_PRODUCTNAME VALUE "ProductVersion", VER_STR_PRODUCTVERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END
これがファイルのバージョン情報になります。エクスプローラで右クリックしたときに見える、あれです。 特にこれの書き方でパフォーマンスが向上するというものでもありませんし、ほぼ決まりきった書き方になります。 ですから、「なるほどファイルのバージョン情報はリソースファイルで、こうして定義するんだ」とわかっていただければ十分です。
ご自身のプログラムで使用する場合は、resource.h で定義されている、VER_STR_COMPANYNAME などの文字列を、 適当に変更して使ってください。
// // Icon // IDI_APP ICON "app.ico"
アイコンは ICON リソースに、ファイル名を書くだけです。 この行の IDI_APP はヘッダーファイルに定数として定義されています。
メニューは MENU リソースです。 ここでもやはり、IDR_MENU_MAIN はヘッダーファイルで定義されている定数です。
// // Menu // IDR_MENU_MAIN MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "開く(&O)...", IDM_FILE_OPEN MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_FILE_EXIT END POPUP "ヘルプ(&H)" BEGIN MENUITEM "バージョン情報(&A)...", IDM_HELP_ABOUT END END
メニュー項目一つ一つは MENUITEM として記述します。 MENUITEM に付記されている IDM_FILE_OPEN, IDM_FILE_EXIT, IDM_HELP_ABOUT は ヘッダーファイルで定義されている定数です。
上記のリソーススクリプトをリソースコンパイラでコンパイルすると、 コンパイル済みリソースファイル (*.res) が出来上がります。
*.res ファイルを *.obj ファイルと共にリンクすると、最終的な *.exe ファイルを作成します。