メニュー、アイコン、バージョン情報の設定 ~ リソースファイルの作成

ここでは、プログラムにアイコン、メニュー及びバージョン情報を付けてみましょう。 出来上がりはこのようになります (赤枠は説明のために描いています。実際のプログラムには含まれません)。


図1. アイコン、メニューがついている

特定のファイルで使用するメニュー、アイコン、バージョン情報、ダイアログボックス等の情報は、 リソースファイル にそれを定義することができます。

後述のようにリソースファイルは、リソース・スクリプト (*.rc) と呼ばれるテキストファイルから作成されます。 アイコンやビットマップなど、バイナリファイルをリソースファイルとは別に用意する必要がある場合もありますが、 メニュー、ダイアログボックス、ストリングテーブルなどは、リソース・スクリプトというテキストファイルを用意し、 それをリソースコンパイラによってコンパイルすることによって作成できます。

手順は次の通りです。

  1. リソースを定義した リソース・スクリプト (*.rc) を記述する
    * リソースファイルは後述の通り普通のテキストファイルです。
    * リソースファイル内で使う定数はヘッダファイルにまとめて記述してください。そうすることによって C のコードから定数が参照できます。
  2. リソース・スクリプトを リソースコンパイラ でコンパイルする
  3. コンパイルの結果作られたコンパイル済みリソース・ファイル (*.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 ファイルを作成します。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説