6 장 MDI 응용프로그램 MDI 응용프로그램의형태 응용프로그램마법사 (AppWizard) 가생성하는 MDI 응용프로그램의주실행창을나타내는객체는 CFrameWnd에서파생된클래스인스턴스이며, 기본외형은아래그림과같이메뉴와툴바를포함한다. 문서내용을보여주는뷰들은이창의클라이언트영역안에자식창으로만들어지는윈도우들을통해표시된다. 주실행창의클라이언트영역안에는여러개의자식창이만들어질수있으며, 한개의문서에대응되는뷰가여러개일수도있다. 이점을제외하면 MDI 응용프로그램의형태는 SDI 응용프로그램의형태와거의같다. 이장에서는먼저 AppWizard, 클래스마법사 (ClassWizard), 리소스편집기등의도구들에대해다시요약하여설명하고, 특히 AppWizard를통해만들어지는것이무엇인지살펴본다. 그런다음예제로서간단한그림편집기응용프로그램을만들어본다. 하나의문서에대응되는둘이상의뷰가있을경우이들이항상동일한내용을나타낼수있도록동기화 (synchronization) 시켜주는방법을알아본다. 끝으로특정기능을사용하는뷰클래스를기본클래스로이용하는응용프로그램개발예를살펴본다. - 165 -
6.1 AppWizard, 클래스마법사, 리소스편집기 Visual C++ 개발환경안에는소프트웨어개발속도를크게향상시킬수있는여러가지도구들이포함되어있는데, 특히응용프로그램위저드 (AppWizard), 클래스마법사 (ClassWizard), 리소스편집기 (Resource Editor) 등이중요한도구들이다. 리소스편집기는각리소스유형의편집에사용되는여러편집기들의모음이다. AppWizard는프로그램틀생성기 (template generator) 라고볼수있다. 흔히새로운프로그램을작성할때기존의유사한프로그램소스에서불필요한부분들을제거한다음필요한기능들을추가하게될것이다. AppWizard는이중첫번째단계에해당하는작업을대신해주는도구이다. 즉, 새로작성하고자하는응용프로그램을위한 깨끗한 코드틀을만들어준다. AppWizard는개발자가선택한응용프로그램유형 (Dialog 기반, SDI, MDI), 여러선택항목등을반영하는프로그램소스를만들어준다. 응용프로그램의작성에서 AppWizard는시작부분에서단한번만사용된다는점을유념하자. AppWizard를사용한결과로여러파일들이만들어지며, 이파일들은컴파일되어실행될수있는완전한프로그램임을앞에서살펴본바있다. ClassWizard는 AppWizard가만들어준프로그램골격을수정하는데사용되는도구인데, 특히메시지맵의작성 / 변경, 새로운 MFC 파생클래스의생성, 멤버변수추가등의작업에주로이용된다. AppWizard에의해생성된프로그램골격에만적용될수있음을유념하자. 리소스는리소스편집기를사용하여생성하거나편집할수있는사용자인터페이스객체들이며, 여기에는비트맵, 커서, 다이얼로그, 아이콘, 메뉴, 단축키테이블, 스트링테이블, 버전정보등이포함된다. 리소스들이나타내는내용들은 MFC 코드를사용하여표현될수도있지만, 리소스편집기를사용함으로써훨씬쉽게이용할수있다. 6.2 AppWizard 의생성물 MDI 응용프로그램에서 AppWizard의진행절차는응용프로그램유형으로 Multiple Document를선택하는것을제외하면 SDI의경우와정확히같다. MDI 응용프로그램유형을선택하더라도실제취급하는문서유형은한가지인경우가많으며, 여러유형의문서를취급할수있기위해서필요한작업에대해서는 6.6절에서다룬다. 그렇지만한문서에대해여러개의뷰를사용할수있고또뷰를포함하는창이주실행창의클라이언트영역전체가아니라그안에포함된다는점등의차이가있다. MDI 응용프로그램의경우 AppWizard는 20개가넘는파일들을만들어낸다. 이파일들중의많은부분은프로그램소스를구성하는 C++ 헤더파일들과 C++ 클래스구현파일들이며, 이외에도여러리소스관련파일이나프로젝트관리와관련된파일들이있다. AppWizard 종료후프로젝트워크스페이스를통해클래스, 리소스, 파일등을살펴보면아래그림들과같다. MDI 응용프로그램의기본클래스들은 SDI 응용프로그램의기본클래스들과거의같으며, - 166 -
단지 CChildFrame 클래스만이추가되어있다. 파일들의경우도 CChildFrame 클래스를위한헤더파일과클래스구현파일을제외하고는차이가없다. 리소스는둘다 7개의기본리소스를포함하는것으로정확히같다. 클래스뷰에서사용되는아이콘들의의미는다음과같다. - 클래스 - protected 멤버함수 - private 멤버함수 - public 멤버함수 - protected 멤버변수 - private 멤버변수 - public 멤버변수 AppWizard가생성하는 MDI 응용프로그램의기본클래스구조는아래그림과같다. 그림에서가장하단에위치한클래스들이실제로생성되는클래스들이며, 그위의클래스들은 MFC 계층구조안의클래스들이다. - 167 -
CObject CCmdTarget CWndThread CDocument CWnd CWinApp CFrameWnd CView CDialog CWinAppEx CMDIFrameWnd CMDIChildWnd CDialogEx CMDIFrameWndEx CMDIChildWndEx CMyApp CMyDoc CMainFrame CChildFrame CMyView CAboutDlg 6.3 간단한그림편집기의작성 예제프로그램은마우스드래깅 ( 왼쪽버튼을누른상태에서이동 ) 을따라 5x5 크기의정사각형을그린다. 이를위해프로젝트이름은 Drawing, 응용프로그램종류는 < 다중문서 >(< 탭문서 > 선택은해제 ), 리소스언어는 < 한국어 >, 프로젝트스타일은 <MFC 표준 > 등을선택한다. 마우스드래깅에반응하도록만들기위해뷰클래스안에 WM_MOUSEMOVE 메시지에대한처리기함수를만들고아래와같이정의한다. void CDrawingView::OnMouseMove(UINT nflags, CPoint point) if (nflags == MK_LBUTTON) // 마우스왼쪽버튼이눌려져있으면 CClientDC dc(this); dc.rectangle(point.x, point.y, point.x + 5, point.y + 5); CView::OnMouseMove(nFlags, point); OnMouseMove() 함수의첫번째파라미터는마우스버튼이나 CTRL/SHIFT 키상태를나타내며, 다음상태심볼들이정의되어있다. MK_CONTROL, MK_SHIFT, MK_LBUTTON, MK_MBUTTON, MK_RBUTTON - 168 -
연습문제 1. 위의프로그램을컴파일하여실행시켜보라. 2. [ 창 ] 메뉴의 [ 새창 ] 메뉴항목은동일문서에대해뷰창을추가로만들기위해사용된다. 물론아직은문서를나타내기위한작업이없으므로위의프로그램의경우뷰들이별의미를갖지는않는다. 뷰의배열을 [ 창 ] 메뉴에서 [ 바둑판식배열 ] 을선택하여프로그램을수행해보라. 3. OnMouseMove() 함수안에서 dc 객체는매번새로만들어지는데이는낭비처럼생각될수있을것이다. 이러한낭비를피하기위해서는 static 선언을이용할수있다. dc 객체를 static으로선언한다음위의 2번문제에서와같이두개의뷰를연다음실험해보라. 이상한현상을관찰할수있을텐데, 그원인을설명해보라. 4. 위의 OnMouseMove() 함수를만들기위한방법이두가지있는데, 하나는 Visual Studio [ 프로젝트 ] 메뉴의 [ 클래스마법사 ] 메뉴항목을사용하는방법이며, 또하나는클래스뷰에대한팝업에서 [ 클래스마법사 ] 메뉴항목을사용하는것이다. 이들을각기사용해보고, 나타나는화면들을캡처하고설명을붙여제출하라. 5. 뷰가가려졌다다시노출될때가려졌던부분에위치한사각형들은사라진것을볼수있다. 풀다운메뉴에의해가려졌던부분은메뉴가사라진후어떻게되는지관찰하라. 관찰된결과의원인을설명하라. 앞의프로그램은문서파일을저장하거나읽어들이는기능, 가려졌다나타나는화면에대한재생기능이없는데, 이들은도큐먼트 / 뷰구조를사용하여해결될수있다. 도큐먼트 / 뷰구조를반영하기위한작업은다음 4가지이다. 1 사용자가그리는점들에관한정보를저장하기위한자료구조를도큐먼트클래스에추가한다. 2 도큐먼트클래스의자료구조를디스크에저장하고읽어들이기위한코드를도큐먼트클래스에추가한다. 3 사용자가점하나를추가할때마다이점을도큐먼트클래스의자료구조에도추가하기위한코드를뷰클래스에추가한다. 4 뷰의노출시내용을적절히재생하기위한코드를뷰클래스에추가한다. 이작업들을차례로살펴보자. 단계 1: 도큐먼트클래스에자료구조를추가한다. - 169 -
점을나타내는좌표들의열을저장하는방법은여러가지가있다. CPoint 배열은자연스러운선택중의하나이겠지만배열은선언할때크기가고정되는데, 이예제의경우점들의개수를미리예측하기어렵다는점에서바람직한선택은아니다. MFC에서는 CArray, CObArray, CByteArray, CUIntArray, CWordArray, CDWordArray, CPtrArray, CStringArray 등다양한배열클래스들을지원하고있는데, 이들은단순한 C++ 배열과는달리필요에따라크기가신축적으로변경될수있다. 또한이들은다양한멤버함수들을통해삽입, 추가, 삭제, 복사등의기능들을지원할뿐만아니라자체적으로 Serialize() 함수기능도지원한다. 이러한클래스들의객체에대해서는일반배열과마찬가지로 [] 안에배열인덱스를사용할수도있다. 여기서는두개의 CDWordArray를사용하여각기 x 좌표열과 y 좌표열을나타내기로한다. 이배열의원소는 32 비트정수인 DWORD 타입을갖는다. CDrawingDoc 클래스안에서 private 영역에다음과같은선언을둔다. 이는도큐먼트클래스헤더파일인 DrawingDoc.h를편집하거나도큐먼트클래스에대한팝업에서 [ 추가 - 변수추가 ] 메뉴항목을사용하여달성될수있다. CDWordArray x, y; 단계 2: 도큐먼트자료구조에대한저장및열기. AppWizard가마련한프로그램골격과 MFC 클래스들이파일의저장 / 열기등과관련한작업의많은부분을처리해주고있다. 예를들면, 그림편집기프로그램에서파일메뉴의열기항목을선택하면적절한파일열기다이얼로그를열어서읽어들일파일을선택할수있게해준다. 프로그램골격은또한선택된파일을열고그파일에연계된 CArchive 객체를만들고최종적으로 CDrawingDoc 클래스의 Serialize() 함수를호출한다. 이는파일의저장시에도마찬가지이다. 프로그래머가해야할일은 Serialize() 함수를채워도큐먼트자료구조, 즉, CDWordArray 타입의 x, y를적절히읽어들이거나저장하는일인데, CDWordArray 클래스는자체적으로 Serialize() 함수를지원하므로이작업은더욱쉬워진다. 아래코드를참고하라. void CDrawingDoc::Serialize(CArchive& ar) x.serialize(ar); y.serialize(ar); 단계 3: 뷰클래스를수정하여추가되는점들을도큐먼트자료구조에반영한다. 앞에서뷰에그릴사각형의크기는 5x5로고정되어있었다. 그러나나중에사각형의크기를변경시키는메뉴항목을둘예정이며, 이를위해사각형의크기를나타내는 private 가시성정 - 170 -
수형멤버변수 w를뷰클래스안에둔다. ( 헝가리식표기법을따르자면 m_nwidth와같은이름을사용해야겠지만식의길이를줄이기위해 w를사용한다.) 이변수는생성자에서 5로초기화한다. 추가되는점을도큐먼트자료구조에반영하기위해 OnMouseMove() 함수는아래와같이고쳐쓴다. 추가된코드부분은진하게표시되어있다. void CDrawingView::OnMouseMove(UINT nflags, CPoint point) CDrawingDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (!pdoc) return if (nflags == MK_LBUTTON) // 마우스왼쪽버튼이눌려져있으면 CClientDC dc(this); dc.rectangle(point.x, point.y, point.x + w, point.y + w); pdoc->add(point); pdoc->setmodifiedflag(); CView::OnMouseMove(nFlags, point); 도큐먼트클래스에는 Add() 라는함수가아래와같이정의되어야한다. void CDrawingDoc::Add(CPoint point) x.add(point.x); y.add(point.y); 단계 4: 뷰클래스에서노출이벤트의처리 가려졌던뷰가다시노출될때 WM_PAINT라는메시지가발생되며, 이는뷰클래스의 OnPaint() 함수를호출하게만드는데, 이함수는다시뷰클래스의 OnDraw() 멤버함수를호출한다. OnDraw() 함수안에노출처리코드를넣어줌으로써화면을적절히재생할수있게된다. - 171 -
void CDrawingView::OnDraw(CDC* pdc) CDrawingDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); for (int i = 0; i < pdoc->size(); i++) CPoint p = pdoc->getpoint(i); pdc->rectangle(p.x, p.y, p.x + w, p.y + w); 도큐먼트클래스에는 Size(), GetPoint() 등의함수들이아래와같이정의되어야한다. int CDrawingDoc::Size() return x.getsize(); CPoint CDrawingDoc::GetPoint(int i) return CPoint(x[i], y[i]); 지금쯤프로그램을저장한후컴파일하여실행해보고파일저장 / 열기기능과뷰노출등의기능이제대로동작하는지확인해야할좋은시점이다. 여러파일을열어두거나하나의문서에대해여러뷰를여는등의작업이제대로수행되는지도점검해보면좋을것이다. 또전체프로그램을교재를보지않고다시반복해작성해보는것도좋을것이다. 도큐먼트 / 뷰구조에관한기본적인사항은완료되었다. 하나의문서에대해여러뷰가열려있을경우실시간동기화는이루어지고있지않은데, 이는다음절에서다룰것이다. 여기에서는추가기능으로사각형의크기를변경하는메뉴항목을첨가해본다. 먼저사각형의크기를입력받을다이얼로그리소스를먼저설계한다음메뉴항목의추가및관련코드를만들어볼것이다. 단계 5: 다이얼로그리소스의추가. 프로그램에다이얼로그를추가하기위해필요한작업은다음과같다. 1 리소스편집기를사용하여새로운다이얼로그리소스를만든다. Visual Studio의 [ 서식 ] 메뉴의 [ 탭순서 ] 기능을사용하여 Edit 컨트롤이 1번이되도록한다. 2 새로운다이얼로그를위한클래스를만든다. ( 클래스이름 : CSizeDlg) 3 다이얼로그안의 Edit 컨트롤을위한 int 타입의 DDX 변수 m_nsize를정한다. 이변수 - 172 -
에대한 DDV 조건은 2에서 50 사이의값을갖는것으로정한다. 4 다이얼로그객체를생성하여화면에나타나게만든다. 이부분은다음단계의메뉴항목처리기함수안에서이루어질것이다. 단계 6: 메뉴항목및처리기함수추가. 예제의메뉴리소스를열어보면네개의메뉴가들어있으며, 주실행창에연계되어있고뷰창이하나도열려있지않을경우사용되는 IDR_MAINFRAME 메뉴와뷰창에연계된 IDR_DrawingTYPE 등의메뉴가있다. IDR_MAINFRAME 메뉴에는 [ 파일 ], [ 보기 ], [ 도움말 ] 세가지메뉴가있으며, IDR_DrawingTYPE 메뉴에는이들외에도 [ 편집 ], [ 창 ] 등의메뉴가더있다. 여기에서는 IDR_DRAWINTYPE 메뉴리소스에 [ 선택 ] 메뉴, 그리고그안에 [ 크기 ] 메뉴항목을만들어넣는다. 이를위해먼저메뉴바끝에위치한빈사각형에 [ 선택 ] 메뉴를만든후이를마우스로끌어 [ 편집 ] 메뉴와 [ 보기 ] 메뉴사이로옮긴다. 나머지는앞의그림이나타내는바와같다. 특히 [ 크기 ] 메뉴항목을위한 ID는 ID_OPTION_SIZE로정한다. 클래스마법사를사용하여추가된메뉴항목을위한처리기함수 OnOptionSize() 를 CDrawingView 클래스안에만들어넣는다. 다이얼로그는열리면서 UpdateData(FALSE) 함수를호출하여 DDX 변수들을화면에보여주고, 닫히면서 UpdateData(TRUE) 함수를호출하여사용자가입력한값을 DDX 변수들에저장한다. 따라서아래함수에서도다이얼로그가열릴때 dlg.m_isize에저장된 w의현재값이화면의 Edit 컨트롤에나타나며, 사용자가 Edit 컨트롤에입력한값은다이얼로그가닫힐때 dlg.m_nsize에저장되었다가 w로옮겨간다. #include "SizeDlg.h" void CDrawingView::OnOptionSize() CSizeDlg dlg; dlg.m_nsize = w; - 173 -
if (dlg.domodal() == IDOK) w = dlg.m_nsize; 이제프로그램을다시컴파일하여실행해보자. 연습문제 6. CDWordArray 클래스의멤버함수에대해조사해보라. 7. 사각형크기변경기능을사용하되, DDV 범위인 2~50 사이를벗어나는값을입력해보라. 8. 크기를변경한후뷰의일부만을다른창으로가렸다가다시나타나게해보라. 관찰된현상을설명하라. 6.4 다중뷰의동기화 그림그리기응용프로그램에서 [ 창 ] 메뉴의 [ 다음창 ] 기능을사용하여동일문서에대해두개의뷰를 [ 바둑판식 ] 으로연다음각뷰안에그림을그려넣어본다. 두개의뷰는마치별개의문서를위한것처럼보이지만주실행창을최소화시켰다가다시불러내보면각뷰에그린내용이합쳐져서나타나는것을관찰할수있을것이다. 각뷰에서추가되는점들은모두도큐먼트자료구조에추가되며, OnDraw() 함수가불려나올때는도큐먼트자료구조안에저장되어있는좌표들을사용하여새로그리게된다. 이경우각뷰에대해노출이벤트가발생하며, 따라서뷰마다 OnDraw() 함수가호출되어두개의뷰는일치된모습을보이게된다. 그러나 OnMouseMove() 함수안에서사각형을그릴때는해당뷰안에서만이루어지므로다른뷰들에대해서는실시간동기화가이루어지지않는것이다. 이문제는뷰클래스안의가상함수 OnUpdate() 함수를사용하여해결될수있다. - 174 -
CDocument 클래스객체는그문서에연계되어있는모든뷰들의목록을유지한다. 또 CDocument 클래스는 UpdateAllViews() 함수를갖고있는데, 특정문서에대해이함수가호출되면그문서에연계되어있는각뷰에대해 OnUpdate() 함수를호출한다. 이함수를적절히수정하여필요한뷰동기화를구현할수있다. 하나의사각형을추가하는작업은 OnMouseMove() 함수안에서이루어진다. 즉, 사각형추가라는사실을인지하는곳이 OnMouseMove() 함수이며, 여러뷰에동기화가필요한이벤트가발생했음을이함수에서알려줄수있다. 따라서아래와같이 OnMouseMove() 함수안에뷰동기화를위해 UpdateAllViews() 함수호출하나를추가한다. void CDrawingView::OnMouseMove(UINT nflags, CPoint point) CDrawingDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (!pdoc) return; if (nflags == MK_LBUTTON) CClientDC dc(this); dc.rectangle(point.x, point.y, point.x + w, point.y + w); pdoc->add(point); pdoc->setmodifiedflag(); pdoc->updateallviews(this, 0, 0); CView::OnMouseMove(nFlags, point); 그리고클래스마법사에서 [ 가상함수 ] 탭을사용하여가상함수 OnUpdate() 를추가한다음아래와같이편집한다. OnUpdate() 함수에서는도큐먼트자료구조의마지막좌표를받아와서사각형을그린다. void CDrawingView::OnUpdate(CView* psender, LPARAM lhint, CObject* phint) CDrawingDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (!pdoc) return; int n = pdoc->size(); if (n > 0) CPoint p = pdoc->getpoint(n - 1); CClientDC dc(this); dc.rectangle(p.x, p.y, p.x + w, p.y + w); - 175 -
뷰의초기화과정에서불려나오는 OnInitialUpdate() 함수안에서도 OnUpdate() 함수를호출하는데, 이때는아직아무좌표도도큐먼트자료구조에들어있지않다. 이경우 OnUpdate() 함수안에서 n은 0이될것이며, 따라서이함수안의 if 문은필요함을유념하자. UpdateAllViews() 함수와 OnUpdate() 함수의파라미터는동일하며, UpdateAllViews() 함수의실인수들이 OnUpdate() 함수의파라미터로전달된다. 파라미터 lhint와 phint는뷰갱신에필요한정보의전달을위해사용될수있지만, 이예제에서는사용되고있지않으며, 이경우 UpdateAllViews() 함수에서는디폴트인수를사용할수있어생략되어도좋다. psender는문서를수정하고있는뷰를나타내며, 이뷰는이미갱신되었으므로갱신이필요없음을표시한다. 현재뷰갱신도 OnMouseMove() 함수에서처리하는대신 OnUpdate() 에맡길수있으며, 이경우 OnMouseMove() 함수는아래와같이고쳐쓸수있다. void CDrawingView::OnMouseMove(UINT nflags, CPoint point) CDrawingDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (!pdoc) return; if (nflags == MK_LBUTTON) pdoc->add(point); pdoc->setmodifiedflag(); pdoc->updateallviews(null); // 파라미터 NULL은모든뷰에 update 적용을의미 CView::OnMouseMove(nFlags, point); 이제프로그램을다시컴파일하고실행하여다중뷰에대한실시간동기화를체험해보자. 6.5 텍스트편집기의작성 또다른유형의문서를처리하는예제프로그램으로서메모장과유사한텍스트편집기응용프로그램을작성해본다. 이를위해프로젝트이름은 Ed, 응용프로그램종류는 < 다중문서 > (< 탭문서 > 선택은해제 ), 리소스언어는 < 한국어 >, 프로젝트스타일은 <MFC 표준 > 등을선택한다. 이응용프로그램의경우모든코드와리소스는 AppWizard에의해만들어지며, 프로그래머는단한줄의코드도추가하지않는다. 텍스트편집기기능을갖도록만들기위해 AppWizard 진행과정에서두가지작업을해준다. - 176 -
[ 문서템플릿속성 ] 화면에서 < 파일확장명 > 필드에확장자 tex를넣는다. ( 이과정은꼭필요한것은아니다.) [ 생성된클래스 ] 화면에서뷰클래스의 CEdView의기본클래스를 CView에서 CEditView로변경한다. 이제이프로그램을컴파일하여실행해보면텍스트의편집, 파일의저장 / 열기 / 인쇄, 텍스트의오려두기 / 복사하기 / 붙이기, 모두선택 / 찾기 / 다음찾기 / 바꾸기등의기능을사용할수있을것이다. 편집기데이터가도큐먼트클래스가아니라뷰클래스안에포함되어있음을언급하였다. 따라서도큐먼트데이터를공유하는다중뷰의사용이이경우해당되지않으며, 이는텍스트편집기를너무쉽게만든것에대한대가로생각해야할것이다. 따라서 [ 창 ] 메뉴의 [ 새창 ] 기능은불필요하므로삭제하는것이바람직할것이다. 오른쪽의 [ 문서템플릿속성 ] 화면에서정해지는스트링들은스트링리소스의 IDR_MAINFRAME 스트링과 IDR_EDTYPE 스트링에아래와같이들어있다. 모두 7 개의스트링인이들에대한설명은 CDocTemplate::GetDocString() 함수에대한도움말안에포함되어있다. - 177 -
1 CDocTemplate::windowTitle (IDR_MAINFRAME: "Ed") 응용프로그램의주실행창타이틀바에나타나는이름. ( 예 : "Microsoft Excel") 2 CDocTemplate::docName ("Ed") 문서의디폴트이름어간부분. ( 예 : "Book"). 파일메뉴의새파일기능을선택할때디폴트파일이름은여기에숫자를붙여만들어진다. ( 예 : "Book1", "Book2" 등등 ). 지정되어있지않으면 "Untitled" 또는 " 제목없음 " 등이사용된다. 3 CDocTemplate::fileNewName ("Ed") 문서유형을나타내는이름. 응용프로그램이둘이상의문서유형을지원할때새파일메뉴항목을선택하면파일유형목록이나타나는데, 여기에사용되는스트링이다.( 예 : "Worksheet"). 4 CDocTemplate::filterExt (".tex") 문서 유형을 위한 파일 확장자. ( 예 : ".xls"). 5 CDocTemplate::filterName ("Ed Files (*.tex)") 문서유형에대한설명과와일드카드필터. 파일열기다이얼로그의파일형식필드에사용되는스트링이다. ( 예 : "Worksheets (*.xls)") 6 CDocTemplate::regFileTypeId ("Ed.Document") 윈도우운영체제에등록되어있는파일유형식별자. ( 예 : "ExcelWorksheet") 7 CDocTemplate::regFileTypeName ("Ed.Document") 윈도우운영체제에등록되어있는파일유형이름. ( 예 : "Microsoft Excel Worksheet"). - 178 -