I looked at Notepad in Vista and I think it uses the newer CPrintDialogEx
that let us switch printer without printing by using the Apply button in the
Print dialog.
I want to do the same in my application but it seems very hard to make MFC
use the newer CPrintDialogEx with the Apply button. I found this 4,5 year
old thread discussing this:
http://www.themssforum.com/MFC/substitute-CPrintDialogEx/
Is there a solution now? (I can use the latest MFC version if it helps)
Best regards from Gaute
Like the link says, the MFC printing loop operates with the old dialog.
I have a global, BOOL DoPreparePrinting( CPrintInfo* pInfo ) that I can
call from from the view member. In pInfo->m_lpUserData I have a
CPrintDialogEx created on the heap. In this call I take care of
associating the data between the the new dialog and the old.
I'll post below. Where the dialog is run you can handle an 'apply -
cancel' and grab the new printer name.
Best, Dan.
BOOL DoPreparePrinting( CPrintInfo* pInfo )
{
ASSERT(pInfo != NULL);
ASSERT(pInfo->m_pPD != NULL);
if (pInfo->m_pPD->m_pd.nMinPage > pInfo->m_pPD->m_pd.nMaxPage)
pInfo->m_pPD->m_pd.nMaxPage = pInfo->m_pPD->m_pd.nMinPage;
CWinApp* pApp = AfxGetApp();
pInfo->m_pPD->m_pd.nFromPage = (WORD)pInfo->GetMinPage( );
pInfo->m_pPD->m_pd.nToPage = (WORD)pInfo->GetMaxPage( );
CPrintInfoEx* pExInfo= static_cast< CPrintInfoEx* >( pInfo->m_lpUserData );
ASSERT_VALID( pExInfo->pPrintDialog );
CPRINTDIALOGEX& dlg= *pExInfo->pPrintDialog;
dlg.m_hWndOwner= *AfxGetMainWnd( );
dlg.m_pdex.Flags|= PD_ALLPAGES | PD_HIDEPRINTTOFILE | PD_RETURNDC;
dlg.m_pdex.nCopies= 1;
dlg.m_pdex.nMinPage= (WORD)pInfo->GetMinPage( );
dlg.m_pdex.nMaxPage= (WORD)pInfo->GetMaxPage( );
dlg.m_pdex.lpPageRanges= &pExInfo->printRange.front( );
dlg.m_pdex.Flags&= ~( PD_NOPAGENUMS /*| PD_NOPAGENUMS*/ );
dlg.m_pdex.nMaxPageRanges= pExInfo->printRange.size( );
if( ! pInfo->m_bPreview )
{
INT_PTR response= dlg.DoModal( );
if( response != S_OK || dlg.m_pdex.dwResultAction != PD_RESULT_PRINT )
return FALSE; // do not print
}
else if( pInfo->m_pPD->m_pd.hDC == NULL )
{
// call CreatePrinterDC if DC was not created by above
HDC hDC= dlg.CreatePrinterDC( );
if( hDC == NULL )
return FALSE;
pInfo->m_pPD->m_pd.hDC= hDC;
}
ASSERT( dlg.m_pdex.hDC );
if( ! dlg.m_pdex.hDC )
return FALSE;
pInfo->m_pPD->m_pd.hDC= dlg.m_pdex.hDC;
pInfo->m_pPD->m_pd.nFromPage= (int)dlg.m_pdex.nMinPage;
pInfo->m_pPD->m_pd.nToPage= (int)dlg.m_pdex.nMaxPage;
pInfo->m_nNumPreviewPages = pApp->m_nNumPreviewPages;
VERIFY( pInfo->m_strPageDesc.LoadString(AFX_IDS_PREVIEWPAGEDESC ) );
return TRUE;
}
Best regards from Gaute
This is your member, anything you would like.
struct YourPrintStruct
{
//Your stuff
...
CPrintDialogEx* pPrintDialog;
//This is for the print range object for CPrintDialogEx
std::vector< PRINTPAGERANGE > printRange;
YourPrintStruct( )
...
,pPrintDialog( NULL )
{
printRange.resize( 64 );
}
~YourPrintStruct( )
{
if( pPrintDialog )
delete pPrintDialog;
}
};
And somewhere before you call that ::DoPreparePrinting:
YourPrintStruct* pInfoEx= new YourPrintStruct;
//check and set other stuff
pInfoEx->pPrintDialog=
new CPrintDialogEx( PD_HIDEPRINTTOFILE, this );
//if you have some other printer
SomeSetPrinterCall( ...
&pInfoEx->pPrintDialog->m_pdex.hDevMode,
&pInfoEx->pPrintDialog->m_pdex.hDevNames )
pInfo->m_lpUserData= pInfoEx;
...
It ends up becoming accessible through my print object. In
OnEndPrinting, delete it.
YourPrintStruct* pExInfo= pReport->GetPreviewExInfo( );
//or just cast pInfo->m_lpUserData
//Finish using it
delete pExInfo;
Best, Dan.
Function( ..., hDevNames, hDevMode );
Drove me nuts because the problem is not obvious. Make them all conform.
Function( ..., hDevMode, hDevNames );
Best, Dan.