home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OWLSRC.PAK / PRINTER.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  20.9 KB  |  830 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1992, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.21  $
  6. //----------------------------------------------------------------------------
  7. #pragma hdrignore SECTION
  8. #include <owl/pch.h>
  9. #if !defined(OWL_APPLICAT_H)
  10. # include <owl/applicat.h>
  11. #endif
  12. #if !defined(OWL_APPDICT_H)
  13. # include <owl/appdict.h>
  14. #endif
  15. #if !defined(OWL_WINDOW_H)
  16. # include <owl/window.h>
  17. #endif
  18. #if !defined(OWL_FRAMEWIN_H)
  19. # include <owl/framewin.h>
  20. #endif
  21. #if !defined(OWL_DC_H)
  22. # include <owl/dc.h>
  23. #endif
  24. #if !defined(OWL_STATIC_H)
  25. # include <owl/static.h>
  26. #endif
  27. #if !defined(OWL_PRINTER_H)
  28. # include <owl/printer.h>
  29. #endif
  30. #include <stdio.h>
  31.  
  32. OWL_DIAGINFO;
  33.  
  34. #if !defined(SECTION) || SECTION == 1
  35.  
  36. //
  37. // Template used to set and clear a bunch of flags at once
  38. //
  39. template <class T1, class T2>
  40. inline void SetClear(T1& var, T2 bitsOn, T2 bitsOff) {
  41.   var &= ~bitsOff;
  42.   var |=  bitsOn;
  43. }
  44.  
  45. // Define 'MANUAL_ABORT_CALL to enable the explicit abort proc call
  46. //
  47. // #define MANUAL_ABORT_CALL
  48.  
  49.  
  50. //----------------------------------------------------------------------------
  51.  
  52. //
  53. // class TFormattedStatic
  54. // ~~~~~ ~~~~~~~~~~~~~~~~
  55. // Static control that uses its resource title as a printf format string to
  56. // format one or two text strings provided in the constructor
  57. //
  58. class TFormattedStatic: public TStatic {
  59.   public:
  60.     TFormattedStatic(TWindow* parent, int resId, const char far* text,
  61.                      const char far* text2 = 0);
  62.    ~TFormattedStatic();
  63.  
  64.   protected:
  65.     void SetupWindow();
  66.  
  67.   private:
  68.     char far* Text;    // Text to display
  69.     char far* Text2;
  70. };
  71.  
  72. //
  73. // Construct the object.
  74. // Copy the two strings passed.
  75. // Second string is optional.
  76. //
  77. TFormattedStatic::TFormattedStatic(TWindow* parent, int resId,
  78.                                    const char far* text, const char far* text2)
  79. :
  80.   TStatic(parent, resId, 0)
  81. {
  82.   Text = strnewdup(text);
  83.   Text2 = text2 ? strnewdup(text2) : strnewdup("");
  84. }
  85.  
  86. //
  87. // Destructor.
  88. // Delete any previously allocated memory.
  89. //
  90. TFormattedStatic::~TFormattedStatic()
  91. {
  92.   delete[] Text;
  93.   delete[] Text2;
  94. }
  95.  
  96. //
  97. // Override SetupWindow to set the text for the static control.
  98. //
  99. void
  100. TFormattedStatic::SetupWindow()
  101. {
  102.   TStatic::SetupWindow();
  103.  
  104.   // Use the Title retrieved from the resource as a printf template for
  105.   // the one or two text strings, then set the text directly to the control to
  106.   // preserve the Title
  107.   //
  108.  
  109.   int len = strlen(Title) + strlen(Text) + strlen(Text2) + 5;
  110.   char* buff = new char[len];
  111.   sprintf(buff, Title, Text, Text2);
  112.   SetText(buff);
  113.   delete[] buff;
  114. }
  115.  
  116. //
  117. // class TNumericStatic
  118. // ~~~~~ ~~~~~~~~~~~~~~
  119. // Static control that uses its resource title as a printf format string to
  120. // format one or two text strings provided in the constructor
  121. //
  122. class TNumericStatic: public TStatic {
  123.   public:
  124.     TNumericStatic(TWindow* parent, int resId, int number);
  125.  
  126.   protected:
  127.     TResult EvSetNumber(TParam1 param1, TParam2 param2);
  128.  
  129.   private:
  130.     int Number;         // Number to display
  131.  
  132.   DECLARE_RESPONSE_TABLE(TNumericStatic);
  133. };
  134. #define WM_SETNUMBER    WM_USER+100
  135.  
  136. DEFINE_RESPONSE_TABLE1(TNumericStatic, TStatic)
  137.   EV_MESSAGE(WM_SETNUMBER, EvSetNumber),
  138. END_RESPONSE_TABLE;
  139.  
  140. //
  141. // Construct the object and remember the number to display.
  142. //
  143. TNumericStatic::TNumericStatic(TWindow* parent, int resId, int number)
  144. :
  145.   TStatic(parent, resId, 0),
  146.   Number(number)
  147. {
  148. }
  149.  
  150. //
  151. // Handle our user defined message to set the number displayed in the %d part
  152. // of the Title format string. If the number is <= 0, then hide this window
  153. //
  154. TResult
  155. TNumericStatic::EvSetNumber(TParam1 param1, TParam2)
  156. {
  157.   Number = param1;
  158.   if (Number > 0) {
  159.     int len = strlen(Title) + sizeof(Number) + 5;
  160.     char* buff = new char[len];
  161.     wsprintf(buff, Title, Number);
  162.     SetText(buff);
  163.     delete[] buff;
  164.   }
  165.   THandle hWndDefault = Parent->GetDlgItem(-1);
  166.   if (Number > 0) {
  167.     SetWindowPos(HWND_TOP, 0, 0, 0, 0,
  168.                  SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
  169.     if (hWndDefault)
  170.       ::ShowWindow(hWndDefault, SW_HIDE);
  171.     UpdateWindow();
  172.   }
  173.   return 0;
  174. }
  175.  
  176.  
  177. //----------------------------------------------------------------------------
  178.  
  179. DEFINE_RESPONSE_TABLE1(TPrinterAbortDlg, TDialog)
  180.   EV_COMMAND(IDCANCEL, CmCancel),
  181. END_RESPONSE_TABLE;
  182.  
  183.  
  184. //
  185. // Construct the object.
  186. // The information passed-in will be displayed in the abort dialog.
  187. //
  188. TPrinterAbortDlg::TPrinterAbortDlg(TWindow*        parent,
  189.                                    TResId          resId,
  190.                                    const char far* title,
  191.                                    const char far* device,
  192.                                    const char far* port,
  193.                                    HDC             prnDC)
  194. :
  195.   TDialog(parent, resId),
  196.   PrnDC(prnDC)
  197. {
  198.   new TNumericStatic(this, ID_PAGE, 0);
  199.   new TFormattedStatic(this, ID_TITLE, title);
  200.   new TFormattedStatic(this, ID_DEVICE, device, port);
  201.   new TNumericStatic(this, ID_TOPAGE, 0);
  202. }
  203.  
  204. //
  205. // Override SetupWindow.
  206. // This function disables the Close system menu option.
  207. //
  208. void
  209. TPrinterAbortDlg::SetupWindow()
  210. {
  211.   // Ignore missing controls, resource may be different
  212.   //
  213.   TRY {
  214.     TDialog::SetupWindow();
  215.   }
  216.   CATCH( (...) {
  217.   } )
  218.   EnableMenuItem(GetSystemMenu(false), SC_CLOSE, MF_GRAYED);
  219. }
  220.  
  221. //
  222. // Handle the print-cancel button by setting the user print abort flag in the
  223. // application.
  224. //
  225. void
  226. TPrinterAbortDlg::CmCancel()
  227. {
  228.   TPrinter::SetUserAbort(PrnDC);
  229.   THandle hBtn = GetDlgItem(IDCANCEL);
  230.   if (hBtn)
  231.     ::EnableWindow(hBtn, false);
  232. }
  233.  
  234.  
  235. //----------------------------------------------------------------------------
  236. //
  237. //  TPrinter is an encapsulation around the Windows printer device interface.
  238. //
  239. //  Examples:
  240. //   Creating a default device printing object:
  241. //
  242. //     DefaultPrinter = new TPrinter();
  243. //
  244. //   Creating a device for a specific printer:
  245. //
  246. //     PostScriptPrinter = new TPrinter();
  247. //     PostScriptPrinter->SetDevice("PostScript Printer", "PSCRIPT", "LPT2:");
  248. //
  249. //   Allowing the user to setup the printer:
  250. //
  251. //     DefaultPrinter->Setup(MyWindow);
  252. //
  253.  
  254. // Set by printing dialog if user cancels
  255. //
  256. HDC TPrinter::UserAbortDC = 0;
  257.  
  258. //
  259. // Initialize the TPrinter object assigned to the default printer
  260. //
  261. TPrinter::TPrinter(TApplication* app)
  262. {
  263.   Data = new TPrintDialog::TData;
  264.   Error = 0;
  265.   Application = app ? app : ::GetApplicationObject();
  266.   CHECK(Application);
  267.  
  268.   // Initialize with user's default printer.
  269.   // NOTE: GetDefaultPrinter is virtual. However, we're currently
  270.   //       in the constructor. Hence, TPrinter's version will be called
  271.   //       in this case even for derived classes which override that
  272.   //       method
  273.   //
  274.   GetDefaultPrinter();
  275. }
  276.  
  277. //
  278. // Deallocate allocated resources
  279. //
  280. TPrinter::~TPrinter()
  281. {
  282.   delete Data;
  283. }
  284.  
  285. //
  286. // Clears the association of this printer object with the current device
  287. //
  288. void TPrinter::ClearDevice()
  289. {
  290.   Data->ClearDevMode();
  291.   Data->ClearDevNames();
  292. }
  293.  
  294. //
  295. // Updata Data with info on the user's default printer.
  296. //
  297. void
  298. TPrinter::GetDefaultPrinter()
  299. {
  300.   //
  301.   // Have a printDialog go get the default printer information for us
  302.   // into DevMode and DevNames. We never actually Execute() the dialog.
  303.   //
  304.   SetClear(Data->Flags, 0L, long(PD_RETURNDC));
  305.   TPrintDialog printDialog(Application->GetMainWindow(), *Data);
  306.   if (!printDialog.GetDefaultPrinter()) {
  307.     Data->Error = PDERR_NODEFAULTPRN;
  308.   }
  309. }
  310.  
  311. //
  312. // Associate this printer object with actual printer info: driver name, device
  313. // name and output port name.
  314. //
  315. void
  316. TPrinter::SetPrinter(const char* driver, const char* device, const char* output)
  317. {
  318.   Data->SetDevNames(driver, device, output);
  319. }
  320.  
  321. //
  322. // Abort procedure used during printing, called by windows. Returns true to
  323. // continue the print job, false to cancel.
  324. //
  325. int CALLBACK OWL_EXPORT16
  326. TPrinterAbortProc(HDC hDC, int code)
  327. {
  328.   GetApplicationObject()->PumpWaitingMessages();
  329.  
  330.   // UserAbortDC will have been set by the AbortDialog
  331.   //
  332.   if (TPrinter::GetUserAbort() == hDC || TPrinter::GetUserAbort() == HDC(-1)) {
  333.     TPrinter::SetUserAbort(0);
  334.     return false;
  335.   }
  336.   return code == 0 || code == SP_OUTOFDISK;
  337. }
  338.  
  339. //
  340. // Virtual called from within Print() to construct and execute a print dialog
  341. // before actual printing occurs. Return true to continue printing, false to
  342. // cancel
  343. //
  344. bool
  345. TPrinter::ExecPrintDialog(TWindow* parent)
  346. {
  347.   return TPrintDialog(parent, *Data).Execute() == IDOK;
  348. }
  349.  
  350. //
  351. // Page setup dialog for Win95 support.
  352. //
  353. #pragma warn -par
  354. bool
  355. TPrinter::ExecPageSetupDialog(TWindow* parent)
  356. {
  357. #if defined(BI_PLAT_WIN32)
  358.   Data->DoPageSetup = true;
  359.   bool ret = TPrintDialog(parent, *Data).Execute() == IDOK;
  360.   Data->DoPageSetup = false;
  361.   return ret;
  362. #else
  363.   return false;
  364. #endif
  365. }
  366. #pragma warn .par
  367.  
  368. //
  369. // Virtual called from withing Print() just before the main printing loop to
  370. // construct and create the printing status, or abort window. This window
  371. // should use the control IDs specified in printer.rh
  372. //
  373. TWindow*
  374. TPrinter::CreateAbortWindow(TWindow* parent, TPrintout& printout)
  375. {
  376.   TDC* dc = printout.GetPrintDC();
  377.   TWindow* win = new TPrinterAbortDlg(parent, IDD_ABORTDIALOG,
  378.                                       printout.GetTitle(),
  379.                                       Data->GetDeviceName(),
  380.                                       Data->GetOutputName(),
  381.                                       dc ? HDC(*dc) : HDC(-1));
  382.   win->Create();
  383.   return win;
  384. }
  385.  
  386. //
  387. // Updates the PageSize variables by querying the device capabilities
  388. // of the specified device context
  389. //
  390. void
  391. TPrinter::SetPageSizes(const TPrintDC& prnDC)
  392. {
  393.   PageSize.cx = prnDC.GetDeviceCaps(HORZRES);
  394.   PageSize.cy = prnDC.GetDeviceCaps(VERTRES);
  395.   PageSizeInch.cx = prnDC.GetDeviceCaps(LOGPIXELSX);
  396.   PageSizeInch.cy = prnDC.GetDeviceCaps(LOGPIXELSY);
  397. }
  398.  
  399. //
  400. // Helper function for Print when it is banding used to calculate banding flags
  401. // and rectangle.
  402. //
  403. void
  404. TPrinter::CalcBandingFlags(TPrintDC& prnDC)
  405. {
  406.   //
  407.   // Calculate text versus graphics banding
  408.   //
  409.   if (UseBandInfo) {
  410.     TBandInfo bandInfo;
  411.     unsigned  flags = 0;
  412.  
  413.     prnDC.BandInfo(bandInfo);
  414.     if (bandInfo.HasGraphics)
  415.       flags = pfGraphics;
  416.     if (bandInfo.HasText)
  417.       flags |= pfGraphics;
  418.     Flags = (Flags & ~pfBoth) | flags;
  419.   }
  420.   else {
  421.     //
  422.     // If a driver does not support BANDINFO the Microsoft recommended way
  423.     // of determining text only bands is if the first band is the full page,
  424.     // all others are graphics only.  Otherwise it handles both.
  425.     //
  426.     if (FirstBand && !BandRect.left && !BandRect.top &&
  427.         BandRect.right == PageSize.cx && BandRect.bottom == PageSize.cy)
  428.       Flags = pfText;
  429.     else
  430.       if ((Flags & pfBoth) == pfGraphics)
  431.         // All other bands are graphics only
  432.         Flags = (Flags & ~pfBoth) | pfGraphics;
  433.       else
  434.         Flags = Flags | pfBoth;
  435.   }
  436.   FirstBand = false;
  437. }
  438.  
  439. //
  440. // Print the given printout to the printer, prompting the user with a
  441. // commdlg print dialog if indicated.
  442. //
  443. bool
  444. TPrinter::Print(TWindow* parent, TPrintout& printout, bool prompt)
  445. {
  446.   PRECONDITION(parent);
  447.  
  448.   // Start from scratch
  449.   //
  450.   Error = 1;            // Positive 'Error' means print job is OK
  451.   TPrintDC* prnDC = 0;  // Pointer to printer DC created by Printer Object
  452.   HCURSOR hOrigCursor = ::SetCursor(::LoadCursor(0, IDC_WAIT));
  453.  
  454.   //
  455.  
  456.   //
  457.   // Get page range & selection range (if any) from document
  458.   //
  459.   int selFromPage = 0;
  460.   int selToPage = 0;
  461.   printout.GetDialogInfo(Data->MinPage, Data->MaxPage, selFromPage, selToPage);
  462.  
  463.   if (selFromPage) {
  464.     Data->Flags &= ~PD_NOSELECTION;
  465.     Data->FromPage = selFromPage;
  466.     Data->ToPage   = selToPage;
  467.   }
  468.   else {
  469.     Data->Flags |= PD_NOSELECTION;
  470.     Data->FromPage = 0;
  471.     Data->ToPage = 999;
  472.   }
  473.  
  474.   if (Data->MinPage) {
  475.     Data->Flags &= ~PD_NOPAGENUMS;
  476.     if (Data->FromPage < Data->MinPage)
  477.       Data->FromPage = Data->MinPage;
  478.     else if (Data->FromPage > Data->MaxPage)
  479.       Data->FromPage = Data->MaxPage;
  480.     if (Data->ToPage < Data->MinPage)
  481.       Data->ToPage = Data->MinPage;
  482.     else if (Data->ToPage > Data->MaxPage)
  483.       Data->ToPage = Data->MaxPage;
  484.   }
  485.   else
  486.     Data->Flags |= PD_NOPAGENUMS;
  487.  
  488.   //
  489.   // Create & execute a TPrintDialog (or derived) and have it return a usable
  490.   // DC if prompt is enabled. If the dialog fails because the default printer
  491.   // changed, clear our device information & try again.
  492.   //
  493.   if (prompt) {
  494.     SetClear(Data->Flags, PD_RETURNDC, PD_RETURNDEFAULT|PD_PRINTSETUP);
  495.     bool ok = ExecPrintDialog(parent);
  496.     if (!ok && Data->Error == PDERR_DEFAULTDIFFERENT) {
  497.       ClearDevice();
  498.       ok = ExecPrintDialog(parent);
  499.     }
  500.     if (!ok)
  501.       return false;
  502.  
  503.     prnDC = Data->TransferDC();   // We now own the DC, let prnDC manage it
  504.   }
  505.   // Construct the DC directly if prompting was not enabled.
  506.   //
  507.   else {
  508.     prnDC = new TPrintDC(Data->GetDriverName(), Data->GetDeviceName(),
  509.                          Data->GetOutputName(), Data->GetDevMode());
  510.   }
  511.   if (!prnDC)
  512.     TXPrinter::Raise();
  513.  
  514.   // Update the printer's page and forward DC and pageSize to printout
  515.   //
  516.   SetPageSizes(*prnDC);
  517.   printout.SetPrintParams(prnDC, GetPageSize());
  518.  
  519.   // Create modeless abort dialog using strings
  520.   //
  521.   TWindow* abortWin;
  522.   TRY {
  523.     abortWin = CreateAbortWindow(parent, printout);
  524.   }
  525.   CATCH( (...) {
  526.     delete prnDC;
  527.     RETHROW;
  528.   })
  529.  
  530.   ::SetCursor(hOrigCursor);
  531.   parent->EnableWindow(false);
  532.  
  533.   prnDC->SetAbortProc(TPrinterAbortProc);
  534.  
  535.   // Only band if the user requests banding and the printer
  536.   // supports banding
  537.   //
  538.   bool banding = printout.WantBanding() &&
  539.                 (prnDC->GetDeviceCaps(RASTERCAPS) & RC_BANDING);
  540.   if (banding)
  541.  
  542.     // Only use BANDINFO if supported.
  543.     //
  544.     UseBandInfo = ToBool(prnDC->QueryEscSupport(BANDINFO));
  545.  
  546.   else
  547.     //
  548.     // Set the banding rectangle to full page
  549.     //
  550.     BandRect.Set(0, 0, PageSize.cx, PageSize.cy);
  551.  
  552.   // If more than one (uncollated) copy was requested, see if printer can
  553.   // handle it for performance and user convenience.
  554.   //
  555.   int copiesPerPass = 1;
  556.   int tempCopiesPerPass = copiesPerPass;
  557.   if (!(Data->Flags & PD_COLLATE))
  558.     prnDC->SetCopyCount(Data->Copies, copiesPerPass);
  559.  
  560.   // Figure out which page range to use: Selection, Dialog's from/to,
  561.   // whole doc range or all possible pages.
  562.   //
  563.   int fromPage;
  564.   int toPage;
  565.   if (prompt && (Data->Flags & PD_SELECTION) || selFromPage) {
  566.     fromPage = selFromPage;
  567.     toPage = selToPage;
  568.   }
  569.   else if (prompt && (Data->Flags & PD_PAGENUMS)) {
  570.     fromPage = Data->FromPage;
  571.     toPage = Data->ToPage;
  572.   }
  573.   else if (Data->MinPage) {
  574.     fromPage = Data->MinPage;
  575.     toPage = Data->MaxPage;
  576.   }
  577.   else {
  578.     fromPage = 1;
  579.     toPage = INT_MAX;
  580.   }
  581.  
  582.   // Copies loop, one pass per block of document copies.
  583.   //
  584.   printout.BeginPrinting();
  585.   for (int copies = Data->Copies;
  586.        copies > 0 && Error > 0;
  587.        copies -= tempCopiesPerPass) {
  588.  
  589.     // On last multi-copy pass, may need to adjust copy count
  590.     //
  591.     if (copiesPerPass > 1 && copies < copiesPerPass)
  592.       prnDC->SetCopyCount(copies, copiesPerPass);
  593.  
  594.     // Whole document loop, one pass per page
  595.     //
  596.     Flags = pfBoth;
  597.     Error = prnDC->StartDoc(printout.GetTitle(), 0);  // get PD_PRINTTOFILE ?
  598.     printout.BeginDocument(fromPage, toPage, Flags);
  599.  
  600.     abortWin->SendDlgItemMessage(ID_TOPAGE, WM_SETNUMBER, toPage);
  601.     for (int pageNum = fromPage;
  602.          Error > 0 && pageNum <= toPage && printout.HasPage(pageNum);
  603.          pageNum++) {
  604.  
  605.       abortWin->SendDlgItemMessage(ID_PAGE, WM_SETNUMBER, pageNum);
  606.  
  607.       // Begin the page by getting the first band or calling StartPage()
  608.       //
  609.       if (banding) {
  610.         FirstBand = true;
  611.         Error = prnDC->NextBand(BandRect);
  612.       }
  613.       else
  614.         Error = prnDC->StartPage();
  615.  
  616.       // Whole page loop, one pass per band (once when not banding)
  617.       //
  618.       while (Error > 0 && !BandRect.IsEmpty()) {
  619.         //
  620.         // [Manually call the abort proc between bands or pages]
  621.         //
  622. #if defined(MANUAL_ABORT_CALL) && defined(BI_PLAT_WIN16)
  623.  
  624.         // Allows Abort procedure to set UserAbortDC
  625.         //
  626.         prnDC->QueryAbort();
  627. #endif
  628.  
  629.         if (banding) {
  630.           CalcBandingFlags(*prnDC);
  631.           if (printout.WantForceAllBands() && (Flags & pfBoth) == pfGraphics)
  632.             prnDC->SetPixel(TPoint(0, 0), 0);  // Some old drivers need this
  633.           prnDC->DPtoLP(BandRect, 2);
  634.         }
  635.  
  636.         printout.PrintPage(pageNum, BandRect, Flags);
  637.         if (banding)
  638.           Error = prnDC->NextBand(BandRect);
  639.         else
  640.           break;
  641.       }
  642.  
  643.       // EndPage (NEWFRAME) need only called if not banding
  644.       //
  645.       if (Error > 0 && !banding) {
  646.         Error = prnDC->EndPage();
  647.         if (Error == 0)    // a zero return here is OK for this call
  648.           Error = 1;
  649.       }
  650.     }  // End of Whole Document-loop
  651.  
  652.     // Tell GDI the document is finished
  653.     //
  654.     if (Error > 0)
  655. #if defined(MANUAL_ABORT_CALL)
  656.       if (banding && (UserAbortDC == *prnDC || UserAbortDC == HDC(-1)))
  657.         prnDC->AbortDoc();
  658.       else
  659.         prnDC->EndDoc();
  660. #else
  661.       prnDC->EndDoc();
  662. #endif
  663.  
  664.     printout.EndDocument();
  665.  
  666.   } // End of Copy-loop
  667.   printout.EndPrinting();
  668.  
  669.   // Set the printer back to 1 copy
  670.   //
  671.   if (copiesPerPass > 1)
  672.     prnDC->SetCopyCount(1, copiesPerPass);
  673.  
  674.   // Re-enable parent and free allocated resources
  675.   //
  676.   parent->EnableWindow(true);
  677.   abortWin->Destroy();
  678.   delete abortWin;
  679.   if (UserAbortDC == *prnDC)  // User tried to abort, but it was too late
  680.     UserAbortDC = 0;
  681.   delete prnDC;
  682.  
  683.   // Report error if not already done so by printmgr
  684.   //
  685.   if (Error & SP_NOTREPORTED)
  686.     ReportError(parent, printout);
  687.  
  688.   return Error > 0;
  689. }
  690.  
  691. //
  692. // Setup opens a dialog as a child of the given window to setup the
  693. // printer using the commdlg printer setup. The options button
  694. // allows the user acces to the specific driver's options.
  695. //
  696. void TPrinter::Setup(TWindow* parent)
  697. {
  698. #if defined(BI_PLAT_WIN32)  
  699.   ExecPageSetupDialog(parent);
  700. #else
  701.   SetClear(Data->Flags, PD_PRINTSETUP, PD_RETURNDEFAULT|PD_RETURNDC);
  702.   ExecPrintDialog(parent);
  703. #endif
  704. }
  705.  
  706. //
  707. // Report the printer error in a message box. First translate the SP_ codes
  708. // into ObjectWindows string resource IDs, and then load the strings. Don't
  709. // display anything if the string is not found, or the code is unknown.
  710. //
  711. void
  712. TPrinter::ReportError(TWindow* parent, TPrintout& printout)
  713. {
  714.   uint16  errorId;
  715.  
  716.   switch (Error) {
  717.     case SP_ERROR:
  718.       errorId = IDS_PRNGENERROR;
  719.       break;
  720.     case SP_APPABORT:
  721.       errorId = IDS_PRNCANCEL;
  722.       break;
  723.     case SP_USERABORT:
  724.       errorId = IDS_PRNMGRABORT;
  725.       break;
  726.     case SP_OUTOFDISK:
  727.       errorId = IDS_PRNOUTOFDISK;
  728.       break;
  729.     case SP_OUTOFMEMORY:
  730.       errorId = IDS_PRNOUTOFMEMORY;
  731.       break;
  732.     default:
  733.       return;
  734.   }
  735.  
  736.   TModule& module = *parent->GetModule();
  737.  
  738.   char  errorCaption[80];
  739.   if (!module.LoadString(IDS_PRNERRORCAPTION, errorCaption, sizeof(errorCaption)))
  740.     return;
  741.  
  742.   char  errorTemplate[40];
  743.   char  errorStr[40];
  744.   if (!module.LoadString(IDS_PRNERRORTEMPLATE, errorTemplate, sizeof(errorTemplate)))
  745.     return;
  746.   if (!module.LoadString(errorId, errorStr, sizeof(errorStr)))
  747.     return;
  748.  
  749.   int len = strlen(errorTemplate) + strlen(printout.GetTitle()) +
  750.             strlen(errorStr) + 5;
  751.   char* errorMsg = new char[len];
  752.   sprintf(errorMsg, errorTemplate, printout.GetTitle(), (char far*)errorStr);
  753.  
  754.   parent->MessageBox(errorMsg, errorCaption, MB_OK | MB_ICONSTOP);
  755.   delete[] errorMsg;
  756. }
  757.  
  758. //----------------------------------------------------------------------------
  759.  
  760. //
  761. // Construct the exception object with the string resource.
  762. //
  763. TXPrinter::TXPrinter(uint resId)
  764. :
  765.   TXOwl(resId)
  766. {
  767. }
  768.  
  769. //
  770. // Clone the exception object for safe throwing across Win16 stack frames.
  771. //
  772. #if defined(BI_NO_COVAR_RET)
  773. TXBase*
  774. #else
  775. TXPrinter*
  776. #endif
  777. TXPrinter::Clone()
  778. {
  779.   return new TXPrinter(*this);
  780. }
  781.  
  782. //
  783. // Throws the exception.
  784. //
  785. void
  786. TXPrinter::Throw()
  787. {
  788.   THROW( *this );
  789. }
  790.  
  791. //
  792. // Create the exception object and throws it.
  793. //
  794. void
  795. TXPrinter::Raise(uint resId)
  796. {
  797.   TXPrinter(resId).Throw();
  798. }
  799.  
  800. #endif
  801. #if !defined(SECTION) || SECTION == 2
  802.  
  803. IMPLEMENT_STREAMABLE(TPrinter);
  804.  
  805. #if !defined(BI_NO_OBJ_STREAMING)
  806.  
  807. //
  808. // Restore the printer object from the persistent stream.
  809. //
  810. void*
  811. TPrinter::Streamer::Read(ipstream& is, uint32 version) const
  812. {
  813.   GetObject()->Data->Read(is, version);
  814.   return GetObject();
  815. }
  816.  
  817. //
  818. // Save the object into the persistent stream.
  819. //
  820. void
  821. TPrinter::Streamer::Write(opstream& os) const
  822. {
  823.   GetObject()->Data->Write(os);
  824. }
  825.  
  826. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  827.  
  828. #endif
  829.  
  830.