[[Page001]]

* Application class の作成 [#q5632480]
Program の規模が大きくなると、module化が必要である。ここでは C++ を使っているので、class化を考える。まずは、application 全体にわたる object を保持する class を考える。

** Resource file の導入 [#iae1cd29]
前節の概要を見てわかるように、application が起動すると、system から instance の handle が渡される。ここで考える class の第一の目的は、この handle の隠蔽である。

この instance handle は application と結び付けられた resource との橋渡しも行ってくれる。特に言語など、環境依存の部分は resource に押し込めると、開発や保守がやりやすくなる。まずは、resouce file を用意しよう。

とりあえず必要なのは、前節で define 文を使って固定している Window class の名前と、title の文字列である。Resource file では STRINGTABLE を使って与える。また、割り当てには identifier 番号を付ける必要があるので、その番号を記した file を resource.h として用意する(このあたりは Microsoft Visual Studio を模す)。番号は、16 bit 整数であればよい(はずである)が、後でicon や menu なども割り付けるので、適当な大きい数にしておく。

まずは resouce.h
 // resource.h
 
 #ifndef RESOURCE_H_INCLUDED
 #define RESOURCE_H_INCLUDED
 
 #define IDS_MY_WINCLASS		1025
 #define IDS_MY_APPTITLE		1026
 
 #endif	// RESOURCE_H_INCLUDED


次に、resource file として、myapp.rc を用意する。
 // myapp.rc
 
 #include "resource.h"
 
 // String Table
 STRINGTABLE
 BEGIN
 	IDS_MY_WINCLASS	"MyAppWin"
 	IDS_MY_APPTITLE	"My Application"
 END

MinGW での resource file の compile には windres を用いる。
 windres myapp.rc -o res.o

** CMyApp class の導入 [#v2c1b1b6]
さて、CMyApp class であるが、constructor で Window class名や title 文字列を取得した後、Window class の登録まで行うものとしよう。

ここで、WndProc の取扱いが問題になる。汎用 Window class を作ることも考えられるが、この application では基底となる window は一つとし、CMyApp class で取り扱うものとしよう。

また、基底となる window の生成、及び message loop は CMyApp class に Run() という関数を用意して、これを呼び出すものとしよう。Contructor でいきなり window まで作ってしまうことの考えられるが、戻り値が必要なことや、初期化段階でのエラーと実行段階でのエラーを区別してよいた方がよかろうということから、ここでは Run() 関数を用意する。
また、基底となる window の生成、及び message loop は CMyApp class に Run() という関数を用意して、これを呼び出すものとしよう。Contructor でいきなり window まで作ってしまうことも考えられるが、戻り値が必要なことや、初期化段階でのエラーと実行段階でのエラーを区別してよいた方がよかろうということから、ここでは Run() 関数を用意する。

まずは myapp.h
 // myapp.h
 
 #ifndef MYAPP_H_INCLUDED
 #define MYAPP_H_INCLUDED
 
 class CMyApp
 {
 private:
 	static const int MAX_LOAD_STRING = 256;
 	static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 
 public:
 	CMyApp(HINSTANCE hInstance, HINSTANCE hPrevInstance);
 	~CMyApp();
 	int Run(int nCmdShow);
 
 public:
 	HINSTANCE m_hInstance;
 
 private:
 	TCHAR m_szWinClass[(MAX_LOAD_STRING+1)];
 	TCHAR m_szAppTitle[(MAX_LOAD_STRING+1)];
 };
 
 #endif	// MYAPP_H_INCLUDED

続いて、myapp.cpp
 #include <windows.h>
 #include <tchar.h>
 #include "resource.h"
 #include "myapp.h"
 
 CMyApp::CMyApp(HINSTANCE hInstance, HINSTANCE hPrevInstance)
 {
 	// Save the instance handle
 	m_hInstance = hInstance;
 
 	// Load the strings
 	int nChar;
 	nChar = LoadString(hInstance, IDS_MY_WINCLASS, m_szWinClass, MAX_LOAD_STRING);
 	m_szWinClass[nChar] = 0;
 	nChar = LoadString(hInstance, IDS_MY_APPTITLE, m_szAppTitle, MAX_LOAD_STRING);
 	m_szAppTitle[nChar] = 0;
 
 	// Register the Window Class
 	if(hPrevInstance == 0)
 	{
 		WNDCLASSEX wcex;
 		wcex.cbSize = sizeof(WNDCLASSEX);
 		wcex.style = CS_HREDRAW | CS_VREDRAW;
 		wcex.lpfnWndProc = WndProc;
 		wcex.cbClsExtra = 0;
 		wcex.cbWndExtra = 0;
 		wcex.hInstance = hInstance;
 		wcex.hIcon = LoadIcon(0, IDI_APPLICATION);
 		wcex.hCursor = LoadCursor(0, IDC_ARROW);
 		wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
 		wcex.lpszMenuName = 0;
 		wcex.lpszClassName = m_szWinClass;
 		wcex.hIconSm = LoadIcon(0, IDI_APPLICATION);
 		RegisterClassEx(&wcex);
 	}
 }
 
 CMyApp::~CMyApp()
 {
 }
 
 LRESULT CALLBACK 
 CMyApp::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 	switch(message)
 	{
 	case WM_DESTROY:
 		PostQuitMessage(0);
 		break;
 	default:
 		return DefWindowProc(hWnd, message, wParam, lParam);
 	}
 	return 0;
 }
 
 int
 CMyApp::Run(int nCmdShow)
 {
 	// Create Window
 	HWND hWnd = CreateWindow(m_szWinClass, m_szAppTitle, WS_OVERLAPPEDWINDOW,
 		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, m_hInstance, 0);
 	if(!hWnd)
 		return 0;
 	ShowWindow(hWnd, nCmdShow);
 	UpdateWindow(hWnd);
 	
 	// Enter Message Loop
 	MSG msg;
 	while(GetMessage(&msg, 0, 0, 0))
 	{
 		TranslateMessage(&msg);
 		DispatchMessage(&msg);
 	}
 	return (int)msg.wParam;
 }

** Main program [#qfb6cffb]
これで一応 CMyApp class ができたので、前節の myapp01.cpp を myapp02.cpp として書き換えてみる。

 #include <windows.h>
 #include <tchar.h>
 #include "myapp.h"
 
 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 	LPSTR lpCmdLine, int nCmdShow)
 {
 	// Create my application
 	CMyApp app(hInstance, hPrevInstance);
 	return app.Run(nCmdShow);
 }

** Compile と link [#k02a9ada]
Compile と link は
 windres myapp.res -o res.o
 g++ -Wall -mwindows myapp02.cpp myapp.cpp res.o -o myapp02.exe
である。makefile を作る手もあるが、この程度であれば、上記内容を build.bat とでもしておいてもよい。

ここまでのファイル
- myapp02.cpp
- resource.h
- myapp.res
- myapp.cpp
- myapp.h
- build.bat

を tar と gzip で固めたものを、このページに &ref("myapp02.tgz"); として添付しておく。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS