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