[[Page002]]

* Document class の作成 [#l96b3717]
Microsoft の software development kit (SDK)などでは、昔から Document-View model での実装を想定した作りになっていた。ここでは、それに習って document と document を表示するための window class を制作しよう。

まずは plain text document を考える。CMyPlain class としよう。なお、今回から、多数の class を作成する可能性があるので、名前の衝突を防ぐために、namespace を導入する。

 // myplain.h
 
 #ifndef MYPLAIN_H_INCLUDED
 #define MYPLAIN_H_INCLUDED
 
 #include <windows.h>
 #include <tchar.h>
 #include <vector>
 
 namespace mylib
 {
 class CMyPlain
 {
 public:
 	CMyPlain();
 	CMyPlain(const TCHAR* pszFileName);
 	virtual ~CMyPlain();
 	virtual int Draw(HDC hdc, int x, int y, PAINTSTRUCT& ps);
 
 private:
 	std::vector<std::vector<TCHAR> > m_linebuf;
 };
 }	// namespace mylib
 
 #endif	// MYPLAIN_H_INCLUDED

CMyPlain の本体
 // myplain.cpp
 
 #include "myplain.h"
 
 namespace mylib
 {
 
 CMyPlain::CMyPlain()
 {
 }
 
 CMyPlain::CMyPlain(const TCHAR* pszFileName)
 {
 	HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, 0,
 		OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0);
 
 	if(hFile == INVALID_HANDLE_VALUE)
 		return;
 
 	DWORD nRead = 0;
 	unsigned char buf[2];
 	while(1)
 	{
 		std::vector<TCHAR> linebuf;
 		while(ReadFile(hFile, buf, 1, &nRead, 0))
 		{
 			if((nRead == 0) || (buf[0] == '\n'))
 			{
 				m_linebuf.push_back(linebuf);
 				break;
 			}
 			if(buf[0] > ' ')
 				linebuf.push_back((TCHAR)buf[0]);
 			else
 				linebuf.push_back((TCHAR)' ');
 		}
 		if(nRead == 0)
 		{
 			CloseHandle(hFile);
 			return;
 		}
 	}
 	CloseHandle(hFile);
 }
 
 CMyPlain::~CMyPlain()
 {
 }
 
 int
 CMyPlain::Draw(HDC hdc, int x, int y, PAINTSTRUCT& ps)
 {
 	TEXTMETRIC tm;
 	GetTextMetrics(hdc, &tm);
 	int ystep = (int)(tm.tmHeight + tm.tmExternalLeading);
 	std::vector<std::vector<TCHAR> >::iterator p = m_linebuf.begin();
 	while(p != m_linebuf.end() )
 	{
 		if(p->size() > 0)
 		{
 			std::vector<TCHAR>::iterator q = p->begin();
 			TextOut(hdc, x, y, &*q, p->size());
 		}
 		p++;
 		y += 20;
 		y += ystep;
 	}
 	return 0;
 }
 
 }	// namespace mylib

当然ながら、CMyApp も変更される。
 // myapp.h
 
 #ifndef MYAPP_H_INCLUDED
 #define MYAPP_H_INCLUDED
 
 #include "myplain.h"
 
 namespace mylib
 {
 
 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;
 	CMyPlain m_doc;
 
 private:
 	BOOL ParseCommandLine();
 
 private:
 	std::vector<TCHAR> m_DocName;
 	TCHAR m_szWinClass[(MAX_LOAD_STRING+1)];
 	TCHAR m_szAppTitle[(MAX_LOAD_STRING+1)];
 };
 }	// namespace mylib
 #endif	// MYAPP_H_INCLUDED

CMyApp の本体。
 #include <windows.h>
 #include <tchar.h>
 #include "resource.h"
 #include "myapp.h"
 
 extern mylib::CMyApp* g_pApp;
 
 namespace mylib
 {
 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);
 	}
 	ParseCommandLine();
 }
 
 CMyApp::~CMyApp()
 {
 }
 
 LRESULT CALLBACK 
 CMyApp::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 	switch(message)
 	{
 	case WM_PAINT:
 	{
 		PAINTSTRUCT ps;
 		HDC hdc = BeginPaint(hWnd, &ps);
 		g_pApp->m_doc.Draw(hdc, 0, 0, ps);
 		EndPaint(hWnd, &ps);
 		break;
 	}
 	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;
 
 	// Create the document
 	if(m_DocName.size() > 0)
 	{
 		std::vector<TCHAR>::const_iterator p = m_DocName.begin();
 		m_doc = CMyPlain(&*p);
 	}
 
 	ShowWindow(hWnd, nCmdShow);
 	UpdateWindow(hWnd);
 	
 	// Enter Message Loop
 	MSG msg;
 	while(GetMessage(&msg, 0, 0, 0))
 	{
 		TranslateMessage(&msg);
 		DispatchMessage(&msg);
 	}
 	return (int)msg.wParam;
 }
 
 BOOL
 CMyApp::ParseCommandLine()
 {
 	const TCHAR* pCmdLine = GetCommandLine();
 	if(pCmdLine == 0)
 		return FALSE;
 
 	// First argument (executable name)
 	const TCHAR* p = pCmdLine;
 	while(*p <= (TCHAR)' ')
 	{
 		if(*p == 0)
 			return FALSE;
 		++p;
 	}
 	TCHAR q = ' ';
 	if((*p == '"') || (*p == '\''))
 	{
 		q = *p;
 		++p;
 	}
 	while(*p != q)
 	{
 		if(*p == 0)
 			return FALSE;
 		++p;
 	}
 	++p;
 	// Second argument
 	while(*p <= (TCHAR)' ')
 	{
 		if(*p == 0)
 			return FALSE;
 		++p;
 	}
 	if((*p == '"') || (*p == '\''))
 	{
 		q = *p;
 		++p;
 	}
 	std::vector<TCHAR> arg;
 	while(*p != q)
 	{
 		if(*p == 0)
 		{
 			arg.push_back((TCHAR)0);
 			m_DocName = arg;
 			return TRUE;
 		}
 		arg.push_back(*p);
 		++p;
 	}
 	arg.push_back((TCHAR)0);
 	m_DocName = arg;
 	return TRUE;
 }
 
 }	// namespace mylib

Main program も若干修正を受ける。myapp03.cpp としよう。CMyApp の object(ただ一つしかない)への pointer を global にして、各 module から参照できるようにしておく。
 #include <windows.h>
 #include <tchar.h>
 #include "myapp.h"
 
 mylib::CMyApp* g_pApp;
 
 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 	LPSTR lpCmdLine, int nCmdShow)
 {
 	using namespace mylib;
 	// Create my application
 	CMyApp app(hInstance, hPrevInstance);
 	g_pApp = &app;
 	return app.Run(nCmdShow);
 }

残りの resource.h と myapp.rc には変更は無い。前頁同様、全ファイル一式を tar と gzip で固めて &ref("myapp03.tgz"); として添付しておく。

全ファイルを展開したフォルダで、
 myapp03 build.bat

として実行すると、以下のような結果が得られるだろう。
#ref("myapp03.jpg");
なお、これは Windows-XP SP2 で実行した結果である。[[Page001]]に示してあるのは Windows 2000 SP4 での結果である。

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