본문 바로가기

Application Programming Interface/Microsoft Foundation Class

마법사 없이 SDI Frame-View-Document를 사용하는 최소 구조

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

이번 포스팅에서는 Visual Studio의 프로젝트 생성 마법사를 사용하지 않고
순수 코딩과 편집만으로 Frame-View-Document가 연결된 SDI 인터페이스를 만들어 보도록 하겠습니다.
SDI를 구현하기 위해서는

1. 최소한 Application, Frame, View, Document의 4개의 클래스가 선언되어야 합니다.
2. MainFrame에서 사용하기 위해 최소한 Menu, Accelerator, Icon, String의 4개의 리소스(ID가 같아야 함)가 필요합니다.

4개의 리소스 중 하나라도 빠지면 Application의 InitInstance 함수를 수행하는 중 Debug Assertion Error가 뜹니다.

SDI 구조를 만들기 위한 최소한의 Application 클래스 내용

// Application.h
#ifndef __Application
#define __Application

class CApplication : public CWinApp
{
	DECLARE_MESSAGE_MAP()

public:
	CApplication();
	virtual ~CApplication();

public:
	virtual BOOL InitInstance();
};

extern CApplication theApp;

#endif
 // Application.cpp
#include "stdafx.h"
#include "resource.h"
#include "MainDocument.h"
#include "MainView.h"
#include "MainFrame.h"
#include "Application.h"

CApplication theApp;

// Main Frame의 메뉴를 통해서 새로 만들기, 열기, 인쇄 설정 등의 작업 요청이 들어오면 이것을 CWinApp으로 넘겨줍니다. CWinApp에서는 View-Document를 알아서 연결해 줍니다.
BEGIN_MESSAGE_MAP(CApplication, CWinApp)
	ON_COMMAND(ID_FILE_NEW, CApplication::OnFileNew)
	ON_COMMAND(ID_FILE_OPEN, CApplication::OnFileOpen)
	ON_COMMAND(ID_FILE_PRINT_SETUP, CApplication::OnFilePrintSetup)
END_MESSAGE_MAP()

CApplication::CApplication()
{	
}

CApplication::~CApplication()
{

}

BOOL CApplication::InitInstance()
{
	int ret = CWinApp::InitInstance();

	if(ret)
	{
		// 메인 프레임-뷰-도큐먼트간 짝지어서 하나의 템플릿(서식)을 만들어줍니다.
		// 이 중 IDR_MAINFRAME은 메인 프레임과 관련된 리소스들을 나타내는데요
		// SDI 구조로 프로그램이 실행되기 위해서는 최소한 IDR_MAINFRAME이란 이름이 붙은 Menu, Accelerator, Icon, String이 있어야 합니다.
		CDocTemplate * pDocTemplate;
		pDocTemplate = new CSingleDocTemplate(IDR_MAINFRAME, RUNTIME_CLASS(CMainDocument), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CMainView));
		if(!pDocTemplate) return FALSE;

		this->AddDocTemplate(pDocTemplate);
		
		// 표준 셸 명령, DDE, 파일 열기에 대한 명령줄을 구문 분석합니다.
		CCommandLineInfo cmdInfo;
		this->ParseCommandLine(cmdInfo);
		
		// DDE Execute 열기를 활성화합니다.
		EnableShellOpen();
		RegisterShellFileTypes(TRUE);

		// 명령줄에 지정된 명령을 디스패치합니다.
		// 응용 프로그램이 /RegServer, /Register, /Unregserver 또는 /Unregister로 시작된 경우 FALSE를 반환합니다.
		if (!this->ProcessShellCommand(cmdInfo)) return FALSE;
		
		// CSingleDocTemplate에 의해 자동으로 메인 프레임이 생성되었습니다. 생성된 메인 프레임을 화면에 보이는 일만 남았습니다.
		this->m_pMainWnd->ShowWindow(SW_SHOW);
		this->m_pMainWnd->UpdateWindow();
	}

	return ret;
}
위와 같이 Application에서 최소한의 SDI 구현을 위한 작업을 했기 때문에
이후 Frame, Document, View에는 별도로 구현할 내용이 없습니다.

SDI 구조를 만들기 위한 최소한의 MainFrame 클래스 내용

// MainFrame.h : 메뉴 바와 제목 표시줄 같은 프로그램 화면의 가장 겉면을 지정하는 클래스
#ifndef __MainFrame
#define __MainFrame

class CMainFrame : public CFrameWnd {
	DECLARE_DYNCREATE(CMainFrame)
	DECLARE_MESSAGE_MAP()

public:
	CMainFrame();
	virtual ~CMainFrame();
};

#endif
// MainFrame.cpp
#include "stdafx.h"
#include "MainDocument.h"
#include "MainView.h"
#include "MainFrame.h"
#include "Application.h"

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
END_MESSAGE_MAP()

CMainFrame::CMainFrame()
{

}

CMainFrame::~CMainFrame()
{
}

SDI 구조를 만들기 위한 최소한의 MainView 클래스 내용

//MainView.h: Document에 저장된 내용을 화면에 보여주는 클래스 
#ifndef __MainView
#define __MainView

class CMainView : public CView
{	
	DECLARE_DYNCREATE(CMainView)
	DECLARE_MESSAGE_MAP()

public:
	CMainView();
	virtual ~CMainView();

public:
	/* 이 View가 보여주고 있는 Document를 반환합니다. */
	CMainDocument * GetDocument() const;

public:
	/* Document의 내용을 화면에 보여주는 것과 관련된 함수들 */
	virtual void OnDraw(CDC* pDC); // CView에는 OnDraw가 완전 추상함수로 되어 있으므로 구현해야 됨
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:
	/* Document의 내용을 프린터에 인쇄하는 것과 관련된 함수들 */
	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
};

#endif
// CMainView.cpp
#include "stdafx.h"
#include "MainDocument.h"
#include "MainView.h"
#include "MainFrame.h"
#include "Application.h"

IMPLEMENT_DYNCREATE(CMainView, CView)

BEGIN_MESSAGE_MAP(CMainView, CView)
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()


CMainView::CMainView()
{

}

CMainView::~CMainView()
{
}

CMainDocument * CMainView::GetDocument() const
{
	return reinterpret_cast<CMainDocument *>(m_pDocument);
}

BOOL CMainView::PreCreateWindow(CREATESTRUCT& cs)
{
	return CView::PreCreateWindow(cs);
}

void CMainView::OnDraw(CDC * pDC)
{
	CMainDocument * pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc) return;
	// TODO: 여기에 원시 데이터에 대한 그리기 코드를 추가합니다.
}

BOOL CMainView::OnPreparePrinting(CPrintInfo * pInfo)
{
	// 기본적인 준비
	return DoPreparePrinting(pInfo);
}

void CMainView::OnBeginPrinting(CDC * pDC, CPrintInfo * pInfo)
{
	// TODO: 인쇄하기 전에 추가 초기화 작업을 추가합니다.
}

void CMainView::OnEndPrinting(CDC * pDC, CPrintInfo * pInfo)
{
	// TODO: 인쇄 후 정리 작업을 추가합니다.
}

SDI 구조를 만들기 위한 최소한의 Document 클래스 내용

// MainDocument.h
#ifndef __MainDocument
#define __MainDocument

class CMainDocument : public CDocument
{
	DECLARE_DYNCREATE(CMainDocument)
	DECLARE_MESSAGE_MAP()

public:
	CMainDocument();
	virtual ~CMainDocument();

public:
	/* 파일(&F)->새로 만들기(&N)을 누를때마다 실행되는 함수 */
	virtual BOOL OnNewDocument();
	/* 파일(&F)->저장(&S)을 누를때마다 실행되는 함수 */
	virtual void Serialize(CArchive & ar);
};

#endif
// MainDocument.cpp
#include "stdafx.h"
#include "MainDocument.h"
#include "MainView.h"
#include "MainFrame.h"
#include "Application.h"

#include <propkey.h>

IMPLEMENT_DYNCREATE(CMainDocument, CDocument)

BEGIN_MESSAGE_MAP(CMainDocument, CDocument)
END_MESSAGE_MAP()

CMainDocument::CMainDocument()
{
	// TODO: 여기에 일회성 생성 코드를 추가합니다.
}

CMainDocument::~CMainDocument()
{
}

BOOL CMainDocument::OnNewDocument()
{
	if (!CDocument::OnNewDocument()) return FALSE;

	// TODO: 여기에 재초기화 코드를 추가합니다.
	// SDI 문서는 이 문서를 다시 사용합니다.

	return TRUE;
}

void CMainDocument::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: 여기에 저장 코드를 추가합니다.
	}
	else
	{
		// TODO: 여기에 로딩 코드를 추가합니다.
	}
}
실행 결과는 다음과 같이 SDI 구조의 빈 화면이 출력됩니다.