X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/dca0f651782d5c2659203c97b3243f613966998d..1fd850ab550a30bc600d5a10c5aed5386bf3624b:/src/msw/printdlg.cpp diff --git a/src/msw/printdlg.cpp b/src/msw/printdlg.cpp index 9d96491f67..a3da80615a 100644 --- a/src/msw/printdlg.cpp +++ b/src/msw/printdlg.cpp @@ -39,18 +39,63 @@ #include "wx/msw/printdlg.h" #include "wx/msw/dcprint.h" #include "wx/paper.h" +#include "wx/testing.h" #include -#ifndef __WIN32__ - #include -#endif +// smart pointer like class using OpenPrinter and ClosePrinter +class WinPrinter +{ +public: + // default ctor + WinPrinter() + { + m_hPrinter = (HANDLE)NULL; + } + + WinPrinter( const wxString& printerName ) + { + Open( printerName ); + } + + ~WinPrinter() + { + Close(); + } + + BOOL Open( const wxString& printerName, LPPRINTER_DEFAULTS pDefault=(LPPRINTER_DEFAULTS)NULL ) + { + Close(); + return OpenPrinter( wxMSW_CONV_LPTSTR(printerName), &m_hPrinter, pDefault ); + } + + BOOL Close() + { + BOOL result = TRUE; + if( m_hPrinter ) + { + result = ClosePrinter( m_hPrinter ); + m_hPrinter = (HANDLE)NULL; + } + return result; + } + + operator HANDLE() { return m_hPrinter; } + operator bool() { return m_hPrinter != (HANDLE)NULL; } + +private: + HANDLE m_hPrinter; + + wxDECLARE_NO_COPY_CLASS(WinPrinter); +}; + //---------------------------------------------------------------------------- // wxWindowsPrintNativeData //---------------------------------------------------------------------------- -#ifdef __WXDEBUG__ +#if wxDEBUG_LEVEL + static wxString wxGetPrintDlgError() { DWORD err = CommDlgExtendedError(); @@ -83,9 +128,14 @@ static wxString wxGetPrintDlgError() } return msg; } -#endif -static HGLOBAL wxCreateDevNames(const wxString& driverName, const wxString& printerName, const wxString& portName) +#endif // wxDEBUG_LEVEL + + +static HGLOBAL +wxCreateDevNames(const wxString& driverName, + const wxString& printerName, + const wxString& portName) { HGLOBAL hDev = NULL; // if (!driverName.empty() && !printerName.empty() && !portName.empty()) @@ -130,10 +180,10 @@ wxWindowsPrintNativeData::wxWindowsPrintNativeData() wxWindowsPrintNativeData::~wxWindowsPrintNativeData() { if ( m_devMode ) - ::GlobalFree(wx_static_cast(HGLOBAL, m_devMode)); + ::GlobalFree(static_cast(m_devMode)); if ( m_devNames ) - ::GlobalFree(wx_static_cast(HGLOBAL, m_devNames)); + ::GlobalFree(static_cast(m_devNames)); } bool wxWindowsPrintNativeData::IsOk() const @@ -143,16 +193,19 @@ bool wxWindowsPrintNativeData::IsOk() const bool wxWindowsPrintNativeData::TransferTo( wxPrintData &data ) { + if ( !m_devMode ) + InitializeDevMode(); + if ( !m_devMode ) return false; GlobalPtrLock lockDevMode(m_devMode); - LPDEVMODE devMode = wx_static_cast(LPDEVMODE, lockDevMode.Get()); + LPDEVMODE devMode = static_cast(lockDevMode.Get()); //// Orientation if (devMode->dmFields & DM_ORIENTATION) - data.SetOrientation( devMode->dmOrientation ); + data.SetOrientation( (wxPrintOrientation)devMode->dmOrientation ); //// Collation if (devMode->dmFields & DM_COLLATE) @@ -184,12 +237,10 @@ bool wxWindowsPrintNativeData::TransferTo( wxPrintData &data ) case DMBIN_CASSETTE : data.SetBin(wxPRINTBIN_CASSETTE ); break; case DMBIN_FORMSOURCE : data.SetBin(wxPRINTBIN_FORMSOURCE ); break; default: - if (devMode->dmDefaultSource>=DMBIN_USER) { + if (devMode->dmDefaultSource >= DMBIN_USER) data.SetBin((wxPrintBin)((devMode->dmDefaultSource)-DMBIN_USER+(int)wxPRINTBIN_USER)); - } else { + else data.SetBin(wxPRINTBIN_DEFAULT); - } - break; } } else { data.SetBin(wxPRINTBIN_DEFAULT); @@ -315,7 +366,7 @@ bool wxWindowsPrintNativeData::TransferTo( wxPrintData &data ) if ( m_devNames ) { GlobalPtrLock lockDevNames(m_devNames); - LPDEVNAMES lpDevNames = wx_static_cast(LPDEVNAMES, lockDevNames.Get()); + LPDEVNAMES lpDevNames = static_cast(lockDevNames.Get()); // TODO: Unicode-ification @@ -336,31 +387,73 @@ bool wxWindowsPrintNativeData::TransferTo( wxPrintData &data ) return true; } -bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) +void wxWindowsPrintNativeData::InitializeDevMode(const wxString& printerName, WinPrinter* printer) { - HGLOBAL hDevMode = wx_static_cast(HGLOBAL, m_devMode); + if (m_devMode) + return; + + LPTSTR szPrinterName = wxMSW_CONV_LPTSTR(printerName); + + // From MSDN: How To Modify Printer Settings with the DocumentProperties() Function + // The purpose of this is to fill the DEVMODE with privdata from printer driver. + // If we have a printer name and OpenPrinter successfully returns + // this replaces the PrintDlg function which creates the DEVMODE filled only with data from default printer. + if ( !m_devMode && !printerName.IsEmpty() ) + { + // Open printer + if ( printer && printer->Open( printerName ) == TRUE ) + { + DWORD dwNeeded, dwRet; + + // Step 1: + // Allocate a buffer of the correct size. + dwNeeded = DocumentProperties( NULL, + *printer, // Handle to our printer. + szPrinterName, // Name of the printer. + NULL, // Asking for size, so + NULL, // these are not used. + 0 ); // Zero returns buffer size. + + LPDEVMODE tempDevMode = static_cast( GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, dwNeeded ) ); + + // Step 2: + // Get the default DevMode for the printer + dwRet = DocumentProperties( NULL, + *printer, + szPrinterName, + tempDevMode, // The address of the buffer to fill. + NULL, // Not using the input buffer. + DM_OUT_BUFFER ); // Have the output buffer filled. + + if ( dwRet != IDOK ) + { + // If failure, cleanup + GlobalFree( tempDevMode ); + printer->Close(); + } + else + { + m_devMode = tempDevMode; + tempDevMode = NULL; + } + } + } + if ( !m_devMode ) { // Use PRINTDLG as a way of creating a DEVMODE object PRINTDLG pd; - // GNU-WIN32 has the wrong size PRINTDLG - can't work out why. -#ifdef __GNUWIN32__ - memset(&pd, 0, 66); - pd.lStructSize = 66; -#else memset(&pd, 0, sizeof(PRINTDLG)); #ifdef __WXWINCE__ pd.cbStruct = sizeof(PRINTDLG); #else pd.lStructSize = sizeof(PRINTDLG); -#endif #endif - pd.hwndOwner = (HWND)NULL; + pd.hwndOwner = NULL; pd.hDevMode = NULL; // Will be created by PrintDlg pd.hDevNames = NULL; // Ditto - //pd.hInstance = (HINSTANCE) wxGetInstance(); pd.Flags = PD_RETURNDEFAULT; pd.nCopies = 1; @@ -376,16 +469,13 @@ bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) pd.hDevMode = NULL; pd.hDevNames = NULL; -#if defined(__WXDEBUG__) && defined(__WIN32__) - wxString str(wxT("Printing error: ")); - str += wxGetPrintDlgError(); - wxLogDebug(str); -#endif +#if wxDEBUG_LEVEL + wxLogDebug(wxT("Printing error: ") + wxGetPrintDlgError()); +#endif // wxDEBUG_LEVEL } else { - hDevMode = pd.hDevMode; - m_devMode = hDevMode; + m_devMode = pd.hDevMode; pd.hDevMode = NULL; // We'll create a new DEVNAMEs structure below. @@ -400,10 +490,22 @@ bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) } } +} + +bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) +{ + WinPrinter printer; + LPTSTR szPrinterName = wxMSW_CONV_LPTSTR(data.GetPrinterName()); + + if (!m_devMode) + InitializeDevMode(data.GetPrinterName(), &printer); + + HGLOBAL hDevMode = static_cast(m_devMode); + if ( hDevMode ) { GlobalPtrLock lockDevMode(hDevMode); - DEVMODE * const devMode = wx_static_cast(DEVMODE *, lockDevMode.Get()); + DEVMODE * const devMode = static_cast(lockDevMode.Get()); //// Orientation devMode->dmOrientation = (short)data.GetOrientation(); @@ -420,9 +522,11 @@ bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) wxString name = data.GetPrinterName(); if (!name.empty()) { - wxStrncpy(devMode->dmDeviceName, name.wx_str(), - WXSIZEOF(devMode->dmDeviceName) - 1); - devMode->dmDeviceName[WXSIZEOF(devMode->dmDeviceName) - 1] = wxT('\0'); + // NB: the cast is needed in the ANSI build, strangely enough + // dmDeviceName is BYTE[] and not char[] there + wxStrlcpy(reinterpret_cast(devMode->dmDeviceName), + name.t_str(), + WXSIZEOF(devMode->dmDeviceName)); } //// Colour @@ -464,6 +568,15 @@ bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) devMode->dmPaperLength = (short)(paperSize.y * 10); devMode->dmFields |= DM_PAPERWIDTH; devMode->dmFields |= DM_PAPERLENGTH; + + // A printer driver may or may not also want DM_PAPERSIZE to + // be specified. Also, if the printer driver doesn't implement the DMPAPER_USER + // size, then this won't work, and even if you found the correct id by + // enumerating the driver's paper sizes, it probably won't change the actual size, + // it'll just select that custom paper type with its own current setting. + // For a discussion on this, see http://www.codeguru.com/forum/showthread.php?threadid=458617 + // Although m_customWindowsPaperId is intended to work around this, it's + // unclear how it can help you set the custom paper size programmatically. } //else: neither paper type nor size specified, don't fill DEVMODE // at all so that the system defaults are used @@ -506,6 +619,8 @@ bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) break; default: quality = (short)data.GetQuality(); + devMode->dmYResolution = quality; + devMode->dmFields |= DM_YRESOLUTION; break; } devMode->dmPrintQuality = quality; @@ -547,11 +662,26 @@ bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) devMode->dmMediaType = data.GetMedia(); devMode->dmFields |= DM_MEDIATYPE; } + + if( printer ) + { + // Step 3: + // Merge the new settings with the old. + // This gives the driver an opportunity to update any private + // portions of the DevMode structure. + DocumentProperties( NULL, + printer, + szPrinterName, + (LPDEVMODE)hDevMode, // Reuse our buffer for output. + (LPDEVMODE)hDevMode, // Pass the driver our changes + DM_IN_BUFFER | // Commands to Merge our changes and + DM_OUT_BUFFER ); // write the result. + } } if ( m_devNames ) { - ::GlobalFree(wx_static_cast(HGLOBAL, m_devNames)); + ::GlobalFree(static_cast(m_devNames)); } // TODO: I hope it's OK to pass some empty strings to DEVNAMES. @@ -609,6 +739,8 @@ wxWindowsPrintDialog::~wxWindowsPrintDialog() int wxWindowsPrintDialog::ShowModal() { + WX_TESTING_SHOW_MODAL_HOOK(); + ConvertToNative( m_printDialogData ); PRINTDLG *pd = (PRINTDLG*) m_printDlg; @@ -645,7 +777,7 @@ wxDC *wxWindowsPrintDialog::GetPrintDC() return m_printerDC; } else - return (wxPrinterDC*) NULL; + return NULL; } bool wxWindowsPrintDialog::ConvertToNative( wxPrintDialogData &data ) @@ -664,13 +796,8 @@ bool wxWindowsPrintDialog::ConvertToNative( wxPrintDialogData &data ) memset( pd, 0, sizeof(PRINTDLG) ); m_printDlg = (void*) pd; - // GNU-WIN32 has the wrong size PRINTDLG - can't work out why. -#ifdef __GNUWIN32__ - pd->lStructSize = 66; -#else pd->lStructSize = sizeof(PRINTDLG); -#endif - pd->hwndOwner = (HWND)NULL; + pd->hwndOwner = NULL; pd->hDevMode = NULL; // Will be created by PrintDlg pd->hDevNames = NULL; // Ditto @@ -687,17 +814,17 @@ bool wxWindowsPrintDialog::ConvertToNative( wxPrintDialogData &data ) if (pd->hDevNames) GlobalFree(pd->hDevNames); - pd->hDevMode = wx_static_cast(HGLOBAL, native_data->GetDevMode()); + pd->hDevMode = static_cast(native_data->GetDevMode()); native_data->SetDevMode(NULL); // Shouldn't assert; we should be able to test Ok-ness at a higher level //wxASSERT_MSG( (pd->hDevMode), wxT("hDevMode must be non-NULL in ConvertToNative!")); - pd->hDevNames = wx_static_cast(HGLOBAL, native_data->GetDevNames()); + pd->hDevNames = static_cast(native_data->GetDevNames()); native_data->SetDevNames(NULL); - pd->hDC = (HDC) NULL; + pd->hDC = NULL; pd->nFromPage = (WORD)data.GetFromPage(); pd->nToPage = (WORD)data.GetToPage(); pd->nMinPage = (WORD)data.GetMinPage(); @@ -705,23 +832,17 @@ bool wxWindowsPrintDialog::ConvertToNative( wxPrintDialogData &data ) pd->nCopies = (WORD)data.GetNoCopies(); pd->Flags = PD_RETURNDC; - -#ifdef __GNUWIN32__ - pd->lStructSize = 66; -#else pd->lStructSize = sizeof( PRINTDLG ); -#endif - pd->hwndOwner=(HWND)NULL; -// pd->hDevNames=(HANDLE)NULL; - pd->hInstance=(HINSTANCE)NULL; - pd->lCustData = (LPARAM) NULL; + pd->hwndOwner = NULL; + pd->hInstance = NULL; + pd->lCustData = 0; pd->lpfnPrintHook = NULL; pd->lpfnSetupHook = NULL; pd->lpPrintTemplateName = NULL; pd->lpSetupTemplateName = NULL; - pd->hPrintTemplate = (HGLOBAL) NULL; - pd->hSetupTemplate = (HGLOBAL) NULL; + pd->hPrintTemplate = NULL; + pd->hSetupTemplate = NULL; if ( data.GetAllPages() ) pd->Flags |= PD_ALLPAGES; @@ -759,7 +880,7 @@ bool wxWindowsPrintDialog::ConvertFromNative( wxPrintDialogData &data ) { if (native_data->GetDevMode()) { - ::GlobalFree(wx_static_cast(HGLOBAL, native_data->GetDevMode())); + ::GlobalFree(static_cast(native_data->GetDevMode())); } native_data->SetDevMode(pd->hDevMode); pd->hDevMode = NULL; @@ -770,7 +891,7 @@ bool wxWindowsPrintDialog::ConvertFromNative( wxPrintDialogData &data ) { if (native_data->GetDevNames()) { - ::GlobalFree(wx_static_cast(HGLOBAL, native_data->GetDevNames())); + ::GlobalFree(static_cast(native_data->GetDevNames())); } native_data->SetDevNames(pd->hDevNames); pd->hDevNames = NULL; @@ -839,6 +960,8 @@ wxWindowsPageSetupDialog::~wxWindowsPageSetupDialog() int wxWindowsPageSetupDialog::ShowModal() { + WX_TESTING_SHOW_MODAL_HOOK(); + ConvertToNative( m_pageSetupData ); PAGESETUPDLG *pd = (PAGESETUPDLG *) m_pageDlg; @@ -872,38 +995,34 @@ bool wxWindowsPageSetupDialog::ConvertToNative( wxPageSetupDialogData &data ) return false; pd = new PAGESETUPDLG; - pd->hDevMode = NULL; - pd->hDevNames = NULL; m_pageDlg = (void *)pd; - // Pass the devmode data (created in m_printData.ConvertToNative) - // to the PRINTDLG structure, since it'll - // be needed when PrintDlg is called. - - if (pd->hDevMode) + // We must not set hDevMode and hDevNames when using PSD_RETURNDEFAULT, + // otherwise the call to PageSetupDlg() would fail. + if ( data.GetDefaultInfo() ) { - GlobalFree(pd->hDevMode); pd->hDevMode = NULL; + pd->hDevNames = NULL; } - pd->hDevMode = (HGLOBAL) native_data->GetDevMode(); - native_data->SetDevMode( (void*) NULL ); + else + { + // Pass the devmode data (created in m_printData.ConvertToNative) + // to the PRINTDLG structure, since it'll + // be needed when PrintDlg is called. - // Shouldn't assert; we should be able to test Ok-ness at a higher level - //wxASSERT_MSG( (pd->hDevMode), wxT("hDevMode must be non-NULL in ConvertToNative!")); + pd->hDevMode = (HGLOBAL) native_data->GetDevMode(); + native_data->SetDevMode(NULL); - // Pass the devnames data (created in m_printData.ConvertToNative) - // to the PRINTDLG structure, since it'll - // be needed when PrintDlg is called. + // Shouldn't assert; we should be able to test Ok-ness at a higher level + //wxASSERT_MSG( (pd->hDevMode), wxT("hDevMode must be non-NULL in ConvertToNative!")); - if (pd->hDevNames) - { - GlobalFree(pd->hDevNames); - pd->hDevNames = NULL; - } - pd->hDevNames = (HGLOBAL) native_data->GetDevNames(); - native_data->SetDevNames((void*) NULL); + // Pass the devnames data (created in m_printData.ConvertToNative) + // to the PRINTDLG structure, since it'll + // be needed when PrintDlg is called. -// pd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, sizeof(DEVMODE)); + pd->hDevNames = (HGLOBAL) native_data->GetDevNames(); + native_data->SetDevNames(NULL); + } pd->Flags = PSD_MARGINS|PSD_MINMARGINS; @@ -926,9 +1045,8 @@ bool wxWindowsPageSetupDialog::ConvertToNative( wxPageSetupDialogData &data ) pd->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; pd->lStructSize = sizeof( PAGESETUPDLG ); - pd->hwndOwner=(HWND)NULL; -// pd->hDevNames=(HWND)NULL; - pd->hInstance=(HINSTANCE)NULL; + pd->hwndOwner = NULL; + pd->hInstance = NULL; // PAGESETUPDLG is in hundreds of a mm pd->ptPaperSize.x = data.GetPaperSize().x * 100; pd->ptPaperSize.y = data.GetPaperSize().y * 100; @@ -949,17 +1067,6 @@ bool wxWindowsPageSetupDialog::ConvertToNative( wxPageSetupDialogData &data ) pd->hPageSetupTemplate = NULL; pd->lpPageSetupTemplateName = NULL; -/* - if ( pd->hDevMode ) - { - DEVMODE *devMode = (DEVMODE*) GlobalLock(pd->hDevMode); - memset(devMode, 0, sizeof(DEVMODE)); - devMode->dmSize = sizeof(DEVMODE); - devMode->dmOrientation = m_orientation; - devMode->dmFields = DM_ORIENTATION; - GlobalUnlock(pd->hDevMode); - } -*/ return true; }