tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / vcl / win / gdi / salprn.cxx
blob393c8c7b1f3a7c7a639cda2a5e001453254c3ea4
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 assert(pWinInfo4 && "Don't handle OOM conditions");
168 if ( EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, reinterpret_cast<LPBYTE>(pWinInfo4), nBytes, &nBytes, &nInfoPrn4 ) )
170 for ( i = 0; i < nInfoPrn4; i++ )
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) );
179 std::free( pWinInfo4 );
183 void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
185 HANDLE hPrinter = nullptr;
186 LPWSTR pPrnName = const_cast<LPWSTR>(o3tl::toW(pInfo->maPrinterName.getStr()));
187 if( OpenPrinterW( pPrnName, &hPrinter, nullptr ) )
189 DWORD nBytes = 0;
190 GetPrinterW( hPrinter, 2, nullptr, 0, &nBytes );
191 if( nBytes )
193 PRINTER_INFO_2W* pWinInfo2 = static_cast<PRINTER_INFO_2W*>(std::malloc(nBytes));
194 assert(pWinInfo2 && "Don't handle OOM conditions");
195 if( GetPrinterW( hPrinter, 2, reinterpret_cast<LPBYTE>(pWinInfo2), nBytes, &nBytes ) )
197 if( pWinInfo2->pDriverName )
198 pInfo->maDriver = o3tl::toU(pWinInfo2->pDriverName);
199 OUString aPortName;
200 if ( pWinInfo2->pPortName )
201 aPortName = o3tl::toU(pWinInfo2->pPortName);
202 // pLocation can be 0 (the Windows docu doesn't describe this)
203 if ( pWinInfo2->pLocation && *pWinInfo2->pLocation )
204 pInfo->maLocation = o3tl::toU(pWinInfo2->pLocation);
205 else
206 pInfo->maLocation = aPortName;
207 // pComment can be 0 (the Windows docu doesn't describe this)
208 if ( pWinInfo2->pComment )
209 pInfo->maComment = o3tl::toU(pWinInfo2->pComment);
210 pInfo->mnStatus = ImplWinQueueStatusToSal( pWinInfo2->Status );
211 pInfo->mnJobs = pWinInfo2->cJobs;
212 if( ! pInfo->moPortName )
213 pInfo->moPortName = aPortName;
215 std::free(pWinInfo2);
217 ClosePrinter( hPrinter );
221 OUString WinSalInstance::GetDefaultPrinter()
223 DWORD nChars = 0;
224 GetDefaultPrinterW( nullptr, &nChars );
225 if( nChars )
227 std::vector<WCHAR> pStr(nChars);
228 if (GetDefaultPrinterW(pStr.data(), &nChars))
229 return OUString(o3tl::toU(pStr.data()));
231 return OUString();
234 static DWORD ImplDeviceCaps( WinSalInfoPrinter const * pPrinter, WORD nCaps,
235 BYTE* pOutput, const ImplJobSetup* pSetupData )
237 DEVMODEW const * pDevMode;
238 if ( !pSetupData || !pSetupData->GetDriverData() )
239 pDevMode = nullptr;
240 else
241 pDevMode = SAL_DEVMODE_W( pSetupData );
243 return DeviceCapabilitiesW( o3tl::toW(pPrinter->maDeviceName.getStr()),
244 o3tl::toW(pPrinter->maPortName.getStr()),
245 nCaps, reinterpret_cast<LPWSTR>(pOutput), pDevMode );
248 static bool ImplTestSalJobSetup( WinSalInfoPrinter const * pPrinter,
249 ImplJobSetup* pSetupData, bool bDelete )
251 if ( pSetupData && pSetupData->GetDriverData() )
253 // signature and size must fit to avoid using
254 // JobSetups from a wrong system
256 // initialize versions from jobsetup
257 // those will be overwritten with driver's version
258 DEVMODEW const * pDevModeW = nullptr;
259 LONG dmSpecVersion = -1;
260 LONG dmDriverVersion = -1;
261 SalDriverData const * pSalDriverData = reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData());
262 BYTE const * pDriverData = reinterpret_cast<BYTE const *>(pSalDriverData) + pSalDriverData->mnDriverOffset;
263 pDevModeW = reinterpret_cast<DEVMODEW const *>(pDriverData);
265 LONG nSysJobSize = -1;
266 if( pPrinter && pDevModeW )
268 // just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
269 // this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
270 // can avoid potential driver crashes as their jobsetups are often not compatible
271 // #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
272 HANDLE hPrn;
273 LPWSTR pPrinterNameW = const_cast<LPWSTR>(o3tl::toW(pPrinter->maDeviceName.getStr()));
274 if ( !OpenPrinterW( pPrinterNameW, &hPrn, nullptr ) )
275 return false;
277 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
278 if( hPrn == HGDI_ERROR )
279 return false;
281 nSysJobSize = DocumentPropertiesW( nullptr, hPrn,
282 pPrinterNameW,
283 nullptr, nullptr, 0 );
285 if( nSysJobSize < 0 )
287 ClosePrinter( hPrn );
288 return false;
290 DEVMODEW *pBuffer = static_cast<DEVMODEW*>(_alloca( nSysJobSize ));
291 LONG nRet = DocumentPropertiesW( nullptr, hPrn,
292 pPrinterNameW,
293 pBuffer, nullptr, DM_OUT_BUFFER );
294 if( nRet < 0 )
296 ClosePrinter( hPrn );
297 return false;
300 // the spec version differs between the windows platforms, ie 98,NT,2000/XP
301 // this allows us to throw away printer settings from other platforms that might crash a buggy driver
302 // we check the driver version as well
303 dmSpecVersion = pBuffer->dmSpecVersion;
304 dmDriverVersion = pBuffer->dmDriverVersion;
306 ClosePrinter( hPrn );
308 SalDriverData const * pSetupDriverData = reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData());
309 if ( (pSetupData->GetSystem() == JOBSETUP_SYSTEM_WINDOWS) &&
310 (pPrinter && pPrinter->maDriverName == pSetupData->GetDriver()) &&
311 (pSetupData->GetDriverDataLen() > sizeof( SalDriverData )) &&
312 static_cast<tools::Long>(pSetupData->GetDriverDataLen() - pSetupDriverData->mnDriverOffset) == nSysJobSize &&
313 pSetupDriverData->mnSysSignature == SAL_DRIVERDATA_SYSSIGN )
315 if( pDevModeW &&
316 (dmSpecVersion == pDevModeW->dmSpecVersion) &&
317 (dmDriverVersion == pDevModeW->dmDriverVersion) )
318 return true;
320 if ( bDelete )
322 pSetupData->SetDriverData( nullptr, 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 std::unique_ptr<sal_uInt8[]> pDriverData;
344 SalDriverData* pOutBuffer = nullptr;
345 BYTE const * pInBuffer = nullptr;
347 LONG nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
348 pPrinterNameW,
349 nullptr, nullptr, 0 );
350 if ( nSysJobSize < 0 )
352 ClosePrinter( hPrn );
353 return false;
356 // make Outputbuffer
357 const std::size_t nDriverDataLen = sizeof(SalDriverData) + nSysJobSize-1;
358 pDriverData = std::make_unique<sal_uInt8[]>( nDriverDataLen );
359 memset(pDriverData.get(), 0, nDriverDataLen);
360 pOutBuffer = reinterpret_cast<SalDriverData*>(pDriverData.get());
361 pOutBuffer->mnSysSignature = SAL_DRIVERDATA_SYSSIGN;
362 // calculate driver data offset including structure padding
363 pOutBuffer->mnDriverOffset = sal::static_int_cast<sal_uInt16>(
364 reinterpret_cast<char*>(pOutBuffer->maDriverData) -
365 reinterpret_cast<char*>(pOutBuffer) );
367 // check if we have a suitable input buffer
368 if ( bIn && ImplTestSalJobSetup( pPrinter, pSetupData, false ) )
370 pInBuffer = pSetupData->GetDriverData() + reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData())->mnDriverOffset;
371 nMode |= DM_IN_BUFFER;
374 // check if the dialog should be shown
375 if ( pVisibleDlgParent )
377 hWnd = pVisibleDlgParent->get_system_data().hWnd;
378 nMode |= DM_IN_PROMPT;
381 // Release mutex, in the other case we don't get paints and so on
382 sal_uInt32 nMutexCount = 0;
383 WinSalInstance* pInst = GetSalData()->mpInstance;
384 if ( pInst && pVisibleDlgParent )
385 nMutexCount = pInst->ReleaseYieldMutex(true);
387 BYTE* pOutDevMode = reinterpret_cast<BYTE*>(pOutBuffer) + pOutBuffer->mnDriverOffset;
388 nRet = DocumentPropertiesW( hWnd, hPrn,
389 pPrinterNameW,
390 reinterpret_cast<LPDEVMODEW>(pOutDevMode), reinterpret_cast<LPDEVMODEW>(const_cast<BYTE *>(pInBuffer)), nMode );
391 if ( pInst && pVisibleDlgParent )
392 pInst->AcquireYieldMutex( nMutexCount );
393 ClosePrinter( hPrn );
395 if( (nRet < 0) || (pVisibleDlgParent && (nRet == IDCANCEL)) )
396 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 pSetupData->SetDriverData(std::move(pDriverData), nDriverDataLen);
414 pSetupData->SetSystem( JOBSETUP_SYSTEM_WINDOWS );
416 return true;
419 static void ImplDevModeToJobSetup( WinSalInfoPrinter const * pPrinter, ImplJobSetup* pSetupData, JobSetFlags nFlags )
421 if ( !pSetupData || !pSetupData->GetDriverData() )
422 return;
424 DEVMODEW const * pDevModeW = SAL_DEVMODE_W(pSetupData);
425 if( pDevModeW == nullptr )
426 return;
428 // Orientation
429 if ( nFlags & JobSetFlags::ORIENTATION )
431 if ( pDevModeW->dmOrientation == DMORIENT_PORTRAIT )
432 pSetupData->SetOrientation( Orientation::Portrait );
433 else if ( pDevModeW->dmOrientation == DMORIENT_LANDSCAPE )
434 pSetupData->SetOrientation( Orientation::Landscape );
437 // PaperBin
438 if ( nFlags & JobSetFlags::PAPERBIN )
440 const DWORD nCount = ImplDeviceCaps( pPrinter, DC_BINS, nullptr, pSetupData );
442 if ( nCount && (nCount != GDI_ERROR) )
444 WORD* pBins = static_cast<WORD*>(rtl_allocateZeroMemory( nCount*sizeof(WORD) ));
445 ImplDeviceCaps( pPrinter, DC_BINS, reinterpret_cast<BYTE*>(pBins), pSetupData );
446 pSetupData->SetPaperBin( 0 );
448 // search the right bin and assign index to mnPaperBin
449 for( DWORD i = 0; i < nCount; ++i )
451 if( pDevModeW->dmDefaultSource == pBins[ i ] )
453 pSetupData->SetPaperBin( static_cast<sal_uInt16>(i) );
454 break;
458 std::free( pBins );
462 // PaperSize
463 if ( nFlags & JobSetFlags::PAPERSIZE )
465 if( (pDevModeW->dmFields & (DM_PAPERWIDTH|DM_PAPERLENGTH)) == (DM_PAPERWIDTH|DM_PAPERLENGTH) )
467 pSetupData->SetPaperWidth( pDevModeW->dmPaperWidth*10 );
468 pSetupData->SetPaperHeight( pDevModeW->dmPaperLength*10 );
470 else
472 const DWORD nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, nullptr, pSetupData );
473 WORD* pPapers = nullptr;
474 const DWORD nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, nullptr, pSetupData );
475 POINT* pPaperSizes = nullptr;
476 if ( nPaperCount && (nPaperCount != GDI_ERROR) )
478 pPapers = static_cast<WORD*>(rtl_allocateZeroMemory(nPaperCount*sizeof(WORD)));
479 ImplDeviceCaps( pPrinter, DC_PAPERS, reinterpret_cast<BYTE*>(pPapers), pSetupData );
481 if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
483 pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT)));
484 ImplDeviceCaps( pPrinter, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );
486 if( nPaperSizeCount == nPaperCount && pPaperSizes && pPapers )
488 for( DWORD i = 0; i < nPaperCount; ++i )
490 if( pPapers[ i ] == pDevModeW->dmPaperSize )
492 pSetupData->SetPaperWidth( pPaperSizes[ i ].x*10 );
493 pSetupData->SetPaperHeight( pPaperSizes[ i ].y*10 );
494 break;
498 if( pPapers )
499 std::free( pPapers );
500 if( pPaperSizes )
501 std::free( pPaperSizes );
503 switch( pDevModeW->dmPaperSize )
505 case DMPAPER_LETTER:
506 pSetupData->SetPaperFormat( PAPER_LETTER );
507 break;
508 case DMPAPER_TABLOID:
509 pSetupData->SetPaperFormat( PAPER_TABLOID );
510 break;
511 case DMPAPER_LEDGER:
512 pSetupData->SetPaperFormat( PAPER_LEDGER );
513 break;
514 case DMPAPER_LEGAL:
515 pSetupData->SetPaperFormat( PAPER_LEGAL );
516 break;
517 case DMPAPER_STATEMENT:
518 pSetupData->SetPaperFormat( PAPER_STATEMENT );
519 break;
520 case DMPAPER_EXECUTIVE:
521 pSetupData->SetPaperFormat( PAPER_EXECUTIVE );
522 break;
523 case DMPAPER_A3:
524 pSetupData->SetPaperFormat( PAPER_A3 );
525 break;
526 case DMPAPER_A4:
527 pSetupData->SetPaperFormat( PAPER_A4 );
528 break;
529 case DMPAPER_A5:
530 pSetupData->SetPaperFormat( PAPER_A5 );
531 break;
532 //See http://wiki.openoffice.org/wiki/DefaultPaperSize
533 //i.e.
534 //http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
535 //DMPAPER_B4 12 B4 (JIS) 257 x 364 mm
536 //http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
537 //also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
538 //matches our Excel filter's belief about the matching XlPaperSize
539 //enumeration.
541 //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
542 ////"DMPAPER_B4 12 B4 (JIS) 250 x 354"
543 //which is bogus as it's either JIS 257 x 364 or ISO 250 x 353
544 //(cmc)
545 case DMPAPER_B4:
546 pSetupData->SetPaperFormat( PAPER_B4_JIS );
547 break;
548 case DMPAPER_B5:
549 pSetupData->SetPaperFormat( PAPER_B5_JIS );
550 break;
551 case DMPAPER_QUARTO:
552 pSetupData->SetPaperFormat( PAPER_QUARTO );
553 break;
554 case DMPAPER_10X14:
555 pSetupData->SetPaperFormat( PAPER_10x14 );
556 break;
557 case DMPAPER_NOTE:
558 pSetupData->SetPaperFormat( PAPER_LETTER );
559 break;
560 case DMPAPER_ENV_9:
561 pSetupData->SetPaperFormat( PAPER_ENV_9 );
562 break;
563 case DMPAPER_ENV_10:
564 pSetupData->SetPaperFormat( PAPER_ENV_10 );
565 break;
566 case DMPAPER_ENV_11:
567 pSetupData->SetPaperFormat( PAPER_ENV_11 );
568 break;
569 case DMPAPER_ENV_12:
570 pSetupData->SetPaperFormat( PAPER_ENV_12 );
571 break;
572 case DMPAPER_ENV_14:
573 pSetupData->SetPaperFormat( PAPER_ENV_14 );
574 break;
575 case DMPAPER_CSHEET:
576 pSetupData->SetPaperFormat( PAPER_C );
577 break;
578 case DMPAPER_DSHEET:
579 pSetupData->SetPaperFormat( PAPER_D );
580 break;
581 case DMPAPER_ESHEET:
582 pSetupData->SetPaperFormat( PAPER_E );
583 break;
584 case DMPAPER_ENV_DL:
585 pSetupData->SetPaperFormat( PAPER_ENV_DL );
586 break;
587 case DMPAPER_ENV_C5:
588 pSetupData->SetPaperFormat( PAPER_ENV_C5 );
589 break;
590 case DMPAPER_ENV_C3:
591 pSetupData->SetPaperFormat( PAPER_ENV_C3 );
592 break;
593 case DMPAPER_ENV_C4:
594 pSetupData->SetPaperFormat( PAPER_ENV_C4 );
595 break;
596 case DMPAPER_ENV_C6:
597 pSetupData->SetPaperFormat( PAPER_ENV_C6 );
598 break;
599 case DMPAPER_ENV_C65:
600 pSetupData->SetPaperFormat( PAPER_ENV_C65 );
601 break;
602 case DMPAPER_ENV_ITALY:
603 pSetupData->SetPaperFormat( PAPER_ENV_ITALY );
604 break;
605 case DMPAPER_ENV_MONARCH:
606 pSetupData->SetPaperFormat( PAPER_ENV_MONARCH );
607 break;
608 case DMPAPER_ENV_PERSONAL:
609 pSetupData->SetPaperFormat( PAPER_ENV_PERSONAL );
610 break;
611 case DMPAPER_FANFOLD_US:
612 pSetupData->SetPaperFormat( PAPER_FANFOLD_US );
613 break;
614 case DMPAPER_FANFOLD_STD_GERMAN:
615 pSetupData->SetPaperFormat( PAPER_FANFOLD_DE );
616 break;
617 case DMPAPER_FANFOLD_LGL_GERMAN:
618 pSetupData->SetPaperFormat( PAPER_FANFOLD_LEGAL_DE );
619 break;
620 case DMPAPER_ISO_B4:
621 pSetupData->SetPaperFormat( PAPER_B4_ISO );
622 break;
623 case DMPAPER_JAPANESE_POSTCARD:
624 pSetupData->SetPaperFormat( PAPER_POSTCARD_JP );
625 break;
626 case DMPAPER_9X11:
627 pSetupData->SetPaperFormat( PAPER_9x11 );
628 break;
629 case DMPAPER_10X11:
630 pSetupData->SetPaperFormat( PAPER_10x11 );
631 break;
632 case DMPAPER_15X11:
633 pSetupData->SetPaperFormat( PAPER_15x11 );
634 break;
635 case DMPAPER_ENV_INVITE:
636 pSetupData->SetPaperFormat( PAPER_ENV_INVITE );
637 break;
638 case DMPAPER_A_PLUS:
639 pSetupData->SetPaperFormat( PAPER_A_PLUS );
640 break;
641 case DMPAPER_B_PLUS:
642 pSetupData->SetPaperFormat( PAPER_B_PLUS );
643 break;
644 case DMPAPER_LETTER_PLUS:
645 pSetupData->SetPaperFormat( PAPER_LETTER_PLUS );
646 break;
647 case DMPAPER_A4_PLUS:
648 pSetupData->SetPaperFormat( PAPER_A4_PLUS );
649 break;
650 case DMPAPER_A2:
651 pSetupData->SetPaperFormat( PAPER_A2 );
652 break;
653 case DMPAPER_DBL_JAPANESE_POSTCARD:
654 pSetupData->SetPaperFormat( PAPER_DOUBLEPOSTCARD_JP );
655 break;
656 case DMPAPER_A6:
657 pSetupData->SetPaperFormat( PAPER_A6 );
658 break;
659 case DMPAPER_B6_JIS:
660 pSetupData->SetPaperFormat( PAPER_B6_JIS );
661 break;
662 case DMPAPER_12X11:
663 pSetupData->SetPaperFormat( PAPER_12x11 );
664 break;
665 default:
666 pSetupData->SetPaperFormat( PAPER_USER );
667 break;
671 if( nFlags & JobSetFlags::DUPLEXMODE )
673 DuplexMode eDuplex = DuplexMode::Unknown;
674 if( pDevModeW->dmFields & DM_DUPLEX )
676 if( pDevModeW->dmDuplex == DMDUP_SIMPLEX )
677 eDuplex = DuplexMode::Off;
678 else if( pDevModeW->dmDuplex == DMDUP_VERTICAL )
679 eDuplex = DuplexMode::LongEdge;
680 else if( pDevModeW->dmDuplex == DMDUP_HORIZONTAL )
681 eDuplex = DuplexMode::ShortEdge;
683 pSetupData->SetDuplexMode( eDuplex );
687 static void ImplJobSetupToDevMode( WinSalInfoPrinter const * pPrinter, const ImplJobSetup* pSetupData, JobSetFlags nFlags )
689 if ( !pSetupData || !pSetupData->GetDriverData() )
690 return;
692 DEVMODEW* pDevModeW = const_cast<DEVMODEW *>(SAL_DEVMODE_W(pSetupData));
693 if( pDevModeW == nullptr )
694 return;
696 // Orientation
697 if ( nFlags & JobSetFlags::ORIENTATION )
699 pDevModeW->dmFields |= DM_ORIENTATION;
700 if ( pSetupData->GetOrientation() == Orientation::Portrait )
701 pDevModeW->dmOrientation = DMORIENT_PORTRAIT;
702 else
703 pDevModeW->dmOrientation = DMORIENT_LANDSCAPE;
706 // PaperBin
707 if ( nFlags & JobSetFlags::PAPERBIN )
709 const DWORD nCount = ImplDeviceCaps( pPrinter, DC_BINS, nullptr, pSetupData );
711 if ( nCount && (nCount != GDI_ERROR) )
713 WORD* pBins = static_cast<WORD*>(rtl_allocateZeroMemory(nCount*sizeof(WORD)));
714 ImplDeviceCaps( pPrinter, DC_BINS, reinterpret_cast<BYTE*>(pBins), pSetupData );
715 pDevModeW->dmFields |= DM_DEFAULTSOURCE;
716 pDevModeW->dmDefaultSource = pBins[ pSetupData->GetPaperBin() ];
717 std::free( pBins );
721 // PaperSize
722 if ( nFlags & JobSetFlags::PAPERSIZE )
724 pDevModeW->dmFields |= DM_PAPERSIZE;
725 pDevModeW->dmPaperWidth = 0;
726 pDevModeW->dmPaperLength = 0;
728 switch( pSetupData->GetPaperFormat() )
730 case PAPER_A2:
731 pDevModeW->dmPaperSize = DMPAPER_A2;
732 break;
733 case PAPER_A3:
734 pDevModeW->dmPaperSize = DMPAPER_A3;
735 break;
736 case PAPER_A4:
737 pDevModeW->dmPaperSize = DMPAPER_A4;
738 break;
739 case PAPER_A5:
740 pDevModeW->dmPaperSize = DMPAPER_A5;
741 break;
742 case PAPER_B4_ISO:
743 pDevModeW->dmPaperSize = DMPAPER_ISO_B4;
744 break;
745 case PAPER_LETTER:
746 pDevModeW->dmPaperSize = DMPAPER_LETTER;
747 break;
748 case PAPER_LEGAL:
749 pDevModeW->dmPaperSize = DMPAPER_LEGAL;
750 break;
751 case PAPER_TABLOID:
752 pDevModeW->dmPaperSize = DMPAPER_TABLOID;
753 break;
755 // http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
756 // DMPAPER_ENV_B6 is documented as:
757 // "DMPAPER_ENV_B6 35 Envelope B6 176 x 125 mm"
758 // which is the wrong way around, it is surely 125 x 176, i.e.
759 // compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
760 // DMPAPER_ENV_B4 33 Envelope B4 250 x 353 mm
761 // DMPAPER_ENV_B5 34 Envelope B5 176 x 250 mm
763 case PAPER_ENV_C4:
764 pDevModeW->dmPaperSize = DMPAPER_ENV_C4;
765 break;
766 case PAPER_ENV_C5:
767 pDevModeW->dmPaperSize = DMPAPER_ENV_C5;
768 break;
769 case PAPER_ENV_C6:
770 pDevModeW->dmPaperSize = DMPAPER_ENV_C6;
771 break;
772 case PAPER_ENV_C65:
773 pDevModeW->dmPaperSize = DMPAPER_ENV_C65;
774 break;
775 case PAPER_ENV_DL:
776 pDevModeW->dmPaperSize = DMPAPER_ENV_DL;
777 break;
778 case PAPER_C:
779 pDevModeW->dmPaperSize = DMPAPER_CSHEET;
780 break;
781 case PAPER_D:
782 pDevModeW->dmPaperSize = DMPAPER_DSHEET;
783 break;
784 case PAPER_E:
785 pDevModeW->dmPaperSize = DMPAPER_ESHEET;
786 break;
787 case PAPER_EXECUTIVE:
788 pDevModeW->dmPaperSize = DMPAPER_EXECUTIVE;
789 break;
790 case PAPER_FANFOLD_LEGAL_DE:
791 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_LGL_GERMAN;
792 break;
793 case PAPER_ENV_MONARCH:
794 pDevModeW->dmPaperSize = DMPAPER_ENV_MONARCH;
795 break;
796 case PAPER_ENV_PERSONAL:
797 pDevModeW->dmPaperSize = DMPAPER_ENV_PERSONAL;
798 break;
799 case PAPER_ENV_9:
800 pDevModeW->dmPaperSize = DMPAPER_ENV_9;
801 break;
802 case PAPER_ENV_10:
803 pDevModeW->dmPaperSize = DMPAPER_ENV_10;
804 break;
805 case PAPER_ENV_11:
806 pDevModeW->dmPaperSize = DMPAPER_ENV_11;
807 break;
808 case PAPER_ENV_12:
809 pDevModeW->dmPaperSize = DMPAPER_ENV_12;
810 break;
811 //See the comments on DMPAPER_B4 above
812 case PAPER_B4_JIS:
813 pDevModeW->dmPaperSize = DMPAPER_B4;
814 break;
815 case PAPER_B5_JIS:
816 pDevModeW->dmPaperSize = DMPAPER_B5;
817 break;
818 case PAPER_B6_JIS:
819 pDevModeW->dmPaperSize = DMPAPER_B6_JIS;
820 break;
821 case PAPER_LEDGER:
822 pDevModeW->dmPaperSize = DMPAPER_LEDGER;
823 break;
824 case PAPER_STATEMENT:
825 pDevModeW->dmPaperSize = DMPAPER_STATEMENT;
826 break;
827 case PAPER_10x14:
828 pDevModeW->dmPaperSize = DMPAPER_10X14;
829 break;
830 case PAPER_ENV_14:
831 pDevModeW->dmPaperSize = DMPAPER_ENV_14;
832 break;
833 case PAPER_ENV_C3:
834 pDevModeW->dmPaperSize = DMPAPER_ENV_C3;
835 break;
836 case PAPER_ENV_ITALY:
837 pDevModeW->dmPaperSize = DMPAPER_ENV_ITALY;
838 break;
839 case PAPER_FANFOLD_US:
840 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_US;
841 break;
842 case PAPER_FANFOLD_DE:
843 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_STD_GERMAN;
844 break;
845 case PAPER_POSTCARD_JP:
846 pDevModeW->dmPaperSize = DMPAPER_JAPANESE_POSTCARD;
847 break;
848 case PAPER_9x11:
849 pDevModeW->dmPaperSize = DMPAPER_9X11;
850 break;
851 case PAPER_10x11:
852 pDevModeW->dmPaperSize = DMPAPER_10X11;
853 break;
854 case PAPER_15x11:
855 pDevModeW->dmPaperSize = DMPAPER_15X11;
856 break;
857 case PAPER_ENV_INVITE:
858 pDevModeW->dmPaperSize = DMPAPER_ENV_INVITE;
859 break;
860 case PAPER_A_PLUS:
861 pDevModeW->dmPaperSize = DMPAPER_A_PLUS;
862 break;
863 case PAPER_B_PLUS:
864 pDevModeW->dmPaperSize = DMPAPER_B_PLUS;
865 break;
866 case PAPER_LETTER_PLUS:
867 pDevModeW->dmPaperSize = DMPAPER_LETTER_PLUS;
868 break;
869 case PAPER_A4_PLUS:
870 pDevModeW->dmPaperSize = DMPAPER_A4_PLUS;
871 break;
872 case PAPER_DOUBLEPOSTCARD_JP:
873 pDevModeW->dmPaperSize = DMPAPER_DBL_JAPANESE_POSTCARD;
874 break;
875 case PAPER_A6:
876 pDevModeW->dmPaperSize = DMPAPER_A6;
877 break;
878 case PAPER_12x11:
879 pDevModeW->dmPaperSize = DMPAPER_12X11;
880 break;
881 default:
883 short nPaper = 0;
884 const DWORD nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, nullptr, pSetupData );
885 WORD* pPapers = nullptr;
886 const DWORD nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, nullptr, pSetupData );
887 POINT* pPaperSizes = nullptr;
888 DWORD nLandscapeAngle = ImplDeviceCaps( pPrinter, DC_ORIENTATION, nullptr, pSetupData );
889 if ( nPaperCount && (nPaperCount != GDI_ERROR) )
891 pPapers = static_cast<WORD*>(rtl_allocateZeroMemory(nPaperCount*sizeof(WORD)));
892 ImplDeviceCaps( pPrinter, DC_PAPERS, reinterpret_cast<BYTE*>(pPapers), pSetupData );
894 if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
896 pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT)));
897 ImplDeviceCaps( pPrinter, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );
899 if ( (nPaperSizeCount == nPaperCount) && pPapers && pPaperSizes )
901 PaperInfo aInfo(pSetupData->GetPaperWidth(), pSetupData->GetPaperHeight());
902 // compare paper formats and select a good match
903 for ( DWORD i = 0; i < nPaperCount; ++i )
905 if ( aInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)))
907 nPaper = pPapers[i];
908 break;
912 // If the printer supports landscape orientation, check paper sizes again
913 // with landscape orientation. This is necessary as a printer driver provides
914 // all paper sizes with portrait orientation only!!
915 if ( !nPaper && nLandscapeAngle != 0 )
917 PaperInfo aRotatedInfo(pSetupData->GetPaperHeight(), pSetupData->GetPaperWidth());
918 for ( DWORD i = 0; i < nPaperCount; ++i )
920 if ( aRotatedInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)) )
922 nPaper = pPapers[i];
923 break;
928 if ( nPaper )
929 pDevModeW->dmPaperSize = nPaper;
932 if ( !nPaper )
934 pDevModeW->dmFields |= DM_PAPERLENGTH | DM_PAPERWIDTH;
935 pDevModeW->dmPaperSize = DMPAPER_USER;
936 pDevModeW->dmPaperWidth = static_cast<short>(pSetupData->GetPaperWidth()/10);
937 pDevModeW->dmPaperLength = static_cast<short>(pSetupData->GetPaperHeight()/10);
940 if ( pPapers )
941 std::free(pPapers);
942 if ( pPaperSizes )
943 std::free(pPaperSizes);
945 break;
949 if( nFlags & JobSetFlags::DUPLEXMODE )
951 switch( pSetupData->GetDuplexMode() )
953 case DuplexMode::Off:
954 pDevModeW->dmFields |= DM_DUPLEX;
955 pDevModeW->dmDuplex = DMDUP_SIMPLEX;
956 break;
957 case DuplexMode::ShortEdge:
958 pDevModeW->dmFields |= DM_DUPLEX;
959 pDevModeW->dmDuplex = DMDUP_HORIZONTAL;
960 break;
961 case DuplexMode::LongEdge:
962 pDevModeW->dmFields |= DM_DUPLEX;
963 pDevModeW->dmDuplex = DMDUP_VERTICAL;
964 break;
965 case DuplexMode::Unknown:
966 break;
971 static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
972 LPCWSTR pDevice,
973 DEVMODEW const * pDevMode )
975 HDC hDC = nullptr;
976 CATCH_DRIVER_EX_BEGIN;
977 hDC = CreateICW( pDriver, pDevice, nullptr, pDevMode );
978 CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
979 return hDC;
982 static HDC ImplCreateSalPrnIC( WinSalInfoPrinter const * pPrinter, const ImplJobSetup* pSetupData )
984 HDC hDC = nullptr;
985 DEVMODEW const * pDevMode;
986 if ( pSetupData && pSetupData->GetDriverData() )
987 pDevMode = SAL_DEVMODE_W( pSetupData );
988 else
989 pDevMode = nullptr;
990 // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
991 // pl: does this hold true for Unicode functions ?
992 if( pPrinter->maDriverName.getLength() > 2048 || pPrinter->maDeviceName.getLength() > 2048 )
993 return nullptr;
994 sal_Unicode pDriverName[ 4096 ];
995 sal_Unicode pDeviceName[ 4096 ];
996 memcpy( pDriverName, pPrinter->maDriverName.getStr(), pPrinter->maDriverName.getLength()*sizeof(sal_Unicode));
997 memset( pDriverName+pPrinter->maDriverName.getLength(), 0, 32 );
998 memcpy( pDeviceName, pPrinter->maDeviceName.getStr(), pPrinter->maDeviceName.getLength()*sizeof(sal_Unicode));
999 memset( pDeviceName+pPrinter->maDeviceName.getLength(), 0, 32 );
1000 hDC = ImplCreateICW_WithCatch( o3tl::toW(pDriverName),
1001 o3tl::toW(pDeviceName),
1002 pDevMode );
1003 return hDC;
1006 static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC )
1008 WinSalGraphics* pGraphics = new WinSalGraphics(WinSalGraphics::PRINTER, false, nullptr, /* CHECKME */ nullptr);
1009 pGraphics->SetLayout( SalLayoutFlags::NONE );
1010 pGraphics->setHDC(hDC);
1011 return pGraphics;
1014 static bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, const ImplJobSetup* pSetupData )
1016 HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1017 if ( !hNewDC )
1018 return false;
1020 pPrinter->setHDC(hNewDC);
1021 return true;
1025 SalInfoPrinter* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
1026 ImplJobSetup* pSetupData )
1028 WinSalInfoPrinter* pPrinter = new WinSalInfoPrinter;
1029 if( ! pQueueInfo->moPortName )
1030 GetPrinterQueueState( pQueueInfo );
1031 pPrinter->maDriverName = pQueueInfo->maDriver;
1032 pPrinter->maDeviceName = pQueueInfo->maPrinterName;
1033 pPrinter->maPortName = pQueueInfo->moPortName ? *pQueueInfo->moPortName : OUString();
1035 // check if the provided setup data match the actual printer
1036 ImplTestSalJobSetup( pPrinter, pSetupData, true );
1038 HDC hDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1039 if ( !hDC )
1041 delete pPrinter;
1042 return nullptr;
1045 pPrinter->setHDC(hDC);
1046 if ( !pSetupData->GetDriverData() )
1047 ImplUpdateSalJobSetup( pPrinter, pSetupData, false, nullptr );
1048 ImplDevModeToJobSetup( pPrinter, pSetupData, JobSetFlags::ALL );
1049 pSetupData->SetSystem( JOBSETUP_SYSTEM_WINDOWS );
1051 return pPrinter;
1054 void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
1056 delete pPrinter;
1060 WinSalInfoPrinter::WinSalInfoPrinter() :
1061 m_hDC(nullptr),
1062 m_pGraphics(nullptr),
1063 m_bGraphics(false)
1065 m_bPapersInit = false;
1068 WinSalInfoPrinter::~WinSalInfoPrinter()
1070 setHDC(nullptr);
1073 void WinSalInfoPrinter::setHDC(HDC hNewDC)
1075 assert(!m_bGraphics);
1077 if (m_hDC)
1079 assert(!m_pGraphics || m_hDC == m_pGraphics->getHDC());
1080 delete m_pGraphics;
1081 m_pGraphics = nullptr;
1082 DeleteDC(m_hDC);
1085 m_hDC = hNewDC;
1088 void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
1090 m_aPaperFormats.clear();
1092 DWORD nCount = ImplDeviceCaps( this, DC_PAPERSIZE, nullptr, pSetupData );
1093 if( nCount == GDI_ERROR )
1094 nCount = 0;
1096 if( nCount )
1098 POINT* pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nCount*sizeof(POINT)));
1099 ImplDeviceCaps( this, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );
1101 sal_Unicode* pNamesBuffer = static_cast<sal_Unicode*>(std::malloc(nCount*64*sizeof(sal_Unicode)));
1102 ImplDeviceCaps( this, DC_PAPERNAMES, reinterpret_cast<BYTE*>(pNamesBuffer), pSetupData );
1104 SAL_INFO("vcl.print", "DC_PAPERSIZE sizes (mm) from printer: " << DC_PAPERSIZE_array_to_string(pPaperSizes, nCount));
1106 for( DWORD i = 0; i < nCount; ++i )
1108 PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
1109 m_aPaperFormats.push_back( aInfo );
1111 std::free( pNamesBuffer );
1112 std::free( pPaperSizes );
1115 m_bPapersInit = true;
1118 int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
1120 const DWORD nRet = ImplDeviceCaps( this, DC_ORIENTATION, nullptr, pSetupData );
1122 if( nRet != GDI_ERROR )
1123 return static_cast<int>(nRet) * 10;
1124 return 900; // guess
1127 SalGraphics* WinSalInfoPrinter::AcquireGraphics()
1129 assert(m_hDC);
1130 if (m_bGraphics)
1131 return nullptr;
1133 if (!m_pGraphics)
1134 m_pGraphics = ImplCreateSalPrnGraphics(m_hDC);
1135 if (m_pGraphics)
1136 m_bGraphics = true;
1138 return m_pGraphics;
1141 void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
1143 m_bGraphics = false;
1146 bool WinSalInfoPrinter::Setup(weld::Window* pFrame, ImplJobSetup* pSetupData)
1148 if ( ImplUpdateSalJobSetup(this, pSetupData, true, pFrame))
1150 ImplDevModeToJobSetup( this, pSetupData, JobSetFlags::ALL );
1151 return ImplUpdateSalPrnIC( this, pSetupData );
1154 return false;
1157 bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
1159 if ( !ImplTestSalJobSetup( this, pSetupData, false ) )
1160 return false;
1161 return ImplUpdateSalPrnIC( this, pSetupData );
1164 bool WinSalInfoPrinter::SetData( JobSetFlags nFlags, ImplJobSetup* pSetupData )
1166 ImplJobSetupToDevMode( this, pSetupData, nFlags );
1167 if ( ImplUpdateSalJobSetup( this, pSetupData, true, nullptr ) )
1169 ImplDevModeToJobSetup( this, pSetupData, nFlags );
1170 return ImplUpdateSalPrnIC( this, pSetupData );
1173 return false;
1176 sal_uInt16 WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
1178 DWORD nRet = ImplDeviceCaps( this, DC_BINS, nullptr, pSetupData );
1179 if ( nRet && (nRet != GDI_ERROR) )
1180 return nRet;
1181 else
1182 return 0;
1185 OUString WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pSetupData, sal_uInt16 nPaperBin )
1187 OUString aPaperBinName;
1189 DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, nullptr, pSetupData );
1190 if ( (nPaperBin < nBins) && (nBins != GDI_ERROR) )
1192 auto pBuffer = std::make_unique<sal_Unicode[]>(nBins*24);
1193 DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, reinterpret_cast<BYTE*>(pBuffer.get()), pSetupData );
1194 if ( nRet && (nRet != GDI_ERROR) )
1195 aPaperBinName = OUString( pBuffer.get() + (nPaperBin*24) );
1198 return aPaperBinName;
1201 sal_uInt16 WinSalInfoPrinter::GetPaperBinBySourceIndex( const ImplJobSetup* pSetupData, sal_uInt16 nPaperSource )
1203 DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, nullptr, pSetupData );
1204 if (nBins != GDI_ERROR)
1206 auto pBuffer = std::make_unique<sal_uInt16[]>(nBins);
1207 nBins = ImplDeviceCaps( this, DC_BINS, reinterpret_cast<BYTE*>(pBuffer.get()), pSetupData );
1208 if (nBins != GDI_ERROR)
1210 for (DWORD nBin = 0; nBin < nBins; ++nBin)
1212 if (nPaperSource == *(pBuffer.get() + nBin))
1213 return nBin;
1217 return 0xffff;
1220 sal_uInt16 WinSalInfoPrinter::GetSourceIndexByPaperBin(const ImplJobSetup* pSetupData, sal_uInt16 nPaperBin)
1222 DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, nullptr, pSetupData );
1223 if (nBins != GDI_ERROR)
1225 auto pBuffer = std::make_unique<sal_uInt16[]>(nBins);
1226 nBins = ImplDeviceCaps( this, DC_BINS, reinterpret_cast<BYTE*>(pBuffer.get()), pSetupData );
1227 if (nBins != GDI_ERROR && nBins > nPaperBin)
1229 return *(pBuffer.get() + nPaperBin);
1232 return 0;
1236 sal_uInt32 WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, PrinterCapType nType )
1238 DWORD nRet;
1240 switch ( nType )
1242 case PrinterCapType::SupportDialog:
1243 return TRUE;
1244 case PrinterCapType::Copies:
1245 nRet = ImplDeviceCaps( this, DC_COPIES, nullptr, pSetupData );
1246 if ( nRet && (nRet != GDI_ERROR) )
1247 return nRet;
1248 return 0;
1249 case PrinterCapType::CollateCopies:
1250 nRet = ImplDeviceCaps( this, DC_COLLATE, nullptr, pSetupData );
1251 if ( nRet && (nRet != GDI_ERROR) )
1253 nRet = ImplDeviceCaps( this, DC_COPIES, nullptr, pSetupData );
1254 if ( nRet && (nRet != GDI_ERROR) )
1255 return nRet;
1257 return 0;
1259 case PrinterCapType::SetOrientation:
1260 nRet = ImplDeviceCaps( this, DC_ORIENTATION, nullptr, pSetupData );
1261 if ( nRet && (nRet != GDI_ERROR) )
1262 return TRUE;
1263 return FALSE;
1265 case PrinterCapType::SetPaperSize:
1266 case PrinterCapType::SetPaper:
1267 nRet = ImplDeviceCaps( this, DC_PAPERS, nullptr, pSetupData );
1268 if ( nRet && (nRet != GDI_ERROR) )
1269 return TRUE;
1270 return FALSE;
1272 default:
1273 break;
1276 return 0;
1279 void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
1280 tools::Long& rOutWidth, tools::Long& rOutHeight,
1281 Point& rPageOffset,
1282 Size& rPaperSize )
1284 HDC hDC = m_hDC;
1286 rOutWidth = GetDeviceCaps( hDC, HORZRES );
1287 rOutHeight = GetDeviceCaps( hDC, VERTRES );
1289 rPageOffset.setX( GetDeviceCaps( hDC, PHYSICALOFFSETX ) );
1290 rPageOffset.setY( GetDeviceCaps( hDC, PHYSICALOFFSETY ) );
1291 rPaperSize.setWidth( GetDeviceCaps( hDC, PHYSICALWIDTH ) );
1292 rPaperSize.setHeight( GetDeviceCaps( hDC, PHYSICALHEIGHT ) );
1296 std::unique_ptr<SalPrinter> WinSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
1298 WinSalPrinter* pPrinter = new WinSalPrinter;
1299 pPrinter->mpInfoPrinter = static_cast<WinSalInfoPrinter*>(pInfoPrinter);
1300 return std::unique_ptr<SalPrinter>(pPrinter);
1303 static BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
1305 SalData* pSalData = GetSalData();
1306 WinSalPrinter* pPrinter;
1307 int i = 0;
1308 bool bWhile = true;
1310 // Ensure we handle the mutex which will be released in WinSalInstance::DoYield
1311 SolarMutexGuard aSolarMutexGuard;
1314 // process messages
1315 bWhile = Application::Reschedule( true );
1316 if (i > 15)
1317 bWhile = false;
1318 else
1319 ++i;
1321 pPrinter = pSalData->mpFirstPrinter;
1322 while ( pPrinter )
1324 if( pPrinter->mhDC == hPrnDC )
1325 break;
1327 pPrinter = pPrinter->mpNextPrinter;
1330 if ( !pPrinter || pPrinter->mbAbort )
1331 return FALSE;
1333 while ( bWhile );
1335 return TRUE;
1338 static DEVMODEW const * ImplSalSetCopies( DEVMODEW const * pDevMode, sal_uInt32 nCopies, bool bCollate )
1340 if ( pDevMode && (nCopies > 1) )
1342 if ( nCopies > 32765 )
1343 nCopies = 32765;
1344 sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
1345 LPDEVMODEW pNewDevMode = static_cast<LPDEVMODEW>(std::malloc( nDevSize ));
1346 assert(pNewDevMode); // Don't handle OOM conditions
1347 memcpy( pNewDevMode, pDevMode, nDevSize );
1348 pNewDevMode->dmFields |= DM_COPIES;
1349 pNewDevMode->dmCopies = static_cast<short>(static_cast<sal_uInt16>(nCopies));
1350 pNewDevMode->dmFields |= DM_COLLATE;
1351 if ( bCollate )
1352 pNewDevMode->dmCollate = DMCOLLATE_TRUE;
1353 else
1354 pNewDevMode->dmCollate = DMCOLLATE_FALSE;
1355 return pNewDevMode;
1357 else
1359 return pDevMode;
1364 WinSalPrinter::WinSalPrinter() :
1365 mpInfoPrinter( nullptr ),
1366 mpNextPrinter( nullptr ),
1367 mhDC( nullptr ),
1368 mnError( SalPrinterError::NONE ),
1369 mnCopies( 0 ),
1370 mbCollate( false ),
1371 mbAbort( false ),
1372 mbValid( true )
1374 SalData* pSalData = GetSalData();
1375 // insert printer in printerlist
1376 mpNextPrinter = pSalData->mpFirstPrinter;
1377 pSalData->mpFirstPrinter = this;
1380 WinSalPrinter::~WinSalPrinter()
1382 SalData* pSalData = GetSalData();
1384 // release DC if there is one still around because of AbortJob
1385 HDC hDC = mhDC;
1386 if ( hDC )
1388 // explicitly reset(), so the mxGraphics's borrowed HDC defaults are
1389 // restored and WinSalGraphics's destructor won't work on a deleted HDC.
1390 mxGraphics.reset();
1391 DeleteDC( hDC );
1394 // remove printer from printerlist
1395 if ( this == pSalData->mpFirstPrinter )
1396 pSalData->mpFirstPrinter = mpNextPrinter;
1397 else
1399 WinSalPrinter* pTempPrinter = pSalData->mpFirstPrinter;
1401 while( pTempPrinter->mpNextPrinter != this )
1402 pTempPrinter = pTempPrinter->mpNextPrinter;
1404 pTempPrinter->mpNextPrinter = mpNextPrinter;
1408 void WinSalPrinter::markInvalid()
1410 mbValid = false;
1413 // need wrappers for StarTocW/A to use structured exception handling
1414 // since SEH does not mix with standard exception handling's cleanup
1415 static int lcl_StartDocW1( HDC hDC, DOCINFOW const * pInfo, WinSalPrinter* pPrt )
1417 int nRet = 0;
1418 CATCH_DRIVER_EX_BEGIN;
1419 nRet = ::StartDocW( hDC, pInfo );
1420 CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
1421 return nRet;
1424 static int lcl_StartDocW( HDC hDC, DOCINFOW const * pInfo, WinSalPrinter* pPrt )
1426 //tdf#127547 - Freeze/crash in Microsoft Print to PDF dialog, if we try to paste while
1427 // executing the StartDocW method, Windows will call back into us on a separate thread,
1428 // where we will attempt to take the SolarMutex.
1429 SolarMutexReleaser aReleaser;
1431 return lcl_StartDocW1(hDC, pInfo, pPrt);
1434 bool WinSalPrinter::StartJob( const OUString* pFileName,
1435 const OUString& rJobName,
1436 const OUString&,
1437 sal_uInt32 nCopies,
1438 bool bCollate,
1439 bool /*bDirect*/,
1440 ImplJobSetup* pSetupData )
1442 mnError = SalPrinterError::NONE;
1443 mbAbort = false;
1444 mnCopies = nCopies;
1445 mbCollate = bCollate;
1447 DEVMODEW const * pOrgDevModeW = nullptr;
1448 DEVMODEW const * pDevModeW = nullptr;
1449 HDC hDC = nullptr;
1450 if ( pSetupData && pSetupData->GetDriverData() )
1452 pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
1453 pDevModeW = ImplSalSetCopies( pOrgDevModeW, nCopies, bCollate );
1456 // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
1457 sal_Unicode aDrvBuf[4096];
1458 sal_Unicode aDevBuf[4096];
1459 memcpy( aDrvBuf, mpInfoPrinter->maDriverName.getStr(), (mpInfoPrinter->maDriverName.getLength()+1)*sizeof(sal_Unicode));
1460 memcpy( aDevBuf, mpInfoPrinter->maDeviceName.getStr(), (mpInfoPrinter->maDeviceName.getLength()+1)*sizeof(sal_Unicode));
1461 hDC = CreateDCW( o3tl::toW(aDrvBuf),
1462 o3tl::toW(aDevBuf),
1463 nullptr,
1464 pDevModeW );
1466 if ( pDevModeW != pOrgDevModeW )
1467 std::free( const_cast<DEVMODEW *>(pDevModeW) );
1469 if ( !hDC )
1471 mnError = SalPrinterError::General;
1472 return false;
1475 // make sure mhDC is set before the printer driver may call our abortproc
1476 mhDC = hDC;
1477 if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
1479 mnError = SalPrinterError::General;
1480 return false;
1483 mnError = SalPrinterError::NONE;
1484 mbAbort = false;
1486 // As the Telecom Balloon Fax driver tends to send messages repeatedly
1487 // we try to process first all, and then insert a dummy message
1488 for (int i = 0; Application::Reschedule( true ) && i <= 15; ++i);
1489 bool const ret = PostMessageW(GetSalData()->mpInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0);
1490 SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
1492 // bring up a file chooser if printing to file port but no file name given
1493 OUString aOutFileName;
1494 if( mpInfoPrinter->maPortName.equalsIgnoreAsciiCase( "FILE:" ) && (!pFileName || pFileName->isEmpty()) )
1497 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1498 uno::Reference< XFilePicker3 > xFilePicker = FilePicker::createWithMode(xContext, TemplateDescription::FILESAVE_SIMPLE);
1500 if( xFilePicker->execute() == ExecutableDialogResults::OK )
1502 Sequence< OUString > aPathSeq( xFilePicker->getSelectedFiles() );
1503 INetURLObject aObj( aPathSeq[0] );
1504 aOutFileName = aObj.PathToFileName();
1506 else
1508 mnError = SalPrinterError::Abort;
1509 return false;
1513 DOCINFOW aInfo = {};
1514 aInfo.cbSize = sizeof( aInfo );
1515 aInfo.lpszDocName = o3tl::toW(rJobName.getStr());
1516 if ( pFileName || aOutFileName.getLength() )
1518 if ( (pFileName && !pFileName->isEmpty()) || aOutFileName.getLength() )
1520 aInfo.lpszOutput = o3tl::toW((pFileName && !pFileName->isEmpty()) ? pFileName->getStr() : aOutFileName.getStr());
1522 else
1523 aInfo.lpszOutput = L"FILE:";
1525 else
1526 aInfo.lpszOutput = nullptr;
1528 // start Job, in the main thread
1529 int nRet = vcl::solarthread::syncExecute([hDC, this, &aInfo]() -> int { return lcl_StartDocW(hDC, &aInfo, this); });
1531 if ( nRet <= 0 )
1533 DWORD nError = GetLastError();
1534 if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
1535 mnError = SalPrinterError::Abort;
1536 else
1537 mnError = SalPrinterError::General;
1538 return false;
1541 return true;
1544 void WinSalPrinter::DoEndDoc(HDC hDC)
1546 CATCH_DRIVER_EX_BEGIN;
1547 if( ::EndDoc( hDC ) <= 0 )
1548 GetLastError();
1549 CATCH_DRIVER_EX_END( "exception in EndDoc", this );
1552 bool WinSalPrinter::EndJob()
1554 HDC hDC = mhDC;
1555 if (isValid())
1557 mxGraphics.reset();
1559 // #i54419# Windows fax printer brings up a dialog in EndDoc
1560 // which text previously copied in soffice process can be
1561 // pasted to -> deadlock due to mutex not released.
1562 // it should be safe to release the yield mutex over the EndDoc
1563 // call, however the real solution is supposed to be the threading
1564 // framework yet to come.
1566 SolarMutexReleaser aReleaser;
1567 DoEndDoc( hDC );
1569 DeleteDC( hDC );
1570 mhDC = nullptr;
1573 return true;
1576 SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, bool bNewJobData )
1578 if (!isValid())
1579 return nullptr;
1581 HDC hDC = mhDC;
1582 if ( pSetupData && pSetupData->GetDriverData() && bNewJobData )
1584 DEVMODEW const * pOrgDevModeW;
1585 DEVMODEW const * pDevModeW;
1586 pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
1587 pDevModeW = ImplSalSetCopies( pOrgDevModeW, mnCopies, mbCollate );
1588 ResetDCW( hDC, pDevModeW );
1589 if ( pDevModeW != pOrgDevModeW )
1590 std::free( const_cast<DEVMODEW *>(pDevModeW) );
1592 volatile int nRet = 0;
1593 CATCH_DRIVER_EX_BEGIN;
1594 nRet = ::StartPage( hDC );
1595 CATCH_DRIVER_EX_END( "exception in StartPage", this );
1597 if ( nRet <= 0 )
1599 GetLastError();
1600 mnError = SalPrinterError::General;
1601 return nullptr;
1604 // Hack to work around old PostScript printer drivers optimizing away empty pages
1605 // TODO: move into ImplCreateSalPrnGraphics()?
1606 HPEN hTempPen = SelectPen( hDC, GetStockPen( NULL_PEN ) );
1607 HBRUSH hTempBrush = SelectBrush( hDC, GetStockBrush( NULL_BRUSH ) );
1608 Rectangle( hDC, -8000, -8000, -7999, -7999 );
1609 SelectPen( hDC, hTempPen );
1610 SelectBrush( hDC, hTempBrush );
1612 mxGraphics.reset(ImplCreateSalPrnGraphics( hDC ));
1613 return mxGraphics.get();
1616 void WinSalPrinter::EndPage()
1618 mxGraphics.reset();
1620 if (!isValid())
1621 return;
1623 HDC hDC = mhDC;
1624 volatile int nRet = 0;
1625 CATCH_DRIVER_EX_BEGIN;
1626 nRet = ::EndPage( hDC );
1627 CATCH_DRIVER_EX_END( "exception in EndPage", this );
1629 if ( nRet <= 0 )
1631 GetLastError();
1632 mnError = SalPrinterError::General;
1636 SalPrinterError WinSalPrinter::GetErrorCode()
1638 return mnError;
1641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */