_UNDOCUMENTED CORNER_ by Scot Wingo and George Sheperd Listing One 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; } Listing Two class CMirrorFile : public CFile { // Implementation public: virtual void Abort(); virtual void Close(); virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL); protected: CString m_strMirrorName; }; Listing Three BOOL CMirrorFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError) { m_strMirrorName.Empty(); CFileStatus status; if (nOpenFlags & CFile::modeCreate) { if (CFile::GetStatus(lpszFileName, status)){ CString strRoot; AfxGetRoot(lpszFileName, strRoot); DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus; int nBytes = 0; if (GetDiskFreeSpace(strRoot, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus, &dwTotalClus)){ nBytes = dwFreeClus*dwSecPerClus*dwBytesPerSec; if (nBytes > 2*status.m_size){ // get the directory for the file TCHAR szPath[_MAX_PATH]; LPTSTR lpszName; GetFullPathName(lpszFileName,_MAX_PATH, szPath, &lpszName); *lpszName = NULL; GetTempFileName(szPath, _T("MFC"), 0, m_strMirrorName.GetBuffer(_MAX_PATH+1)); m_strMirrorName.ReleaseBuffer(); } } } 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; 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); } Listing Four void CMirrorFile::Close() { CString m_strName = m_strFileName; CFile::Close(); if (!m_strMirrorName.IsEmpty()) { CFile::Remove(m_strName); CFile::Rename(m_strMirrorName, m_strName); } } Listing Five BOOL CView::DoPrintPreview(UINT nIDResource, CView* pPrintView, CRuntimeClass* pPreviewViewClass, CPrintPreviewState* pState) { CFrameWnd* pParent = (CFrameWnd*)AfxGetThread()->m_pMainWnd; CCreateContext context; context.m_pCurrentFrame = pParent; context.m_pCurrentDoc = GetDocument(); context.m_pLastView = this; // Create the preview view object CPreviewView* pView = (CPreviewView*)pPreviewViewClass->CreateObject(); pView->m_pPreviewState = pState; // save pointer pParent->OnSetPreviewMode(TRUE, pState); // Take over Frame Window // 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)){ TRACE0("Error: Preview could not create toolbar dialog.\n"); return FALSE; } pView->m_pToolBar->m_bAutoDelete = TRUE; // automatic cleanup if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), pParent, AFX_IDW_PANE_FIRST, &context)) { TRACE0("Error: couldn't create preview view for frame.\n"); return FALSE; } pState->pViewActiveOld = pParent->GetActiveView(); CView* pActiveView = pParent->GetActiveFrame()->GetActiveView(); pActiveView->OnActivateView(FALSE, pActiveView, pActiveView); pView->SetPrintView(pPrintView); pParent->SetActiveView(pView); // set active view - even for MDI // update toolbar and redraw everything pView->m_pToolBar->SendMessage(WM_IDLEUPDATECMDUI, (WPARAM)TRUE); pParent->RecalcLayout(); // position and size everything pParent->UpdateWindow(); return TRUE; } Listing Six class CPreviewView : public CScrollView { DECLARE_DYNCREATE(CPreviewView) // Constructors public: CPreviewView(); BOOL SetPrintView(CView* pPrintView); // Attributes protected: CView* m_pOrigView; CView* m_pPrintView; CPreviewDC* m_pPreviewDC; // Output and attrib DCs Set, not created CDC m_dcPrint; // Actual printer DC // Operations *omitted // Overridables *omitted // Implementation * some omitted public: virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL); protected: afx_msg void OnPreviewClose(); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnDraw(CDC* pDC); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnNextPage(); afx_msg void OnPrevPage(); afx_msg void OnPreviewPrint(); afx_msg void OnZoomIn(); afx_msg void OnZoomOut(); void DoZoom(UINT nPage, CPoint point); void SetScaledSize(UINT nPage); CSize CalcPageDisplaySize(); CPrintPreviewState* m_pPreviewState; // State to restore CDialogBar* m_pToolBar; // Toolbar for preview struct 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 default implementation BOOL m_bPageNumDisplayed; // Flags whether or not page number has yet // been displayed on status line 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; DECLARE_MESSAGE_MAP() }; Listing Seven 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 // 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; 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) SetScrollRange(SB_VERT, m_pPreviewInfo->GetMinPage(), m_pPreviewInfo->GetMaxPage(), FALSE); else ShowScrollBar(SB_VERT, FALSE); SetCurrentPage(m_pPreviewInfo->m_nCurPage, TRUE); return TRUE; }