Page002

Document class の作成

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 += 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 で固めて filemyapp03.tgz として添付しておく。

全ファイルを展開したフォルダで、

myapp03 build.bat

として実行すると、以下のような結果が得られるだろう。

myapp03.jpg

なお、これは Windows-XP SP2 で実行した結果である。Page001に示してあるのは Windows 2000 SP4 での結果である。


添付ファイル: filemyapp03.tgz 16378件 [詳細] filemyapp03.jpg 16379件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2007-08-02 (木) 11:18:45 (89d)