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