1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/printdlg.cpp
3 // Purpose: wxPrintDialog, wxPageSetupDialog
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 // Don't use the Windows print dialog if we're in wxUniv mode and using
28 // the PostScript architecture
29 #if wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXUNIVERSAL__) || !wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW)
32 #include "wx/msw/wrapcdlg.h"
34 #include "wx/dcprint.h"
35 #include "wx/cmndata.h"
38 #include "wx/printdlg.h"
39 #include "wx/msw/printdlg.h"
40 #include "wx/msw/dcprint.h"
42 #include "wx/modalhook.h"
46 // smart pointer like class using OpenPrinter and ClosePrinter
53 m_hPrinter
= (HANDLE
)NULL
;
56 WinPrinter( const wxString
& printerName
)
66 BOOL
Open( const wxString
& printerName
, LPPRINTER_DEFAULTS pDefault
=(LPPRINTER_DEFAULTS
)NULL
)
69 return OpenPrinter( wxMSW_CONV_LPTSTR(printerName
), &m_hPrinter
, pDefault
);
77 result
= ClosePrinter( m_hPrinter
);
78 m_hPrinter
= (HANDLE
)NULL
;
83 operator HANDLE() { return m_hPrinter
; }
84 operator bool() { return m_hPrinter
!= (HANDLE
)NULL
; }
89 wxDECLARE_NO_COPY_CLASS(WinPrinter
);
93 //----------------------------------------------------------------------------
94 // wxWindowsPrintNativeData
95 //----------------------------------------------------------------------------
99 static wxString
wxGetPrintDlgError()
101 DWORD err
= CommDlgExtendedError();
102 wxString msg
= wxT("Unknown");
105 case CDERR_FINDRESFAILURE
: msg
= wxT("CDERR_FINDRESFAILURE"); break;
106 case CDERR_INITIALIZATION
: msg
= wxT("CDERR_INITIALIZATION"); break;
107 case CDERR_LOADRESFAILURE
: msg
= wxT("CDERR_LOADRESFAILURE"); break;
108 case CDERR_LOADSTRFAILURE
: msg
= wxT("CDERR_LOADSTRFAILURE"); break;
109 case CDERR_LOCKRESFAILURE
: msg
= wxT("CDERR_LOCKRESFAILURE"); break;
110 case CDERR_MEMALLOCFAILURE
: msg
= wxT("CDERR_MEMALLOCFAILURE"); break;
111 case CDERR_MEMLOCKFAILURE
: msg
= wxT("CDERR_MEMLOCKFAILURE"); break;
112 case CDERR_NOHINSTANCE
: msg
= wxT("CDERR_NOHINSTANCE"); break;
113 case CDERR_NOHOOK
: msg
= wxT("CDERR_NOHOOK"); break;
114 case CDERR_NOTEMPLATE
: msg
= wxT("CDERR_NOTEMPLATE"); break;
115 case CDERR_STRUCTSIZE
: msg
= wxT("CDERR_STRUCTSIZE"); break;
116 case PDERR_RETDEFFAILURE
: msg
= wxT("PDERR_RETDEFFAILURE"); break;
117 case PDERR_PRINTERNOTFOUND
: msg
= wxT("PDERR_PRINTERNOTFOUND"); break;
118 case PDERR_PARSEFAILURE
: msg
= wxT("PDERR_PARSEFAILURE"); break;
119 case PDERR_NODEVICES
: msg
= wxT("PDERR_NODEVICES"); break;
120 case PDERR_NODEFAULTPRN
: msg
= wxT("PDERR_NODEFAULTPRN"); break;
121 case PDERR_LOADDRVFAILURE
: msg
= wxT("PDERR_LOADDRVFAILURE"); break;
122 case PDERR_INITFAILURE
: msg
= wxT("PDERR_INITFAILURE"); break;
123 case PDERR_GETDEVMODEFAIL
: msg
= wxT("PDERR_GETDEVMODEFAIL"); break;
124 case PDERR_DNDMMISMATCH
: msg
= wxT("PDERR_DNDMMISMATCH"); break;
125 case PDERR_DEFAULTDIFFERENT
: msg
= wxT("PDERR_DEFAULTDIFFERENT"); break;
126 case PDERR_CREATEICFAILURE
: msg
= wxT("PDERR_CREATEICFAILURE"); break;
132 #endif // wxDEBUG_LEVEL
136 wxCreateDevNames(const wxString
& driverName
,
137 const wxString
& printerName
,
138 const wxString
& portName
)
141 // if (!driverName.empty() && !printerName.empty() && !portName.empty())
142 if (driverName
.empty() && printerName
.empty() && portName
.empty())
147 hDev
= GlobalAlloc(GPTR
, 4*sizeof(WORD
)+
148 ( driverName
.length() + 1 +
149 printerName
.length() + 1 +
150 portName
.length()+1 ) * sizeof(wxChar
) );
151 LPDEVNAMES lpDev
= (LPDEVNAMES
)GlobalLock(hDev
);
152 lpDev
->wDriverOffset
= sizeof(WORD
) * 4 / sizeof(wxChar
);
153 wxStrcpy((wxChar
*)lpDev
+ lpDev
->wDriverOffset
, driverName
);
155 lpDev
->wDeviceOffset
= (WORD
)( lpDev
->wDriverOffset
+
156 driverName
.length() + 1 );
157 wxStrcpy((wxChar
*)lpDev
+ lpDev
->wDeviceOffset
, printerName
);
159 lpDev
->wOutputOffset
= (WORD
)( lpDev
->wDeviceOffset
+
160 printerName
.length() + 1 );
161 wxStrcpy((wxChar
*)lpDev
+ lpDev
->wOutputOffset
, portName
);
171 IMPLEMENT_CLASS(wxWindowsPrintNativeData
, wxPrintNativeDataBase
)
173 wxWindowsPrintNativeData::wxWindowsPrintNativeData()
177 m_customWindowsPaperId
= 0;
180 wxWindowsPrintNativeData::~wxWindowsPrintNativeData()
183 ::GlobalFree(static_cast<HGLOBAL
>(m_devMode
));
186 ::GlobalFree(static_cast<HGLOBAL
>(m_devNames
));
189 bool wxWindowsPrintNativeData::IsOk() const
191 return (m_devMode
!= NULL
) ;
194 bool wxWindowsPrintNativeData::TransferTo( wxPrintData
&data
)
202 GlobalPtrLock
lockDevMode(m_devMode
);
204 LPDEVMODE devMode
= static_cast<LPDEVMODE
>(lockDevMode
.Get());
207 if (devMode
->dmFields
& DM_ORIENTATION
)
208 data
.SetOrientation( (wxPrintOrientation
)devMode
->dmOrientation
);
211 if (devMode
->dmFields
& DM_COLLATE
)
213 if (devMode
->dmCollate
== DMCOLLATE_TRUE
)
214 data
.SetCollate( true );
216 data
.SetCollate( false );
219 //// Number of copies
220 if (devMode
->dmFields
& DM_COPIES
)
221 data
.SetNoCopies( devMode
->dmCopies
);
224 if (devMode
->dmFields
& DM_DEFAULTSOURCE
) {
225 switch (devMode
->dmDefaultSource
) {
226 case DMBIN_ONLYONE
: data
.SetBin(wxPRINTBIN_ONLYONE
); break;
227 case DMBIN_LOWER
: data
.SetBin(wxPRINTBIN_LOWER
); break;
228 case DMBIN_MIDDLE
: data
.SetBin(wxPRINTBIN_MIDDLE
); break;
229 case DMBIN_MANUAL
: data
.SetBin(wxPRINTBIN_MANUAL
); break;
230 case DMBIN_ENVELOPE
: data
.SetBin(wxPRINTBIN_ENVELOPE
); break;
231 case DMBIN_ENVMANUAL
: data
.SetBin(wxPRINTBIN_ENVMANUAL
); break;
232 case DMBIN_AUTO
: data
.SetBin(wxPRINTBIN_AUTO
); break;
233 case DMBIN_TRACTOR
: data
.SetBin(wxPRINTBIN_TRACTOR
); break;
234 case DMBIN_SMALLFMT
: data
.SetBin(wxPRINTBIN_SMALLFMT
); break;
235 case DMBIN_LARGEFMT
: data
.SetBin(wxPRINTBIN_LARGEFMT
); break;
236 case DMBIN_LARGECAPACITY
: data
.SetBin(wxPRINTBIN_LARGECAPACITY
); break;
237 case DMBIN_CASSETTE
: data
.SetBin(wxPRINTBIN_CASSETTE
); break;
238 case DMBIN_FORMSOURCE
: data
.SetBin(wxPRINTBIN_FORMSOURCE
); break;
240 if (devMode
->dmDefaultSource
>= DMBIN_USER
)
241 data
.SetBin((wxPrintBin
)((devMode
->dmDefaultSource
)-DMBIN_USER
+(int)wxPRINTBIN_USER
));
243 data
.SetBin(wxPRINTBIN_DEFAULT
);
246 data
.SetBin(wxPRINTBIN_DEFAULT
);
248 if (devMode
->dmFields
& DM_MEDIATYPE
)
250 wxASSERT( (int)devMode
->dmMediaType
!= wxPRINTMEDIA_DEFAULT
);
251 data
.SetMedia(devMode
->dmMediaType
);
254 if (devMode
->dmDeviceName
[0] != 0)
255 // This syntax fixes a crash when using VS 7.1
256 data
.SetPrinterName( wxString(devMode
->dmDeviceName
, CCHDEVICENAME
) );
259 if (devMode
->dmFields
& DM_COLOR
)
261 if (devMode
->dmColor
== DMCOLOR_COLOR
)
262 data
.SetColour( true );
264 data
.SetColour( false );
267 data
.SetColour( true );
271 // We don't know size of user defined paper and some buggy drivers
272 // set both DM_PAPERSIZE and DM_PAPERWIDTH & DM_PAPERLENGTH. Since
273 // dmPaperSize >= DMPAPER_USER wouldn't be in wxWin's database, this
274 // code wouldn't set m_paperSize correctly.
276 bool foundPaperSize
= false;
277 if ((devMode
->dmFields
& DM_PAPERSIZE
) && (devMode
->dmPaperSize
< DMPAPER_USER
))
279 if (wxThePrintPaperDatabase
)
281 wxPrintPaperType
* paper
= wxThePrintPaperDatabase
->FindPaperTypeByPlatformId(devMode
->dmPaperSize
);
284 data
.SetPaperId( paper
->GetId() );
285 data
.SetPaperSize( wxSize(paper
->GetWidth() / 10,paper
->GetHeight() / 10) );
286 m_customWindowsPaperId
= 0;
287 foundPaperSize
= true;
292 // Shouldn't really get here
293 wxFAIL_MSG(wxT("Paper database wasn't initialized in wxPrintData::ConvertFromNative."));
294 data
.SetPaperId( wxPAPER_NONE
);
295 data
.SetPaperSize( wxSize(0,0) );
296 m_customWindowsPaperId
= 0;
302 if (!foundPaperSize
) {
303 if ((devMode
->dmFields
& DM_PAPERWIDTH
) && (devMode
->dmFields
& DM_PAPERLENGTH
))
305 // DEVMODE is in tenths of a millimeter
306 data
.SetPaperSize( wxSize(devMode
->dmPaperWidth
/ 10, devMode
->dmPaperLength
/ 10) );
307 data
.SetPaperId( wxPAPER_NONE
);
308 m_customWindowsPaperId
= devMode
->dmPaperSize
;
312 // Often will reach this for non-standard paper sizes (sizes which
313 // wouldn't be in wxWidget's paper database). Setting
314 // m_customWindowsPaperId to devMode->dmPaperSize should be enough
315 // to get this paper size working.
316 data
.SetPaperSize( wxSize(0,0) );
317 data
.SetPaperId( wxPAPER_NONE
);
318 m_customWindowsPaperId
= devMode
->dmPaperSize
;
324 if (devMode
->dmFields
& DM_DUPLEX
)
326 switch (devMode
->dmDuplex
)
328 case DMDUP_HORIZONTAL
: data
.SetDuplex( wxDUPLEX_HORIZONTAL
); break;
329 case DMDUP_VERTICAL
: data
.SetDuplex( wxDUPLEX_VERTICAL
); break;
331 case DMDUP_SIMPLEX
: data
.SetDuplex( wxDUPLEX_SIMPLEX
); break;
335 data
.SetDuplex( wxDUPLEX_SIMPLEX
);
339 if (devMode
->dmFields
& DM_PRINTQUALITY
)
341 switch (devMode
->dmPrintQuality
)
343 case DMRES_MEDIUM
: data
.SetQuality( wxPRINT_QUALITY_MEDIUM
); break;
344 case DMRES_LOW
: data
.SetQuality( wxPRINT_QUALITY_LOW
); break;
345 case DMRES_DRAFT
: data
.SetQuality( wxPRINT_QUALITY_DRAFT
); break;
346 case DMRES_HIGH
: data
.SetQuality( wxPRINT_QUALITY_HIGH
); break;
349 // TODO: if the printer fills in the resolution in DPI, how
350 // will the application know if it's high, low, draft etc.??
351 // wxFAIL_MSG("Warning: DM_PRINTQUALITY was not one of the standard values.");
352 data
.SetQuality( devMode
->dmPrintQuality
);
359 data
.SetQuality( wxPRINT_QUALITY_HIGH
);
361 if (devMode
->dmDriverExtra
> 0)
362 data
.SetPrivData( (char *)devMode
+devMode
->dmSize
, devMode
->dmDriverExtra
);
364 data
.SetPrivData( NULL
, 0 );
368 GlobalPtrLock
lockDevNames(m_devNames
);
369 LPDEVNAMES lpDevNames
= static_cast<LPDEVNAMES
>(lockDevNames
.Get());
371 // TODO: Unicode-ification
374 // port is obsolete in WIN32
375 // m_printData.SetPortName((LPSTR)lpDevNames + lpDevNames->wDriverOffset);
377 // Get the printer name
378 wxString printerName
= (LPTSTR
)lpDevNames
+ lpDevNames
->wDeviceOffset
;
380 // Not sure if we should check for this mismatch
381 // wxASSERT_MSG( (m_printerName.empty() || (devName == m_printerName)), "Printer name obtained from DEVMODE and DEVNAMES were different!");
383 if (!printerName
.empty())
384 data
.SetPrinterName( printerName
);
390 void wxWindowsPrintNativeData::InitializeDevMode(const wxString
& printerName
, WinPrinter
* printer
)
395 LPTSTR szPrinterName
= wxMSW_CONV_LPTSTR(printerName
);
397 // From MSDN: How To Modify Printer Settings with the DocumentProperties() Function
398 // The purpose of this is to fill the DEVMODE with privdata from printer driver.
399 // If we have a printer name and OpenPrinter successfully returns
400 // this replaces the PrintDlg function which creates the DEVMODE filled only with data from default printer.
401 if ( !m_devMode
&& !printerName
.IsEmpty() )
404 if ( printer
&& printer
->Open( printerName
) == TRUE
)
406 DWORD dwNeeded
, dwRet
;
409 // Allocate a buffer of the correct size.
410 dwNeeded
= DocumentProperties( NULL
,
411 *printer
, // Handle to our printer.
412 szPrinterName
, // Name of the printer.
413 NULL
, // Asking for size, so
414 NULL
, // these are not used.
415 0 ); // Zero returns buffer size.
417 LPDEVMODE tempDevMode
= static_cast<LPDEVMODE
>( GlobalAlloc( GMEM_FIXED
| GMEM_ZEROINIT
, dwNeeded
) );
420 // Get the default DevMode for the printer
421 dwRet
= DocumentProperties( NULL
,
424 tempDevMode
, // The address of the buffer to fill.
425 NULL
, // Not using the input buffer.
426 DM_OUT_BUFFER
); // Have the output buffer filled.
430 // If failure, cleanup
431 GlobalFree( tempDevMode
);
436 m_devMode
= tempDevMode
;
444 // Use PRINTDLG as a way of creating a DEVMODE object
447 memset(&pd
, 0, sizeof(PRINTDLG
));
449 pd
.cbStruct
= sizeof(PRINTDLG
);
451 pd
.lStructSize
= sizeof(PRINTDLG
);
455 pd
.hDevMode
= NULL
; // Will be created by PrintDlg
456 pd
.hDevNames
= NULL
; // Ditto
458 pd
.Flags
= PD_RETURNDEFAULT
;
461 // Fill out the DEVMODE structure
462 // so we can use it as input in the 'real' PrintDlg
466 GlobalFree(pd
.hDevMode
);
468 GlobalFree(pd
.hDevNames
);
473 wxLogDebug(wxT("Printing error: ") + wxGetPrintDlgError());
474 #endif // wxDEBUG_LEVEL
478 m_devMode
= pd
.hDevMode
;
481 // We'll create a new DEVNAMEs structure below.
483 GlobalFree(pd
.hDevNames
);
486 // hDevNames = pd->hDevNames;
487 // m_devNames = (void*)(long) hDevNames;
488 // pd->hDevnames = NULL;
495 bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData
&data
)
498 LPTSTR szPrinterName
= wxMSW_CONV_LPTSTR(data
.GetPrinterName());
501 InitializeDevMode(data
.GetPrinterName(), &printer
);
503 HGLOBAL hDevMode
= static_cast<HGLOBAL
>(m_devMode
);
507 GlobalPtrLock
lockDevMode(hDevMode
);
508 DEVMODE
* const devMode
= static_cast<DEVMODE
*>(lockDevMode
.Get());
511 devMode
->dmOrientation
= (short)data
.GetOrientation();
514 devMode
->dmCollate
= (data
.GetCollate() ? DMCOLLATE_TRUE
: DMCOLLATE_FALSE
);
515 devMode
->dmFields
|= DM_COLLATE
;
517 //// Number of copies
518 devMode
->dmCopies
= (short)data
.GetNoCopies();
519 devMode
->dmFields
|= DM_COPIES
;
522 wxString name
= data
.GetPrinterName();
525 // NB: the cast is needed in the ANSI build, strangely enough
526 // dmDeviceName is BYTE[] and not char[] there
527 wxStrlcpy(reinterpret_cast<wxChar
*>(devMode
->dmDeviceName
),
529 WXSIZEOF(devMode
->dmDeviceName
));
533 if (data
.GetColour())
534 devMode
->dmColor
= DMCOLOR_COLOR
;
536 devMode
->dmColor
= DMCOLOR_MONOCHROME
;
537 devMode
->dmFields
|= DM_COLOR
;
541 // Paper id has priority over paper size. If id is specified, then size
542 // is ignored (as it can be filled in even for standard paper sizes)
544 wxPrintPaperType
*paperType
= NULL
;
546 const wxPaperSize paperId
= data
.GetPaperId();
547 if ( paperId
!= wxPAPER_NONE
&& wxThePrintPaperDatabase
)
549 paperType
= wxThePrintPaperDatabase
->FindPaperType(paperId
);
554 devMode
->dmPaperSize
= (short)paperType
->GetPlatformId();
555 devMode
->dmFields
|= DM_PAPERSIZE
;
557 else // custom (or no) paper size
559 const wxSize paperSize
= data
.GetPaperSize();
560 if ( paperSize
!= wxDefaultSize
)
562 // Fall back on specifying the paper size explicitly
563 if(m_customWindowsPaperId
!= 0)
564 devMode
->dmPaperSize
= m_customWindowsPaperId
;
566 devMode
->dmPaperSize
= DMPAPER_USER
;
567 devMode
->dmPaperWidth
= (short)(paperSize
.x
* 10);
568 devMode
->dmPaperLength
= (short)(paperSize
.y
* 10);
569 devMode
->dmFields
|= DM_PAPERWIDTH
;
570 devMode
->dmFields
|= DM_PAPERLENGTH
;
572 // A printer driver may or may not also want DM_PAPERSIZE to
573 // be specified. Also, if the printer driver doesn't implement the DMPAPER_USER
574 // size, then this won't work, and even if you found the correct id by
575 // enumerating the driver's paper sizes, it probably won't change the actual size,
576 // it'll just select that custom paper type with its own current setting.
577 // For a discussion on this, see http://www.codeguru.com/forum/showthread.php?threadid=458617
578 // Although m_customWindowsPaperId is intended to work around this, it's
579 // unclear how it can help you set the custom paper size programmatically.
581 //else: neither paper type nor size specified, don't fill DEVMODE
582 // at all so that the system defaults are used
587 switch (data
.GetDuplex())
589 case wxDUPLEX_HORIZONTAL
:
590 duplex
= DMDUP_HORIZONTAL
;
592 case wxDUPLEX_VERTICAL
:
593 duplex
= DMDUP_VERTICAL
;
596 // in fact case wxDUPLEX_SIMPLEX:
597 duplex
= DMDUP_SIMPLEX
;
600 devMode
->dmDuplex
= duplex
;
601 devMode
->dmFields
|= DM_DUPLEX
;
606 switch (data
.GetQuality())
608 case wxPRINT_QUALITY_MEDIUM
:
609 quality
= DMRES_MEDIUM
;
611 case wxPRINT_QUALITY_LOW
:
614 case wxPRINT_QUALITY_DRAFT
:
615 quality
= DMRES_DRAFT
;
617 case wxPRINT_QUALITY_HIGH
:
618 quality
= DMRES_HIGH
;
621 quality
= (short)data
.GetQuality();
622 devMode
->dmYResolution
= quality
;
623 devMode
->dmFields
|= DM_YRESOLUTION
;
626 devMode
->dmPrintQuality
= quality
;
627 devMode
->dmFields
|= DM_PRINTQUALITY
;
629 if (data
.GetPrivDataLen() > 0)
631 memcpy( (char *)devMode
+devMode
->dmSize
, data
.GetPrivData(), data
.GetPrivDataLen() );
632 devMode
->dmDriverExtra
= (WXWORD
)data
.GetPrivDataLen();
635 if (data
.GetBin() != wxPRINTBIN_DEFAULT
)
637 switch (data
.GetBin())
639 case wxPRINTBIN_ONLYONE
: devMode
->dmDefaultSource
= DMBIN_ONLYONE
; break;
640 case wxPRINTBIN_LOWER
: devMode
->dmDefaultSource
= DMBIN_LOWER
; break;
641 case wxPRINTBIN_MIDDLE
: devMode
->dmDefaultSource
= DMBIN_MIDDLE
; break;
642 case wxPRINTBIN_MANUAL
: devMode
->dmDefaultSource
= DMBIN_MANUAL
; break;
643 case wxPRINTBIN_ENVELOPE
: devMode
->dmDefaultSource
= DMBIN_ENVELOPE
; break;
644 case wxPRINTBIN_ENVMANUAL
: devMode
->dmDefaultSource
= DMBIN_ENVMANUAL
; break;
645 case wxPRINTBIN_AUTO
: devMode
->dmDefaultSource
= DMBIN_AUTO
; break;
646 case wxPRINTBIN_TRACTOR
: devMode
->dmDefaultSource
= DMBIN_TRACTOR
; break;
647 case wxPRINTBIN_SMALLFMT
: devMode
->dmDefaultSource
= DMBIN_SMALLFMT
; break;
648 case wxPRINTBIN_LARGEFMT
: devMode
->dmDefaultSource
= DMBIN_LARGEFMT
; break;
649 case wxPRINTBIN_LARGECAPACITY
: devMode
->dmDefaultSource
= DMBIN_LARGECAPACITY
; break;
650 case wxPRINTBIN_CASSETTE
: devMode
->dmDefaultSource
= DMBIN_CASSETTE
; break;
651 case wxPRINTBIN_FORMSOURCE
: devMode
->dmDefaultSource
= DMBIN_FORMSOURCE
; break;
654 devMode
->dmDefaultSource
= (short)(DMBIN_USER
+ data
.GetBin() - wxPRINTBIN_USER
); // 256 + data.GetBin() - 14 = 242 + data.GetBin()
658 devMode
->dmFields
|= DM_DEFAULTSOURCE
;
660 if (data
.GetMedia() != wxPRINTMEDIA_DEFAULT
)
662 devMode
->dmMediaType
= data
.GetMedia();
663 devMode
->dmFields
|= DM_MEDIATYPE
;
669 // Merge the new settings with the old.
670 // This gives the driver an opportunity to update any private
671 // portions of the DevMode structure.
672 DocumentProperties( NULL
,
675 (LPDEVMODE
)hDevMode
, // Reuse our buffer for output.
676 (LPDEVMODE
)hDevMode
, // Pass the driver our changes
677 DM_IN_BUFFER
| // Commands to Merge our changes and
678 DM_OUT_BUFFER
); // write the result.
684 ::GlobalFree(static_cast<HGLOBAL
>(m_devNames
));
687 // TODO: I hope it's OK to pass some empty strings to DEVNAMES.
688 m_devNames
= wxCreateDevNames(wxEmptyString
, data
.GetPrinterName(), wxEmptyString
);
693 // ---------------------------------------------------------------------------
695 // ---------------------------------------------------------------------------
697 IMPLEMENT_CLASS(wxWindowsPrintDialog
, wxPrintDialogBase
)
699 wxWindowsPrintDialog::wxWindowsPrintDialog(wxWindow
*p
, wxPrintDialogData
* data
)
704 wxWindowsPrintDialog::wxWindowsPrintDialog(wxWindow
*p
, wxPrintData
* data
)
706 wxPrintDialogData data2
;
713 bool wxWindowsPrintDialog::Create(wxWindow
*p
, wxPrintDialogData
* data
)
723 m_printDialogData
= *data
;
728 wxWindowsPrintDialog::~wxWindowsPrintDialog()
730 PRINTDLG
*pd
= (PRINTDLG
*) m_printDlg
;
731 if (pd
&& pd
->hDevMode
)
732 GlobalFree(pd
->hDevMode
);
736 if (m_destroyDC
&& m_printerDC
)
740 int wxWindowsPrintDialog::ShowModal()
742 WX_HOOK_MODAL_DIALOG();
744 ConvertToNative( m_printDialogData
);
746 PRINTDLG
*pd
= (PRINTDLG
*) m_printDlg
;
749 pd
->hwndOwner
= (HWND
) m_dialogParent
->GetHWND();
750 else if (wxTheApp
->GetTopWindow())
751 pd
->hwndOwner
= (HWND
) wxTheApp
->GetTopWindow()->GetHWND();
755 bool ret
= (PrintDlg( pd
) != 0);
759 if ( ret
&& (pd
->hDC
) )
761 wxPrinterDC
*pdc
= new wxPrinterDCFromHDC( (WXHDC
) pd
->hDC
);
763 ConvertFromNative( m_printDialogData
);
772 wxDC
*wxWindowsPrintDialog::GetPrintDC()
783 bool wxWindowsPrintDialog::ConvertToNative( wxPrintDialogData
&data
)
785 wxWindowsPrintNativeData
*native_data
=
786 (wxWindowsPrintNativeData
*) data
.GetPrintData().GetNativeData();
787 data
.GetPrintData().ConvertToNative();
789 PRINTDLG
*pd
= (PRINTDLG
*) m_printDlg
;
791 // Shouldn't have been defined anywhere
796 memset( pd
, 0, sizeof(PRINTDLG
) );
797 m_printDlg
= (void*) pd
;
799 pd
->lStructSize
= sizeof(PRINTDLG
);
800 pd
->hwndOwner
= NULL
;
801 pd
->hDevMode
= NULL
; // Will be created by PrintDlg
802 pd
->hDevNames
= NULL
; // Ditto
804 pd
->Flags
= PD_RETURNDEFAULT
;
807 // Pass the devmode data to the PRINTDLG structure, since it'll
808 // be needed when PrintDlg is called.
810 GlobalFree(pd
->hDevMode
);
812 // Pass the devnames data to the PRINTDLG structure, since it'll
813 // be needed when PrintDlg is called.
815 GlobalFree(pd
->hDevNames
);
817 pd
->hDevMode
= static_cast<HGLOBAL
>(native_data
->GetDevMode());
818 native_data
->SetDevMode(NULL
);
820 // Shouldn't assert; we should be able to test Ok-ness at a higher level
821 //wxASSERT_MSG( (pd->hDevMode), wxT("hDevMode must be non-NULL in ConvertToNative!"));
823 pd
->hDevNames
= static_cast<HGLOBAL
>(native_data
->GetDevNames());
824 native_data
->SetDevNames(NULL
);
828 pd
->nFromPage
= (WORD
)data
.GetFromPage();
829 pd
->nToPage
= (WORD
)data
.GetToPage();
830 pd
->nMinPage
= (WORD
)data
.GetMinPage();
831 pd
->nMaxPage
= (WORD
)data
.GetMaxPage();
832 pd
->nCopies
= (WORD
)data
.GetNoCopies();
834 pd
->Flags
= PD_RETURNDC
;
835 pd
->lStructSize
= sizeof( PRINTDLG
);
837 pd
->hwndOwner
= NULL
;
838 pd
->hInstance
= NULL
;
840 pd
->lpfnPrintHook
= NULL
;
841 pd
->lpfnSetupHook
= NULL
;
842 pd
->lpPrintTemplateName
= NULL
;
843 pd
->lpSetupTemplateName
= NULL
;
844 pd
->hPrintTemplate
= NULL
;
845 pd
->hSetupTemplate
= NULL
;
847 if ( data
.GetAllPages() )
848 pd
->Flags
|= PD_ALLPAGES
;
849 if ( data
.GetSelection() )
850 pd
->Flags
|= PD_SELECTION
;
851 if ( data
.GetCollate() )
852 pd
->Flags
|= PD_COLLATE
;
853 if ( data
.GetPrintToFile() )
854 pd
->Flags
|= PD_PRINTTOFILE
;
855 if ( !data
.GetEnablePrintToFile() )
856 pd
->Flags
|= PD_DISABLEPRINTTOFILE
;
857 if ( !data
.GetEnableSelection() )
858 pd
->Flags
|= PD_NOSELECTION
;
859 if ( !data
.GetEnablePageNumbers() )
860 pd
->Flags
|= PD_NOPAGENUMS
;
861 else if ( (!data
.GetAllPages()) && (!data
.GetSelection()) && (data
.GetFromPage() != 0) && (data
.GetToPage() != 0))
862 pd
->Flags
|= PD_PAGENUMS
;
863 if ( data
.GetEnableHelp() )
864 pd
->Flags
|= PD_SHOWHELP
;
869 bool wxWindowsPrintDialog::ConvertFromNative( wxPrintDialogData
&data
)
871 PRINTDLG
*pd
= (PRINTDLG
*) m_printDlg
;
875 wxWindowsPrintNativeData
*native_data
=
876 (wxWindowsPrintNativeData
*) data
.GetPrintData().GetNativeData();
878 // Pass the devmode data back to the wxPrintData structure where it really belongs.
881 if (native_data
->GetDevMode())
883 ::GlobalFree(static_cast<HGLOBAL
>(native_data
->GetDevMode()));
885 native_data
->SetDevMode(pd
->hDevMode
);
889 // Pass the devnames data back to the wxPrintData structure where it really belongs.
892 if (native_data
->GetDevNames())
894 ::GlobalFree(static_cast<HGLOBAL
>(native_data
->GetDevNames()));
896 native_data
->SetDevNames(pd
->hDevNames
);
897 pd
->hDevNames
= NULL
;
900 // Now convert the DEVMODE object, passed down from the PRINTDLG object,
901 // into wxWidgets form.
902 native_data
->TransferTo( data
.GetPrintData() );
904 data
.SetFromPage( pd
->nFromPage
);
905 data
.SetToPage( pd
->nToPage
);
906 data
.SetMinPage( pd
->nMinPage
);
907 data
.SetMaxPage( pd
->nMaxPage
);
908 data
.SetNoCopies( pd
->nCopies
);
910 data
.SetAllPages( (((pd
->Flags
& PD_PAGENUMS
) != PD_PAGENUMS
) && ((pd
->Flags
& PD_SELECTION
) != PD_SELECTION
)) );
911 data
.SetSelection( ((pd
->Flags
& PD_SELECTION
) == PD_SELECTION
) );
912 data
.SetCollate( ((pd
->Flags
& PD_COLLATE
) == PD_COLLATE
) );
913 data
.SetPrintToFile( ((pd
->Flags
& PD_PRINTTOFILE
) == PD_PRINTTOFILE
) );
914 data
.EnablePrintToFile( ((pd
->Flags
& PD_DISABLEPRINTTOFILE
) != PD_DISABLEPRINTTOFILE
) );
915 data
.EnableSelection( ((pd
->Flags
& PD_NOSELECTION
) != PD_NOSELECTION
) );
916 data
.EnablePageNumbers( ((pd
->Flags
& PD_NOPAGENUMS
) != PD_NOPAGENUMS
) );
917 data
.EnableHelp( ((pd
->Flags
& PD_SHOWHELP
) == PD_SHOWHELP
) );
922 // ---------------------------------------------------------------------------
923 // wxWidnowsPageSetupDialog
924 // ---------------------------------------------------------------------------
926 IMPLEMENT_CLASS(wxWindowsPageSetupDialog
, wxPageSetupDialogBase
)
928 wxWindowsPageSetupDialog::wxWindowsPageSetupDialog()
930 m_dialogParent
= NULL
;
934 wxWindowsPageSetupDialog::wxWindowsPageSetupDialog(wxWindow
*p
, wxPageSetupDialogData
*data
)
939 bool wxWindowsPageSetupDialog::Create(wxWindow
*p
, wxPageSetupDialogData
*data
)
945 m_pageSetupData
= (*data
);
950 wxWindowsPageSetupDialog::~wxWindowsPageSetupDialog()
952 PAGESETUPDLG
*pd
= (PAGESETUPDLG
*)m_pageDlg
;
953 if ( pd
&& pd
->hDevMode
)
954 GlobalFree(pd
->hDevMode
);
955 if ( pd
&& pd
->hDevNames
)
956 GlobalFree(pd
->hDevNames
);
961 int wxWindowsPageSetupDialog::ShowModal()
963 WX_HOOK_MODAL_DIALOG();
965 ConvertToNative( m_pageSetupData
);
967 PAGESETUPDLG
*pd
= (PAGESETUPDLG
*) m_pageDlg
;
969 pd
->hwndOwner
= (HWND
) m_dialogParent
->GetHWND();
970 else if (wxTheApp
->GetTopWindow())
971 pd
->hwndOwner
= (HWND
) wxTheApp
->GetTopWindow()->GetHWND();
974 BOOL retVal
= PageSetupDlg( pd
) ;
978 ConvertFromNative( m_pageSetupData
);
985 bool wxWindowsPageSetupDialog::ConvertToNative( wxPageSetupDialogData
&data
)
987 wxWindowsPrintNativeData
*native_data
=
988 (wxWindowsPrintNativeData
*) data
.GetPrintData().GetNativeData();
989 data
.GetPrintData().ConvertToNative();
991 PAGESETUPDLG
*pd
= (PAGESETUPDLG
*) m_pageDlg
;
993 // Shouldn't have been defined anywhere
997 pd
= new PAGESETUPDLG
;
998 m_pageDlg
= (void *)pd
;
1000 // We must not set hDevMode and hDevNames when using PSD_RETURNDEFAULT,
1001 // otherwise the call to PageSetupDlg() would fail.
1002 if ( data
.GetDefaultInfo() )
1004 pd
->hDevMode
= NULL
;
1005 pd
->hDevNames
= NULL
;
1009 // Pass the devmode data (created in m_printData.ConvertToNative)
1010 // to the PRINTDLG structure, since it'll
1011 // be needed when PrintDlg is called.
1013 pd
->hDevMode
= (HGLOBAL
) native_data
->GetDevMode();
1014 native_data
->SetDevMode(NULL
);
1016 // Shouldn't assert; we should be able to test Ok-ness at a higher level
1017 //wxASSERT_MSG( (pd->hDevMode), wxT("hDevMode must be non-NULL in ConvertToNative!"));
1019 // Pass the devnames data (created in m_printData.ConvertToNative)
1020 // to the PRINTDLG structure, since it'll
1021 // be needed when PrintDlg is called.
1023 pd
->hDevNames
= (HGLOBAL
) native_data
->GetDevNames();
1024 native_data
->SetDevNames(NULL
);
1027 pd
->Flags
= PSD_MARGINS
|PSD_MINMARGINS
;
1029 if ( data
.GetDefaultMinMargins() )
1030 pd
->Flags
|= PSD_DEFAULTMINMARGINS
;
1031 if ( !data
.GetEnableMargins() )
1032 pd
->Flags
|= PSD_DISABLEMARGINS
;
1033 if ( !data
.GetEnableOrientation() )
1034 pd
->Flags
|= PSD_DISABLEORIENTATION
;
1035 if ( !data
.GetEnablePaper() )
1036 pd
->Flags
|= PSD_DISABLEPAPER
;
1037 if ( !data
.GetEnablePrinter() )
1038 pd
->Flags
|= PSD_DISABLEPRINTER
;
1039 if ( data
.GetDefaultInfo() )
1040 pd
->Flags
|= PSD_RETURNDEFAULT
;
1041 if ( data
.GetEnableHelp() )
1042 pd
->Flags
|= PSD_SHOWHELP
;
1044 // We want the units to be in hundredths of a millimetre
1045 pd
->Flags
|= PSD_INHUNDREDTHSOFMILLIMETERS
;
1047 pd
->lStructSize
= sizeof( PAGESETUPDLG
);
1048 pd
->hwndOwner
= NULL
;
1049 pd
->hInstance
= NULL
;
1050 // PAGESETUPDLG is in hundreds of a mm
1051 pd
->ptPaperSize
.x
= data
.GetPaperSize().x
* 100;
1052 pd
->ptPaperSize
.y
= data
.GetPaperSize().y
* 100;
1054 pd
->rtMinMargin
.left
= data
.GetMinMarginTopLeft().x
* 100;
1055 pd
->rtMinMargin
.top
= data
.GetMinMarginTopLeft().y
* 100;
1056 pd
->rtMinMargin
.right
= data
.GetMinMarginBottomRight().x
* 100;
1057 pd
->rtMinMargin
.bottom
= data
.GetMinMarginBottomRight().y
* 100;
1059 pd
->rtMargin
.left
= data
.GetMarginTopLeft().x
* 100;
1060 pd
->rtMargin
.top
= data
.GetMarginTopLeft().y
* 100;
1061 pd
->rtMargin
.right
= data
.GetMarginBottomRight().x
* 100;
1062 pd
->rtMargin
.bottom
= data
.GetMarginBottomRight().y
* 100;
1065 pd
->lpfnPageSetupHook
= NULL
;
1066 pd
->lpfnPagePaintHook
= NULL
;
1067 pd
->hPageSetupTemplate
= NULL
;
1068 pd
->lpPageSetupTemplateName
= NULL
;
1073 bool wxWindowsPageSetupDialog::ConvertFromNative( wxPageSetupDialogData
&data
)
1075 PAGESETUPDLG
*pd
= (PAGESETUPDLG
*) m_pageDlg
;
1079 wxWindowsPrintNativeData
*native_data
=
1080 (wxWindowsPrintNativeData
*) data
.GetPrintData().GetNativeData();
1082 // Pass the devmode data back to the wxPrintData structure where it really belongs.
1085 if (native_data
->GetDevMode())
1087 // Make sure we don't leak memory
1088 GlobalFree((HGLOBAL
) native_data
->GetDevMode());
1090 native_data
->SetDevMode( (void*) pd
->hDevMode
);
1091 pd
->hDevMode
= NULL
;
1094 // Isn't this superfluous? It's called again below.
1095 // data.GetPrintData().ConvertFromNative();
1097 // Pass the devnames data back to the wxPrintData structure where it really belongs.
1100 if (native_data
->GetDevNames())
1102 // Make sure we don't leak memory
1103 GlobalFree((HGLOBAL
) native_data
->GetDevNames());
1105 native_data
->SetDevNames((void*) pd
->hDevNames
);
1106 pd
->hDevNames
= NULL
;
1109 data
.GetPrintData().ConvertFromNative();
1111 pd
->Flags
= PSD_MARGINS
|PSD_MINMARGINS
;
1113 data
.SetDefaultMinMargins( ((pd
->Flags
& PSD_DEFAULTMINMARGINS
) == PSD_DEFAULTMINMARGINS
) );
1114 data
.EnableMargins( ((pd
->Flags
& PSD_DISABLEMARGINS
) != PSD_DISABLEMARGINS
) );
1115 data
.EnableOrientation( ((pd
->Flags
& PSD_DISABLEORIENTATION
) != PSD_DISABLEORIENTATION
) );
1116 data
.EnablePaper( ((pd
->Flags
& PSD_DISABLEPAPER
) != PSD_DISABLEPAPER
) );
1117 data
.EnablePrinter( ((pd
->Flags
& PSD_DISABLEPRINTER
) != PSD_DISABLEPRINTER
) );
1118 data
.SetDefaultInfo( ((pd
->Flags
& PSD_RETURNDEFAULT
) == PSD_RETURNDEFAULT
) );
1119 data
.EnableHelp( ((pd
->Flags
& PSD_SHOWHELP
) == PSD_SHOWHELP
) );
1121 // PAGESETUPDLG is in hundreds of a mm
1122 if (data
.GetPrintData().GetOrientation() == wxLANDSCAPE
)
1123 data
.SetPaperSize( wxSize(pd
->ptPaperSize
.y
/ 100, pd
->ptPaperSize
.x
/ 100) );
1125 data
.SetPaperSize( wxSize(pd
->ptPaperSize
.x
/ 100, pd
->ptPaperSize
.y
/ 100) );
1127 data
.SetMinMarginTopLeft( wxPoint(pd
->rtMinMargin
.left
/ 100, pd
->rtMinMargin
.top
/ 100) );
1128 data
.SetMinMarginBottomRight( wxPoint(pd
->rtMinMargin
.right
/ 100, pd
->rtMinMargin
.bottom
/ 100) );
1130 data
.SetMarginTopLeft( wxPoint(pd
->rtMargin
.left
/ 100, pd
->rtMargin
.top
/ 100) );
1131 data
.SetMarginBottomRight( wxPoint(pd
->rtMargin
.right
/ 100, pd
->rtMargin
.bottom
/ 100) );
1137 // wxUSE_PRINTING_ARCHITECTURE