| Document object の置き換え †前節までで、command line で指定された file を表示することはできるようになった。しかしながら、 program 起動後に file を読みたいことや、更に別の file を表示させたいことも多い。Windows program では、むしろその用法の方が多い。これを実装するには、current document の置き換えが必要になる。起動後の表示は empty document との置き換えと考えればよい。 前節の実装では、current document は pointer として保持していたので、その思想をそのまま延長すると、 
 とすればよい。 しかしながら、例えば印刷とか、file への保存などを表示と同時に行いたい場合など単純に delete できない。どれが先に終了するかわからない複数の thread が同一 object に access するので、固定されたどれかの thread で消去するわけにはいかない。これを安全に実行するためには、各 thread 毎に object のコピーを持たせるのがよいが、画像などでは占有 memory が大きいことも想定され、非効率になることも考えられる。そこで、ここでは handle を使った方法で実装する。 ここでの source 類は  Document の handle 化 †// mydoc.h
#ifndef MYDOC_H_INCLUDED
#define MYDOC_H_INCLUDED
#include "myconten.h"
namespace mylib
{
class CMyDoc
{
public:
	CMyDoc();
	CMyDoc(CMyContent* pContent);
	CMyDoc(const CMyDoc& src);
	virtual ~CMyDoc();
	CMyDoc& operator=(const CMyDoc& src);
	SIZE Size(HDC hdc);
	int Draw(HDC hdc, int x, int y, PAINTSTRUCT& ps);
protected:
	int* m_pCounter;
	CMyContent* m_pContent;
};
}	// namespace mylib
#endif	// MYDOC_H_INCLUDED以下に実装を示すが、代入演算子で、自己代入の検査を行う部分が、m_pContent の比較ではなく、m_pCounter の比較であることに注意する。m_pContent は 0(NULL) に成り得るので、同一 object でなくとも互いに 0 で一致する可能性があるからである。一方、m_pCounter は必ず new するので、0 で一致することはない。 // mydoc.cpp
#include "mydoc.h"
namespace mylib
{
CMyDoc::CMyDoc() :
	m_pCounter(new int(1)), m_pContent(0)
{
}
CMyDoc::CMyDoc(CMyContent* pContent) :
	m_pCounter(new int(1)), m_pContent(pContent)
{
}
CMyDoc::CMyDoc(const CMyDoc& src) :
	m_pCounter(src.m_pCounter), m_pContent(src.m_pContent)
{
	(*m_pCounter)++;
}
CMyDoc::~CMyDoc()
{
	if(--(*m_pCounter) == 0)
	{
		delete m_pContent;
		delete m_pCounter;
	}
}
CMyDoc&
CMyDoc::operator=(const CMyDoc& src)
{
	if(m_pCounter == src.m_pCounter)
		return *this;
	if(--(*m_pCounter) == 0)
	{
		delete m_pContent;
		delete m_pCounter;
	}
	m_pContent = src.m_pContent;
	m_pCounter = src.m_pCounter;
	(*m_pCounter)++;
	return *this;
}
SIZE
CMyDoc::Size(HDC hdc)
{
	SIZE sz;
	if(m_pContent)
		sz = m_pContent->Size(hdc);
	else
	{
		sz.cx = 0;
		sz.cy = 0;
	}
	return sz;
}
int
CMyDoc::Draw(HDC hdc, int x, int y, PAINTSTRUCT& ps)
{
	int n;
	if(m_pContent)
		n = m_pContent->Draw(hdc, x, y, ps);
	else
		n = 0;
	return n;
}
} // namespace mylibCMyApp class と CMyAppWin class の変更 †上記変更に伴い従来 myapp.h の中で public: CMyContent* m_pDoc; としていた部分を public: CMyDoc m_curDoc; とする。また、これに伴い destructor 中での delete m_pDoc; は不要となるので削除する。 Run 関数まわりは若干変更となるので全部示しておく。 int
CMyApp::Run(int nCmdShow)
{
	// Create Window
	CMyAppWin appwin(m_szAppTitle);
	// Create the document
	if(m_DocName.size() > 0)
	{
		std::vector<TCHAR>::const_iterator p = m_DocName.begin();
		switch(ContentType(&*p))
		{
		case CMyContent::TEXT_PLAIN:
			m_curDoc = CMyDoc((CMyContent*)(new CMyPlain(&*p)));
			break;
		case CMyContent::IMAGE_JPEG:
			m_curDoc = CMyDoc((CMyContent*)(new CMyDjpeg(&*p)));
			break;
		case CMyContent::IMAGE_BMP:
			m_curDoc = CMyDoc((CMyContent*)(new CMyBMP(&*p)));
			break;
		default:
			break;
		}
	}
	appwin.Show(nCmdShow);
	appwin.Update();
	POINT pt;
	pt.x = 0;
	pt.y = 0;
	HDC hdc = appwin.GetDC();
	SIZE sz = m_curDoc.Size(hdc);
	appwin.ReleaseDC(hdc);
	appwin.SetDrawSize(pt, sz);
	
	// Enter Message Loop
	MSG msg;
	while(GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return (int)msg.wParam;
}一方、CMyAppWin の方は、OnPaint 関数が BOOL
CMyAppWin::OnPaint()
{
	PAINTSTRUCT ps;
	HDC hdc = CMyWin::BeginPaint(&ps);
	g_pApp->m_curDoc.Draw(hdc, -m_ptOffset.x, -m_ptOffset.y, ps);
	CMyWin::EndPaint(&ps);
	return TRUE;
}となるだけである。 |