void OnMenuPrint(WindowInfo *win, bool waitForCompletion) { // we remember some printer settings per process static ScopedMem<DEVMODE> defaultDevMode; static PrintScaleAdv defaultScaleAdv = PrintScaleShrink; static bool defaultAsImage = false; bool printSelection = false; Vec<PRINTPAGERANGE> ranges; PRINTER_INFO_2 printerInfo = { 0 }; if (!HasPermission(Perm_PrinterAccess)) return; DisplayModel *dm = win->dm; assert(dm); if (!dm) return; if (!dm->engine || !dm->engine->AllowsPrinting()) return; if (win->IsChm()) { win->dm->AsChmEngine()->PrintCurrentPage(); return; } if (win->printThread) { int res = MessageBox(win->hwndFrame, _TR("Printing is still in progress. Abort and start over?"), _TR("Printing in progress."), MB_ICONEXCLAMATION | MB_YESNO | (IsUIRightToLeft() ? MB_RTLREADING : 0)); if (res == IDNO) return; } AbortPrinting(win); PRINTDLGEX pd; ZeroMemory(&pd, sizeof(PRINTDLGEX)); pd.lStructSize = sizeof(PRINTDLGEX); pd.hwndOwner = win->hwndFrame; pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE; if (!win->selectionOnPage) pd.Flags |= PD_NOSELECTION; pd.nCopies = 1; /* by default print all pages */ pd.nPageRanges = 1; pd.nMaxPageRanges = MAXPAGERANGES; PRINTPAGERANGE *ppr = AllocArray<PRINTPAGERANGE>(MAXPAGERANGES); pd.lpPageRanges = ppr; ppr->nFromPage = 1; ppr->nToPage = dm->PageCount(); pd.nMinPage = 1; pd.nMaxPage = dm->PageCount(); pd.nStartPage = START_PAGE_GENERAL; Print_Advanced_Data advanced(PrintRangeAll, defaultScaleAdv, defaultAsImage); ScopedMem<DLGTEMPLATE> dlgTemplate; // needed for RTL languages HPROPSHEETPAGE hPsp = CreatePrintAdvancedPropSheet(&advanced, dlgTemplate); pd.lphPropertyPages = &hPsp; pd.nPropertyPages = 1; // restore remembered settings if (defaultDevMode) pd.hDevMode = GlobalMemDup(defaultDevMode.Get(), defaultDevMode.Get()->dmSize + defaultDevMode.Get()->dmDriverExtra); if (PrintDlgEx(&pd) != S_OK) { if (CommDlgExtendedError() != 0) { /* if PrintDlg was cancelled then CommDlgExtendedError is zero, otherwise it returns the error code, which we could look at here if we wanted. for now just warn the user that printing has stopped becasue of an error */ MessageBox(win->hwndFrame, _TR("Couldn't initialize printer"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK | (IsUIRightToLeft() ? MB_RTLREADING : 0)); } goto Exit; } if (pd.dwResultAction == PD_RESULT_PRINT || pd.dwResultAction == PD_RESULT_APPLY) { // remember settings for this process LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devMode) { defaultDevMode.Set((LPDEVMODE)memdup(devMode, devMode->dmSize + devMode->dmDriverExtra)); GlobalUnlock(pd.hDevMode); } defaultScaleAdv = advanced.scale; defaultAsImage = advanced.asImage; } if (pd.dwResultAction != PD_RESULT_PRINT) goto Exit; if (pd.Flags & PD_CURRENTPAGE) { PRINTPAGERANGE pr = { dm->CurrentPageNo(), dm->CurrentPageNo() }; ranges.Append(pr); } else if (win->selectionOnPage && (pd.Flags & PD_SELECTION)) { printSelection = true; } else if (!(pd.Flags & PD_PAGENUMS)) { PRINTPAGERANGE pr = { 1, dm->PageCount() }; ranges.Append(pr); } else { assert(pd.nPageRanges > 0); for (DWORD i = 0; i < pd.nPageRanges; i++) ranges.Append(pd.lpPageRanges[i]); } LPDEVNAMES devNames = (LPDEVNAMES)GlobalLock(pd.hDevNames); LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devNames) { printerInfo.pDriverName = (LPWSTR)devNames + devNames->wDriverOffset; printerInfo.pPrinterName = (LPWSTR)devNames + devNames->wDeviceOffset; printerInfo.pPortName = (LPWSTR)devNames + devNames->wOutputOffset; } PrintData *data = new PrintData(dm->engine, &printerInfo, devMode, ranges, advanced, dm->Rotation(), printSelection ? win->selectionOnPage : NULL); if (devNames) GlobalUnlock(pd.hDevNames); if (devMode) GlobalUnlock(pd.hDevMode); if (!waitForCompletion) PrintToDeviceOnThread(win, data); else { PrintToDevice(*data); delete data; } Exit: free(ppr); GlobalFree(pd.hDevNames); GlobalFree(pd.hDevMode); }
void OnMenuPrint(WindowInfo *win, bool waitForCompletion) { // we remember some printer settings per process static ScopedMem<DEVMODE> defaultDevMode; static PrintScaleAdv defaultScaleAdv = PrintScaleShrink; static bool defaultAsImage = false; static bool hasDefaults = false; if (!hasDefaults) { hasDefaults = true; defaultAsImage = gGlobalPrefs->printerDefaults.printAsImage; if (str::EqI(gGlobalPrefs->printerDefaults.printScale, "fit")) defaultScaleAdv = PrintScaleFit; else if (str::EqI(gGlobalPrefs->printerDefaults.printScale, "none")) defaultScaleAdv = PrintScaleNone; } bool printSelection = false; Vec<PRINTPAGERANGE> ranges; PRINTER_INFO_2 printerInfo = { 0 }; if (!HasPermission(Perm_PrinterAccess)) return; if (win->AsChm()) { // the Print dialog allows access to the file system, so fall back // to printing the entire document without dialog if that isn't desired bool showUI = HasPermission(Perm_DiskAccess); win->AsChm()->PrintCurrentPage(showUI); return; } if (win->AsEbook()) { // TODO: use EbookEngine for printing? return; } CrashIf(!win->AsFixed()); if (!win->AsFixed()) return; DisplayModel *dm = win->AsFixed(); #ifndef DISABLE_DOCUMENT_RESTRICTIONS if (!dm->engine()->AllowsPrinting()) return; #endif if (win->printThread) { int res = MessageBox(win->hwndFrame, _TR("Printing is still in progress. Abort and start over?"), _TR("Printing in progress."), MB_ICONEXCLAMATION | MB_YESNO | MbRtlReadingMaybe()); if (res == IDNO) return; } AbortPrinting(win); // the Print dialog allows access to the file system, so fall back // to printing the entire document without dialog if that isn't desired if (!HasPermission(Perm_DiskAccess)) { PrintFile(dm->engine()); return; } PRINTDLGEX pd; ZeroMemory(&pd, sizeof(PRINTDLGEX)); pd.lStructSize = sizeof(PRINTDLGEX); pd.hwndOwner = win->hwndFrame; pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE; if (!win->selectionOnPage) pd.Flags |= PD_NOSELECTION; pd.nCopies = 1; /* by default print all pages */ pd.nPageRanges = 1; pd.nMaxPageRanges = MAXPAGERANGES; PRINTPAGERANGE *ppr = AllocArray<PRINTPAGERANGE>(MAXPAGERANGES); pd.lpPageRanges = ppr; ppr->nFromPage = 1; ppr->nToPage = dm->PageCount(); pd.nMinPage = 1; pd.nMaxPage = dm->PageCount(); pd.nStartPage = START_PAGE_GENERAL; Print_Advanced_Data advanced(PrintRangeAll, defaultScaleAdv, defaultAsImage); ScopedMem<DLGTEMPLATE> dlgTemplate; // needed for RTL languages HPROPSHEETPAGE hPsp = CreatePrintAdvancedPropSheet(&advanced, dlgTemplate); pd.lphPropertyPages = &hPsp; pd.nPropertyPages = 1; // restore remembered settings if (defaultDevMode) { DEVMODE *p = defaultDevMode.Get(); pd.hDevMode = GlobalMemDup(p, p->dmSize + p->dmDriverExtra); } if (PrintDlgEx(&pd) != S_OK) { if (CommDlgExtendedError() != 0) { /* if PrintDlg was cancelled then CommDlgExtendedError is zero, otherwise it returns the error code, which we could look at here if we wanted. for now just warn the user that printing has stopped becasue of an error */ MessageBoxWarning(win->hwndFrame, _TR("Couldn't initialize printer"), _TR("Printing problem.")); } goto Exit; } if (pd.dwResultAction == PD_RESULT_PRINT || pd.dwResultAction == PD_RESULT_APPLY) { // remember settings for this process LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devMode) { defaultDevMode.Set((LPDEVMODE)memdup(devMode, devMode->dmSize + devMode->dmDriverExtra)); GlobalUnlock(pd.hDevMode); } defaultScaleAdv = advanced.scale; defaultAsImage = advanced.asImage; } if (pd.dwResultAction != PD_RESULT_PRINT) goto Exit; if (pd.Flags & PD_CURRENTPAGE) { PRINTPAGERANGE pr = { dm->CurrentPageNo(), dm->CurrentPageNo() }; ranges.Append(pr); } else if (win->selectionOnPage && (pd.Flags & PD_SELECTION)) { printSelection = true; } else if (!(pd.Flags & PD_PAGENUMS)) { PRINTPAGERANGE pr = { 1, dm->PageCount() }; ranges.Append(pr); } else { assert(pd.nPageRanges > 0); for (DWORD i = 0; i < pd.nPageRanges; i++) ranges.Append(pd.lpPageRanges[i]); } LPDEVNAMES devNames = (LPDEVNAMES)GlobalLock(pd.hDevNames); LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devNames) { printerInfo.pDriverName = (LPWSTR)devNames + devNames->wDriverOffset; printerInfo.pPrinterName = (LPWSTR)devNames + devNames->wDeviceOffset; printerInfo.pPortName = (LPWSTR)devNames + devNames->wOutputOffset; } PrintData *data = new PrintData(dm->engine(), &printerInfo, devMode, ranges, advanced, dm->GetRotation(), printSelection ? win->selectionOnPage : NULL); if (devNames) GlobalUnlock(pd.hDevNames); if (devMode) GlobalUnlock(pd.hDevMode); // if a file is missing and the engine can't thus be cloned, // we print using the original engine on the main thread // so that the document can't be closed and the original engine // unexpectedly deleted // TODO: instead prevent closing the document so that printing // can still happen on a separate thread and be interruptible bool failedEngineClone = dm->engine() && !data->engine; if (failedEngineClone) data->engine = dm->engine(); if (!waitForCompletion && !failedEngineClone) PrintToDeviceOnThread(win, data); else { PrintToDevice(*data); if (failedEngineClone) data->engine = NULL; delete data; } Exit: free(ppr); GlobalFree(pd.hDevNames); GlobalFree(pd.hDevMode); }