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