Solution to the preview problem while playing a metafile in a CPreviewDC






2.14/5 (4 votes)
Playing a Metfile into a CPreviewDC in print preview can cause further drawing operations to not work correctly.
Introduction
I was checking into a print preview problem in one of our applications, where if we tried to render any clipboard output to the print preview screen, further drawing operations (but not all) on the same page would not work correctly. Typically, this would be seen as font text drawn at an incorrect angle or for clip regions in use not to work correctly, so that the was not be clipped.
I present in the demo code a way around this problem.
You can try running the demo application which demonstrates the problem. Its OnPrint()
function looks like this:
void CPreviewMetafileView::OnPrint(CDC* pDC, CPrintInfo* pInfo) { CString text; CSize size; if (!IsClipboardFormatAvailable(CF_METAFILEPICT)) { CString text("No METAFILE on clipboard"); pDC->TextOut(0, 0, text); } CButton *pButton = static_cast<CButton*>(GetDlgItem(IDC_PREVIEW_DIRECT)); bool previewDirect = (pButton->GetCheck() != 0); // rectangle to render the metafil into CRect metafileRect(pInfo->m_rectDraw.Width() / 2, pInfo->m_rectDraw.top, pInfo->m_rectDraw.right, pInfo->m_rectDraw.Height() / 2); if (IsClipboardFormatAvailable(CF_METAFILEPICT)) { if (previewDirect) { pDC->SaveDC(); // play a metafile from the clipboard if available GLOBALHANDLE hGMem; LPMETAFILEPICT lpMFP; OpenClipboard(); hGMem = GetClipboardData(CF_METAFILEPICT); lpMFP = (LPMETAFILEPICT)GlobalLock(hGMem); pDC->SaveDC(); pDC->SetMapMode(lpMFP->mm); pDC->SetViewportExt(metafileRect.Width(), metafileRect.Height()); pDC->SetViewportOrg(metafileRect.left, metafileRect.top); pDC->PlayMetaFile(lpMFP->hMF); VERIFY(pDC->RestoreDC(-1)); GlobalUnlock(hGMem); CloseClipboard(); pDC->RestoreDC(-1); } else { // render to offscreen bitmap and StretchDIBBits it DrawMetafileToDc(pDC, metafileRect); } } // the following output gets corrupted after a direct render text = "Text to be corrupted!"; size = pDC->GetTextExtent(text); pDC->TextOut(0, size.cy, text); pDC->TextOut(0, size.cy * 2, text); pDC->TextOut(0, size.cy * 3, text); }
As you can see, it checks to see if a metafile is available on the clipboard and renders it to the preview DC using either a direct render or an indirect render. It then adds some extra text to the output "Text to be corrupted". This text is not shown on the direct render but is on the indirect render. Although the way this corruption affects the output may be different depending on what you actually render after the metafile.
To get a metafile on the clipboard, a quick way is to copy some cells to the clipboard from Microsoft Excel.
The two functions you will be interested in the demo which you wish to use this work around are:
HANDLE CPreviewMetafileView::DDBToDIB(CBitmap& bitmap,
DWORD dwCompression, CPalette* pPal)
void CPreviewMetafileView::DrawMetafileToDc(CDC * pDC, CRect targetRect)
Thats it!