1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 #include <osl/diagnose.h>
23 
24 #include <memory>
25 #include <string.h>
26 
27 #include <svsys.h>
28 
29 #include <osl/module.h>
30 #include <o3tl/char16_t2wchar_t.hxx>
31 
32 #include <tools/urlobj.hxx>
33 
34 #include <vcl/weld.hxx>
35 #include <vcl/QueueInfo.hxx>
36 
37 #include <win/wincomp.hxx>
38 #include <win/saldata.hxx>
39 #include <win/salinst.h>
40 #include <win/salgdi.h>
41 #include <win/salframe.h>
42 #include <win/salprn.h>
43 
44 #include <salptype.hxx>
45 #include <print.h>
46 #include <jobset.h>
47 
48 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
49 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
50 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
51 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
52 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
53 #include <com/sun/star/lang/XInitialization.hpp>
54 #include <comphelper/processfactory.hxx>
55 
56 #include <vcl/threadex.hxx>
57 
58 #include <malloc.h>
59 
60 #include <winspool.h>
61 #if defined GetDefaultPrinter
62 #  undef GetDefaultPrinter
63 #endif
64 #if defined SetPrinterData
65 #  undef SetPrinterData
66 #endif
67 
68 #define CATCH_DRIVER_EX_BEGIN                                               \
69     __try                                                                   \
70     {
71 #define CATCH_DRIVER_EX_END(mes, p)                                         \
72     }                                                                       \
73     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
74     {                                                                       \
75         OSL_FAIL( mes );                                                   \
76         p->markInvalid();                                                   \
77     }
78 #define CATCH_DRIVER_EX_END_2(mes)                                         \
79     }                                                                       \
80     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
81     {                                                                       \
82         OSL_FAIL( mes );                                                   \
83     }
84 
85 using namespace com::sun::star;
86 using namespace com::sun::star::uno;
87 using namespace com::sun::star::lang;
88 using namespace com::sun::star::ui::dialogs;
89 
90 const wchar_t aImplWindows[] = L"windows";
91 const wchar_t aImplDevice[]  = L"device";
92 
SAL_DEVMODE_W(const ImplJobSetup * pSetupData)93 static DEVMODEW const * SAL_DEVMODE_W( const ImplJobSetup* pSetupData )
94 {
95     DEVMODEW const * pRet = nullptr;
96     SalDriverData const * pDrv = reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData());
97     if( pSetupData->GetDriverDataLen() >= sizeof(DEVMODEW)+sizeof(SalDriverData)-1 )
98         pRet = reinterpret_cast<DEVMODEW const *>((pSetupData->GetDriverData()) + (pDrv->mnDriverOffset));
99     return pRet;
100 }
101 
ImplWinQueueStatusToSal(DWORD nWinStatus)102 static PrintQueueFlags ImplWinQueueStatusToSal( DWORD nWinStatus )
103 {
104     PrintQueueFlags nStatus = PrintQueueFlags::NONE;
105     if ( nWinStatus & PRINTER_STATUS_PAUSED )
106         nStatus |= PrintQueueFlags::Paused;
107     if ( nWinStatus & PRINTER_STATUS_ERROR )
108         nStatus |= PrintQueueFlags::Error;
109     if ( nWinStatus & PRINTER_STATUS_PENDING_DELETION )
110         nStatus |= PrintQueueFlags::PendingDeletion;
111     if ( nWinStatus & PRINTER_STATUS_PAPER_JAM )
112         nStatus |= PrintQueueFlags::PaperJam;
113     if ( nWinStatus & PRINTER_STATUS_PAPER_OUT )
114         nStatus |= PrintQueueFlags::PaperOut;
115     if ( nWinStatus & PRINTER_STATUS_MANUAL_FEED )
116         nStatus |= PrintQueueFlags::ManualFeed;
117     if ( nWinStatus & PRINTER_STATUS_PAPER_PROBLEM )
118         nStatus |= PrintQueueFlags::PaperProblem;
119     if ( nWinStatus & PRINTER_STATUS_OFFLINE )
120         nStatus |= PrintQueueFlags::Offline;
121     if ( nWinStatus & PRINTER_STATUS_IO_ACTIVE )
122         nStatus |= PrintQueueFlags::IOActive;
123     if ( nWinStatus & PRINTER_STATUS_BUSY )
124         nStatus |= PrintQueueFlags::Busy;
125     if ( nWinStatus & PRINTER_STATUS_PRINTING )
126         nStatus |= PrintQueueFlags::Printing;
127     if ( nWinStatus & PRINTER_STATUS_OUTPUT_BIN_FULL )
128         nStatus |= PrintQueueFlags::OutputBinFull;
129     if ( nWinStatus & PRINTER_STATUS_WAITING )
130         nStatus |= PrintQueueFlags::Waiting;
131     if ( nWinStatus & PRINTER_STATUS_PROCESSING )
132         nStatus |= PrintQueueFlags::Processing;
133     if ( nWinStatus & PRINTER_STATUS_INITIALIZING )
134         nStatus |= PrintQueueFlags::Initializing;
135     if ( nWinStatus & PRINTER_STATUS_WARMING_UP )
136         nStatus |= PrintQueueFlags::WarmingUp;
137     if ( nWinStatus & PRINTER_STATUS_TONER_LOW )
138         nStatus |= PrintQueueFlags::TonerLow;
139     if ( nWinStatus & PRINTER_STATUS_NO_TONER )
140         nStatus |= PrintQueueFlags::NoToner;
141     if ( nWinStatus & PRINTER_STATUS_PAGE_PUNT )
142         nStatus |= PrintQueueFlags::PagePunt;
143     if ( nWinStatus & PRINTER_STATUS_USER_INTERVENTION )
144         nStatus |= PrintQueueFlags::UserIntervention;
145     if ( nWinStatus & PRINTER_STATUS_OUT_OF_MEMORY )
146         nStatus |= PrintQueueFlags::OutOfMemory;
147     if ( nWinStatus & PRINTER_STATUS_DOOR_OPEN )
148         nStatus |= PrintQueueFlags::DoorOpen;
149     if ( nWinStatus & PRINTER_STATUS_SERVER_UNKNOWN )
150         nStatus |= PrintQueueFlags::StatusUnknown;
151     if ( nWinStatus & PRINTER_STATUS_POWER_SAVE )
152         nStatus |= PrintQueueFlags::PowerSave;
153     if ( nStatus == PrintQueueFlags::NONE && !(nWinStatus & PRINTER_STATUS_NOT_AVAILABLE) )
154         nStatus |= PrintQueueFlags::Ready;
155     return nStatus;
156 }
157 
158 
GetPrinterQueueInfo(ImplPrnQueueList * pList)159 void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
160 {
161     DWORD           i;
162     DWORD           nBytes = 0;
163     DWORD           nInfoPrn4 = 0;
164     EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, nullptr, 0, &nBytes, &nInfoPrn4 );
165     if ( nBytes )
166     {
167         PRINTER_INFO_4W* pWinInfo4 = static_cast<PRINTER_INFO_4W*>(std::malloc( nBytes ));
168         if ( EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, reinterpret_cast<LPBYTE>(pWinInfo4), nBytes, &nBytes, &nInfoPrn4 ) )
169         {
170             for ( i = 0; i < nInfoPrn4; i++ )
171             {
172                 std::unique_ptr<SalPrinterQueueInfo> pInfo(new SalPrinterQueueInfo);
173                 pInfo->maPrinterName = o3tl::toU(pWinInfo4[i].pPrinterName);
174                 pInfo->mnStatus      = PrintQueueFlags::NONE;
175                 pInfo->mnJobs        = 0;
176                 pList->Add( std::move(pInfo) );
177             }
178         }
179         std::free( pWinInfo4 );
180     }
181 }
182 
GetPrinterQueueState(SalPrinterQueueInfo * pInfo)183 void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
184 {
185     HANDLE hPrinter = nullptr;
186     LPWSTR pPrnName = const_cast<LPWSTR>(o3tl::toW(pInfo->maPrinterName.getStr()));
187     if( OpenPrinterW( pPrnName, &hPrinter, nullptr ) )
188     {
189         DWORD               nBytes = 0;
190         GetPrinterW( hPrinter, 2, nullptr, 0, &nBytes );
191         if( nBytes )
192         {
193             PRINTER_INFO_2W* pWinInfo2 = static_cast<PRINTER_INFO_2W*>(std::malloc(nBytes));
194             if( GetPrinterW( hPrinter, 2, reinterpret_cast<LPBYTE>(pWinInfo2), nBytes, &nBytes ) )
195             {
196                 if( pWinInfo2->pDriverName )
197                     pInfo->maDriver = o3tl::toU(pWinInfo2->pDriverName);
198                 OUString aPortName;
199                 if ( pWinInfo2->pPortName )
200                     aPortName = o3tl::toU(pWinInfo2->pPortName);
201                 // pLocation can be 0 (the Windows docu doesn't describe this)
202                 if ( pWinInfo2->pLocation && *pWinInfo2->pLocation )
203                     pInfo->maLocation = o3tl::toU(pWinInfo2->pLocation);
204                 else
205                     pInfo->maLocation = aPortName;
206                 // pComment can be 0 (the Windows docu doesn't describe this)
207                 if ( pWinInfo2->pComment )
208                     pInfo->maComment = o3tl::toU(pWinInfo2->pComment);
209                 pInfo->mnStatus      = ImplWinQueueStatusToSal( pWinInfo2->Status );
210                 pInfo->mnJobs        = pWinInfo2->cJobs;
211                 if( ! pInfo->mpPortName )
212                     pInfo->mpPortName.reset(new OUString(aPortName));
213             }
214             std::free(pWinInfo2);
215         }
216         ClosePrinter( hPrinter );
217     }
218 }
219 
GetDefaultPrinter()220 OUString WinSalInstance::GetDefaultPrinter()
221 {
222     DWORD   nChars = 0;
223     GetDefaultPrinterW( nullptr, &nChars );
224     if( nChars )
225     {
226         LPWSTR  pStr = static_cast<LPWSTR>(std::malloc(nChars*sizeof(WCHAR)));
227         OUString aDefPrt;
228         if( GetDefaultPrinterW( pStr, &nChars ) )
229         {
230             aDefPrt = o3tl::toU(pStr);
231         }
232         std::free( pStr );
233         if( !aDefPrt.isEmpty() )
234             return aDefPrt;
235     }
236 
237     // get default printer from win.ini
238     wchar_t szBuffer[256];
239     GetProfileStringW( aImplWindows, aImplDevice, L"", szBuffer, SAL_N_ELEMENTS( szBuffer ) );
240     if ( szBuffer[0] )
241     {
242         // search for printer name
243         wchar_t* pBuf = szBuffer;
244         wchar_t* pTmp = pBuf;
245         while ( *pTmp && (*pTmp != ',') )
246             pTmp++;
247         return OUString( o3tl::toU(pBuf), static_cast<sal_Int32>(pTmp-pBuf) );
248     }
249     else
250         return OUString();
251 }
252 
ImplDeviceCaps(WinSalInfoPrinter const * pPrinter,WORD nCaps,BYTE * pOutput,const ImplJobSetup * pSetupData)253 static DWORD ImplDeviceCaps( WinSalInfoPrinter const * pPrinter, WORD nCaps,
254                              BYTE* pOutput, const ImplJobSetup* pSetupData )
255 {
256     DEVMODEW const * pDevMode;
257     if ( !pSetupData || !pSetupData->GetDriverData() )
258         pDevMode = nullptr;
259     else
260         pDevMode = SAL_DEVMODE_W( pSetupData );
261 
262     return DeviceCapabilitiesW( o3tl::toW(pPrinter->maDeviceName.getStr()),
263                                 o3tl::toW(pPrinter->maPortName.getStr()),
264                                 nCaps, reinterpret_cast<LPWSTR>(pOutput), pDevMode );
265 }
266 
ImplTestSalJobSetup(WinSalInfoPrinter const * pPrinter,ImplJobSetup * pSetupData,bool bDelete)267 static bool ImplTestSalJobSetup( WinSalInfoPrinter const * pPrinter,
268                                  ImplJobSetup* pSetupData, bool bDelete )
269 {
270     if ( pSetupData && pSetupData->GetDriverData() )
271     {
272         // signature and size must fit to avoid using
273         // JobSetups from a wrong system
274 
275         // initialize versions from jobsetup
276         // those will be overwritten with driver's version
277         DEVMODEW const * pDevModeW = nullptr;
278         LONG dmSpecVersion = -1;
279         LONG dmDriverVersion = -1;
280         SalDriverData const * pSalDriverData = reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData());
281         BYTE const * pDriverData = reinterpret_cast<BYTE const *>(pSalDriverData) + pSalDriverData->mnDriverOffset;
282         pDevModeW = reinterpret_cast<DEVMODEW const *>(pDriverData);
283 
284         LONG nSysJobSize = -1;
285         if( pPrinter && pDevModeW )
286         {
287             // just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
288             // this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
289             // can avoid potential driver crashes as their jobsetups are often not compatible
290             // #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
291             HANDLE hPrn;
292             LPWSTR pPrinterNameW = const_cast<LPWSTR>(o3tl::toW(pPrinter->maDeviceName.getStr()));
293             if ( !OpenPrinterW( pPrinterNameW, &hPrn, nullptr ) )
294                 return false;
295 
296             // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
297             if( hPrn == HGDI_ERROR )
298                 return false;
299 
300             nSysJobSize = DocumentPropertiesW( nullptr, hPrn,
301                                                pPrinterNameW,
302                                                nullptr, nullptr, 0 );
303 
304             if( nSysJobSize < 0 )
305             {
306                 ClosePrinter( hPrn );
307                 return false;
308             }
309             DEVMODEW *pBuffer = static_cast<DEVMODEW*>(_alloca( nSysJobSize ));
310             LONG nRet = DocumentPropertiesW( nullptr, hPrn,
311                                         pPrinterNameW,
312                                         pBuffer, nullptr, DM_OUT_BUFFER );
313             if( nRet < 0 )
314             {
315                 ClosePrinter( hPrn );
316                 return false;
317             }
318 
319             // the spec version differs between the windows platforms, ie 98,NT,2000/XP
320             // this allows us to throw away printer settings from other platforms that might crash a buggy driver
321             // we check the driver version as well
322             dmSpecVersion = pBuffer->dmSpecVersion;
323             dmDriverVersion = pBuffer->dmDriverVersion;
324 
325             ClosePrinter( hPrn );
326         }
327         SalDriverData const * pSetupDriverData = reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData());
328         if ( (pSetupData->GetSystem() == JOBSETUP_SYSTEM_WINDOWS) &&
329              (pPrinter->maDriverName == pSetupData->GetDriver()) &&
330              (pSetupData->GetDriverDataLen() > sizeof( SalDriverData )) &&
331              static_cast<tools::Long>(pSetupData->GetDriverDataLen() - pSetupDriverData->mnDriverOffset) == nSysJobSize &&
332              pSetupDriverData->mnSysSignature == SAL_DRIVERDATA_SYSSIGN )
333         {
334             if( pDevModeW &&
335                 (dmSpecVersion == pDevModeW->dmSpecVersion) &&
336                 (dmDriverVersion == pDevModeW->dmDriverVersion) )
337                 return true;
338         }
339         if ( bDelete )
340         {
341             std::free( const_cast<sal_uInt8*>(pSetupData->GetDriverData()) );
342             pSetupData->SetDriverData( nullptr );
343             pSetupData->SetDriverDataLen( 0 );
344         }
345     }
346 
347     return false;
348 }
349 
ImplUpdateSalJobSetup(WinSalInfoPrinter const * pPrinter,ImplJobSetup * pSetupData,bool bIn,weld::Window * pVisibleDlgParent)350 static bool ImplUpdateSalJobSetup( WinSalInfoPrinter const * pPrinter, ImplJobSetup* pSetupData,
351                                    bool bIn, weld::Window* pVisibleDlgParent )
352 {
353     HANDLE hPrn;
354     LPWSTR pPrinterNameW = const_cast<LPWSTR>(o3tl::toW(pPrinter->maDeviceName.getStr()));
355     if ( !OpenPrinterW( pPrinterNameW, &hPrn, nullptr ) )
356         return false;
357     // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
358     if( hPrn == HGDI_ERROR )
359         return false;
360 
361     LONG            nRet;
362     HWND            hWnd = nullptr;
363     DWORD           nMode = DM_OUT_BUFFER;
364     SalDriverData*  pOutBuffer = nullptr;
365     BYTE const *    pInBuffer = nullptr;
366 
367     LONG nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
368                                        pPrinterNameW,
369                                        nullptr, nullptr, 0 );
370     if ( nSysJobSize < 0 )
371     {
372         ClosePrinter( hPrn );
373         return false;
374     }
375 
376     // make Outputbuffer
377     const std::size_t nDriverDataLen = sizeof(SalDriverData) + nSysJobSize-1;
378     pOutBuffer                  = static_cast<SalDriverData*>(rtl_allocateZeroMemory( nDriverDataLen ));
379     pOutBuffer->mnSysSignature  = SAL_DRIVERDATA_SYSSIGN;
380     // calculate driver data offset including structure padding
381     pOutBuffer->mnDriverOffset  = sal::static_int_cast<sal_uInt16>(
382                                     reinterpret_cast<char*>(pOutBuffer->maDriverData) -
383                                     reinterpret_cast<char*>(pOutBuffer) );
384 
385     // check if we have a suitable input buffer
386     if ( bIn && ImplTestSalJobSetup( pPrinter, pSetupData, false ) )
387     {
388         pInBuffer = pSetupData->GetDriverData() + reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData())->mnDriverOffset;
389         nMode |= DM_IN_BUFFER;
390     }
391 
392     // check if the dialog should be shown
393     if ( pVisibleDlgParent )
394     {
395         hWnd = pVisibleDlgParent->get_system_data().hWnd;
396         nMode |= DM_IN_PROMPT;
397     }
398 
399     // Release mutex, in the other case we don't get paints and so on
400     sal_uInt32 nMutexCount = 0;
401     WinSalInstance* pInst = GetSalData()->mpInstance;
402     if ( pInst && pVisibleDlgParent )
403         nMutexCount = pInst->ReleaseYieldMutexAll();
404 
405     BYTE* pOutDevMode = reinterpret_cast<BYTE*>(pOutBuffer) + pOutBuffer->mnDriverOffset;
406     nRet = DocumentPropertiesW( hWnd, hPrn,
407                                 pPrinterNameW,
408                                 reinterpret_cast<LPDEVMODEW>(pOutDevMode), reinterpret_cast<LPDEVMODEW>(const_cast<BYTE *>(pInBuffer)), nMode );
409     if ( pInst && pVisibleDlgParent )
410         pInst->AcquireYieldMutex( nMutexCount );
411     ClosePrinter( hPrn );
412 
413     if( (nRet < 0) || (pVisibleDlgParent && (nRet == IDCANCEL)) )
414     {
415         std::free( pOutBuffer );
416         return false;
417     }
418 
419     // fill up string buffers with 0 so they do not influence a JobSetup's memcmp
420     if( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmSize >= 64 )
421     {
422         sal_Int32 nLen = rtl_ustr_getLength( o3tl::toU(reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmDeviceName) );
423         if ( sal::static_int_cast<size_t>(nLen) < SAL_N_ELEMENTS( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmDeviceName ) )
424             memset( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmDeviceName+nLen, 0, sizeof( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmDeviceName )-(nLen*sizeof(sal_Unicode)) );
425     }
426     if( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmSize >= 166 )
427     {
428         sal_Int32 nLen = rtl_ustr_getLength( o3tl::toU(reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmFormName) );
429         if ( sal::static_int_cast<size_t>(nLen) < SAL_N_ELEMENTS( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmFormName ) )
430             memset( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmFormName+nLen, 0, sizeof( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmFormName )-(nLen*sizeof(sal_Unicode)) );
431     }
432 
433     // update data
434     if ( pSetupData->GetDriverData() )
435         std::free( const_cast<sal_uInt8*>(pSetupData->GetDriverData()) );
436     pSetupData->SetDriverDataLen( nDriverDataLen );
437     pSetupData->SetDriverData(reinterpret_cast<BYTE*>(pOutBuffer));
438     pSetupData->SetSystem( JOBSETUP_SYSTEM_WINDOWS );
439 
440     return true;
441 }
442 
ImplDevModeToJobSetup(WinSalInfoPrinter const * pPrinter,ImplJobSetup * pSetupData,JobSetFlags nFlags)443 static void ImplDevModeToJobSetup( WinSalInfoPrinter const * pPrinter, ImplJobSetup* pSetupData, JobSetFlags nFlags )
444 {
445     if ( !pSetupData || !pSetupData->GetDriverData() )
446         return;
447 
448     DEVMODEW const * pDevModeW = SAL_DEVMODE_W(pSetupData);
449     if( pDevModeW == nullptr )
450         return;
451 
452     // Orientation
453     if ( nFlags & JobSetFlags::ORIENTATION )
454     {
455         if ( pDevModeW->dmOrientation == DMORIENT_PORTRAIT )
456             pSetupData->SetOrientation( Orientation::Portrait );
457         else if ( pDevModeW->dmOrientation == DMORIENT_LANDSCAPE )
458             pSetupData->SetOrientation( Orientation::Landscape );
459     }
460 
461     // PaperBin
462     if ( nFlags & JobSetFlags::PAPERBIN )
463     {
464         const DWORD nCount = ImplDeviceCaps( pPrinter, DC_BINS, nullptr, pSetupData );
465 
466         if ( nCount && (nCount != GDI_ERROR) )
467         {
468             WORD* pBins = static_cast<WORD*>(rtl_allocateZeroMemory( nCount*sizeof(WORD) ));
469             ImplDeviceCaps( pPrinter, DC_BINS, reinterpret_cast<BYTE*>(pBins), pSetupData );
470             pSetupData->SetPaperBin( 0 );
471 
472             // search the right bin and assign index to mnPaperBin
473             for( DWORD i = 0; i < nCount; ++i )
474             {
475                 if( pDevModeW->dmDefaultSource == pBins[ i ] )
476                 {
477                     pSetupData->SetPaperBin( static_cast<sal_uInt16>(i) );
478                     break;
479                 }
480             }
481 
482             std::free( pBins );
483         }
484     }
485 
486     // PaperSize
487     if ( nFlags & JobSetFlags::PAPERSIZE )
488     {
489         if( (pDevModeW->dmFields & (DM_PAPERWIDTH|DM_PAPERLENGTH)) == (DM_PAPERWIDTH|DM_PAPERLENGTH) )
490         {
491             pSetupData->SetPaperWidth( pDevModeW->dmPaperWidth*10 );
492             pSetupData->SetPaperHeight( pDevModeW->dmPaperLength*10 );
493         }
494         else
495         {
496             const DWORD nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, nullptr, pSetupData );
497             WORD*   pPapers = nullptr;
498             const DWORD nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, nullptr, pSetupData );
499             POINT*  pPaperSizes = nullptr;
500             if ( nPaperCount && (nPaperCount != GDI_ERROR) )
501             {
502                 pPapers = static_cast<WORD*>(rtl_allocateZeroMemory(nPaperCount*sizeof(WORD)));
503                 ImplDeviceCaps( pPrinter, DC_PAPERS, reinterpret_cast<BYTE*>(pPapers), pSetupData );
504             }
505             if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
506             {
507                 pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT)));
508                 ImplDeviceCaps( pPrinter, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );
509             }
510             if( nPaperSizeCount == nPaperCount && pPaperSizes && pPapers )
511             {
512                 for( DWORD i = 0; i < nPaperCount; ++i )
513                 {
514                     if( pPapers[ i ] == pDevModeW->dmPaperSize )
515                     {
516                         pSetupData->SetPaperWidth( pPaperSizes[ i ].x*10 );
517                         pSetupData->SetPaperHeight( pPaperSizes[ i ].y*10 );
518                         break;
519                     }
520                 }
521             }
522             if( pPapers )
523                 std::free( pPapers );
524             if( pPaperSizes )
525                 std::free( pPaperSizes );
526         }
527         switch( pDevModeW->dmPaperSize )
528         {
529             case DMPAPER_LETTER:
530                 pSetupData->SetPaperFormat( PAPER_LETTER );
531                 break;
532             case DMPAPER_TABLOID:
533                 pSetupData->SetPaperFormat( PAPER_TABLOID );
534                 break;
535             case DMPAPER_LEDGER:
536                 pSetupData->SetPaperFormat( PAPER_LEDGER );
537                 break;
538             case DMPAPER_LEGAL:
539                 pSetupData->SetPaperFormat( PAPER_LEGAL );
540                 break;
541             case DMPAPER_STATEMENT:
542                 pSetupData->SetPaperFormat( PAPER_STATEMENT );
543                 break;
544             case DMPAPER_EXECUTIVE:
545                 pSetupData->SetPaperFormat( PAPER_EXECUTIVE );
546                 break;
547             case DMPAPER_A3:
548                 pSetupData->SetPaperFormat( PAPER_A3 );
549                 break;
550             case DMPAPER_A4:
551                 pSetupData->SetPaperFormat( PAPER_A4 );
552                 break;
553             case DMPAPER_A5:
554                 pSetupData->SetPaperFormat( PAPER_A5 );
555                 break;
556             //See http://wiki.openoffice.org/wiki/DefaultPaperSize
557             //i.e.
558             //http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
559             //DMPAPER_B4    12  B4 (JIS) 257 x 364 mm
560             //http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
561             //also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
562             //matches our Excel filter's belief about the matching XlPaperSize
563             //enumeration.
564 
565             //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
566             ////"DMPAPER_B4     12  B4 (JIS) 250 x 354"
567             //which is bogus as it's either JIS 257 x 364 or ISO 250 x 353
568             //(cmc)
569             case DMPAPER_B4:
570                 pSetupData->SetPaperFormat( PAPER_B4_JIS );
571                 break;
572             case DMPAPER_B5:
573                 pSetupData->SetPaperFormat( PAPER_B5_JIS );
574                 break;
575             case DMPAPER_QUARTO:
576                 pSetupData->SetPaperFormat( PAPER_QUARTO );
577                 break;
578             case DMPAPER_10X14:
579                 pSetupData->SetPaperFormat( PAPER_10x14 );
580                 break;
581             case DMPAPER_NOTE:
582                 pSetupData->SetPaperFormat( PAPER_LETTER );
583                 break;
584             case DMPAPER_ENV_9:
585                 pSetupData->SetPaperFormat( PAPER_ENV_9 );
586                 break;
587             case DMPAPER_ENV_10:
588                 pSetupData->SetPaperFormat( PAPER_ENV_10 );
589                 break;
590             case DMPAPER_ENV_11:
591                 pSetupData->SetPaperFormat( PAPER_ENV_11 );
592                 break;
593             case DMPAPER_ENV_12:
594                 pSetupData->SetPaperFormat( PAPER_ENV_12 );
595                 break;
596             case DMPAPER_ENV_14:
597                 pSetupData->SetPaperFormat( PAPER_ENV_14 );
598                 break;
599             case DMPAPER_CSHEET:
600                 pSetupData->SetPaperFormat( PAPER_C );
601                 break;
602             case DMPAPER_DSHEET:
603                 pSetupData->SetPaperFormat( PAPER_D );
604                 break;
605             case DMPAPER_ESHEET:
606                 pSetupData->SetPaperFormat( PAPER_E );
607                 break;
608             case DMPAPER_ENV_DL:
609                 pSetupData->SetPaperFormat( PAPER_ENV_DL );
610                 break;
611             case DMPAPER_ENV_C5:
612                 pSetupData->SetPaperFormat( PAPER_ENV_C5 );
613                 break;
614             case DMPAPER_ENV_C3:
615                 pSetupData->SetPaperFormat( PAPER_ENV_C3 );
616                 break;
617             case DMPAPER_ENV_C4:
618                 pSetupData->SetPaperFormat( PAPER_ENV_C4 );
619                 break;
620             case DMPAPER_ENV_C6:
621                 pSetupData->SetPaperFormat( PAPER_ENV_C6 );
622                 break;
623             case DMPAPER_ENV_C65:
624                 pSetupData->SetPaperFormat( PAPER_ENV_C65 );
625                 break;
626             case DMPAPER_ENV_ITALY:
627                 pSetupData->SetPaperFormat( PAPER_ENV_ITALY );
628                 break;
629             case DMPAPER_ENV_MONARCH:
630                 pSetupData->SetPaperFormat( PAPER_ENV_MONARCH );
631                 break;
632             case DMPAPER_ENV_PERSONAL:
633                 pSetupData->SetPaperFormat( PAPER_ENV_PERSONAL );
634                 break;
635             case DMPAPER_FANFOLD_US:
636                 pSetupData->SetPaperFormat( PAPER_FANFOLD_US );
637                 break;
638             case DMPAPER_FANFOLD_STD_GERMAN:
639                 pSetupData->SetPaperFormat( PAPER_FANFOLD_DE );
640                 break;
641             case DMPAPER_FANFOLD_LGL_GERMAN:
642                 pSetupData->SetPaperFormat( PAPER_FANFOLD_LEGAL_DE );
643                 break;
644             case DMPAPER_ISO_B4:
645                 pSetupData->SetPaperFormat( PAPER_B4_ISO );
646                 break;
647             case DMPAPER_JAPANESE_POSTCARD:
648                 pSetupData->SetPaperFormat( PAPER_POSTCARD_JP );
649                 break;
650             case DMPAPER_9X11:
651                 pSetupData->SetPaperFormat( PAPER_9x11 );
652                 break;
653             case DMPAPER_10X11:
654                 pSetupData->SetPaperFormat( PAPER_10x11 );
655                 break;
656             case DMPAPER_15X11:
657                 pSetupData->SetPaperFormat( PAPER_15x11 );
658                 break;
659             case DMPAPER_ENV_INVITE:
660                 pSetupData->SetPaperFormat( PAPER_ENV_INVITE );
661                 break;
662             case DMPAPER_A_PLUS:
663                 pSetupData->SetPaperFormat( PAPER_A_PLUS );
664                 break;
665             case DMPAPER_B_PLUS:
666                 pSetupData->SetPaperFormat( PAPER_B_PLUS );
667                 break;
668             case DMPAPER_LETTER_PLUS:
669                 pSetupData->SetPaperFormat( PAPER_LETTER_PLUS );
670                 break;
671             case DMPAPER_A4_PLUS:
672                 pSetupData->SetPaperFormat( PAPER_A4_PLUS );
673                 break;
674             case DMPAPER_A2:
675                 pSetupData->SetPaperFormat( PAPER_A2 );
676                 break;
677             case DMPAPER_DBL_JAPANESE_POSTCARD:
678                 pSetupData->SetPaperFormat( PAPER_DOUBLEPOSTCARD_JP );
679                 break;
680             case DMPAPER_A6:
681                 pSetupData->SetPaperFormat( PAPER_A6 );
682                 break;
683             case DMPAPER_B6_JIS:
684                 pSetupData->SetPaperFormat( PAPER_B6_JIS );
685                 break;
686             case DMPAPER_12X11:
687                 pSetupData->SetPaperFormat( PAPER_12x11 );
688                 break;
689             default:
690                 pSetupData->SetPaperFormat( PAPER_USER );
691                 break;
692         }
693     }
694 
695     if( nFlags & JobSetFlags::DUPLEXMODE )
696     {
697         DuplexMode eDuplex = DuplexMode::Unknown;
698         if( pDevModeW->dmFields & DM_DUPLEX )
699         {
700             if( pDevModeW->dmDuplex == DMDUP_SIMPLEX )
701                 eDuplex = DuplexMode::Off;
702             else if( pDevModeW->dmDuplex == DMDUP_VERTICAL )
703                 eDuplex = DuplexMode::LongEdge;
704             else if( pDevModeW->dmDuplex == DMDUP_HORIZONTAL )
705                 eDuplex = DuplexMode::ShortEdge;
706         }
707         pSetupData->SetDuplexMode( eDuplex );
708     }
709 }
710 
ImplJobSetupToDevMode(WinSalInfoPrinter const * pPrinter,const ImplJobSetup * pSetupData,JobSetFlags nFlags)711 static void ImplJobSetupToDevMode( WinSalInfoPrinter const * pPrinter, const ImplJobSetup* pSetupData, JobSetFlags nFlags )
712 {
713     if ( !pSetupData || !pSetupData->GetDriverData() )
714         return;
715 
716     DEVMODEW* pDevModeW = const_cast<DEVMODEW *>(SAL_DEVMODE_W(pSetupData));
717     if( pDevModeW == nullptr )
718         return;
719 
720     // Orientation
721     if ( nFlags & JobSetFlags::ORIENTATION )
722     {
723         pDevModeW->dmFields |= DM_ORIENTATION;
724         if ( pSetupData->GetOrientation() == Orientation::Portrait )
725             pDevModeW->dmOrientation = DMORIENT_PORTRAIT;
726         else
727             pDevModeW->dmOrientation = DMORIENT_LANDSCAPE;
728     }
729 
730     // PaperBin
731     if ( nFlags & JobSetFlags::PAPERBIN )
732     {
733         const DWORD nCount = ImplDeviceCaps( pPrinter, DC_BINS, nullptr, pSetupData );
734 
735         if ( nCount && (nCount != GDI_ERROR) )
736         {
737             WORD* pBins = static_cast<WORD*>(rtl_allocateZeroMemory(nCount*sizeof(WORD)));
738             ImplDeviceCaps( pPrinter, DC_BINS, reinterpret_cast<BYTE*>(pBins), pSetupData );
739             pDevModeW->dmFields |= DM_DEFAULTSOURCE;
740             pDevModeW->dmDefaultSource = pBins[ pSetupData->GetPaperBin() ];
741             std::free( pBins );
742         }
743     }
744 
745     // PaperSize
746     if ( nFlags & JobSetFlags::PAPERSIZE )
747     {
748         pDevModeW->dmFields        |= DM_PAPERSIZE;
749         pDevModeW->dmPaperWidth     = 0;
750         pDevModeW->dmPaperLength    = 0;
751 
752         switch( pSetupData->GetPaperFormat() )
753         {
754             case PAPER_A2:
755                 pDevModeW->dmPaperSize = DMPAPER_A2;
756                 break;
757             case PAPER_A3:
758                 pDevModeW->dmPaperSize = DMPAPER_A3;
759                 break;
760             case PAPER_A4:
761                 pDevModeW->dmPaperSize = DMPAPER_A4;
762                 break;
763             case PAPER_A5:
764                 pDevModeW->dmPaperSize = DMPAPER_A5;
765                 break;
766             case PAPER_B4_ISO:
767                 pDevModeW->dmPaperSize = DMPAPER_ISO_B4;
768                 break;
769             case PAPER_LETTER:
770                 pDevModeW->dmPaperSize = DMPAPER_LETTER;
771                 break;
772             case PAPER_LEGAL:
773                 pDevModeW->dmPaperSize = DMPAPER_LEGAL;
774                 break;
775             case PAPER_TABLOID:
776                 pDevModeW->dmPaperSize = DMPAPER_TABLOID;
777                 break;
778 
779             // http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
780             // DMPAPER_ENV_B6 is documented as:
781             // "DMPAPER_ENV_B6   35  Envelope B6 176 x 125 mm"
782             // which is the wrong way around, it is surely 125 x 176, i.e.
783             // compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
784             // DMPAPER_ENV_B4    33  Envelope B4 250 x 353 mm
785             // DMPAPER_ENV_B5    34  Envelope B5 176 x 250 mm
786 
787             case PAPER_ENV_C4:
788                 pDevModeW->dmPaperSize = DMPAPER_ENV_C4;
789                 break;
790             case PAPER_ENV_C5:
791                 pDevModeW->dmPaperSize = DMPAPER_ENV_C5;
792                 break;
793             case PAPER_ENV_C6:
794                 pDevModeW->dmPaperSize = DMPAPER_ENV_C6;
795                 break;
796             case PAPER_ENV_C65:
797                 pDevModeW->dmPaperSize = DMPAPER_ENV_C65;
798                 break;
799             case PAPER_ENV_DL:
800                 pDevModeW->dmPaperSize = DMPAPER_ENV_DL;
801                 break;
802             case PAPER_C:
803                 pDevModeW->dmPaperSize = DMPAPER_CSHEET;
804                 break;
805             case PAPER_D:
806                 pDevModeW->dmPaperSize = DMPAPER_DSHEET;
807                 break;
808             case PAPER_E:
809                 pDevModeW->dmPaperSize = DMPAPER_ESHEET;
810                 break;
811             case PAPER_EXECUTIVE:
812                 pDevModeW->dmPaperSize = DMPAPER_EXECUTIVE;
813                 break;
814             case PAPER_FANFOLD_LEGAL_DE:
815                 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_LGL_GERMAN;
816                 break;
817             case PAPER_ENV_MONARCH:
818                 pDevModeW->dmPaperSize = DMPAPER_ENV_MONARCH;
819                 break;
820             case PAPER_ENV_PERSONAL:
821                 pDevModeW->dmPaperSize = DMPAPER_ENV_PERSONAL;
822                 break;
823             case PAPER_ENV_9:
824                 pDevModeW->dmPaperSize = DMPAPER_ENV_9;
825                 break;
826             case PAPER_ENV_10:
827                 pDevModeW->dmPaperSize = DMPAPER_ENV_10;
828                 break;
829             case PAPER_ENV_11:
830                 pDevModeW->dmPaperSize = DMPAPER_ENV_11;
831                 break;
832             case PAPER_ENV_12:
833                 pDevModeW->dmPaperSize = DMPAPER_ENV_12;
834                 break;
835             //See the comments on DMPAPER_B4 above
836             case PAPER_B4_JIS:
837                 pDevModeW->dmPaperSize = DMPAPER_B4;
838                 break;
839             case PAPER_B5_JIS:
840                 pDevModeW->dmPaperSize = DMPAPER_B5;
841                 break;
842             case PAPER_B6_JIS:
843                 pDevModeW->dmPaperSize = DMPAPER_B6_JIS;
844                 break;
845             case PAPER_LEDGER:
846                 pDevModeW->dmPaperSize = DMPAPER_LEDGER;
847                 break;
848             case PAPER_STATEMENT:
849                 pDevModeW->dmPaperSize = DMPAPER_STATEMENT;
850                 break;
851             case PAPER_10x14:
852                 pDevModeW->dmPaperSize = DMPAPER_10X14;
853                 break;
854             case PAPER_ENV_14:
855                 pDevModeW->dmPaperSize = DMPAPER_ENV_14;
856                 break;
857             case PAPER_ENV_C3:
858                 pDevModeW->dmPaperSize = DMPAPER_ENV_C3;
859                 break;
860             case PAPER_ENV_ITALY:
861                 pDevModeW->dmPaperSize = DMPAPER_ENV_ITALY;
862                 break;
863             case PAPER_FANFOLD_US:
864                 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_US;
865                 break;
866             case PAPER_FANFOLD_DE:
867                 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_STD_GERMAN;
868                 break;
869             case PAPER_POSTCARD_JP:
870                 pDevModeW->dmPaperSize = DMPAPER_JAPANESE_POSTCARD;
871                 break;
872             case PAPER_9x11:
873                 pDevModeW->dmPaperSize = DMPAPER_9X11;
874                 break;
875             case PAPER_10x11:
876                 pDevModeW->dmPaperSize = DMPAPER_10X11;
877                 break;
878             case PAPER_15x11:
879                 pDevModeW->dmPaperSize = DMPAPER_15X11;
880                 break;
881             case PAPER_ENV_INVITE:
882                 pDevModeW->dmPaperSize = DMPAPER_ENV_INVITE;
883                 break;
884             case PAPER_A_PLUS:
885                 pDevModeW->dmPaperSize = DMPAPER_A_PLUS;
886                 break;
887             case PAPER_B_PLUS:
888                 pDevModeW->dmPaperSize = DMPAPER_B_PLUS;
889                 break;
890             case PAPER_LETTER_PLUS:
891                 pDevModeW->dmPaperSize = DMPAPER_LETTER_PLUS;
892                 break;
893             case PAPER_A4_PLUS:
894                 pDevModeW->dmPaperSize = DMPAPER_A4_PLUS;
895                 break;
896             case PAPER_DOUBLEPOSTCARD_JP:
897                 pDevModeW->dmPaperSize = DMPAPER_DBL_JAPANESE_POSTCARD;
898                 break;
899             case PAPER_A6:
900                 pDevModeW->dmPaperSize = DMPAPER_A6;
901                 break;
902             case PAPER_12x11:
903                 pDevModeW->dmPaperSize = DMPAPER_12X11;
904                 break;
905             default:
906             {
907                 short   nPaper = 0;
908                 const DWORD nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, nullptr, pSetupData );
909                 WORD*   pPapers = nullptr;
910                 const DWORD nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, nullptr, pSetupData );
911                 POINT*  pPaperSizes = nullptr;
912                 DWORD   nLandscapeAngle = ImplDeviceCaps( pPrinter, DC_ORIENTATION, nullptr, pSetupData );
913                 if ( nPaperCount && (nPaperCount != GDI_ERROR) )
914                 {
915                     pPapers = static_cast<WORD*>(rtl_allocateZeroMemory(nPaperCount*sizeof(WORD)));
916                     ImplDeviceCaps( pPrinter, DC_PAPERS, reinterpret_cast<BYTE*>(pPapers), pSetupData );
917                 }
918                 if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
919                 {
920                     pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT)));
921                     ImplDeviceCaps( pPrinter, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );
922                 }
923                 if ( (nPaperSizeCount == nPaperCount) && pPapers && pPaperSizes )
924                 {
925                     PaperInfo aInfo(pSetupData->GetPaperWidth(), pSetupData->GetPaperHeight());
926                     // compare paper formats and select a good match
927                     for ( DWORD i = 0; i < nPaperCount; ++i )
928                     {
929                         if ( aInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)))
930                         {
931                             nPaper = pPapers[i];
932                             break;
933                         }
934                     }
935 
936                     // If the printer supports landscape orientation, check paper sizes again
937                     // with landscape orientation. This is necessary as a printer driver provides
938                     // all paper sizes with portrait orientation only!!
939                     if ( !nPaper && nLandscapeAngle != 0 )
940                     {
941                         PaperInfo aRotatedInfo(pSetupData->GetPaperHeight(), pSetupData->GetPaperWidth());
942                         for ( DWORD i = 0; i < nPaperCount; ++i )
943                         {
944                             if ( aRotatedInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)) )
945                             {
946                                 nPaper = pPapers[i];
947                                 break;
948                             }
949                         }
950                     }
951 
952                     if ( nPaper )
953                         pDevModeW->dmPaperSize = nPaper;
954                 }
955 
956                 if ( !nPaper )
957                 {
958                     pDevModeW->dmFields       |= DM_PAPERLENGTH | DM_PAPERWIDTH;
959                     pDevModeW->dmPaperSize     = DMPAPER_USER;
960                     pDevModeW->dmPaperWidth    = static_cast<short>(pSetupData->GetPaperWidth()/10);
961                     pDevModeW->dmPaperLength   = static_cast<short>(pSetupData->GetPaperHeight()/10);
962                 }
963 
964                 if ( pPapers )
965                     std::free(pPapers);
966                 if ( pPaperSizes )
967                     std::free(pPaperSizes);
968 
969                 break;
970             }
971         }
972     }
973     if( nFlags & JobSetFlags::DUPLEXMODE )
974     {
975         switch( pSetupData->GetDuplexMode() )
976         {
977         case DuplexMode::Off:
978             pDevModeW->dmFields |= DM_DUPLEX;
979             pDevModeW->dmDuplex = DMDUP_SIMPLEX;
980             break;
981         case DuplexMode::ShortEdge:
982             pDevModeW->dmFields |= DM_DUPLEX;
983             pDevModeW->dmDuplex = DMDUP_HORIZONTAL;
984             break;
985         case DuplexMode::LongEdge:
986             pDevModeW->dmFields |= DM_DUPLEX;
987             pDevModeW->dmDuplex = DMDUP_VERTICAL;
988             break;
989         case DuplexMode::Unknown:
990             break;
991         }
992     }
993 }
994 
ImplCreateICW_WithCatch(LPWSTR pDriver,LPCWSTR pDevice,DEVMODEW const * pDevMode)995 static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
996                                     LPCWSTR pDevice,
997                                     DEVMODEW const * pDevMode )
998 {
999     HDC hDC = nullptr;
1000     CATCH_DRIVER_EX_BEGIN;
1001     hDC = CreateICW( pDriver, pDevice, nullptr, pDevMode );
1002     CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
1003     return hDC;
1004 }
1005 
ImplCreateSalPrnIC(WinSalInfoPrinter const * pPrinter,const ImplJobSetup * pSetupData)1006 static HDC ImplCreateSalPrnIC( WinSalInfoPrinter const * pPrinter, const ImplJobSetup* pSetupData )
1007 {
1008     HDC hDC = nullptr;
1009     DEVMODEW const * pDevMode;
1010     if ( pSetupData && pSetupData->GetDriverData() )
1011         pDevMode = SAL_DEVMODE_W( pSetupData );
1012     else
1013         pDevMode = nullptr;
1014     // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
1015     // pl: does this hold true for Unicode functions ?
1016     if( pPrinter->maDriverName.getLength() > 2048 || pPrinter->maDeviceName.getLength() > 2048 )
1017         return nullptr;
1018     sal_Unicode pDriverName[ 4096 ];
1019     sal_Unicode pDeviceName[ 4096 ];
1020     memcpy( pDriverName, pPrinter->maDriverName.getStr(), pPrinter->maDriverName.getLength()*sizeof(sal_Unicode));
1021     memset( pDriverName+pPrinter->maDriverName.getLength(), 0, 32 );
1022     memcpy( pDeviceName, pPrinter->maDeviceName.getStr(), pPrinter->maDeviceName.getLength()*sizeof(sal_Unicode));
1023     memset( pDeviceName+pPrinter->maDeviceName.getLength(), 0, 32 );
1024     hDC = ImplCreateICW_WithCatch( o3tl::toW(pDriverName),
1025                                    o3tl::toW(pDeviceName),
1026                                    pDevMode );
1027     return hDC;
1028 }
1029 
ImplCreateSalPrnGraphics(HDC hDC)1030 static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC )
1031 {
1032     WinSalGraphics* pGraphics = new WinSalGraphics(WinSalGraphics::PRINTER, false, nullptr, /* CHECKME */ nullptr);
1033     pGraphics->SetLayout( SalLayoutFlags::NONE );
1034     pGraphics->setHDC(hDC);
1035     pGraphics->InitGraphics();
1036     return pGraphics;
1037 }
1038 
ImplUpdateSalPrnIC(WinSalInfoPrinter * pPrinter,const ImplJobSetup * pSetupData)1039 static bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, const ImplJobSetup* pSetupData )
1040 {
1041     HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1042     if ( !hNewDC )
1043         return false;
1044 
1045     if ( pPrinter->mpGraphics )
1046     {
1047         pPrinter->mpGraphics->DeInitGraphics();
1048         DeleteDC( pPrinter->mpGraphics->getHDC() );
1049         delete pPrinter->mpGraphics;
1050     }
1051 
1052     pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hNewDC );
1053     pPrinter->mhDC      = hNewDC;
1054 
1055     return true;
1056 }
1057 
1058 
CreateInfoPrinter(SalPrinterQueueInfo * pQueueInfo,ImplJobSetup * pSetupData)1059 SalInfoPrinter* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
1060                                                    ImplJobSetup* pSetupData )
1061 {
1062     WinSalInfoPrinter* pPrinter = new WinSalInfoPrinter;
1063     if( ! pQueueInfo->mpPortName )
1064         GetPrinterQueueState( pQueueInfo );
1065     pPrinter->maDriverName  = pQueueInfo->maDriver;
1066     pPrinter->maDeviceName  = pQueueInfo->maPrinterName;
1067     pPrinter->maPortName    = pQueueInfo->mpPortName ? *pQueueInfo->mpPortName : OUString();
1068 
1069     // check if the provided setup data match the actual printer
1070     ImplTestSalJobSetup( pPrinter, pSetupData, true );
1071 
1072     HDC hDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1073     if ( !hDC )
1074     {
1075         delete pPrinter;
1076         return nullptr;
1077     }
1078 
1079     pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hDC );
1080     pPrinter->mhDC      = hDC;
1081     if ( !pSetupData->GetDriverData() )
1082         ImplUpdateSalJobSetup( pPrinter, pSetupData, false, nullptr );
1083     ImplDevModeToJobSetup( pPrinter, pSetupData, JobSetFlags::ALL );
1084     pSetupData->SetSystem( JOBSETUP_SYSTEM_WINDOWS );
1085 
1086     return pPrinter;
1087 }
1088 
DestroyInfoPrinter(SalInfoPrinter * pPrinter)1089 void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
1090 {
1091     delete pPrinter;
1092 }
1093 
1094 
WinSalInfoPrinter()1095 WinSalInfoPrinter::WinSalInfoPrinter() :
1096     mpGraphics( nullptr ),
1097     mhDC( nullptr ),
1098     mbGraphics( false )
1099 {
1100     m_bPapersInit = false;
1101 }
1102 
~WinSalInfoPrinter()1103 WinSalInfoPrinter::~WinSalInfoPrinter()
1104 {
1105     if ( mpGraphics )
1106     {
1107         mpGraphics->DeInitGraphics();
1108         DeleteDC( mpGraphics->getHDC() );
1109         delete mpGraphics;
1110     }
1111 }
1112 
InitPaperFormats(const ImplJobSetup * pSetupData)1113 void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
1114 {
1115     m_aPaperFormats.clear();
1116 
1117     DWORD nCount = ImplDeviceCaps( this, DC_PAPERSIZE, nullptr, pSetupData );
1118     if( nCount == GDI_ERROR )
1119         nCount = 0;
1120 
1121     if( nCount )
1122     {
1123         POINT* pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nCount*sizeof(POINT)));
1124         ImplDeviceCaps( this, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );
1125 
1126         sal_Unicode* pNamesBuffer = static_cast<sal_Unicode*>(std::malloc(nCount*64*sizeof(sal_Unicode)));
1127         ImplDeviceCaps( this, DC_PAPERNAMES, reinterpret_cast<BYTE*>(pNamesBuffer), pSetupData );
1128         for( DWORD i = 0; i < nCount; ++i )
1129         {
1130             PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
1131             m_aPaperFormats.push_back( aInfo );
1132         }
1133         std::free( pNamesBuffer );
1134         std::free( pPaperSizes );
1135     }
1136 
1137     m_bPapersInit = true;
1138 }
1139 
GetLandscapeAngle(const ImplJobSetup * pSetupData)1140 int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
1141 {
1142     const DWORD nRet = ImplDeviceCaps( this, DC_ORIENTATION, nullptr, pSetupData );
1143 
1144     if( nRet != GDI_ERROR )
1145         return static_cast<int>(nRet) * 10;
1146     return 900; // guess
1147 }
1148 
AcquireGraphics()1149 SalGraphics* WinSalInfoPrinter::AcquireGraphics()
1150 {
1151     if ( mbGraphics )
1152         return nullptr;
1153 
1154     if ( mpGraphics )
1155         mbGraphics = true;
1156 
1157     return mpGraphics;
1158 }
1159 
ReleaseGraphics(SalGraphics *)1160 void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
1161 {
1162     mbGraphics = false;
1163 }
1164 
Setup(weld::Window * pFrame,ImplJobSetup * pSetupData)1165 bool WinSalInfoPrinter::Setup(weld::Window* pFrame, ImplJobSetup* pSetupData)
1166 {
1167     if ( ImplUpdateSalJobSetup(this, pSetupData, true, pFrame))
1168     {
1169         ImplDevModeToJobSetup( this, pSetupData, JobSetFlags::ALL );
1170         return ImplUpdateSalPrnIC( this, pSetupData );
1171     }
1172 
1173     return false;
1174 }
1175 
SetPrinterData(ImplJobSetup * pSetupData)1176 bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
1177 {
1178     if ( !ImplTestSalJobSetup( this, pSetupData, false ) )
1179         return false;
1180     return ImplUpdateSalPrnIC( this, pSetupData );
1181 }
1182 
SetData(JobSetFlags nFlags,ImplJobSetup * pSetupData)1183 bool WinSalInfoPrinter::SetData( JobSetFlags nFlags, ImplJobSetup* pSetupData )
1184 {
1185     ImplJobSetupToDevMode( this, pSetupData, nFlags );
1186     if ( ImplUpdateSalJobSetup( this, pSetupData, true, nullptr ) )
1187     {
1188         ImplDevModeToJobSetup( this, pSetupData, nFlags );
1189         return ImplUpdateSalPrnIC( this, pSetupData );
1190     }
1191 
1192     return false;
1193 }
1194 
GetPaperBinCount(const ImplJobSetup * pSetupData)1195 sal_uInt16 WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
1196 {
1197     DWORD nRet = ImplDeviceCaps( this, DC_BINS, nullptr, pSetupData );
1198     if ( nRet && (nRet != GDI_ERROR) )
1199         return nRet;
1200     else
1201         return 0;
1202 }
1203 
GetPaperBinName(const ImplJobSetup * pSetupData,sal_uInt16 nPaperBin)1204 OUString WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pSetupData, sal_uInt16 nPaperBin )
1205 {
1206     OUString aPaperBinName;
1207 
1208     DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, nullptr, pSetupData );
1209     if ( (nPaperBin < nBins) && (nBins != GDI_ERROR) )
1210     {
1211         auto pBuffer = std::make_unique<sal_Unicode[]>(nBins*24);
1212         DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, reinterpret_cast<BYTE*>(pBuffer.get()), pSetupData );
1213         if ( nRet && (nRet != GDI_ERROR) )
1214             aPaperBinName = OUString( pBuffer.get() + (nPaperBin*24) );
1215     }
1216 
1217     return aPaperBinName;
1218 }
1219 
GetCapabilities(const ImplJobSetup * pSetupData,PrinterCapType nType)1220 sal_uInt32 WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, PrinterCapType nType )
1221 {
1222     DWORD nRet;
1223 
1224     switch ( nType )
1225     {
1226         case PrinterCapType::SupportDialog:
1227             return TRUE;
1228         case PrinterCapType::Copies:
1229             nRet = ImplDeviceCaps( this, DC_COPIES, nullptr, pSetupData );
1230             if ( nRet && (nRet != GDI_ERROR) )
1231                 return nRet;
1232             return 0;
1233         case PrinterCapType::CollateCopies:
1234             nRet = ImplDeviceCaps( this, DC_COLLATE, nullptr, pSetupData );
1235             if ( nRet && (nRet != GDI_ERROR) )
1236             {
1237                 nRet = ImplDeviceCaps( this, DC_COPIES, nullptr, pSetupData );
1238                 if ( nRet && (nRet != GDI_ERROR) )
1239                     return nRet;
1240             }
1241             return 0;
1242 
1243         case PrinterCapType::SetOrientation:
1244             nRet = ImplDeviceCaps( this, DC_ORIENTATION, nullptr, pSetupData );
1245             if ( nRet && (nRet != GDI_ERROR) )
1246                 return TRUE;
1247             return FALSE;
1248 
1249         case PrinterCapType::SetPaperSize:
1250         case PrinterCapType::SetPaper:
1251             nRet = ImplDeviceCaps( this, DC_PAPERS, nullptr, pSetupData );
1252             if ( nRet && (nRet != GDI_ERROR) )
1253                 return TRUE;
1254             return FALSE;
1255 
1256         default:
1257             break;
1258     }
1259 
1260     return 0;
1261 }
1262 
GetPageInfo(const ImplJobSetup *,tools::Long & rOutWidth,tools::Long & rOutHeight,Point & rPageOffset,Size & rPaperSize)1263 void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
1264                                   tools::Long& rOutWidth, tools::Long& rOutHeight,
1265                                   Point& rPageOffset,
1266                                   Size& rPaperSize )
1267 {
1268     HDC hDC = mhDC;
1269 
1270     rOutWidth   = GetDeviceCaps( hDC, HORZRES );
1271     rOutHeight  = GetDeviceCaps( hDC, VERTRES );
1272 
1273     rPageOffset.setX( GetDeviceCaps( hDC, PHYSICALOFFSETX ) );
1274     rPageOffset.setY( GetDeviceCaps( hDC, PHYSICALOFFSETY ) );
1275     rPaperSize.setWidth( GetDeviceCaps( hDC, PHYSICALWIDTH ) );
1276     rPaperSize.setHeight( GetDeviceCaps( hDC, PHYSICALHEIGHT ) );
1277 }
1278 
1279 
CreatePrinter(SalInfoPrinter * pInfoPrinter)1280 std::unique_ptr<SalPrinter> WinSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
1281 {
1282     WinSalPrinter* pPrinter = new WinSalPrinter;
1283     pPrinter->mpInfoPrinter = static_cast<WinSalInfoPrinter*>(pInfoPrinter);
1284     return std::unique_ptr<SalPrinter>(pPrinter);
1285 }
1286 
SalPrintAbortProc(HDC hPrnDC,int)1287 static BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
1288 {
1289     SalData*    pSalData = GetSalData();
1290     WinSalPrinter* pPrinter;
1291     int         i = 0;
1292     bool        bWhile = true;
1293 
1294     // Ensure we handle the mutex which will be released in WinSalInstance::DoYield
1295     SolarMutexGuard aSolarMutexGuard;
1296     do
1297     {
1298         // process messages
1299         bWhile = Application::Reschedule( true );
1300         if (i > 15)
1301             bWhile = false;
1302         else
1303             ++i;
1304 
1305         pPrinter = pSalData->mpFirstPrinter;
1306         while ( pPrinter )
1307         {
1308             if( pPrinter->mhDC == hPrnDC )
1309                 break;
1310 
1311             pPrinter = pPrinter->mpNextPrinter;
1312         }
1313 
1314         if ( !pPrinter || pPrinter->mbAbort )
1315             return FALSE;
1316     }
1317     while ( bWhile );
1318 
1319     return TRUE;
1320 }
1321 
ImplSalSetCopies(DEVMODEW const * pDevMode,sal_uInt32 nCopies,bool bCollate)1322 static DEVMODEW const * ImplSalSetCopies( DEVMODEW const * pDevMode, sal_uInt32 nCopies, bool bCollate )
1323 {
1324     if ( pDevMode && (nCopies > 1) )
1325     {
1326         if ( nCopies > 32765 )
1327             nCopies = 32765;
1328         sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
1329         LPDEVMODEW pNewDevMode = static_cast<LPDEVMODEW>(std::malloc( nDevSize ));
1330         assert(pNewDevMode); // Don't handle OOM conditions
1331         memcpy( pNewDevMode, pDevMode, nDevSize );
1332         pNewDevMode->dmFields |= DM_COPIES;
1333         pNewDevMode->dmCopies  = static_cast<short>(static_cast<sal_uInt16>(nCopies));
1334         pNewDevMode->dmFields |= DM_COLLATE;
1335         if ( bCollate )
1336             pNewDevMode->dmCollate = DMCOLLATE_TRUE;
1337         else
1338             pNewDevMode->dmCollate = DMCOLLATE_FALSE;
1339         return pNewDevMode;
1340     }
1341     else
1342     {
1343         return pDevMode;
1344     }
1345 }
1346 
1347 
WinSalPrinter()1348 WinSalPrinter::WinSalPrinter() :
1349     mpGraphics( nullptr ),
1350     mpInfoPrinter( nullptr ),
1351     mpNextPrinter( nullptr ),
1352     mhDC( nullptr ),
1353     mnError( SalPrinterError::NONE ),
1354     mnCopies( 0 ),
1355     mbCollate( false ),
1356     mbAbort( false ),
1357     mbValid( true )
1358 {
1359     SalData* pSalData = GetSalData();
1360     // insert printer in printerlist
1361     mpNextPrinter = pSalData->mpFirstPrinter;
1362     pSalData->mpFirstPrinter = this;
1363 }
1364 
~WinSalPrinter()1365 WinSalPrinter::~WinSalPrinter()
1366 {
1367     SalData* pSalData = GetSalData();
1368 
1369     // release DC if there is one still around because of AbortJob
1370     HDC hDC = mhDC;
1371     if ( hDC )
1372     {
1373         if ( mpGraphics )
1374         {
1375             mpGraphics->DeInitGraphics();
1376             delete mpGraphics;
1377         }
1378 
1379         DeleteDC( hDC );
1380     }
1381 
1382     // remove printer from printerlist
1383     if ( this == pSalData->mpFirstPrinter )
1384         pSalData->mpFirstPrinter = mpNextPrinter;
1385     else
1386     {
1387         WinSalPrinter* pTempPrinter = pSalData->mpFirstPrinter;
1388 
1389         while( pTempPrinter->mpNextPrinter != this )
1390             pTempPrinter = pTempPrinter->mpNextPrinter;
1391 
1392         pTempPrinter->mpNextPrinter = mpNextPrinter;
1393     }
1394     mbValid = false;
1395 }
1396 
markInvalid()1397 void WinSalPrinter::markInvalid()
1398 {
1399     mbValid = false;
1400 }
1401 
1402 // need wrappers for StarTocW/A to use structured exception handling
1403 // since SEH does not mix with standard exception handling's cleanup
lcl_StartDocW(HDC hDC,DOCINFOW const * pInfo,WinSalPrinter * pPrt)1404 static int lcl_StartDocW( HDC hDC, DOCINFOW const * pInfo, WinSalPrinter* pPrt )
1405 {
1406     int nRet = 0;
1407     CATCH_DRIVER_EX_BEGIN;
1408     nRet = ::StartDocW( hDC, pInfo );
1409     CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
1410     return nRet;
1411 }
1412 
StartJob(const OUString * pFileName,const OUString & rJobName,const OUString &,sal_uInt32 nCopies,bool bCollate,bool,ImplJobSetup * pSetupData)1413 bool WinSalPrinter::StartJob( const OUString* pFileName,
1414                            const OUString& rJobName,
1415                            const OUString&,
1416                            sal_uInt32 nCopies,
1417                            bool bCollate,
1418                            bool /*bDirect*/,
1419                            ImplJobSetup* pSetupData )
1420 {
1421     mnError     = SalPrinterError::NONE;
1422     mbAbort     = false;
1423     mnCopies        = nCopies;
1424     mbCollate   = bCollate;
1425 
1426     DEVMODEW const * pOrgDevModeW = nullptr;
1427     DEVMODEW const * pDevModeW = nullptr;
1428     HDC hDC = nullptr;
1429     if ( pSetupData && pSetupData->GetDriverData() )
1430     {
1431         pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
1432         pDevModeW = ImplSalSetCopies( pOrgDevModeW, nCopies, bCollate );
1433     }
1434 
1435     // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
1436     sal_Unicode aDrvBuf[4096];
1437     sal_Unicode aDevBuf[4096];
1438     memcpy( aDrvBuf, mpInfoPrinter->maDriverName.getStr(), (mpInfoPrinter->maDriverName.getLength()+1)*sizeof(sal_Unicode));
1439     memcpy( aDevBuf, mpInfoPrinter->maDeviceName.getStr(), (mpInfoPrinter->maDeviceName.getLength()+1)*sizeof(sal_Unicode));
1440     hDC = CreateDCW( o3tl::toW(aDrvBuf),
1441                      o3tl::toW(aDevBuf),
1442                      nullptr,
1443                      pDevModeW );
1444 
1445     if ( pDevModeW != pOrgDevModeW )
1446         std::free( const_cast<DEVMODEW *>(pDevModeW) );
1447 
1448     if ( !hDC )
1449     {
1450         mnError = SalPrinterError::General;
1451         return false;
1452     }
1453 
1454     // make sure mhDC is set before the printer driver may call our abortproc
1455     mhDC = hDC;
1456     if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
1457     {
1458         mnError = SalPrinterError::General;
1459         return false;
1460     }
1461 
1462     mnError = SalPrinterError::NONE;
1463     mbAbort = false;
1464 
1465     // As the Telecom Balloon Fax driver tends to send messages repeatedly
1466     // we try to process first all, and then insert a dummy message
1467     for (int i = 0; Application::Reschedule( true ) && i <= 15; ++i);
1468     bool const ret = PostMessageW(GetSalData()->mpInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0);
1469     SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
1470 
1471     // bring up a file chooser if printing to file port but no file name given
1472     OUString aOutFileName;
1473     if( mpInfoPrinter->maPortName.equalsIgnoreAsciiCase( "FILE:" ) && (!pFileName || pFileName->isEmpty()) )
1474     {
1475 
1476         uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1477         uno::Reference< XFilePicker3 > xFilePicker = FilePicker::createWithMode(xContext, TemplateDescription::FILESAVE_SIMPLE);
1478 
1479         if( xFilePicker->execute() == ExecutableDialogResults::OK )
1480         {
1481             Sequence< OUString > aPathSeq( xFilePicker->getSelectedFiles() );
1482             INetURLObject aObj( aPathSeq[0] );
1483             aOutFileName = aObj.PathToFileName();
1484         }
1485         else
1486         {
1487             mnError = SalPrinterError::Abort;
1488             return false;
1489         }
1490     }
1491 
1492     DOCINFOW aInfo = {};
1493     aInfo.cbSize = sizeof( aInfo );
1494     aInfo.lpszDocName = o3tl::toW(rJobName.getStr());
1495     if ( pFileName || aOutFileName.getLength() )
1496     {
1497         if ( (pFileName && !pFileName->isEmpty()) || aOutFileName.getLength() )
1498         {
1499             aInfo.lpszOutput = o3tl::toW((pFileName && !pFileName->isEmpty()) ? pFileName->getStr() : aOutFileName.getStr());
1500         }
1501         else
1502             aInfo.lpszOutput = L"FILE:";
1503     }
1504     else
1505         aInfo.lpszOutput = nullptr;
1506 
1507     // start Job, in the main thread
1508     int nRet = vcl::solarthread::syncExecute([hDC, this, &aInfo]() -> int { return lcl_StartDocW(hDC, &aInfo, this); });
1509 
1510     if ( nRet <= 0 )
1511     {
1512         DWORD nError = GetLastError();
1513         if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
1514             mnError = SalPrinterError::Abort;
1515         else
1516             mnError = SalPrinterError::General;
1517         return false;
1518     }
1519 
1520     return true;
1521 }
1522 
DoEndDoc(HDC hDC)1523 void WinSalPrinter::DoEndDoc(HDC hDC)
1524 {
1525     CATCH_DRIVER_EX_BEGIN;
1526     if( ::EndDoc( hDC ) <= 0 )
1527         GetLastError();
1528     CATCH_DRIVER_EX_END( "exception in EndDoc", this );
1529 }
1530 
EndJob()1531 bool WinSalPrinter::EndJob()
1532 {
1533     HDC hDC = mhDC;
1534     if ( isValid() && hDC )
1535     {
1536         if ( mpGraphics )
1537         {
1538             mpGraphics->DeInitGraphics();
1539             delete mpGraphics;
1540             mpGraphics = nullptr;
1541         }
1542 
1543         // #i54419# Windows fax printer brings up a dialog in EndDoc
1544         // which text previously copied in soffice process can be
1545         // pasted to -> deadlock due to mutex not released.
1546         // it should be safe to release the yield mutex over the EndDoc
1547         // call, however the real solution is supposed to be the threading
1548         // framework yet to come.
1549         {
1550             SolarMutexReleaser aReleaser;
1551             DoEndDoc( hDC );
1552         }
1553         DeleteDC( hDC );
1554         mhDC = nullptr;
1555     }
1556 
1557     return true;
1558 }
1559 
StartPage(ImplJobSetup * pSetupData,bool bNewJobData)1560 SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, bool bNewJobData )
1561 {
1562     if( ! isValid() || mhDC == nullptr )
1563         return nullptr;
1564 
1565     HDC hDC = mhDC;
1566     if ( pSetupData && pSetupData->GetDriverData() && bNewJobData )
1567     {
1568         DEVMODEW const * pOrgDevModeW;
1569         DEVMODEW const * pDevModeW;
1570         pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
1571         pDevModeW = ImplSalSetCopies( pOrgDevModeW, mnCopies, mbCollate );
1572         ResetDCW( hDC, pDevModeW );
1573         if ( pDevModeW != pOrgDevModeW )
1574             std::free( const_cast<DEVMODEW *>(pDevModeW) );
1575     }
1576     volatile int nRet = 0;
1577     CATCH_DRIVER_EX_BEGIN;
1578     nRet = ::StartPage( hDC );
1579     CATCH_DRIVER_EX_END( "exception in StartPage", this );
1580 
1581     if ( nRet <= 0 )
1582     {
1583         GetLastError();
1584         mnError = SalPrinterError::General;
1585         return nullptr;
1586     }
1587 
1588     // Hack to work around old PostScript printer drivers optimizing away empty pages
1589     // TODO: move into ImplCreateSalPrnGraphics()?
1590     HPEN    hTempPen = SelectPen( hDC, GetStockPen( NULL_PEN ) );
1591     HBRUSH  hTempBrush = SelectBrush( hDC, GetStockBrush( NULL_BRUSH ) );
1592     Rectangle( hDC, -8000, -8000, -7999, -7999 );
1593     SelectPen( hDC, hTempPen );
1594     SelectBrush( hDC, hTempBrush );
1595 
1596     mpGraphics = ImplCreateSalPrnGraphics( hDC );
1597     return mpGraphics;
1598 }
1599 
EndPage()1600 void WinSalPrinter::EndPage()
1601 {
1602     HDC hDC = mhDC;
1603     if ( hDC && mpGraphics )
1604     {
1605         mpGraphics->DeInitGraphics();
1606         delete mpGraphics;
1607         mpGraphics = nullptr;
1608     }
1609 
1610     if( ! isValid() )
1611         return;
1612 
1613     volatile int nRet = 0;
1614     CATCH_DRIVER_EX_BEGIN;
1615     nRet = ::EndPage( hDC );
1616     CATCH_DRIVER_EX_END( "exception in EndPage", this );
1617 
1618     if ( nRet <= 0 )
1619     {
1620         GetLastError();
1621         mnError = SalPrinterError::General;
1622     }
1623 }
1624 
GetErrorCode()1625 SalPrinterError WinSalPrinter::GetErrorCode()
1626 {
1627     return mnError;
1628 }
1629 
1630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1631