151
Advanced Document/View Advanced Document/View Chap. 8 Chap. 8

Advanced Document/View

Embed Size (px)

DESCRIPTION

Chap. 8. Advanced Document/View. Contents. CDocument Internal CView Printing CView Print Preview CScrollView CCtrlView. CDocument Internal. CDocument 에서의 file 작업 MFC 4.0 GetFile(), ReleaseFile() 함수를 이용. BOOL CDocument:: OnOpenDocument (LPCTSTR lpszPathName) { - PowerPoint PPT Presentation

Citation preview

Advanced Document/ViewAdvanced Document/View

Chap. 8Chap. 8

ContentsContents CDocument InternalCDocument Internal CView PrintingCView Printing CView Print PreviewCView Print Preview CScrollViewCScrollView CCtrlViewCCtrlView

CDocument InternalCDocument Internal CDocumentCDocument 에서의 에서의 filefile 작업작업

MFC 4.0MFC 4.0 GetFile(), ReleaseFile() GetFile(), ReleaseFile() 함수를 이용함수를 이용

BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName){

CFile* pFile = GetFile(lpszPathName,CFile::modeRead|CFile::shareDenyWrite,

&fe);DeleteContents();SetModifiedFlag(); // dirty during de-serializeCarchive loadArchive

(pFile,CArchive::load|CArchive::bNoFlushOnDelete);

Serialize(loadArchive); // load meloadArchive.Close();ReleaseFile(pFile, FALSE);SetModifiedFlag(FALSE); // start off with

unmodifiedreturn TRUE;

}

BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName){

CFile* pFile = NULL;pFile = GetFile(lpszPathName, CFile::modeCreate |

CFile::modeReadWrite | CFile::shareExclusive, &fe);

CArchive saveArchive(pFile, CArchive::store |

CArchive::bNoFlushOnDelete);Serialize(saveArchive); // save mesaveArchive.Close();ReleaseFile(pFile, FALSE);SetModifiedFlag(FALSE); // back to unmodified

return TRUE; // success}

CDocument Internal (cont’d)CDocument Internal (cont’d)

CDocument Internal (cont’d)CDocument Internal (cont’d)

CFile* CDocument::GetFile(LPCTSTR lpszFileName, UINT nOpenFlags,

CFileException* pError){

CMirrorFile* pFile = new CMirrorFile;if (!pFile->Open(lpszFileName, nOpenFlags, pError)){

delete pFile;pFile = NULL;

}return pFile;

}

CMirrorFileCMirrorFile 왜 왜 CFileCFile 을 쓰지 않고 을 쓰지 않고 CMirrorFileCMirrorFile 을을 ?? CMirrorFile classCMirrorFile class

Declaration(AFXPRIV.H)Declaration(AFXPRIV.H)

class CMirrorFile : public CFile{// Implementationpublic: virtual void Abort(); virtual void Close(); virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL); static CString GetTempName(LPCTSTR pstrOriginalFile, BOOL bCreate);protected: CString m_strMirrorName;};

CMirrorFile (cont’d)CMirrorFile (cont’d) CMirrorFile::Open()(DOCCORE.CPP)CMirrorFile::Open()(DOCCORE.CPP)

ReadRead 인 경우에는 원래 파일 인 경우에는 원래 파일 openopen WriteWrite 나 나 truncatetruncate 인 경우에는인 경우에는

File File 명으로 준 파일이 아닌 다른 임시파일을 명으로 준 파일이 아닌 다른 임시파일을 openopen 함함((Mirror file)Mirror file)

CMirrorFile (cont’d)CMirrorFile (cont’d)BOOL CMirrorFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags,

CFileException* pError){ m_strMirrorName.Empty(); if (nOpenFlags & CFile::modeCreate) { if (CFile::GetStatus(lpszFileName, status)) {

AfxGetRoot(lpszFileName, strRoot);if (GetDiskFreeSpace(strRoot, &dwSecPerClus,

&dwBytesPerSec, &dwFreeClus, &dwTotalClus)) {

nBytes=dwFreeClus*dwSecPerClus* dwBytesPerSec;}if (nBytes > 2 * DWORD(status.m_size)) { m_strMirrorName = GetTempName(lpszFileName,

TRUE);}

} }

CMirrorFile (cont’d)CMirrorFile (cont’d) if (!m_strMirrorName.IsEmpty() &&

CFile::Open(m_strMirrorName, nOpenFlags, pError)) { m_strFileName = lpszFileName; FILETIME ftCreate, ftAccess, ftModify;

if (::GetFileTime((HANDLE)m_hFile, &ftCreate, &ftAccess, &ftModify)) {

AfxTimeToFileTime(status.m_ctime, &ftCreate);SetFileTime((HANDLE)m_hFile, &ftCreate, &ftAccess,

&ftModify); } DWORD dwLength = 0; PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;

CMirrorFile (cont’d)CMirrorFile (cont’d) if(GetFileSecurity(lpszFileName,DACL_SECURITY_INFORMATION,

NULL, dwLength, &dwLength)) {pSecurityDescriptor = (PSECURITY_DESCRIPTOR) new

BYTE[dwLength];if (::GetFileSecurity(lpszFileName,

DACL_SECURITY_INFORMATION,pSecurityDescriptor, dwLength, &dwLength))

{ SetFileSecurity(m_strMirrorName,

DACL_SECURITY_INFORMATION, pSecurityDescriptor);

} delete[] (BYTE*)pSecurityDescriptor;

} return TRUE; } m_strMirrorName.Empty(); return CFile::Open(lpszFileName, nOpenFlags, pError);}

CMirrorFile(contd.)CMirrorFile(contd.) CMirrorFile::Close()(DOCCORE.CPP)CMirrorFile::Close()(DOCCORE.CPP)

Mirror fileMirror file 을 실제 을 실제 filefile 로 로 copycopy

CMirrorFileCMirrorFile 의 이러한 기능이 마음에 들지 않으면의 이러한 기능이 마음에 들지 않으면 CDocument::GetFile()CDocument::GetFile() 함수를 함수를 overrideoverride 하면 됨하면 됨

CMirrorFile(contd.)CMirrorFile(contd.)void CMirrorFile::Close(){

CString m_strName = m_strFileName; //file close empties string

CFile::Close();if (!m_strMirrorName.IsEmpty()){

CFile::Remove(m_strName);CFile::Rename(m_strMirrorName, m_strName);

}}

CMirrorFile(contd.)CMirrorFile(contd.) 결론결론

CMirrorFileCMirrorFile 의 역할의 역할 원래의 파일을 보관원래의 파일을 보관 새로운 새로운 mirror filemirror file 을 생성하고 여기에 작업을 생성하고 여기에 작업 모든 작업이 잘 끝날때 까지 원래 파일을 보존하는 효과모든 작업이 잘 끝날때 까지 원래 파일을 보존하는 효과

CView PrintingCView Printing Printing overviewPrinting overview

작업에 관련된 작업에 관련된 virtual functionvirtual function OnPreparePrinting()OnPreparePrinting()

PrintPrint 가 시작되기 전에 호출가 시작되기 전에 호출 CPrintInfo structureCPrintInfo structure 가 가 argumentargument 쪽수와 전체 범위 지정쪽수와 전체 범위 지정 DocumentDocument 의 의 printprint 할 페이지를 지정하는데 쓰임할 페이지를 지정하는데 쓰임

OnBeginPrinting()OnBeginPrinting() PrintPrint 가 시작되면 호출가 시작되면 호출

Printing OverviewPrinting Overview Printer device contextPrinter device context 의 의 pointerpointer 와 와 CPrintInfo structureCPrintInfo structure 의 의

pointerpointer 가 가 argumentargument 특별한 특별한 GDI resourceGDI resource 의 할당의 할당 Printer device contextPrinter device context 에 의존적인 작업을 할 때 이용에 의존적인 작업을 할 때 이용

OnPrint()OnPrint() DocumentDocument 의 특정 의 특정 sectionsection 을 을 printprint 할 때 호출할 때 호출 화면에 보이는 모습과 화면에 보이는 모습과 printprint 되는 모습을 다르게 하고자 할 때되는 모습을 다르게 하고자 할 때 예 예 : : Title pageTitle page 의 추가의 추가 Printer device contextPrinter device context 가 가 argumentargument

Printing Overview (cont’d)Printing Overview (cont’d) OnEndPrinting()OnEndPrinting()

PrintPrint 가 끝난후 호출가 끝난후 호출 Clean up any resourceClean up any resource

OnPrepareDC()OnPrepareDC() 특별한 특별한 device contextdevice context 의 준비의 준비 mapping mode mapping mode 의 전환의 전환 미리 미리 documentdocument 의 끝인지를 검사의 끝인지를 검사 프린터 부가 기능 제공프린터 부가 기능 제공

CView::DoPreparePrinting()CView::DoPreparePrinting() Print dialog boxPrint dialog box 를 보여줌를 보여줌 Dialog boxDialog box 에서 선택된 에서 선택된 printerprinter 의 의 device contextdevice context 의 생성의 생성

CPrintInfo structureCPrintInfo structure Declaration(AFXEXT.H)Declaration(AFXEXT.H) CPrintDialog instanceCPrintDialog instance 와 정보를 가져오는 함수와 정보를 가져오는 함수 CPrintDialogCPrintDialog 의 의 instanceinstance PrintPrint 인지 인지 print previewprint preview 인지에 대한 정보인지에 대한 정보 현재 현재 printprint 하는 하는 pagepage 정보정보

Printing Overview (cont’d)Printing Overview (cont’d)

Printing Overview (cont’d)Printing Overview (cont’d)struct CPrintInfo // Printing information structure{ CPrintDialog* m_pPD; // pointer to print dialog BOOL m_bDocObject; // TRUE if printing by IPrint interface BOOL m_bPreview; // TRUE if in preview mode BOOL m_bDirect; // TRUE if bypassing Print Dialog BOOL m_bContinuePrinting;// set to FALSE to prematurely end printing UINT m_nCurPage; // Current page UINT m_nNumPreviewPages; // Desired number of preview pages CString m_strPageDesc; // Format string for page number display LPVOID m_lpUserData; // pointer to user created struct CRect m_rectDraw; // rectangle defining current usable page area void SetMinPage(UINT nMinPage); void SetMaxPage(UINT nMaxPage); UINT GetMinPage() const; UINT GetMaxPage() const; UINT GetFromPage() const; UINT GetToPage() const; UINT GetOffsetPage() const;};

CView Printing InternalsCView Printing Internals Printing stepsPrinting steps

“ViewPrnt.cpp”

ON_COMMAND(ID_FILE_PRINT, Cview::OnFilePrint) // built-in

CView Printing Internals (cont’d)CView Printing Internals (cont’d)

void CView::OnFilePrint(){ CPrintInfo printInfo; if (OnPreparePrinting(&printInfo)) {

// (did you remember to call DoPreparePrinting?)ASSERT(printInfo.m_pPD->m_pd.hDC != NULL);CString strTitle;CDocument* pDoc = GetDocument();strTitle = pDoc->GetTitle();DOCINFO docInfo;docInfo.lpszDocName = strTitle;

// setup the printing DCCDC dcPrint;dcPrint.Attach(printInfo.m_pPD->m_pd.hDC); dcPrint.m_bPrinting = TRUE;OnBeginPrinting(&dcPrint, &printInfo);dcPrint.SetAbortProc(_AfxAbortProc);

CView Printing Internals (cont’d)CView Printing Internals (cont’d)AfxGetMainWnd()->EnableWindow(FALSE);CPrintingDialog dlgPrintStatus(this);dlgPrintStatus.ShowWindow(SW_SHOW);dlgPrintStatus.UpdateWindow();

// start document printing processdcPrint.StartDoc(&docInfo);int nStep = (nEndPage >= nStartPage) ? 1 : -1;nEndPage = (nEndPage == 0xffff) ? 0xffff : nEndPage +

nStep;

// begin page printing loopfor (printInfo.m_nCurPage = nStartPage;

printInfo.m_nCurPage != nEndPage;printInfo.m_nCurPage += nStep)

{OnPrepareDC(&dcPrint, &printInfo);// check for end of printif (!printInfo.m_bContinuePrinting) break;

CView Printing Internals (cont’d)CView Printing Internals (cont’d)// write current pageTCHAR szBuf[80];wsprintf(szBuf, strTemp, printInfo.m_nCurPage);dlgPrintStatus.SetDlgItemText(

AFX_IDC_PRINT_PAGENUM, szBuf);printInfo.m_rectDraw.SetRect(0, 0,

dcPrint.GetDeviceCaps(HORZRES),dcPrint.GetDeviceCaps(VERTRES));

dcPrint.DPtoLP(&printInfo.m_rectDraw);// attempt to start the current pageif (dcPrint.StartPage() < 0) {

bError = TRUE; break;}OnPrint(&dcPrint, &printInfo);if (dcPrint.EndPage() < 0

|| !_AfxAbortProc(dcPrint.m_hDC, 0)) {bError = TRUE; break;

}}

}

CView Printing Internals (cont’d)CView Printing Internals (cont’d)// cleanup document printing processif (!printInfo.m_bDocObject) {

if (!bError)dcPrint.EndDoc();

elsedcPrint.AbortDoc();

}AfxGetMainWnd()->EnableWindow(); // enable main

windowOnEndPrinting(&dcPrint, &printInfo); // clean up after

printingdlgPrintStatus.DestroyWindow();dcPrint.Detach(); // will be cleaned up by CPrintInfo

destructor }}

CView Printing Internals (cont’d)CView Printing Internals (cont’d)CPrintInfo::CPrintInfo(){

m_pPD = new CPrintDialog(FALSE, PD_ALLPAGES |PD_USEDEVMODECOPIES |PD_NOSELECTION);

SetMinPage(1); // one based page numbersSetMaxPage(0xffff); // unknown how many pages

m_nCurPage = 1;m_lpUserData = NULL; // Initialize to no user datam_bPreview = FALSE; // initialize to not previewm_bDirect = FALSE; // initialize to not directm_bDocObject = FALSE; // initialize to not IPrintm_bContinuePrinting = TRUE; // Assume it is OK to printm_dwFlags = 0;m_nOffsetPage = 0;

}

CView Printing Internals (cont’d)CView Printing Internals (cont’d)

BOOL CView::DoPreparePrinting(CPrintInfo* pInfo){ CWinApp* pApp = AfxGetApp(); if (pInfo->m_bPreview || pInfo->m_bDirect || (pInfo->m_bDocObject

&& !(pInfo->m_dwFlags & PRINTFLAG_PROMPTUSER))) {

if (pInfo->m_pPD->m_pd.hDC == NULL){// if no printer set then, get default printer DC and // create DC without calling print dialog.

…}

} else {// otherwise, bring up the print dialog and allow user to //change things preset From-To range same as Min-Max

range

CView Printing Internals (cont’d)CView Printing Internals (cont’d)

pInfo->m_pPD->m_pd.nFromPage = (WORD)pInfo->GetMinPage();

pInfo->m_pPD->m_pd.nToPage = (WORD)pInfo->GetMaxPage();

if (pApp->DoPrintDialog(pInfo->m_pPD) != IDOK)return FALSE; // do not print

}

ASSERT(pInfo->m_pPD != NULL); ASSERT(pInfo->m_pPD->m_pd.hDC != NULL); if (pInfo->m_pPD->m_pd.hDC == NULL)

return FALSE;

pInfo->m_nNumPreviewPages = pApp->m_nNumPreviewPages; VERIFY(pInfo->m_strPageDesc.LoadString(AFX_IDS_PREVIEWPAGEDESC)); return TRUE;

}

관련 함수관련 함수 CView::OnFilePrint()(VIEWPRNT.CPP)CView::OnFilePrint()(VIEWPRNT.CPP)

CPrintInfo instanceCPrintInfo instance 생성생성 Print dialog Print dialog 를 할당한 후 를 할당한 후 m_pPDm_pPD 변수에 변수에 assignassign 기타 여러 변수의 값을 채움기타 여러 변수의 값을 채움

OnPreparePrinting()OnPreparePrinting() 함수 호출함수 호출 Virtual functionVirtual function 이기 때문에 이기 때문에 CMyView::OnPreparePrinting()CMyView::OnPreparePrinting()

을 호출하게 되고 내부에서 다시 을 호출하게 되고 내부에서 다시 CView::DoPreparePrinting()CView::DoPreparePrinting()호출호출

CView Printing Internals (cont’d)CView Printing Internals (cont’d)

DoPreparePrinting()DoPreparePrinting() Print dialogPrint dialog 를 보여주고를 보여주고 , , print DCprint DC 를 생성를 생성

Document titleDocument title 을 가져오고 을 가져오고 DOCINFO structureDOCINFO structure 를 생성를 생성 Local DCLocal DC 를 만들고 를 만들고 DoPreparePrinting()DoPreparePrinting() 과정에서 과정에서

만들어진 만들어진 DC handleDC handle 에 에 attachattach 함함 OnBeginPrinting()OnBeginPrinting()

DCDC 의 수정을 가하고자 하면 의 수정을 가하고자 하면 overrideoverride _AfxAbortProc()_AfxAbortProc() 의 설정의 설정

PrintPrint 도중 사용자가 도중 사용자가 cancelcancel 버튼을 누르는지 감시버튼을 누르는지 감시

CView Printing Internals (cont’d)CView Printing Internals (cont’d)

Main windowMain window 를 를 disabledisable 시키고 시키고 print print 진행 상황 진행 상황 dialogdialog를 보여줌를 보여줌

StartDoc()StartDoc() 호출호출 Printing LoopPrinting Loop 의 시작의 시작

OnPrepareDC()OnPrepareDC() StartPage()StartPage() OnPrint() OnPrint() OnDraw() OnDraw() 함수의 호출함수의 호출 EndPage()EndPage()

EndDoc()EndDoc() 호출호출 Main windowMain window 를 를 enableenable 시키고 시키고 OnEndPrinting()OnEndPrinting()

CView Printing Internals (cont’d)CView Printing Internals (cont’d)

CView::OnFilePrint()CView::OnFilePrint()

CView::OnPreparePrinting()CView::OnPreparePrinting()

CView::DoPreparePrinting()CView::DoPreparePrinting()

CPrintDialog::DoModal()CPrintDialog::DoModal()

CView::OnBeginPrinting()CView::OnBeginPrinting()

CView::OnPrepareDC()CView::OnPrepareDC()

CView::OnPrint()CView::OnPrint()

AnotherPage?

CView::OnDraw()CView::OnDraw()

CView::OnEndPrinting()CView::OnEndPrinting()

No

Yes

CView Printing Internals (cont’d)CView Printing Internals (cont’d)

CView Printing Internals (cont’d)CView Printing Internals (cont’d)

Customizing PrintingCustomizing Printing

Standard printingStandard printing EndPage()EndPage() 가 호출될 때가 호출될 때 , , WindowsWindows 가 한 가 한 pagepage 를 를

프린트하는 데 필요한 프린트하는 데 필요한 physical bandphysical band 를 그린다를 그린다 .. AbortAbort 를 자주 체크한다를 자주 체크한다 .. 프린트 작업이 느려진다프린트 작업이 느려진다 ..

Efficient printingEfficient printing Band Band 를 줄인다를 줄인다 . . 즉즉 , , 한 페이지당 여러 번 한 페이지당 여러 번

프린트한다프린트한다 .. 오버로딩 오버로딩 CMyView::OnFilePrint()CMyView::OnFilePrint()

CView Print PreviewCView Print Preview QuestionQuestion

Normal windowNormal window 에서 에서 print preview windowprint preview window 로의 로의 변환 방법변환 방법

Page outlinePage outline 의 표시 방법의 표시 방법 Printer outputPrinter output 을 화면에 표시하는 과정을 화면에 표시하는 과정 ToolbarToolbar 는 어디에서 온건지는 어디에서 온건지

Print Preview InternalPrint Preview Internal Print preview stepsPrint preview steps

“ViewPrev.cpp”

ON_COMMAND(ID_FILE_PRINT_PREVIEW, Cview::OnFilePrintPreview) // built-in

void CView::OnFilePrintPreview(){ CPrintPreviewState* pState = new CPrintPreviewState; if (!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this,

RUNTIME_CLASS(CPreviewView), pState)) {

delete pState; // preview failed to initialize, delete State now }}

Print Preview Internal (cont’d)Print Preview Internal (cont’d)

BOOL CView::DoPrintPreview(UINT nIDResource, CView* pPrintView,

CRuntimeClass* pPreviewViewClass, CPrintPreviewState* pState){

CFrameWnd* pParent = AfxGetMainWnd();

CCreateContext context;context.m_pCurrentFrame = pParent;context.m_pCurrentDoc = GetDocument();context.m_pLastView = this;

// Create the preview view objectCPreviewView* pView =

(CPreviewView*)pPreviewViewClass->CreateObject();

pView->m_pPreviewState = pState; // save pointer

pParent->OnSetPreviewMode(TRUE, pState);

Print Preview Internal (cont’d)Print Preview Internal (cont’d)

// Create the toolbar from the dialog resource pView->m_pToolBar = new CDialogBar; if (!pView->m_pToolBar->Create(pParent,

MAKEINTRESOURCE(nIDResource),CBRS_TOP,AFX_IDW_PREVIEW_BAR))

{pParent->OnSetPreviewMode(FALSE, pState); delete pView->m_pToolBar; // not autodestruct yetreturn FALSE;

} if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,

CRect(0,0,0,0), pParent, AFX_IDW_PANE_FIRST, &context)) {

pParent->OnSetPreviewMode(FALSE, pState); pView->m_pPreviewState = NULL; delete pView;return FALSE;

}

Print Preview Internal (cont’d)Print Preview Internal (cont’d)

// Preview window shown now pState->pViewActiveOld = pParent->GetActiveView(); CView* pActiveView = pParent->GetActiveFrame()->GetActiveView(); if (pActiveView != NULL)

pActiveView->OnActivateView(FALSE, pActiveView, pActiveView); if (!pView->SetPrintView(pPrintView)) { pView->OnPreviewClose();

return TRUE; } pParent->SetActiveView(pView); // update toolbar and redraw everything pView->m_pToolBar->SendMessage(WM_IDLEUPDATECMDUI, (WPARAM)TRUE); pParent->RecalcLayout(); // position and size everything pParent->UpdateWindow(); return TRUE;}

Print Preview Internal (cont’d)Print Preview Internal (cont’d)

CPreviewView classCPreviewView class AFXPRIV.HAFXPRIV.H

Print Preview Internal (cont’d)Print Preview Internal (cont’d)

class CPreviewView : public CScrollView{ DECLARE_DYNCREATE(CPreviewView) CPreviewView(); BOOL SetPrintView(CView* pPrintView);protected: CView* m_pOrigView; CView* m_pPrintView; CPreviewDC* m_pPreviewDC; // Output and attrib DCs Set, not created CDC m_dcPrint; // Actual printer DCpublic: virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);protected: CPrintPreviewState* m_pPreviewState; // State to restore CDialogBar* m_pToolBar; // Toolbar for preview

Print Preview Internal (cont’d)Print Preview Internal (cont’d) struct PAGE_INFO {

PAGE_INFO();CRect rectScreen; // screen rect (screen device units)CSize sizeUnscaled; // unscaled screen rect (screen device

units)CSize sizeScaleRatio; // scale ratio (cx/cy)CSize sizeZoomOutRatio; // scale ratio when zoomed out

(cx/cy) }; PAGE_INFO* m_pPageInfo; // Array of page info structures PAGE_INFO m_pageInfoArray[2]; // Embedded array for the default BOOL m_bPageNumDisplayed;// Flags whether or not page number has yet UINT m_nZoomOutPages; // number of pages when zoomed out UINT m_nZoomState; UINT m_nMaxPages; // for sanity checks UINT m_nCurrentPage; UINT m_nPages; int m_nSecondPageOffset; // used to shift second page position HCURSOR m_hMagnifyCursor; CSize m_sizePrinterPPI; // printer pixels per inch CPoint m_ptCenterPoint; CPrintInfo* m_pPreviewInfo;};

Print Preview Internal (cont’d)Print Preview Internal (cont’d)BOOL CPreviewView::SetPrintView(CView* pPrintView){ m_pPrintView = pPrintView; m_pPreviewInfo = new CPrintInfo; m_pPreviewInfo->m_pPD->SetHelpID(AFX_IDD_PRINTSETUP); m_pPreviewInfo->m_pPD->m_pd.Flags |= PD_PRINTSETUP; m_pPreviewInfo->m_pPD->m_pd.Flags &= ~PD_RETURNDC; m_pPreviewInfo->m_bPreview = TRUE; // signal that this is preview m_pPreviewDC = new CPreviewDC; // must be created before any if (!m_pPrintView->OnPreparePrinting(m_pPreviewInfo))

return FALSE; m_dcPrint.Attach(m_pPreviewInfo->m_pPD->m_pd.hDC); m_pPreviewDC->SetAttribDC(m_pPreviewInfo->m_pPD->m_pd.hDC); m_pPreviewDC->m_bPrinting = TRUE; m_dcPrint.m_bPrinting = TRUE; m_dcPrint.SaveDC(); // Save pristine state of DC HDC hDC = ::GetDC(m_hWnd); m_pPreviewDC->SetOutputDC(hDC); m_pPrintView->OnBeginPrinting(m_pPreviewDC, m_pPreviewInfo); m_pPreviewDC->ReleaseOutputDC(); ::ReleaseDC(m_hWnd, hDC); m_dcPrint.RestoreDC(-1); // restore to untouched state

Print Preview Internal (cont’d)Print Preview Internal (cont’d) // Get Pixels per inch from Printer m_sizePrinterPPI.cx = m_dcPrint.GetDeviceCaps(LOGPIXELSX); m_sizePrinterPPI.cy = m_dcPrint.GetDeviceCaps(LOGPIXELSY); m_nPages = m_pPreviewInfo->m_nNumPreviewPages; if (m_nPages == 0) m_nPages = 1; else if (m_nPages > m_nMaxPages) m_nPages = m_nMaxPages; m_nZoomOutPages = m_nPages; SetScrollSizes(MM_TEXT, CSize(1, 1)); // initialize mapping mode only if (m_pPreviewInfo->GetMaxPage() < 0x8000 &&

m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() <= 32767U) {

SCROLLINFO info;info.fMask = SIF_PAGE|SIF_RANGE;info.nMin = m_pPreviewInfo->GetMinPage();info.nMax = m_pPreviewInfo->GetMaxPage();info.nPage = 1;if (!SetScrollInfo(SB_VERT, &info, FALSE))

SetScrollRange(SB_VERT, info.nMin, info.nMax, FALSE); } else ShowScrollBar(SB_VERT, FALSE); // if no range specified, or too SetCurrentPage(m_pPreviewInfo->m_nCurPage, TRUE); return TRUE;}

Print Preview Internal (cont’d)Print Preview Internal (cont’d)void CPreviewView::OnDraw(CDC* pDC){ rectPen.CreatePen(PS_SOLID, 2, GetSysColor(COLOR_WINDOWFRAME)); shadowPen.CreatePen(PS_SOLID, 3, GetSysColor(COLOR_BTNSHADOW)); for (UINT nPage = 0; nPage < m_nPages; nPage++) {

pDC->SelectObject(&shadowPen);pDC->MoveTo(pRect->right + 1, pRect->top + 3);pDC->LineTo(pRect->right + 1, pRect->bottom + 1);pDC->MoveTo(pRect->left + 3, pRect->bottom + 1);pDC->LineTo(pRect->right + 1, pRect->bottom + 1);::FillRect(pDC->m_hDC, rectFill,

(HBRUSH)GetStockObject(WHITE_BRUSH));// Display page numberOnDisplayPageNumber(m_nCurrentPage, nPage + 1);m_pPrintView->OnPrint(m_pPreviewDC, m_pPreviewInfo);…

}

CView::OnFilePrintPreview()CView::OnFilePrintPreview() VIEWPREV.CPPVIEWPREV.CPP CPrintPreviewState structureCPrintPreviewState structure

PreviewPreview 를 위한 정보 저장를 위한 정보 저장 DoPrintPreview() DoPrintPreview() 호출호출

Print Preview Internal (cont’d)Print Preview Internal (cont’d)

CView::DoPrintPreview()CView::DoPrintPreview() VIEWPREV.CPPVIEWPREV.CPP CPreviewView instanceCPreviewView instance 를 생성를 생성 ((AFXPRIV.H)AFXPRIV.H)

미리보기 했을 때 나오는 미리보기 했을 때 나오는 viewview 임임 내부적으로 내부적으로 CPreviewDCCPreviewDC 를 사용를 사용 CFrameWnd::OnSetPreviewMode()CFrameWnd::OnSetPreviewMode() 함수 이용함수 이용

Normal windowNormal window 에서 에서 print preview modeprint preview mode 로 전환로 전환 원래 원래 viewview 의 의 UpdateWindow()UpdateWindow() 호출호출

실제 실제 renderingrendering 작업작업

Print Preview Internal (cont’d)Print Preview Internal (cont’d)

CPreviewView::SetPrintView()CPreviewView::SetPrintView() VIEWPREV.CPPVIEWPREV.CPP Device contextDevice context 의 준비의 준비 CDCCDC 의 두 멤버 변수의 두 멤버 변수

m_hDC m_hDC Screen Screen 에 대한 에 대한 device contextdevice context m_hAttribDC m_hAttribDC Printer Printer 에 대한 에 대한 device contextdevice context

CPreviewView::OnDraw()CPreviewView::OnDraw() VIEWPREV.CPPVIEWPREV.CPP 각 페이지의 각 페이지의 outlineoutline 을 그리고 실제 을 그리고 실제 renderingrendering

Print Preview Internal (cont’d)Print Preview Internal (cont’d)

CScrollViewCScrollView 사용 과정사용 과정

CScrollViewCScrollView 에서 에서 viewview 를 상속받음를 상속받음 SetScrollSize()SetScrollSize() 를 이용하여 를 이용하여 settingsetting

CScrollView classCScrollView class Declaration(AFXWIN.H)Declaration(AFXWIN.H) Implementation(VIEWSCRL.CPP)Implementation(VIEWSCRL.CPP)

CScrollView (cont’d)CScrollView (cont’d)class CScrollView : public CView{ DECLARE_DYNAMIC(CScrollView)protected: int m_nMapMode; CSize m_totalLog; // total size in logical units (no rounding) CSize m_totalDev; // total size in device units CSize m_pageDev; // per page scroll size in device units CSize m_lineDev; // per line scroll size in device units BOOL m_bCenter; // Center output if larger than total size BOOL m_bInsideUpdate; // internal state for OnSize callback void CenterOnPoint(CPoint ptCenter); void ScrollToDevicePosition(POINT ptDev); // explicit scrolling no checkingprotected: void UpdateBars(); // adjust scrollbars etc BOOL GetTrueClientSize(CSize& size, CSize& sizeSb); void GetScrollBarSizes(CSize& sizeSb); void GetScrollBarState(CSize sizeClient, CSize& needSb,

CSize& sizeRange, CPoint& ptMove, BOOL bInsideClient);

CScrollView (cont’d)CScrollView (cont’d)

public: virtual void CalcWindowRect(LPRECT lpClientRect,

UINT nAdjustType = adjustBorder); virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL); virtual BOOL OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll = TRUE); virtual BOOL OnScrollBy(CSize sizeScroll, BOOL bDoScroll = TRUE); //{{AFX_MSG(CScrollView) afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg BOOL OnMouseWheel(UINT fFlags, short zDelta, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP()};

CScrollView::SetScrollSizes()CScrollView::SetScrollSizes() Mapping modeMapping mode 설정설정 DocumentDocument 의 의 scroll sizescroll size 설정설정 Scroll barScroll bar 설치를 위해 설치를 위해 UpdateBars()UpdateBars() 함수 호출함수 호출 Mapping modeMapping mode 가 변경되었으면 가 변경되었으면 Invalidate()Invalidate() 함수 함수

호출 호출 화면 새로 그림 화면 새로 그림 CScrollView::OnPrepareDC()CScrollView::OnPrepareDC()

주어진 주어진 mapping modemapping mode 에 따른 에 따른 DCDC 관련 준비작업관련 준비작업 실제 실제 scrollscroll 에 관련된 함수에 관련된 함수

OnScrollBy(), ScrollToDevicePosition()OnScrollBy(), ScrollToDevicePosition() 내부적으로 내부적으로 ScrollWindow()ScrollWindow() 함수를 이용함함수를 이용함

CScrollView (cont’d)CScrollView (cont’d)

CScrollView (cont’d)CScrollView (cont’d)

void CMyView::OnInitialUpdate(){ // The GetDocSize( ) member function is implemented in // your document class. The return type is CSize. SetScrollSizes(MM_TEXT, GetDocument( )->GetDocSize( ) ); CScrollView::OnInitialUpdate();}

CScrollView (cont’d)CScrollView (cont’d)void CScrollView::SetScrollSizes(int nMapMode, SIZE sizeTotal,

const SIZE& sizePage, const SIZE& sizeLine){ int nOldMapMode = m_nMapMode; m_nMapMode = nMapMode; m_totalLog = sizeTotal; //BLOCK: convert logical coordinate space to device coordinates {

CWindowDC dc(NULL);dc.SetMapMode(m_nMapMode);m_totalDev = m_totalLog;dc.LPtoDP((LPPOINT)&m_totalDev);m_pageDev = sizePage;dc.LPtoDP((LPPOINT)&m_pageDev);m_lineDev = sizeLine;dc.LPtoDP((LPPOINT)&m_lineDev);if (m_totalDev.cy < 0) m_totalDev.cy = -m_totalDev.cy;if (m_pageDev.cy < 0) m_pageDev.cy = -m_pageDev.cy;if (m_lineDev.cy < 0) m_lineDev.cy = -m_lineDev.cy;

} // release DC here

CScrollView (cont’d)CScrollView (cont’d)

if (m_pageDev.cx == 0) m_pageDev.cx = m_totalDev.cx / 10; if (m_pageDev.cy == 0) m_pageDev.cy = m_totalDev.cy / 10; if (m_lineDev.cx == 0) m_lineDev.cx = m_pageDev.cx / 10; if (m_lineDev.cy == 0) m_lineDev.cy = m_pageDev.cy / 10;

if (m_hWnd != NULL) {

// window has been created, invalidate nowUpdateBars();if (nOldMapMode != m_nMapMode)

Invalidate(TRUE); }}

CScrollView (cont’d)CScrollView (cont’d)void CScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo){ switch (m_nMapMode) { case MM_SCALETOFIT: pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetWindowExt(m_totalLog); // window is in logical coordinates pDC->SetViewportExt(m_totalDev); break; default: pDC->SetMapMode(m_nMapMode); break; } CPoint ptVpOrg(0, 0); // assume no shift for printing if (!pDC->IsPrinting()) { ptVpOrg = -GetDeviceScrollPosition(); pDC->SetViewportOrg(ptVpOrg); CView::OnPrepareDC(pDC, pInfo); // For default Printing behavior}

CFormViewCFormView CFormView classCFormView class

DialogDialog 의 편리함과 의 편리함과 document/viewdocument/view 의 기능을 같이 의 기능을 같이 쓸 수 있게 해줌쓸 수 있게 해줌

자동 자동 printing, print previewprinting, print preview 기능은 제공하지 않음기능은 제공하지 않음 Declaration(AFXEXT.H)Declaration(AFXEXT.H) Implementation(VIEWFORM.CPP)Implementation(VIEWFORM.CPP)

CFormView::Create()CFormView::Create()

CCtrlViewCCtrlView 특징특징

Windows controlWindows control 을 을 viewview 가 되게 함가 되게 함 종류종류

CEditView, CListView, CTreeView, CRichEditViewCEditView, CListView, CTreeView, CRichEditView

CCtrlViewCCtrlView 는 는 base classbase class 임임 Declaration(AFXWIN.H)Declaration(AFXWIN.H) Implementation(VIEWCORE.CPP)Implementation(VIEWCORE.CPP)

CCtrlView (cont’d)CCtrlView (cont’d)class CCtrlView : public CView{

DECLARE_DYNCREATE(CCtrlView)public:

CCtrlView(LPCTSTR lpszClass, DWORD dwStyle);// Attributesprotected:

CString m_strClass;DWORD m_dwDefaultStyle;

// Overridesvirtual void OnDraw(CDC*);virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

// Implementationprotected:

afx_msg void OnPaint();DECLARE_MESSAGE_MAP()

};

멤버멤버 m_strclass : m_strclass : 해당 해당 controlcontrol 에 대한 에 대한 window classwindow class

의 이름의 이름 m_dwDefaultStyle : view classm_dwDefaultStyle : view class 에 대한 에 대한 default default

stylestyle OnDraw() : OnDraw() : 절대 호출되지 않는 함수절대 호출되지 않는 함수 OnPaint() : Defaul() OnPaint() : Defaul() 호출호출 . . 이는 이는 controlcontrol 들이 들이

스스로 스스로 paint paint 할 수 있기 때문할 수 있기 때문

CCtrlView (cont’d)CCtrlView (cont’d)

CTreeViewCTreeView CTreeView classCTreeView class

Declaration(AFXCVIEW.H)Declaration(AFXCVIEW.H) ImplementationImplementation

VIEWCMN.CPPVIEWCMN.CPP AFXCVIEW.INLAFXCVIEW.INL CTreeView::CTreeView()CTreeView::CTreeView() CTreeView::PreCreateWindow()CTreeView::PreCreateWindow() CTreeView::GetTreeCtrl()CTreeView::GetTreeCtrl()

Control ClassesControl Classes 선언 및 구현 파일선언 및 구현 파일

CEditViewCEditView AFXEXT.H, AFXEXT.INL/VIEWEDIT.CPPAFXEXT.H, AFXEXT.INL/VIEWEDIT.CPP

CListViewCListView AFXCVIEW.H, AFXCVIEW.INL/VIEWCMN.CPPAFXCVIEW.H, AFXCVIEW.INL/VIEWCMN.CPP

CRichEditViewCRichEditView AFXRICH.H, AFXRICH.INL/VIEWRICH.CPPAFXRICH.H, AFXRICH.INL/VIEWRICH.CPP

Enhanced User-Interface Enhanced User-Interface ClassesClasses

Chap. 9Chap. 9

ContentsContents Splitter WindowsSplitter Windows CControlBar ArchitectureCControlBar Architecture CMiniFrameWndCMiniFrameWnd MRU File ListMRU File List

IntroductionIntroduction 일반 일반 user interfaceuser interface

Win32 API Win32 API 에 존재하는 구조에 존재하는 구조 CWnd, CDialog, control, …CWnd, CDialog, control, …

Enhanced user interfaceEnhanced user interface MFC MFC 에 존재하는 구조에 존재하는 구조 splitter window, control bar, …splitter window, control bar, …

MFC Splitter WindowsMFC Splitter Windows

pane1

pane2

Splitter bar

Splitter border

Split box

Splitter WindowSplitter Window 특징특징

PanesPanes 일반적으로 일반적으로 CViewCView

DocumentDocument 내용이 변하면 내용이 변하면 UpdateAllViews()UpdateAllViews() 로 반영가능로 반영가능 모든 모든 CWnd derivativeCWnd derivative 가 가능가 가능

DocumentDocument 내용이 변하면 수동으로 변화를 반영시켜야 함내용이 변하면 수동으로 변화를 반영시켜야 함

Splitter Window (cont’d)Splitter Window (cont’d) 두가지 두가지 typetype

Dynamic splitter windowDynamic splitter window 2X22X2 로 제한로 제한 Create()Create() 함수 이용함수 이용 Document templateDocument template 에 정보 추가에 정보 추가 view view 가 동일한 성질가 동일한 성질 예 예 : : VC++ code editorVC++ code editor

Static splitter windowStatic splitter window 2X22X2 의 제한 없음의 제한 없음 (16(16X16)X16) CreateStatic()CreateStatic() 함수 이용함수 이용 CreateView()CreateView() 함수로 각 함수로 각 panepane 에 에 viewview 를 생성를 생성 viewview 가 서로 다른 성질가 서로 다른 성질 예 예 : : 탐색기탐색기

Splitter Window (cont’d)Splitter Window (cont’d)BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext){

if (!m_wndSplitter.Create(this, 2, 2, CSize(10, 10), pContext))

{TRACE0("Failed to create splitter bar ");

return FALSE; // failed to create}return TRUE;

}

Splitter Window (cont’d)Splitter Window (cont’d)

BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext){

int nRow, nCol;

if (!m_wndSplitter.CreateStatic(this, 4, 4) )return FALSE;

for ( nRow = 0; nRow<4; nRow++ )for ( nCol=0; nCol<4; nCol+= )

m_wndSplitter.CreateView(nRow, nCol,RUNTIME_CLASS(CMyView),Csize(10, 10), pContext);

return TRUE;}

CSplitterWndCSplitterWnd CSplitterWnd classCSplitterWnd class

Declaration(AFXEXT.H)Declaration(AFXEXT.H)

class CSplitterWnd : public CWnd{

DECLARE_DYNAMIC(CSplitterWnd)// Constructionpublic:

CSplitterWnd();// Create a single view type splitter with multiple splitsBOOL Create();BOOL CreateStatic();virtual BOOL CreateView();

// Attributespublic:

int IdFromRowCol(int row, int col) const;virtual void RecalcLayout(); // call after changing sizes

CSplitterWnd (cont’d)CSplitterWnd (cont’d)// Overridablesprotected:

enum ESplitType { splitBox, splitBar, splitIntersection, splitBorder };

virtual void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rect);

virtual void OnInvertTracker(const CRect& rect);public:

// for customizing DYNAMIC_SPLIT behaviorvirtual void DeleteView(int row, int col);virtual BOOL SplitRow(int cyBefore);virtual BOOL SplitColumn(int cxBefore);virtual void DeleteRow(int rowDelete);virtual void DeleteColumn(int colDelete);

// determining active pane from focus or active view in frame

virtual CWnd* GetActivePane(int* pRow = NULL, int* pCol = NULL);

virtual void SetActivePane(int row, int col, CWnd* pWnd = NULL);protected:

CWnd* GetActivePane(int& row, int& col); // obsolete

CSplitterWnd (cont’d)CSplitterWnd (cont’d)public:

struct CRowColInfo{

int nMinSize; // below that try not to showint nIdealSize; // user set size// variable depending on the available size layoutint nCurSize; // 0 => invisible, -1 =>

nonexistant};

protected:CRuntimeClass* m_pDynamicViewClass;int m_nMaxRows, m_nMaxCols;

// current state informationint m_nRows, m_nCols;BOOL m_bHasHScroll, m_bHasVScroll;CRowColInfo* m_pColInfo;CRowColInfo* m_pRowInfo;

CSplitterWnd (cont’d)CSplitterWnd (cont’d)// Tracking info - only valid when 'm_bTracking' is setBOOL m_bTracking, m_bTracking2;CPoint m_ptTrackOffset;CRect m_rectLimit;CRect m_rectTracker, m_rectTracker2;int m_htTrack;BOOL CreateCommon(CWnd* pParentWnd, SIZE sizeMin,

DWORD dwStyle, UINT nID);virtual int HitTest(CPoint pt) const;virtual void GetInsideRect(CRect& rect) const;virtual void GetHitRect(int ht, CRect& rect);virtual void TrackRowSize(int y, int row);virtual void TrackColumnSize(int x, int col);virtual void DrawAllSplitBars(CDC* pDC, int cxInside, int

cyInside);virtual void SetSplitCursor(int ht);CWnd* GetSizingParent();// starting and stopping trackingvirtual void StartTracking(int ht);virtual void StopTracking(BOOL bAccept);

CSplitterWnd (cont’d)CSplitterWnd (cont’d)// special command routing to framevirtual BOOL OnCommand(WPARAM wParam, LPARAM

lParam);virtual BOOL OnNotify(WPARAM wParam, LPARAM

lParam, LRESULT* pResult);afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest,

UINT message);afx_msg void OnMouseMove(UINT nFlags, CPoint pt);afx_msg void OnPaint();afx_msg void OnLButtonDown(UINT nFlags, CPoint pt);afx_msg void OnLButtonDblClk(UINT nFlags, CPoint pt);afx_msg void OnLButtonUp(UINT nFlags, CPoint pt);afx_msg void OnCancelMode();afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt,

UINT nFlags);afx_msg void OnSize(UINT nType, int cx, int cy);afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta,

CPoint pt);afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpcs);afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnDisplayChange();

};

CSplitterWndCSplitterWnd 멤버 멤버 data typedata type

ESplitTypeESplitType Defines type of splitter to be drawnDefines type of splitter to be drawn

CRowColInfoCRowColInfo Mininum, ideal, current size of a row or column(rowMininum, ideal, current size of a row or column(row

이면 높이이면 높이 , , columncolumn 이면 넓이이면 넓이 ))

CSplitterWnd (cont’d)CSplitterWnd (cont’d) 멤버 변수멤버 변수

m_pDynamicViewClassm_pDynamicViewClass DynamicDynamic 하게 생성된 하게 생성된 viewview 의 의 CRuntimeClassCRuntimeClass 에 대한 에 대한

pointerpointer

m_pColInfom_pColInfo Array of CRowColInfoArray of CRowColInfo

m_pRowInfom_pRowInfo Array of CRowColInfoArray of CRowColInfo

멤버 함수멤버 함수 RecalcLayout()RecalcLayout()

모든 모든 splitter window componentsplitter window component 에 대한 위치 조절 작업에 대한 위치 조절 작업

OnDisplayChange()OnDisplayChange() Monitor resolutionMonitor resolution 을 바꾸면 호출됨을 바꾸면 호출됨

이외 수많은 멤버 변수와 함수이외 수많은 멤버 변수와 함수

CSplitterWnd (cont’d)CSplitterWnd (cont’d)

InitializationInitialization CreateCreate 함수함수

Create()Create() 나 나 CreateStatic() CreateStatic() 둘 다 내부적으로 둘 다 내부적으로 CreateCommon()CreateCommon() 함수를 호출함수를 호출

CSplitterWnd::Create()(WINSPLIT.CPP)CSplitterWnd::Create()(WINSPLIT.CPP) 최고 최고 22X2X2 인지 확인인지 확인 현재 현재 rowrow 와 와 colcol 의 수를 의 수를 11 로 초기화로 초기화 ((dynamic)dynamic) CreateCommon()CreateCommon() 함수 호출함수 호출 CreateView()CreateView() 함수 호출함수 호출

Initialization (cont’d)Initialization (cont’d) CSplitterWnd::CreateStatic()CSplitterWnd::CreateStatic()

최고 최고 1616X16X16 의 제한의 제한 CreateCommon()CreateCommon() 함수 호출함수 호출 CreateView()CreateView() 함수의 호출이 없음함수의 호출이 없음

CSplitterWnd::CreateCommon()CSplitterWnd::CreateCommon() 실제 실제 splitter windowsplitter window 가 생성됨가 생성됨 Current sizeCurrent size 를 –를 – 11 로 함로 함

크기 조절 함수크기 조절 함수 SetColumnInfo()/SetRowInfo()SetColumnInfo()/SetRowInfo()

CSplitterWnd::CreateView()CSplitterWnd::CreateView() 특정 특정 panepane 에 에 viewview 의 생성의 생성 IdFromRowCol()IdFromRowCol() 함수 이용함수 이용

RowRow 와 와 columncolumn 값으로 값으로 panepane 의 의 IDID 를 계산를 계산 내부적으로 내부적으로 CWndCWnd 의 의 Create()Create() 함수 호출함수 호출

Initialization (cont’d)Initialization (cont’d)

Initialization (cont’d)Initialization (cont’d)BOOL CSplitterWnd::Create(CWnd* pParentWnd,

int nMaxRows, int nMaxCols, SIZE sizeMin,CCreateContext* pContext, DWORD dwStyle, UINT nID)

{// Dynamic splitters are limited to 2x2ASSERT(nMaxRows >= 1 && nMaxRows <= 2);ASSERT(nMaxCols >= 1 && nMaxCols <= 2);ASSERT(nMaxCols > 1 || nMaxRows > 1); // 1x1 is not

m_nMaxRows = nMaxRows;m_nMaxCols = nMaxCols;m_nRows = m_nCols = 1; // start off as 1x1if (!CreateCommon(pParentWnd, sizeMin, dwStyle, nID))

return FALSE;m_pDynamicViewClass = pContext->m_pNewViewClass;

Initialization (cont’d)Initialization (cont’d)

// add the first initial paneif (!CreateView(0, 0, m_pDynamicViewClass, sizeMin,

pContext)){

DestroyWindow(); // will clean up child windowsreturn FALSE;

}m_pColInfo[0].nIdealSize = sizeMin.cx;m_pRowInfo[0].nIdealSize = sizeMin.cy;

return TRUE;}

Initialization (cont’d)Initialization (cont’d)BOOL CSplitterWnd::CreateStatic(CWnd* pParentWnd,

int nRows, int nCols, DWORD dwStyle, UINT nID){

ASSERT(nRows >= 1 && nRows <= 16);ASSERT(nCols >= 1 && nCols <= 16);ASSERT(nCols > 1 || nRows > 1); // 1x1 is not permitted

ASSERT(m_nRows == 0 && m_nCols == 0); // none yetm_nRows = m_nMaxRows = nRows;m_nCols = m_nMaxCols = nCols;

// create with zero minimum pane sizeif (!CreateCommon(pParentWnd, CSize(0, 0), dwStyle,

nID))return FALSE;

return TRUE;}

Initialization (cont’d)Initialization (cont’d)BOOL CSplitterWnd::CreateCommon(CWnd* pParentWnd,

SIZE sizeMin, DWORD dwStyle, UINT nID){

VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));

if (!CreateEx(0, _afxWndMDIFrame, NULL, dwCreateStyle, 0, 0, 0, 0,

pParentWnd->m_hWnd, (HMENU)nID, NULL))return FALSE; // create invisible

m_pColInfo = new CRowColInfo[m_nMaxCols];for (int col = 0; col < m_nMaxCols; col++) {

m_pColInfo[col].nMinSize = m_pColInfo[col].nIdealSize = sizeMin.cx;

m_pColInfo[col].nCurSize = -1; }

Initialization (cont’d)Initialization (cont’d)m_pRowInfo = new CRowColInfo[m_nMaxRows];for (int row = 0; row < m_nMaxRows; row++) {

m_pRowInfo[row].nMinSize = m_pRowInfo[row].nIdealSize = sizeMin.cy;

m_pRowInfo[row].nCurSize = -1; }

// create scroll bars by setting the styleSetScrollStyle(dwStyle);

return TRUE;}

Initialization (cont’d)Initialization (cont’d)BOOL CSplitterWnd::CreateView(int row, int col,

CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext){

GetDlgItem(IdFromRowCol(row, col));

// set the initial size for that panem_pColInfo[col].nIdealSize = sizeInit.cx;m_pRowInfo[row].nIdealSize = sizeInit.cy;

BOOL bSendInitialUpdate = FALSE;

CCreateContext contextT;if (pContext == NULL){

Initialization (cont’d)Initialization (cont’d)CView* pOldView = (CView*)GetActivePane();if (pOldView != NULL &&

pOldView->IsKindOf(RUNTIME_CLASS(CView))) {contextT.m_pLastView = pOldView;contextT.m_pCurrentDoc = pOldView-

>GetDocument();if (contextT.m_pCurrentDoc != NULL)

contextT.m_pNewDocTemplate = contextT.m_pCurrentDoc-

>GetDocTemplate();}pContext = &contextT;bSendInitialUpdate = TRUE;

} CWnd* pWnd = (CWnd*)pViewClass->CreateObject(); pWnd->Create(NULL, NULL, dwStyle,

rect, this, IdFromRowCol(row, col), pContext); return TRUE;}

Pane ManagementPane Management 살펴볼 사항살펴볼 사항

Dynamic splitter windowDynamic splitter window 에서에서 PanePane 이 이 dynamicdynamic 하게 생성되는 과정하게 생성되는 과정

전체 전체 frame windowframe window 의 크기가 조절될 때의 크기가 조절될 때 각 각 panepane 들의 크기와 위치가 조절되는 과정들의 크기와 위치가 조절되는 과정

관련 함수관련 함수 SplitRow(), SplitColumn()SplitRow(), SplitColumn()

Pane Management (cont’d)Pane Management (cont’d) CSplitterWnd::SplitColumn()CSplitterWnd::SplitColumn()

WINCORE.CPPWINCORE.CPP Dynamic splitter windowsDynamic splitter windows 에서 가능에서 가능 각 각 panepane 에 대하여 에 대하여 CreateView()CreateView() 함수 호출함수 호출 CRowColInfo structureCRowColInfo structure 에 새로운 정보를 저장에 새로운 정보를 저장 RecalcLayout()RecalcLayout() 함수를 호출하여 함수를 호출하여 pane layout pane layout 조절조절

Pane Management (cont’d)Pane Management (cont’d)BOOL CSplitterWnd::SplitColumn(int cxBefore){ cxBefore -= m_cxBorder; int colNew = m_nCols; int cxNew = _AfxCanSplitRowCol(&m_pColInfo[colNew-1], cxBefore, m_cxSplitter); if (cxNew == -1) return FALSE; // too small to split m_nCols++; // bump count during view creation for (int row = 0; row < m_nRows; row++) { CSize size(cxNew, m_pRowInfo[row].nCurSize);

if (!CreateView(row,colNew, m_pDynamicViewClass, size, NULL))

{while (row > 0) DeleteView(--row, colNew);m_nCols--; // it didn't work outreturn FALSE;

} }

Pane Management (cont’d)Pane Management (cont’d)

// new parts created - resize and re-layoutm_pColInfo[colNew-1].nIdealSize = cxBefore;m_pColInfo[colNew].nIdealSize = cxNew;ASSERT(m_nCols == colNew+1);RecalcLayout();

return TRUE;}

CSplitterWnd DrawingCSplitterWnd Drawing 관련 함수관련 함수

DrawAllSplitBars(), OnDrawSplitter()DrawAllSplitBars(), OnDrawSplitter() 실제로 실제로 OnDrawSplitter()OnDrawSplitter() 가 가 drawingdrawing 을 함을 함 CSplitterWnd::OnDrawSplitter()CSplitterWnd::OnDrawSplitter()

WINSPLIT.CPPWINSPLIT.CPP DrawAllSplitBars()DrawAllSplitBars() 함수에서 각 함수에서 각 rowrow 와 와 columncolumn 에 대하여 에 대하여

호출됨호출됨 Split border, box, barSplit border, box, bar 등의 등의 drawingdrawing

CSplitterWnd Drawing (cont’d)CSplitterWnd Drawing (cont’d) DrawAllSplitBars()DrawAllSplitBars()

Splitter barSplitter bar 와 와 splitter bordersplitter border 를 를 OnDrawSplitter()OnDrawSplitter()함수를 이용하여 그림함수를 이용하여 그림

CSplitterWnd::OnPaint()CSplitterWnd::OnPaint() OnDrawSplitter()OnDrawSplitter() 를 이용하여 를 이용하여 splitter boxsplitter box 를 그림를 그림 DrawAllSplitBars()DrawAllSplitBars() 함수를 이용하여 함수를 이용하여 splitter barsplitter bar 와 와

splitter bordersplitter border 를 그림를 그림 결국 결국 OnPaint()OnPaint() 가 모든 그리는 작업을 함가 모든 그리는 작업을 함

CSplitterWnd Drawing (cont’d)CSplitterWnd Drawing (cont’d)void CSplitterWnd::DrawAllSplitBars(CDC* pDC, int cxInside, int cyInside){

// draw column split barsCRect rect;GetClientRect(rect);rect.left += m_cxBorder;for (int col = 0; col < m_nCols - 1; col++){

rect.left += m_pColInfo[col].nCurSize + m_cxBorderShare;

rect.right = rect.left + m_cxSplitter;if (rect.left > cxInside)

break; // stop if not fully visibleOnDrawSplitter(pDC, splitBar, rect);rect.left = rect.right + m_cxBorderShare;

}

CSplitterWnd Drawing (cont’d)CSplitterWnd Drawing (cont’d)// draw row split barsGetClientRect(rect);rect.top += m_cyBorder;for (int row = 0; row < m_nRows - 1; row++){

rect.top += m_pRowInfo[row].nCurSize + m_cyBorderShare;

rect.bottom = rect.top + m_cySplitter;if (rect.top > cyInside) break; // stop if not

fully visibleOnDrawSplitter(pDC, splitBar, rect);rect.top = rect.bottom + m_cyBorderShare;

}

// draw pane bordersGetClientRect(rect);int x = rect.left;

CSplitterWnd Drawing (cont’d)CSplitterWnd Drawing (cont’d)for (col = 0; col < m_nCols; col++) {

int cx = m_pColInfo[col].nCurSize + 2*m_cxBorder;if (col == m_nCols-1 && m_bHasVScroll)

cx += afxData.cxVScroll - CX_BORDER;int y = rect.top;for (int row = 0; row < m_nRows; row++){

int cy = m_pRowInfo[row].nCurSize + 2*m_cyBorder;

if (row == m_nRows-1 && m_bHasHScroll)cy += afxData.cyHScroll -

CX_BORDER;OnDrawSplitter(pDC, splitBorder,

CRect(x, y, x+cx, y+cy));y += cy + m_cySplitterGap - 2*m_cyBorder;

}x += cx + m_cxSplitterGap - 2*m_cxBorder;

}}

CSplitterWnd Drawing (cont’d)CSplitterWnd Drawing (cont’d)void CSplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType,

const CRect& rectArg){

// otherwise, actually drawCRect rect = rectArg;switch (nType){case splitBorder:case splitIntersection:case splitBox:case splitBar:

if (!afxData.bWin4)}

// fill the middleCOLORREF clr = afxData.clrBtnFace;pDC->FillSolidRect(rect, clr);

}

CSplitterWnd Drawing (cont’d)CSplitterWnd Drawing (cont’d)void CSplitterWnd::OnPaint(){

CPaintDC dc(this);

// draw the splitter boxesif (m_bHasVScroll && m_nRows < m_nMaxRows)

OnDrawSplitter(&dc, splitBox,…);if (m_bHasHScroll && m_nCols < m_nMaxCols)

OnDrawSplitter(&dc, splitBox,…);

// extend split bars to window border (past margins)DrawAllSplitBars(&dc, rectInside.right,

rectInside.bottom);

// draw splitter intersections (inside only)for (int row = 0; row < m_nRows - 1; row++)

for (int col = 0; col < m_nCols - 1; col++) OnDrawSplitter(&dc, splitIntersection,

rect);}

Hit TestingHit Testing 역할역할

사용자가 어느 사용자가 어느 splitter componentsplitter component 를 를 hithit 했는지…했는지… User interactionsUser interactions

Mouse moveMouse move Splitter barSplitter bar 위에서 위에서 cursorcursor 의 변경의 변경

Button downButton down Drag bar, create barDrag bar, create bar

Button upButton up Stop draggingStop dragging

Hit Testing (cont’d)Hit Testing (cont’d) 관련 함수관련 함수

CSplitterWnd::HitTest()CSplitterWnd::HitTest() WINSPLIT.CPPWINSPLIT.CPP 마우스 왼쪽 버튼의 클릭마우스 왼쪽 버튼의 클릭 , , 마우스 이동마우스 이동 , , 마우스 오른쪽 마우스 오른쪽

버튼의 더블 클릭 시 호출버튼의 더블 클릭 시 호출 PtInRect()PtInRect() 함수를 이용함수를 이용

Splitter componentSplitter component 중 어느 부분인지 구별함중 어느 부분인지 구별함

Splitter Window TrackingSplitter Window Tracking 역할역할

HitTestHitTest 의 결과를 가지고 의 결과를 가지고 splitter componentsplitter component 를 를 다시 그림다시 그림

PanePane 의 의 splitsplit 관련 함수관련 함수

CSplitterWnd::StartTracking()CSplitterWnd::StartTracking() CSplitterWnd::OnInvertTracker()CSplitterWnd::OnInvertTracker() CSplitterWnd::StopTracking()CSplitterWnd::StopTracking()

CSplitterWnd::OnInvertTracker()CSplitterWnd::OnInvertTracker() 마우스가 움직이는 동안 마우스가 움직이는 동안 Split borderSplit border 를 그리는 역할를 그리는 역할

CSplitterWnd::StopTracking()CSplitterWnd::StopTracking() TrackingTracking 이 끝나고 마우스 버튼을 놓으면 호출이 끝나고 마우스 버튼을 놓으면 호출 실제 실제 viewview 의 의 splitsplit 작업작업

Splitter Window Tracking (cont’d)Splitter Window Tracking (cont’d)

CControlBar Arch.CControlBar Arch. Control barControl bar

Frame windowFrame window 의 한 쪽 의 한 쪽 sideside 에 위치하는 특별한 에 위치하는 특별한 windowwindow

DockingDocking 이 가능이 가능 위치 정보를 위치 정보를 INIINI 파일이나 파일이나 registryregistry 에 저장에 저장 종류종류

CDialogBar, COleResizeBar, CStatusBar, CToolBar, CDialogBar, COleResizeBar, CStatusBar, CToolBar, CReBarCReBar

CControlBarCControlBar CControlBar classCControlBar class

Declaration(AFXEXT.H)Declaration(AFXEXT.H) ImplementationImplementation

BARCORE.CPPBARCORE.CPP BARDOCK.CPPBARDOCK.CPP DOCKSTAT.CPPDOCKSTAT.CPP WINFRM.CPPWINFRM.CPP

CControlBar (cont’d)CControlBar (cont’d)class CControlBar : public CWnd{

int m_cxLeftBorder, m_cxRightBorder;int m_cyTopBorder, m_cyBottomBorder;int m_cxDefaultGap; // default gap valueUINT m_nMRUWidth; // For dynamic resizing.int m_nCount;void* m_pData; // m_nCount elementsenum StateFlags{ delayHide = 1, delayShow = 2, tempHide = 4, statusSet

= 8 };UINT m_nStateFlags;// support for dockingDWORD m_dwStyle; // creation style (used for layout)DWORD m_dwDockStyle;// indicates how bar can be

dockedCFrameWnd* m_pDockSite; // current dock site, if

dockableCDockBar* m_pDockBar; // current dock bar, if dockableCDockContext* m_pDockContext; // used during

draggingvirtual void DoPaint(CDC* pDC);void DrawBorders(CDC* pDC, CRect& rect);void DrawGripper(CDC* pDC, const CRect& rect);

CControlBar (cont’d)CControlBar (cont’d)// implementation helpersvirtual LRESULT WindowProc(UINT nMsg, WPARAM

wParam, LPARAM lParam);void CalcInsideRect(CRect& rect, BOOL bHorz) const; //

adjusts borders etcBOOL AllocElements(int nElements, int cbElement);virtual BOOL SetStatusText(int nHit);void ResetTimer(UINT nEvent, UINT nTime);void EraseNonClient();

void GetBarInfo(CControlBarInfo* pInfo);void SetBarInfo(CControlBarInfo* pInfo, CFrameWnd*

pFrameWnd);

friend class CFrameWnd;friend class CDockBar;

};

CControlBar (cont’d)CControlBar (cont’d) 멤버 함수멤버 함수

DoPaint()DoPaint() Control barControl bar 의 경계를 그리는 함수의 경계를 그리는 함수 OnPaint() OnPaint() DoPaint() DoPaint() DrawBorders() DrawBorders()

DrawBorders()DrawBorders() 실제 실제 control barcontrol bar 의 경계를 그리는 함수의 경계를 그리는 함수 Control barControl bar 가 가 dockdock 되었을 때만 역할 수행되었을 때만 역할 수행

Docking Docking CControlBar::EnableDocking()CControlBar::EnableDocking()

BARDOCK.CPPBARDOCK.CPP 변수 초기화변수 초기화

CFrameWnd::EnableDocking()CFrameWnd::EnableDocking() WINFRM2.CPPWINFRM2.CPP CMiniDockFrameWnd CMiniDockFrameWnd 의 사용의 사용 CDockBarCDockBar 의 사용의 사용

좌좌 , , 우우 , , 위위 , , 아래의 아래의 control barcontrol bar 가 놓일 자리임가 놓일 자리임

Docking (cont’d)Docking (cont’d) ArgumentArgument 로 주어진 로 주어진 flagflag 를 보고 좌를 보고 좌 , , 우우 , , 상상 , , 하 하

어느 위치에 어느 위치에 DockBarDockBar 를 만들지 결정를 만들지 결정 , , 생성생성 CFrameWnd::DockControlBar()CFrameWnd::DockControlBar()

WINFRM2.CPPWINFRM2.CPP 두가지 버전이 존재두가지 버전이 존재 저장된 저장된 CDockBarCDockBar 의 의 pointerpointer 를 가져옴를 가져옴 CDockBar::DockControlBar()CDockBar::DockControlBar() 함수 호출함수 호출

CDockBar::DockControlBar()CDockBar::DockControlBar() BARDOCK.CPPBARDOCK.CPP Control barControl bar 를 주어진 위치로 옮김를 주어진 위치로 옮김 중요한 사항중요한 사항

자리만 옮겨진 것 뿐자리만 옮겨진 것 뿐 여전히 여전히 floatingfloating 상태상태 DockDock 을 시키는 매커니즘은을 시키는 매커니즘은 ??

Control barControl bar 의 의 parentparent 를 를 CDockBarCDockBar 로 바꿈로 바꿈 DockDock 의 효과가 발생의 효과가 발생

CDockBar (AFXPRIV.H)CDockBar (AFXPRIV.H)

Docking (cont’d)Docking (cont’d)

Docking (cont’d)Docking (cont’d)void CControlBar::EnableDocking(DWORD dwDockStyle){

m_dwDockStyle = dwDockStyle;if (m_pDockContext == NULL)

m_pDockContext = new CDockContext(this);

// permanently wire the bar's owner to its current parentif (m_hWndOwner == NULL)

m_hWndOwner = ::GetParent(m_hWnd);}

Docking (cont’d)Docking (cont’d)void CFrameWnd::EnableDocking(DWORD dwDockStyle){ m_pFloatingFrameClass = RUNTIME_CLASS(CMiniDockFrameWnd); for (int i = 0; i < 4; i++) {

if (dwDockBarMap[i][1] & dwDockStyle & CBRS_ALIGN_ANY) {

CDockBar* pDock = (CDockBar*)GetControlBar(dwDockBarMap[i]

[0]);pDock = new CDockBar;pDock->Create(this, … );

} }}const DWORD CFrameWnd::dwDockBarMap[4][2] ={

{ AFX_IDW_DOCKBAR_TOP, CBRS_TOP },{ AFX_IDW_DOCKBAR_BOTTOM, CBRS_BOTTOM },{ AFX_IDW_DOCKBAR_LEFT, CBRS_LEFT },{ AFX_IDW_DOCKBAR_RIGHT, CBRS_RIGHT },

};

Docking (cont’d)Docking (cont’d)void CFrameWnd::DockControlBar(CControlBar* pBar, CDockBar* pDockBar, LPCRECT lpRect){ if (pDockBar == NULL) { for (int i = 0; i < 4; i++) {

if ((dwDockBarMap[i][1] & CBRS_ALIGN_ANY) ==(pBar->m_dwStyle & CBRS_ALIGN_ANY)) {pDockBar = GetControlBar(dwDockBarMap[i][0]);break;

}}

} pDockBar->DockControlBar(pBar, lpRect);}

Docking (cont’d)Docking (cont’d)void CDockBar::DockControlBar(CControlBar* pBar, LPCRECT lpRect){

CRect rectBar;pBar->GetWindowRect(&rectBar);if (lpRect != NULL){

// insert into appropriate rowCRect rect(lpRect);pBar->SetWindowPos(NULL, rect,….);

} else {// always add on current row, then create new onem_arrBars.Add(pBar);m_arrBars.Add(NULL);

// align off the edge initiallypBar->SetWindowPos(NULL, ….);

}

Docking (cont’d)Docking (cont’d)// attach it to the docking siteif (pBar->GetParent() != this)

pBar->SetParent(this);if (pBar->m_pDockBar == this)

pBar->m_pDockBar->RemoveControlBar(pBar, nPos);

else if (pBar->m_pDockBar != NULL)pBar->m_pDockBar->RemoveControlBar(pBar, -1,

m_bFloating && !pBar->m_pDockBar->m_bFloating);

pBar->m_pDockBar = this;}

FloatingFloating 관련 함수관련 함수

CFrameWnd::FloatControlBar()CFrameWnd::FloatControlBar() WINFRM2.CPPWINFRM2.CPP CMiniDockFrameWndCMiniDockFrameWnd 를 사용를 사용

Control barControl bar 의 의 frame windowframe window 역할역할 역시 역시 CDockBar::DockControlBar()CDockBar::DockControlBar() 함수 이용함수 이용 CFrameWnd::RecalcLayout()CFrameWnd::RecalcLayout() 함수를 이용함수를 이용

Layout Layout 조절조절 FloatingFloating 의 효과의 효과

Control barControl bar 의 의 parentparent 를 전체 를 전체 frame windowframe window 로 바꾸어 주는 로 바꾸어 주는 것것

Floating (cont’d)Floating (cont’d)void CFrameWnd::FloatControlBar(CControlBar* pBar, CPoint point, DWORD dwStyle){

CMiniDockFrameWnd* pDockFrame = CreateFloatingFrame(dwStyle);

pDockFrame->SetWindowPos(NULL, point.x, point.y, 0, 0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);

CDockBar* pDockBar = (CDockBar*)pDockFrame->GetDlgItem(AFX_IDW_DOCKBAR_FLOAT);

pDockBar->DockControlBar(pBar);pDockFrame->RecalcLayout(TRUE);if (GetWindowLong(pBar->m_hWnd, GWL_STYLE) &

WS_VISIBLE){

pDockFrame->ShowWindow(SW_SHOWNA);pDockFrame->UpdateWindow();

}}

Dragging Dragging 관련 함수관련 함수

CControlBar::OnLButtonDown()CControlBar::OnLButtonDown() BARCORE.CPPBARCORE.CPP

CDockContext classCDockContext class 의 이용의 이용 Declaration : AFXPRIV.HDeclaration : AFXPRIV.H Implementation : DOCKCONT.CPPImplementation : DOCKCONT.CPP

PersistencePersistence 관련 함수관련 함수

CFrameWnd::SaveBarState()CFrameWnd::SaveBarState() DOCKSTAT.CPPDOCKSTAT.CPP

CFrameWnd::GetDockState()CFrameWnd::GetDockState() DOCKSTAT.CPPDOCKSTAT.CPP

Helper classHelper class CDockState, CControlBarInfoCDockState, CControlBarInfo

Layout ManagementLayout Management 관련 함수관련 함수

CFrameWnd::RecalcLayout()CFrameWnd::RecalcLayout() WINFRM.CPPWINFRM.CPP CWnd::RepositionBars()CWnd::RepositionBars() 함수 이용함수 이용 CWnd::SetWindowPos()CWnd::SetWindowPos() 함수 이용함수 이용

CMiniFrameWndCMiniFrameWnd CMiniFrameWnd classCMiniFrameWnd class

Nonclient messageNonclient message 처리를 이용처리를 이용 Mini frameMini frame 모양을 그림모양을 그림

DeclarationDeclaration AFXWIN.HAFXWIN.H

ImplementationImplementation WINMINI.CPPWINMINI.CPP

MRU File ListMRU File List 관련 함수관련 함수

CWinApp::LoadStdProfileSettings()CWinApp::LoadStdProfileSettings() 저장된 저장된 MRU file listMRU file list 를 가져옴를 가져옴 CWinApp::InitInstance()CWinApp::InitInstance() 에서 호출됨에서 호출됨

CWinApp::SaveStdProfileSettings()CWinApp::SaveStdProfileSettings() MRU file listMRU file list 를 를 registryregistry 에 기록에 기록 Document/ViewDocument/View 구조이면구조이면

DocumentDocument 저장시 자동으로 저장시 자동으로 listlist 에 추가됨에 추가됨

MRU File List (cont’d)MRU File List (cont’d) CDocument::DoSave() CDocument::DoSave() CWinApp::AddToRecentFileList() CWinApp::AddToRecentFileList() SaveStdProfileSettings()SaveStdProfileSettings() 는 저장된 는 저장된 file listfile list 를 를 registryregistry 에 에

기록기록

Helper classHelper class CRecentFileList classCRecentFileList class

실제 실제 MRU fileMRU file 에 대한 에 대한 listlist 를 관리함를 관리함 DeclarationDeclaration

AFXPRIV.HAFXPRIV.H

MRU File List(contd.)MRU File List(contd.) ImplementationImplementation

AFXADV.H AFXADV.H ……

DLLs and ThreadsDLLs and Threads

Chap. 10Chap. 10

ContentsContents Understanding StatesUnderstanding States MFC DLLsMFC DLLs MFC ThreadsMFC Threads

Understanding StatesUnderstanding States 2 2 types state informationtypes state information

Module stateModule state Module Module Application Application 의 다른 부분과 독립적으로 의 다른 부분과 독립적으로

실행가능한 실행가능한 executable code(DLL, OLE control)executable code(DLL, OLE control) Unique Unique 한 한 DLLDLL 을 여러 을 여러 programprogram 이 동시에 쓴다면 각 이 동시에 쓴다면 각

programprogram 마다 마다 module statemodule state 가 존재가 존재 Module local dataModule local data

Thread(process) stateThread(process) state Thread local dataThread local data

Module StateModule State Definition(AFXSTAT_.H)Definition(AFXSTAT_.H)

AFX_MODULE_STATEAFX_MODULE_STATE CWinApp objectCWinApp object 에 대한 에 대한 pointerpointer ModuleModule 의 의 instance handleinstance handle ResourceResource 의 의 instance handleinstance handle Application nameApplication name DLLDLL 인지 아닌지를 구별하는 인지 아닌지를 구별하는 flagflag System moduleSystem module 인지 아닌지를 구별하는 인지 아닌지를 구별하는 flagflag Thread state informationThread state information ……

Module State (cont’d)Module State (cont’d)// AFX_MODULE_STATE (global data for a module)class AFX_MODULE_STATE : public CNoTrackObject{public:#ifdef _AFXDLL

AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion);

AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion, BOOL bSystem);#else

AFX_MODULE_STATE(BOOL bDLL);#endif

~AFX_MODULE_STATE();CWinApp* m_pCurrentWinApp;HINSTANCE m_hCurrentInstanceHandle;HINSTANCE m_hCurrentResourceHandle;LPCTSTR m_lpszCurrentAppName;

Module State (cont’d)Module State (cont’d)BYTE m_bDLL; // TRUE if module is a DLL, FALSE if it is

an EXEBYTE m_bSystem; // TRUE if module is a "system" moduleBYTE m_bReserved[2]; // paddingDWORD m_fRegisteredClasses; // flags for registered

window// runtime class data

#ifdef _AFXDLLCRuntimeClass* m_pClassInit;

#endifCTypedSimpleList<CRuntimeClass*> m_classList;long m_nObjectCount;BOOL m_bUserCtrl;TCHAR m_szUnregisterList[4096];

#ifdef _AFXDLLWNDPROC m_pfnAfxWndProc;DWORD m_dwVersion; // version that module linked

against#endif

// define thread local portions of module stateTHREAD_LOCAL(AFX_MODULE_THREAD_STATE, m_thread)

};

Thread StateThread State Definition(AFXSTAT_.H)Definition(AFXSTAT_.H)

AFX_THREAD_STATEAFX_THREAD_STATE 현재의 현재의 module statemodule state 에 대한 에 대한 pointerpointer 이전의 이전의 module statemodule state 에 대한 에 대한 pointerpointer MessageMessage 관련 정보관련 정보 InterruptInterrupt 된 후에 된 후에 recoveryrecovery 를 위한 모든 정보를 위한 모든 정보 ……

Thread State (cont’d)Thread State (cont’d)class _AFX_THREAD_STATE : public CNoTrackObject{public:

_AFX_THREAD_STATE();virtual ~_AFX_THREAD_STATE();AFX_MODULE_STATE* m_pModuleState;AFX_MODULE_STATE* m_pPrevModuleState;void* m_pSafetyPoolBuffer; // current bufferAFX_EXCEPTION_CONTEXT m_exceptionContext;CWnd* m_pWndInit;CWnd* m_pAlternateWndInit; // special case commdlg

hookingDWORD m_dwPropStyle;DWORD m_dwPropExStyle;HWND m_hWndInit;BOOL m_bDlgCreate;HHOOK m_hHookOldCbtFilter;HHOOK m_hHookOldMsgFilter;

Thread State (cont’d)Thread State (cont’d) MSG m_lastSentMsg; // see CWnd::WindowProc HWND m_hTrackingWindow; // see CWnd::TrackPopupMenu HMENU m_hTrackingMenu; TCHAR m_szTempClassName[96]; // see AfxRegisterWndClass HWND m_hLockoutNotifyWindow; // see CWnd::OnCommand BOOL m_bInMsgFilter; CView* m_pRoutingView; // see CCmdTarget::GetRoutingView CFrameWnd* m_pRoutingFrame; // see CCmdTarget::GetRoutingFrame BOOL m_bWaitForDataSource; CToolTipCtrl* m_pToolTip; CWnd* m_pLastHit; // last window to own tooltip int m_nLastHit; // last hittest code TOOLINFO m_lastInfo; // last TOOLINFO structure int m_nLastStatus; // last flyby status message CControlBar* m_pLastStatus; // last flyby status control bar};

MFC StatesMFC States 들의 연관들의 연관 AfxGetThreadState()AfxGetThreadState()

AFXSTAT.CPPAFXSTAT.CPP 현재의 현재의 AFX_THREAD_STATEAFX_THREAD_STATE 를 얻을 때 사용를 얻을 때 사용 __afxThreadStateafxThreadState 이용이용

THREAD_LOCAL(_AFX_THREAD_STATE, THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)_afxThreadState)

MFC StatesMFC States 들의 연관 들의 연관 ((cont’d)cont’d) AfxGetModuleState()AfxGetModuleState()

AFXSTAT.CPPAFXSTAT.CPP AFX_MODULE_STATEAFX_MODULE_STATE 를 얻을 때 사용를 얻을 때 사용 내부적으로 내부적으로 __afxThreadStateafxThreadState 를 이용를 이용

Thread stateThread state 에는 현재의 에는 현재의 module statemodule state 에 대한 에 대한 pointer pointer 가 존재가 존재

만약 만약 NULLNULL 이면 이면 __afxBaseModuleStateafxBaseModuleState 를 이용를 이용 PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, PROCESS_LOCAL(_AFX_BASE_MODULE_STATE,

_afxBaseModuleState)_afxBaseModuleState)

MFC StatesMFC States 들의 연관 들의 연관 ((cont’d)cont’d)_AFX_THREAD_STATE* AFXAPI AfxGetThreadState(){

return _afxThreadState.GetData();}

AFX_MODULE_STATE* AFXAPI AfxGetModuleState(){

_AFX_THREAD_STATE* pState = _afxThreadState;AFX_MODULE_STATE* pResult;if (pState->m_pModuleState != NULL){

pResult = pState->m_pModuleState;}else{

pResult = _afxBaseModuleState.GetData();}return pResult;

}

MFC DLLsMFC DLLs MFC2.0MFC2.0

USRDLLUSRDLL DLLDLL 에 에 staticstatic 하게 하게 linklink 됨됨 MFC codeMFC code 의 사용 가능의 사용 가능 크기가 매우 커짐크기가 매우 커짐 ((MFC MFC 관련 관련 codecode 를 모두 포함를 모두 포함 ))

AFXDLLAFXDLL 자체에서 자체에서 MFCMFC 를 제공하지 않음를 제공하지 않음 ApplicationApplication 이 이 MFC DLLMFC DLL 을 을 linklink 해야 함해야 함

DLLDLL 의 종류의 종류 MFC4.0 MFC4.0 이후이후

Regular DLLRegular DLL StaticStatic 하게 하게 link(USRDLL)link(USRDLL) DynamicDynamic 하게 하게 linklink C styleC style 의 함수만 의 함수만 exportexport 가능가능 MFCMFC 사용은 가능사용은 가능

Extension DLLExtension DLL C++ interface C++ interface 지원지원 ((ClassClass 를 를 exportexport 할 수 있다할 수 있다 .).) DynamicDynamic 하게 하게 linklink 기존의 기존의 AFXDLLAFXDLL

DLL Resource IssuesDLL Resource Issues Resource loadResource load 시시

바로 찾지 않고 바로 찾지 않고 AfxFindResourceHandle()AfxFindResourceHandle() 함수를 함수를 이용이용

AfxFindResourceHandle()AfxFindResourceHandle() LoadLoad 된 된 extension DLLextension DLL 중에서 원하는 중에서 원하는 resourceresource 를 찾음를 찾음

그러면 그러면 extension DLLextension DLL 의 의 listlist 는 어떤식으로 는 어떤식으로 관리되는가관리되는가 ??

DLL Resource Issues (cont’d)DLL Resource Issues (cont’d)

DllMain()DllMain() 함수함수 DLLDLL 이 이 loadload 될 때 호출됨될 때 호출됨 coreDLLcoreDLL 은 은 AFX_EXTENSION_MODULEAFX_EXTENSION_MODULE

AFXDLL_.HAFXDLL_.H

struct AFX_EXTENSION_MODULE{

BOOL bInitialized;HMODULE hModule;HMODULE hResource;CRuntimeClass* pFirstSharedClass;COleObjectFactory*

pFirstSharedFactory;};

AfxInitExtensionModule(coreDLL, hInstance)AfxInitExtensionModule(coreDLL, hInstance)CDynLinkLibrary* pDLL = new CDynLinkLibrary(coreDLL, CDynLinkLibrary* pDLL = new CDynLinkLibrary(coreDLL, TRUE);TRUE);

AfxInitExtensionModule()(DLLINIT.CPP)AfxInitExtensionModule()(DLLINIT.CPP) hModulehModule 과 과 hResourcehResource 에 에 instance handle assigninstance handle assign

CDynLinkLibraryCDynLinkLibrary Declaration(AFXDLL_.H)Declaration(AFXDLL_.H) Implementation(DLLINIT.CPP)Implementation(DLLINIT.CPP)

ConstructorConstructor 에서 에서 module statemodule state 의 의 library listlibrary list 에 자신을 추가에 자신을 추가

결국 결국 module statemodule state 에 에 CDynLinkLibrary objectCDynLinkLibrary object 의 의 listlist 가 관리됨가 관리됨 AfxFindResourceHandle()AfxFindResourceHandle() 는 이 는 이 listlist 를 이용를 이용

DLL Resource Issues (cont’d)DLL Resource Issues (cont’d)

DLL Resource Issues (cont’d)DLL Resource Issues (cont’d)BOOL AFXAPI AfxInitExtensionModule(AFX_EXTENSION_MODULE& state, HMODULE hModule){

if (state.bInitialized) {AfxInitLocalData(hModule);return TRUE;

}state.bInitialized = TRUE;state.hModule = hModule;state.hResource = hModule;AFX_MODULE_STATE* pModuleState =

AfxGetModuleState();state.pFirstSharedClass = pModuleState-

>m_classList.GetHead();pModuleState->m_classList.m_pHead =pModuleState-

>m_pClassInit;state.pFirstSharedFactory = pModuleState-

>m_factoryList.GetHead();pModuleState->m_factoryList.m_pHead=

pModuleState->m_pFactoryInit;return TRUE;

}

DLL Resource Issues (cont’d)DLL Resource Issues (cont’d)class CDynLinkLibrary : public CCmdTarget{ DECLARE_DYNAMIC(CDynLinkLibrary)public:// Constructor CDynLinkLibrary(AFX_EXTENSION_MODULE& state, BOOL bSystem = FALSE);// Attributes HMODULE m_hModule; HMODULE m_hResource; // for shared resources CTypedSimpleList<CRuntimeClass*> m_classList; CTypedSimpleList<COleObjectFactory*> m_factoryList; BOOL m_bSystem; // TRUE only for MFC DLLs// Implementationpublic: CDynLinkLibrary* m_pNextDLL; // simple singly linked list virtual ~CDynLinkLibrary();};

DLL Resource Issues (cont’d)DLL Resource Issues (cont’d)CDynLinkLibrary::CDynLinkLibrary(AFX_EXTENSION_MODULE& state, BOOL bSystem){

m_factoryList.Construct(offsetof(COleObjectFactory, m_pNextFactory));

m_classList.Construct(offsetof(CRuntimeClass, m_pNextClass));

m_hModule = state.hModule;m_hResource = state.hResource;m_classList.m_pHead = state.pFirstSharedClass;m_factoryList.m_pHead = state.pFirstSharedFactory;m_bSystem = bSystem;

// insert at the head of the list (extensions will go in front of core DLL)

AfxLockGlobals(CRIT_DYNLINKLIST);m_pModuleState->m_libraryList.AddHead(this);AfxUnlockGlobals(CRIT_DYNLINKLIST);

}

DLL Resource Issues (cont’d)DLL Resource Issues (cont’d)HINSTANCE AFXAPI AfxFindResourceHandle(LPCTSTR lpszName, LPCTSTR lpszType){ HINSTANCE hInst; // check for non-system DLLs in proper order AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); AfxLockGlobals(CRIT_DYNLINKLIST); for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL; pDLL = pDLL->m_pNextDLL){

if (!pDLL->m_bSystem && pDLL->m_hResource != NULL && ::FindResource(pDLL->m_hResource, lpszName, lpszType)

!= NULL){

// found it in a DLLAfxUnlockGlobals(CRIT_DYNLINKLIST);return pDLL->m_hResource;

} }}

MFC ThreadsMFC Threads MFC ThreadMFC Thread 의 종류의 종류

Worker threadWorker thread 일반적으로 말하는 일반적으로 말하는 threadthread

User-interface threadUser-interface thread Message loopMessage loop 을 가지고 을 가지고 user-interfaceuser-interface 를 관장하는 를 관장하는

threadthread

AfxBeginThread()AfxBeginThread() 함수를 이용하여 생성됨함수를 이용하여 생성됨

Worker ThreadsWorker Threads AfxBeginThread()(THRDCORE.CPP)AfxBeginThread()(THRDCORE.CPP)

CWinThread objectCWinThread object 생성생성 CWinThread::CreateThread()CWinThread::CreateThread() 호출호출 CWinThread::SetThreadPriority()CWinThread::SetThreadPriority() 호출호출

CWinThreadCWinThread Declaration(AFXWIN.H)Declaration(AFXWIN.H) Implementation(THRDCORE.CPP)Implementation(THRDCORE.CPP)

Worker Threads (cont’d)Worker Threads (cont’d) CWinThread::CreateThread()CWinThread::CreateThread()

_AFX_THREAD_STARTUP structure_AFX_THREAD_STARTUP structure 이용이용 __beginthreadex() library functionbeginthreadex() library function 을 이용을 이용

Worker Threads (cont’d)Worker Threads (cont’d)CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,

int nPriority, UINT nStackSize, DWORD dwCreateFlags,LPSECURITY_ATTRIBUTES lpSecurityAttrs)

{ CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam); if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED,

nStackSize, lpSecurityAttrs)) {pThread->Delete();return NULL;

} VERIFY(pThread->SetThreadPriority(nPriority)); if (!(dwCreateFlags & CREATE_SUSPENDED)) VERIFY(pThread->ResumeThread() != (DWORD)-1); return pThread;}

User-Interface ThreadsUser-Interface Threads Worker threadWorker thread 와의 차이점와의 차이점

User eventsUser events 에 대한 반응에 대한 반응 User inputUser input 의 처리의 처리

과정과정 CWinThreadCWinThread 에서 상속받아야 함에서 상속받아야 함 다음의 함수를 이용다음의 함수를 이용

ExitInstance(), InitInstance()ExitInstance(), InitInstance() OnIdle(), PreTranslateMessage(), Run()OnIdle(), PreTranslateMessage(), Run()

CWinAppCWinApp 도 하나의 도 하나의 user-interface user-interface threadthread 임임

CWinThread::Run()(THRDCORE.CPP)CWinThread::Run()(THRDCORE.CPP) Message queueMessage queue 에 에 messagemessage 가 있을때와 가 있을때와

없을때의 수행 코드로 나뉨없을때의 수행 코드로 나뉨 MessageMessage 가 없을때 가 없을때 OnIdle()OnIdle() 함수 호출함수 호출

User-Interface Threads (cont’d)User-Interface Threads (cont’d)

Idle processingIdle processing CWinThread::OnIdle()(THRDCORE.CPP)CWinThread::OnIdle()(THRDCORE.CPP)

OverrideOverride 하면 자신의 하면 자신의 OnIdle()OnIdle() 함수가 호출됨함수가 호출됨 Argument Argument 가 음수이면 가 음수이면 UIUI 를 를 updateupdate 함함 (( 즉즉 , , user user

interface updateinterface update 는 는 idle timeidle time 에 이루어짐에 이루어짐 ))

Message dispatchMessage dispatch IdleIdle 아닐 때아닐 때 PumpMessage()PumpMessage() 함수 이용함수 이용

ThreadThread 의 종료는 의 종료는 WM_QUIT messageWM_QUIT message

User-Interface Threads (cont’d)User-Interface Threads (cont’d)