1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
30 #include <osl/module.h>
31 #include <o3tl/char16_t2wchar_t.hxx>
33 #include <tools/urlobj.hxx>
35 #include <vcl/weld.hxx>
36 #include <vcl/QueueInfo.hxx>
38 #include <win/wincomp.hxx>
39 #include <win/saldata.hxx>
40 #include <win/salinst.h>
41 #include <win/salgdi.h>
42 #include <win/salframe.h>
43 #include <win/salprn.h>
45 #include <salptype.hxx>
49 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
50 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
51 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
52 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
53 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
54 #include <com/sun/star/lang/XInitialization.hpp>
55 #include <comphelper/processfactory.hxx>
56 #include <comphelper/windowsdebugoutput.hxx>
58 #include <vcl/threadex.hxx>
63 #if defined GetDefaultPrinter
64 # undef GetDefaultPrinter
66 #if defined SetPrinterData
67 # undef SetPrinterData
70 #define CATCH_DRIVER_EX_BEGIN \
73 #define CATCH_DRIVER_EX_END(mes, p) \
75 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
80 #define CATCH_DRIVER_EX_END_2(mes) \
82 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
87 using namespace com::sun::star
;
88 using namespace com::sun::star::uno
;
89 using namespace com::sun::star::lang
;
90 using namespace com::sun::star::ui::dialogs
;
92 static DEVMODEW
const * SAL_DEVMODE_W( const ImplJobSetup
* pSetupData
)
94 DEVMODEW
const * pRet
= nullptr;
95 SalDriverData
const * pDrv
= reinterpret_cast<SalDriverData
const *>(pSetupData
->GetDriverData());
96 if( pSetupData
->GetDriverDataLen() >= sizeof(DEVMODEW
)+sizeof(SalDriverData
)-1 )
97 pRet
= reinterpret_cast<DEVMODEW
const *>((pSetupData
->GetDriverData()) + (pDrv
->mnDriverOffset
));
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
;
158 void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList
* pList
)
163 EnumPrintersW( PRINTER_ENUM_LOCAL
| PRINTER_ENUM_CONNECTIONS
, nullptr, 4, nullptr, 0, &nBytes
, &nInfoPrn4
);
166 PRINTER_INFO_4W
* pWinInfo4
= static_cast<PRINTER_INFO_4W
*>(std::malloc( nBytes
));
167 assert(pWinInfo4
&& "Don't handle OOM conditions");
168 if ( EnumPrintersW( PRINTER_ENUM_LOCAL
| PRINTER_ENUM_CONNECTIONS
, nullptr, 4, reinterpret_cast<LPBYTE
>(pWinInfo4
), nBytes
, &nBytes
, &nInfoPrn4
) )
170 for ( i
= 0; i
< nInfoPrn4
; i
++ )
172 std::unique_ptr
<SalPrinterQueueInfo
> pInfo(new SalPrinterQueueInfo
);
173 pInfo
->maPrinterName
= o3tl::toU(pWinInfo4
[i
].pPrinterName
);
174 pInfo
->mnStatus
= PrintQueueFlags::NONE
;
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 ) )
190 GetPrinterW( hPrinter
, 2, nullptr, 0, &nBytes
);
193 PRINTER_INFO_2W
* pWinInfo2
= static_cast<PRINTER_INFO_2W
*>(std::malloc(nBytes
));
194 assert(pWinInfo2
&& "Don't handle OOM conditions");
195 if( GetPrinterW( hPrinter
, 2, reinterpret_cast<LPBYTE
>(pWinInfo2
), nBytes
, &nBytes
) )
197 if( pWinInfo2
->pDriverName
)
198 pInfo
->maDriver
= o3tl::toU(pWinInfo2
->pDriverName
);
200 if ( pWinInfo2
->pPortName
)
201 aPortName
= o3tl::toU(pWinInfo2
->pPortName
);
202 // pLocation can be 0 (the Windows docu doesn't describe this)
203 if ( pWinInfo2
->pLocation
&& *pWinInfo2
->pLocation
)
204 pInfo
->maLocation
= o3tl::toU(pWinInfo2
->pLocation
);
206 pInfo
->maLocation
= aPortName
;
207 // pComment can be 0 (the Windows docu doesn't describe this)
208 if ( pWinInfo2
->pComment
)
209 pInfo
->maComment
= o3tl::toU(pWinInfo2
->pComment
);
210 pInfo
->mnStatus
= ImplWinQueueStatusToSal( pWinInfo2
->Status
);
211 pInfo
->mnJobs
= pWinInfo2
->cJobs
;
212 if( ! pInfo
->moPortName
)
213 pInfo
->moPortName
= aPortName
;
215 std::free(pWinInfo2
);
217 ClosePrinter( hPrinter
);
221 OUString
WinSalInstance::GetDefaultPrinter()
224 GetDefaultPrinterW( nullptr, &nChars
);
227 std::vector
<WCHAR
> pStr(nChars
);
228 if (GetDefaultPrinterW(pStr
.data(), &nChars
))
229 return OUString(o3tl::toU(pStr
.data()));
234 static DWORD
ImplDeviceCaps( WinSalInfoPrinter
const * pPrinter
, WORD nCaps
,
235 BYTE
* pOutput
, const ImplJobSetup
* pSetupData
)
237 DEVMODEW
const * pDevMode
;
238 if ( !pSetupData
|| !pSetupData
->GetDriverData() )
241 pDevMode
= SAL_DEVMODE_W( pSetupData
);
243 return DeviceCapabilitiesW( o3tl::toW(pPrinter
->maDeviceName
.getStr()),
244 o3tl::toW(pPrinter
->maPortName
.getStr()),
245 nCaps
, reinterpret_cast<LPWSTR
>(pOutput
), pDevMode
);
248 static bool ImplTestSalJobSetup( WinSalInfoPrinter
const * pPrinter
,
249 ImplJobSetup
* pSetupData
, bool bDelete
)
251 if ( pSetupData
&& pSetupData
->GetDriverData() )
253 // signature and size must fit to avoid using
254 // JobSetups from a wrong system
256 // initialize versions from jobsetup
257 // those will be overwritten with driver's version
258 DEVMODEW
const * pDevModeW
= nullptr;
259 LONG dmSpecVersion
= -1;
260 LONG dmDriverVersion
= -1;
261 SalDriverData
const * pSalDriverData
= reinterpret_cast<SalDriverData
const *>(pSetupData
->GetDriverData());
262 BYTE
const * pDriverData
= reinterpret_cast<BYTE
const *>(pSalDriverData
) + pSalDriverData
->mnDriverOffset
;
263 pDevModeW
= reinterpret_cast<DEVMODEW
const *>(pDriverData
);
265 LONG nSysJobSize
= -1;
266 if( pPrinter
&& pDevModeW
)
268 // just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
269 // this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
270 // can avoid potential driver crashes as their jobsetups are often not compatible
271 // #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
273 LPWSTR pPrinterNameW
= const_cast<LPWSTR
>(o3tl::toW(pPrinter
->maDeviceName
.getStr()));
274 if ( !OpenPrinterW( pPrinterNameW
, &hPrn
, nullptr ) )
277 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
278 if( hPrn
== HGDI_ERROR
)
281 nSysJobSize
= DocumentPropertiesW( nullptr, hPrn
,
283 nullptr, nullptr, 0 );
285 if( nSysJobSize
< 0 )
287 ClosePrinter( hPrn
);
290 DEVMODEW
*pBuffer
= static_cast<DEVMODEW
*>(_alloca( nSysJobSize
));
291 LONG nRet
= DocumentPropertiesW( nullptr, hPrn
,
293 pBuffer
, nullptr, DM_OUT_BUFFER
);
296 ClosePrinter( hPrn
);
300 // the spec version differs between the windows platforms, ie 98,NT,2000/XP
301 // this allows us to throw away printer settings from other platforms that might crash a buggy driver
302 // we check the driver version as well
303 dmSpecVersion
= pBuffer
->dmSpecVersion
;
304 dmDriverVersion
= pBuffer
->dmDriverVersion
;
306 ClosePrinter( hPrn
);
308 SalDriverData
const * pSetupDriverData
= reinterpret_cast<SalDriverData
const *>(pSetupData
->GetDriverData());
309 if ( (pSetupData
->GetSystem() == JOBSETUP_SYSTEM_WINDOWS
) &&
310 (pPrinter
&& pPrinter
->maDriverName
== pSetupData
->GetDriver()) &&
311 (pSetupData
->GetDriverDataLen() > sizeof( SalDriverData
)) &&
312 static_cast<tools::Long
>(pSetupData
->GetDriverDataLen() - pSetupDriverData
->mnDriverOffset
) == nSysJobSize
&&
313 pSetupDriverData
->mnSysSignature
== SAL_DRIVERDATA_SYSSIGN
)
316 (dmSpecVersion
== pDevModeW
->dmSpecVersion
) &&
317 (dmDriverVersion
== pDevModeW
->dmDriverVersion
) )
322 pSetupData
->SetDriverData( nullptr, 0 );
329 static bool ImplUpdateSalJobSetup( WinSalInfoPrinter
const * pPrinter
, ImplJobSetup
* pSetupData
,
330 bool bIn
, weld::Window
* pVisibleDlgParent
)
333 LPWSTR pPrinterNameW
= const_cast<LPWSTR
>(o3tl::toW(pPrinter
->maDeviceName
.getStr()));
334 if ( !OpenPrinterW( pPrinterNameW
, &hPrn
, nullptr ) )
336 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
337 if( hPrn
== HGDI_ERROR
)
342 DWORD nMode
= DM_OUT_BUFFER
;
343 std::unique_ptr
<sal_uInt8
[]> pDriverData
;
344 SalDriverData
* pOutBuffer
= nullptr;
345 BYTE
const * pInBuffer
= nullptr;
347 LONG nSysJobSize
= DocumentPropertiesW( hWnd
, hPrn
,
349 nullptr, nullptr, 0 );
350 if ( nSysJobSize
< 0 )
352 ClosePrinter( hPrn
);
357 const std::size_t nDriverDataLen
= sizeof(SalDriverData
) + nSysJobSize
-1;
358 pDriverData
= std::make_unique
<sal_uInt8
[]>( nDriverDataLen
);
359 memset(pDriverData
.get(), 0, nDriverDataLen
);
360 pOutBuffer
= reinterpret_cast<SalDriverData
*>(pDriverData
.get());
361 pOutBuffer
->mnSysSignature
= SAL_DRIVERDATA_SYSSIGN
;
362 // calculate driver data offset including structure padding
363 pOutBuffer
->mnDriverOffset
= sal::static_int_cast
<sal_uInt16
>(
364 reinterpret_cast<char*>(pOutBuffer
->maDriverData
) -
365 reinterpret_cast<char*>(pOutBuffer
) );
367 // check if we have a suitable input buffer
368 if ( bIn
&& ImplTestSalJobSetup( pPrinter
, pSetupData
, false ) )
370 pInBuffer
= pSetupData
->GetDriverData() + reinterpret_cast<SalDriverData
const *>(pSetupData
->GetDriverData())->mnDriverOffset
;
371 nMode
|= DM_IN_BUFFER
;
374 // check if the dialog should be shown
375 if ( pVisibleDlgParent
)
377 hWnd
= pVisibleDlgParent
->get_system_data().hWnd
;
378 nMode
|= DM_IN_PROMPT
;
381 // Release mutex, in the other case we don't get paints and so on
382 sal_uInt32 nMutexCount
= 0;
383 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
384 if ( pInst
&& pVisibleDlgParent
)
385 nMutexCount
= pInst
->ReleaseYieldMutex(true);
387 BYTE
* pOutDevMode
= reinterpret_cast<BYTE
*>(pOutBuffer
) + pOutBuffer
->mnDriverOffset
;
388 nRet
= DocumentPropertiesW( hWnd
, hPrn
,
390 reinterpret_cast<LPDEVMODEW
>(pOutDevMode
), reinterpret_cast<LPDEVMODEW
>(const_cast<BYTE
*>(pInBuffer
)), nMode
);
391 if ( pInst
&& pVisibleDlgParent
)
392 pInst
->AcquireYieldMutex( nMutexCount
);
393 ClosePrinter( hPrn
);
395 if( (nRet
< 0) || (pVisibleDlgParent
&& (nRet
== IDCANCEL
)) )
398 // fill up string buffers with 0 so they do not influence a JobSetup's memcmp
399 if( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmSize
>= 64 )
401 sal_Int32 nLen
= rtl_ustr_getLength( o3tl::toU(reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmDeviceName
) );
402 if ( sal::static_int_cast
<size_t>(nLen
) < SAL_N_ELEMENTS( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmDeviceName
) )
403 memset( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmDeviceName
+nLen
, 0, sizeof( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmDeviceName
)-(nLen
*sizeof(sal_Unicode
)) );
405 if( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmSize
>= 166 )
407 sal_Int32 nLen
= rtl_ustr_getLength( o3tl::toU(reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmFormName
) );
408 if ( sal::static_int_cast
<size_t>(nLen
) < SAL_N_ELEMENTS( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmFormName
) )
409 memset( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmFormName
+nLen
, 0, sizeof( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmFormName
)-(nLen
*sizeof(sal_Unicode
)) );
413 pSetupData
->SetDriverData(std::move(pDriverData
), nDriverDataLen
);
414 pSetupData
->SetSystem( JOBSETUP_SYSTEM_WINDOWS
);
419 static void ImplDevModeToJobSetup( WinSalInfoPrinter
const * pPrinter
, ImplJobSetup
* pSetupData
, JobSetFlags nFlags
)
421 if ( !pSetupData
|| !pSetupData
->GetDriverData() )
424 DEVMODEW
const * pDevModeW
= SAL_DEVMODE_W(pSetupData
);
425 if( pDevModeW
== nullptr )
429 if ( nFlags
& JobSetFlags::ORIENTATION
)
431 if ( pDevModeW
->dmOrientation
== DMORIENT_PORTRAIT
)
432 pSetupData
->SetOrientation( Orientation::Portrait
);
433 else if ( pDevModeW
->dmOrientation
== DMORIENT_LANDSCAPE
)
434 pSetupData
->SetOrientation( Orientation::Landscape
);
438 if ( nFlags
& JobSetFlags::PAPERBIN
)
440 const DWORD nCount
= ImplDeviceCaps( pPrinter
, DC_BINS
, nullptr, pSetupData
);
442 if ( nCount
&& (nCount
!= GDI_ERROR
) )
444 WORD
* pBins
= static_cast<WORD
*>(rtl_allocateZeroMemory( nCount
*sizeof(WORD
) ));
445 ImplDeviceCaps( pPrinter
, DC_BINS
, reinterpret_cast<BYTE
*>(pBins
), pSetupData
);
446 pSetupData
->SetPaperBin( 0 );
448 // search the right bin and assign index to mnPaperBin
449 for( DWORD i
= 0; i
< nCount
; ++i
)
451 if( pDevModeW
->dmDefaultSource
== pBins
[ i
] )
453 pSetupData
->SetPaperBin( static_cast<sal_uInt16
>(i
) );
463 if ( nFlags
& JobSetFlags::PAPERSIZE
)
465 if( (pDevModeW
->dmFields
& (DM_PAPERWIDTH
|DM_PAPERLENGTH
)) == (DM_PAPERWIDTH
|DM_PAPERLENGTH
) )
467 pSetupData
->SetPaperWidth( pDevModeW
->dmPaperWidth
*10 );
468 pSetupData
->SetPaperHeight( pDevModeW
->dmPaperLength
*10 );
472 const DWORD nPaperCount
= ImplDeviceCaps( pPrinter
, DC_PAPERS
, nullptr, pSetupData
);
473 WORD
* pPapers
= nullptr;
474 const DWORD nPaperSizeCount
= ImplDeviceCaps( pPrinter
, DC_PAPERSIZE
, nullptr, pSetupData
);
475 POINT
* pPaperSizes
= nullptr;
476 if ( nPaperCount
&& (nPaperCount
!= GDI_ERROR
) )
478 pPapers
= static_cast<WORD
*>(rtl_allocateZeroMemory(nPaperCount
*sizeof(WORD
)));
479 ImplDeviceCaps( pPrinter
, DC_PAPERS
, reinterpret_cast<BYTE
*>(pPapers
), pSetupData
);
481 if ( nPaperSizeCount
&& (nPaperSizeCount
!= GDI_ERROR
) )
483 pPaperSizes
= static_cast<POINT
*>(rtl_allocateZeroMemory(nPaperSizeCount
*sizeof(POINT
)));
484 ImplDeviceCaps( pPrinter
, DC_PAPERSIZE
, reinterpret_cast<BYTE
*>(pPaperSizes
), pSetupData
);
486 if( nPaperSizeCount
== nPaperCount
&& pPaperSizes
&& pPapers
)
488 for( DWORD i
= 0; i
< nPaperCount
; ++i
)
490 if( pPapers
[ i
] == pDevModeW
->dmPaperSize
)
492 pSetupData
->SetPaperWidth( pPaperSizes
[ i
].x
*10 );
493 pSetupData
->SetPaperHeight( pPaperSizes
[ i
].y
*10 );
499 std::free( pPapers
);
501 std::free( pPaperSizes
);
503 switch( pDevModeW
->dmPaperSize
)
506 pSetupData
->SetPaperFormat( PAPER_LETTER
);
508 case DMPAPER_TABLOID
:
509 pSetupData
->SetPaperFormat( PAPER_TABLOID
);
512 pSetupData
->SetPaperFormat( PAPER_LEDGER
);
515 pSetupData
->SetPaperFormat( PAPER_LEGAL
);
517 case DMPAPER_STATEMENT
:
518 pSetupData
->SetPaperFormat( PAPER_STATEMENT
);
520 case DMPAPER_EXECUTIVE
:
521 pSetupData
->SetPaperFormat( PAPER_EXECUTIVE
);
524 pSetupData
->SetPaperFormat( PAPER_A3
);
527 pSetupData
->SetPaperFormat( PAPER_A4
);
530 pSetupData
->SetPaperFormat( PAPER_A5
);
532 //See http://wiki.openoffice.org/wiki/DefaultPaperSize
534 //http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
535 //DMPAPER_B4 12 B4 (JIS) 257 x 364 mm
536 //http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
537 //also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
538 //matches our Excel filter's belief about the matching XlPaperSize
541 //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
542 ////"DMPAPER_B4 12 B4 (JIS) 250 x 354"
543 //which is bogus as it's either JIS 257 x 364 or ISO 250 x 353
546 pSetupData
->SetPaperFormat( PAPER_B4_JIS
);
549 pSetupData
->SetPaperFormat( PAPER_B5_JIS
);
552 pSetupData
->SetPaperFormat( PAPER_QUARTO
);
555 pSetupData
->SetPaperFormat( PAPER_10x14
);
558 pSetupData
->SetPaperFormat( PAPER_LETTER
);
561 pSetupData
->SetPaperFormat( PAPER_ENV_9
);
564 pSetupData
->SetPaperFormat( PAPER_ENV_10
);
567 pSetupData
->SetPaperFormat( PAPER_ENV_11
);
570 pSetupData
->SetPaperFormat( PAPER_ENV_12
);
573 pSetupData
->SetPaperFormat( PAPER_ENV_14
);
576 pSetupData
->SetPaperFormat( PAPER_C
);
579 pSetupData
->SetPaperFormat( PAPER_D
);
582 pSetupData
->SetPaperFormat( PAPER_E
);
585 pSetupData
->SetPaperFormat( PAPER_ENV_DL
);
588 pSetupData
->SetPaperFormat( PAPER_ENV_C5
);
591 pSetupData
->SetPaperFormat( PAPER_ENV_C3
);
594 pSetupData
->SetPaperFormat( PAPER_ENV_C4
);
597 pSetupData
->SetPaperFormat( PAPER_ENV_C6
);
599 case DMPAPER_ENV_C65
:
600 pSetupData
->SetPaperFormat( PAPER_ENV_C65
);
602 case DMPAPER_ENV_ITALY
:
603 pSetupData
->SetPaperFormat( PAPER_ENV_ITALY
);
605 case DMPAPER_ENV_MONARCH
:
606 pSetupData
->SetPaperFormat( PAPER_ENV_MONARCH
);
608 case DMPAPER_ENV_PERSONAL
:
609 pSetupData
->SetPaperFormat( PAPER_ENV_PERSONAL
);
611 case DMPAPER_FANFOLD_US
:
612 pSetupData
->SetPaperFormat( PAPER_FANFOLD_US
);
614 case DMPAPER_FANFOLD_STD_GERMAN
:
615 pSetupData
->SetPaperFormat( PAPER_FANFOLD_DE
);
617 case DMPAPER_FANFOLD_LGL_GERMAN
:
618 pSetupData
->SetPaperFormat( PAPER_FANFOLD_LEGAL_DE
);
621 pSetupData
->SetPaperFormat( PAPER_B4_ISO
);
623 case DMPAPER_JAPANESE_POSTCARD
:
624 pSetupData
->SetPaperFormat( PAPER_POSTCARD_JP
);
627 pSetupData
->SetPaperFormat( PAPER_9x11
);
630 pSetupData
->SetPaperFormat( PAPER_10x11
);
633 pSetupData
->SetPaperFormat( PAPER_15x11
);
635 case DMPAPER_ENV_INVITE
:
636 pSetupData
->SetPaperFormat( PAPER_ENV_INVITE
);
639 pSetupData
->SetPaperFormat( PAPER_A_PLUS
);
642 pSetupData
->SetPaperFormat( PAPER_B_PLUS
);
644 case DMPAPER_LETTER_PLUS
:
645 pSetupData
->SetPaperFormat( PAPER_LETTER_PLUS
);
647 case DMPAPER_A4_PLUS
:
648 pSetupData
->SetPaperFormat( PAPER_A4_PLUS
);
651 pSetupData
->SetPaperFormat( PAPER_A2
);
653 case DMPAPER_DBL_JAPANESE_POSTCARD
:
654 pSetupData
->SetPaperFormat( PAPER_DOUBLEPOSTCARD_JP
);
657 pSetupData
->SetPaperFormat( PAPER_A6
);
660 pSetupData
->SetPaperFormat( PAPER_B6_JIS
);
663 pSetupData
->SetPaperFormat( PAPER_12x11
);
666 pSetupData
->SetPaperFormat( PAPER_USER
);
671 if( nFlags
& JobSetFlags::DUPLEXMODE
)
673 DuplexMode eDuplex
= DuplexMode::Unknown
;
674 if( pDevModeW
->dmFields
& DM_DUPLEX
)
676 if( pDevModeW
->dmDuplex
== DMDUP_SIMPLEX
)
677 eDuplex
= DuplexMode::Off
;
678 else if( pDevModeW
->dmDuplex
== DMDUP_VERTICAL
)
679 eDuplex
= DuplexMode::LongEdge
;
680 else if( pDevModeW
->dmDuplex
== DMDUP_HORIZONTAL
)
681 eDuplex
= DuplexMode::ShortEdge
;
683 pSetupData
->SetDuplexMode( eDuplex
);
687 static void ImplJobSetupToDevMode( WinSalInfoPrinter
const * pPrinter
, const ImplJobSetup
* pSetupData
, JobSetFlags nFlags
)
689 if ( !pSetupData
|| !pSetupData
->GetDriverData() )
692 DEVMODEW
* pDevModeW
= const_cast<DEVMODEW
*>(SAL_DEVMODE_W(pSetupData
));
693 if( pDevModeW
== nullptr )
697 if ( nFlags
& JobSetFlags::ORIENTATION
)
699 pDevModeW
->dmFields
|= DM_ORIENTATION
;
700 if ( pSetupData
->GetOrientation() == Orientation::Portrait
)
701 pDevModeW
->dmOrientation
= DMORIENT_PORTRAIT
;
703 pDevModeW
->dmOrientation
= DMORIENT_LANDSCAPE
;
707 if ( nFlags
& JobSetFlags::PAPERBIN
)
709 const DWORD nCount
= ImplDeviceCaps( pPrinter
, DC_BINS
, nullptr, pSetupData
);
711 if ( nCount
&& (nCount
!= GDI_ERROR
) )
713 WORD
* pBins
= static_cast<WORD
*>(rtl_allocateZeroMemory(nCount
*sizeof(WORD
)));
714 ImplDeviceCaps( pPrinter
, DC_BINS
, reinterpret_cast<BYTE
*>(pBins
), pSetupData
);
715 pDevModeW
->dmFields
|= DM_DEFAULTSOURCE
;
716 pDevModeW
->dmDefaultSource
= pBins
[ pSetupData
->GetPaperBin() ];
722 if ( nFlags
& JobSetFlags::PAPERSIZE
)
724 pDevModeW
->dmFields
|= DM_PAPERSIZE
;
725 pDevModeW
->dmPaperWidth
= 0;
726 pDevModeW
->dmPaperLength
= 0;
728 switch( pSetupData
->GetPaperFormat() )
731 pDevModeW
->dmPaperSize
= DMPAPER_A2
;
734 pDevModeW
->dmPaperSize
= DMPAPER_A3
;
737 pDevModeW
->dmPaperSize
= DMPAPER_A4
;
740 pDevModeW
->dmPaperSize
= DMPAPER_A5
;
743 pDevModeW
->dmPaperSize
= DMPAPER_ISO_B4
;
746 pDevModeW
->dmPaperSize
= DMPAPER_LETTER
;
749 pDevModeW
->dmPaperSize
= DMPAPER_LEGAL
;
752 pDevModeW
->dmPaperSize
= DMPAPER_TABLOID
;
755 // http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
756 // DMPAPER_ENV_B6 is documented as:
757 // "DMPAPER_ENV_B6 35 Envelope B6 176 x 125 mm"
758 // which is the wrong way around, it is surely 125 x 176, i.e.
759 // compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
760 // DMPAPER_ENV_B4 33 Envelope B4 250 x 353 mm
761 // DMPAPER_ENV_B5 34 Envelope B5 176 x 250 mm
764 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C4
;
767 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C5
;
770 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C6
;
773 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C65
;
776 pDevModeW
->dmPaperSize
= DMPAPER_ENV_DL
;
779 pDevModeW
->dmPaperSize
= DMPAPER_CSHEET
;
782 pDevModeW
->dmPaperSize
= DMPAPER_DSHEET
;
785 pDevModeW
->dmPaperSize
= DMPAPER_ESHEET
;
787 case PAPER_EXECUTIVE
:
788 pDevModeW
->dmPaperSize
= DMPAPER_EXECUTIVE
;
790 case PAPER_FANFOLD_LEGAL_DE
:
791 pDevModeW
->dmPaperSize
= DMPAPER_FANFOLD_LGL_GERMAN
;
793 case PAPER_ENV_MONARCH
:
794 pDevModeW
->dmPaperSize
= DMPAPER_ENV_MONARCH
;
796 case PAPER_ENV_PERSONAL
:
797 pDevModeW
->dmPaperSize
= DMPAPER_ENV_PERSONAL
;
800 pDevModeW
->dmPaperSize
= DMPAPER_ENV_9
;
803 pDevModeW
->dmPaperSize
= DMPAPER_ENV_10
;
806 pDevModeW
->dmPaperSize
= DMPAPER_ENV_11
;
809 pDevModeW
->dmPaperSize
= DMPAPER_ENV_12
;
811 //See the comments on DMPAPER_B4 above
813 pDevModeW
->dmPaperSize
= DMPAPER_B4
;
816 pDevModeW
->dmPaperSize
= DMPAPER_B5
;
819 pDevModeW
->dmPaperSize
= DMPAPER_B6_JIS
;
822 pDevModeW
->dmPaperSize
= DMPAPER_LEDGER
;
824 case PAPER_STATEMENT
:
825 pDevModeW
->dmPaperSize
= DMPAPER_STATEMENT
;
828 pDevModeW
->dmPaperSize
= DMPAPER_10X14
;
831 pDevModeW
->dmPaperSize
= DMPAPER_ENV_14
;
834 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C3
;
836 case PAPER_ENV_ITALY
:
837 pDevModeW
->dmPaperSize
= DMPAPER_ENV_ITALY
;
839 case PAPER_FANFOLD_US
:
840 pDevModeW
->dmPaperSize
= DMPAPER_FANFOLD_US
;
842 case PAPER_FANFOLD_DE
:
843 pDevModeW
->dmPaperSize
= DMPAPER_FANFOLD_STD_GERMAN
;
845 case PAPER_POSTCARD_JP
:
846 pDevModeW
->dmPaperSize
= DMPAPER_JAPANESE_POSTCARD
;
849 pDevModeW
->dmPaperSize
= DMPAPER_9X11
;
852 pDevModeW
->dmPaperSize
= DMPAPER_10X11
;
855 pDevModeW
->dmPaperSize
= DMPAPER_15X11
;
857 case PAPER_ENV_INVITE
:
858 pDevModeW
->dmPaperSize
= DMPAPER_ENV_INVITE
;
861 pDevModeW
->dmPaperSize
= DMPAPER_A_PLUS
;
864 pDevModeW
->dmPaperSize
= DMPAPER_B_PLUS
;
866 case PAPER_LETTER_PLUS
:
867 pDevModeW
->dmPaperSize
= DMPAPER_LETTER_PLUS
;
870 pDevModeW
->dmPaperSize
= DMPAPER_A4_PLUS
;
872 case PAPER_DOUBLEPOSTCARD_JP
:
873 pDevModeW
->dmPaperSize
= DMPAPER_DBL_JAPANESE_POSTCARD
;
876 pDevModeW
->dmPaperSize
= DMPAPER_A6
;
879 pDevModeW
->dmPaperSize
= DMPAPER_12X11
;
884 const DWORD nPaperCount
= ImplDeviceCaps( pPrinter
, DC_PAPERS
, nullptr, pSetupData
);
885 WORD
* pPapers
= nullptr;
886 const DWORD nPaperSizeCount
= ImplDeviceCaps( pPrinter
, DC_PAPERSIZE
, nullptr, pSetupData
);
887 POINT
* pPaperSizes
= nullptr;
888 DWORD nLandscapeAngle
= ImplDeviceCaps( pPrinter
, DC_ORIENTATION
, nullptr, pSetupData
);
889 if ( nPaperCount
&& (nPaperCount
!= GDI_ERROR
) )
891 pPapers
= static_cast<WORD
*>(rtl_allocateZeroMemory(nPaperCount
*sizeof(WORD
)));
892 ImplDeviceCaps( pPrinter
, DC_PAPERS
, reinterpret_cast<BYTE
*>(pPapers
), pSetupData
);
894 if ( nPaperSizeCount
&& (nPaperSizeCount
!= GDI_ERROR
) )
896 pPaperSizes
= static_cast<POINT
*>(rtl_allocateZeroMemory(nPaperSizeCount
*sizeof(POINT
)));
897 ImplDeviceCaps( pPrinter
, DC_PAPERSIZE
, reinterpret_cast<BYTE
*>(pPaperSizes
), pSetupData
);
899 if ( (nPaperSizeCount
== nPaperCount
) && pPapers
&& pPaperSizes
)
901 PaperInfo
aInfo(pSetupData
->GetPaperWidth(), pSetupData
->GetPaperHeight());
902 // compare paper formats and select a good match
903 for ( DWORD i
= 0; i
< nPaperCount
; ++i
)
905 if ( aInfo
.sloppyEqual(PaperInfo(pPaperSizes
[i
].x
*10, pPaperSizes
[i
].y
*10)))
912 // If the printer supports landscape orientation, check paper sizes again
913 // with landscape orientation. This is necessary as a printer driver provides
914 // all paper sizes with portrait orientation only!!
915 if ( !nPaper
&& nLandscapeAngle
!= 0 )
917 PaperInfo
aRotatedInfo(pSetupData
->GetPaperHeight(), pSetupData
->GetPaperWidth());
918 for ( DWORD i
= 0; i
< nPaperCount
; ++i
)
920 if ( aRotatedInfo
.sloppyEqual(PaperInfo(pPaperSizes
[i
].x
*10, pPaperSizes
[i
].y
*10)) )
929 pDevModeW
->dmPaperSize
= nPaper
;
934 pDevModeW
->dmFields
|= DM_PAPERLENGTH
| DM_PAPERWIDTH
;
935 pDevModeW
->dmPaperSize
= DMPAPER_USER
;
936 pDevModeW
->dmPaperWidth
= static_cast<short>(pSetupData
->GetPaperWidth()/10);
937 pDevModeW
->dmPaperLength
= static_cast<short>(pSetupData
->GetPaperHeight()/10);
943 std::free(pPaperSizes
);
949 if( nFlags
& JobSetFlags::DUPLEXMODE
)
951 switch( pSetupData
->GetDuplexMode() )
953 case DuplexMode::Off
:
954 pDevModeW
->dmFields
|= DM_DUPLEX
;
955 pDevModeW
->dmDuplex
= DMDUP_SIMPLEX
;
957 case DuplexMode::ShortEdge
:
958 pDevModeW
->dmFields
|= DM_DUPLEX
;
959 pDevModeW
->dmDuplex
= DMDUP_HORIZONTAL
;
961 case DuplexMode::LongEdge
:
962 pDevModeW
->dmFields
|= DM_DUPLEX
;
963 pDevModeW
->dmDuplex
= DMDUP_VERTICAL
;
965 case DuplexMode::Unknown
:
971 static HDC
ImplCreateICW_WithCatch( LPWSTR pDriver
,
973 DEVMODEW
const * pDevMode
)
976 CATCH_DRIVER_EX_BEGIN
;
977 hDC
= CreateICW( pDriver
, pDevice
, nullptr, pDevMode
);
978 CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
982 static HDC
ImplCreateSalPrnIC( WinSalInfoPrinter
const * pPrinter
, const ImplJobSetup
* pSetupData
)
985 DEVMODEW
const * pDevMode
;
986 if ( pSetupData
&& pSetupData
->GetDriverData() )
987 pDevMode
= SAL_DEVMODE_W( pSetupData
);
990 // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
991 // pl: does this hold true for Unicode functions ?
992 if( pPrinter
->maDriverName
.getLength() > 2048 || pPrinter
->maDeviceName
.getLength() > 2048 )
994 sal_Unicode pDriverName
[ 4096 ];
995 sal_Unicode pDeviceName
[ 4096 ];
996 memcpy( pDriverName
, pPrinter
->maDriverName
.getStr(), pPrinter
->maDriverName
.getLength()*sizeof(sal_Unicode
));
997 memset( pDriverName
+pPrinter
->maDriverName
.getLength(), 0, 32 );
998 memcpy( pDeviceName
, pPrinter
->maDeviceName
.getStr(), pPrinter
->maDeviceName
.getLength()*sizeof(sal_Unicode
));
999 memset( pDeviceName
+pPrinter
->maDeviceName
.getLength(), 0, 32 );
1000 hDC
= ImplCreateICW_WithCatch( o3tl::toW(pDriverName
),
1001 o3tl::toW(pDeviceName
),
1006 static WinSalGraphics
* ImplCreateSalPrnGraphics( HDC hDC
)
1008 WinSalGraphics
* pGraphics
= new WinSalGraphics(WinSalGraphics::PRINTER
, false, nullptr, /* CHECKME */ nullptr);
1009 pGraphics
->SetLayout( SalLayoutFlags::NONE
);
1010 pGraphics
->setHDC(hDC
);
1014 static bool ImplUpdateSalPrnIC( WinSalInfoPrinter
* pPrinter
, const ImplJobSetup
* pSetupData
)
1016 HDC hNewDC
= ImplCreateSalPrnIC( pPrinter
, pSetupData
);
1020 pPrinter
->setHDC(hNewDC
);
1025 SalInfoPrinter
* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo
* pQueueInfo
,
1026 ImplJobSetup
* pSetupData
)
1028 WinSalInfoPrinter
* pPrinter
= new WinSalInfoPrinter
;
1029 if( ! pQueueInfo
->moPortName
)
1030 GetPrinterQueueState( pQueueInfo
);
1031 pPrinter
->maDriverName
= pQueueInfo
->maDriver
;
1032 pPrinter
->maDeviceName
= pQueueInfo
->maPrinterName
;
1033 pPrinter
->maPortName
= pQueueInfo
->moPortName
? *pQueueInfo
->moPortName
: OUString();
1035 // check if the provided setup data match the actual printer
1036 ImplTestSalJobSetup( pPrinter
, pSetupData
, true );
1038 HDC hDC
= ImplCreateSalPrnIC( pPrinter
, pSetupData
);
1045 pPrinter
->setHDC(hDC
);
1046 if ( !pSetupData
->GetDriverData() )
1047 ImplUpdateSalJobSetup( pPrinter
, pSetupData
, false, nullptr );
1048 ImplDevModeToJobSetup( pPrinter
, pSetupData
, JobSetFlags::ALL
);
1049 pSetupData
->SetSystem( JOBSETUP_SYSTEM_WINDOWS
);
1054 void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter
* pPrinter
)
1060 WinSalInfoPrinter::WinSalInfoPrinter() :
1062 m_pGraphics(nullptr),
1065 m_bPapersInit
= false;
1068 WinSalInfoPrinter::~WinSalInfoPrinter()
1073 void WinSalInfoPrinter::setHDC(HDC hNewDC
)
1075 assert(!m_bGraphics
);
1079 assert(!m_pGraphics
|| m_hDC
== m_pGraphics
->getHDC());
1081 m_pGraphics
= nullptr;
1088 void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup
* pSetupData
)
1090 m_aPaperFormats
.clear();
1092 DWORD nCount
= ImplDeviceCaps( this, DC_PAPERSIZE
, nullptr, pSetupData
);
1093 if( nCount
== GDI_ERROR
)
1098 POINT
* pPaperSizes
= static_cast<POINT
*>(rtl_allocateZeroMemory(nCount
*sizeof(POINT
)));
1099 ImplDeviceCaps( this, DC_PAPERSIZE
, reinterpret_cast<BYTE
*>(pPaperSizes
), pSetupData
);
1101 sal_Unicode
* pNamesBuffer
= static_cast<sal_Unicode
*>(std::malloc(nCount
*64*sizeof(sal_Unicode
)));
1102 ImplDeviceCaps( this, DC_PAPERNAMES
, reinterpret_cast<BYTE
*>(pNamesBuffer
), pSetupData
);
1104 SAL_INFO("vcl.print", "DC_PAPERSIZE sizes (mm) from printer: " << DC_PAPERSIZE_array_to_string(pPaperSizes
, nCount
));
1106 for( DWORD i
= 0; i
< nCount
; ++i
)
1108 PaperInfo
aInfo(pPaperSizes
[i
].x
* 10, pPaperSizes
[i
].y
* 10);
1109 m_aPaperFormats
.push_back( aInfo
);
1111 std::free( pNamesBuffer
);
1112 std::free( pPaperSizes
);
1115 m_bPapersInit
= true;
1118 int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup
* pSetupData
)
1120 const DWORD nRet
= ImplDeviceCaps( this, DC_ORIENTATION
, nullptr, pSetupData
);
1122 if( nRet
!= GDI_ERROR
)
1123 return static_cast<int>(nRet
) * 10;
1124 return 900; // guess
1127 SalGraphics
* WinSalInfoPrinter::AcquireGraphics()
1134 m_pGraphics
= ImplCreateSalPrnGraphics(m_hDC
);
1141 void WinSalInfoPrinter::ReleaseGraphics( SalGraphics
* )
1143 m_bGraphics
= false;
1146 bool WinSalInfoPrinter::Setup(weld::Window
* pFrame
, ImplJobSetup
* pSetupData
)
1148 if ( ImplUpdateSalJobSetup(this, pSetupData
, true, pFrame
))
1150 ImplDevModeToJobSetup( this, pSetupData
, JobSetFlags::ALL
);
1151 return ImplUpdateSalPrnIC( this, pSetupData
);
1157 bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup
* pSetupData
)
1159 if ( !ImplTestSalJobSetup( this, pSetupData
, false ) )
1161 return ImplUpdateSalPrnIC( this, pSetupData
);
1164 bool WinSalInfoPrinter::SetData( JobSetFlags nFlags
, ImplJobSetup
* pSetupData
)
1166 ImplJobSetupToDevMode( this, pSetupData
, nFlags
);
1167 if ( ImplUpdateSalJobSetup( this, pSetupData
, true, nullptr ) )
1169 ImplDevModeToJobSetup( this, pSetupData
, nFlags
);
1170 return ImplUpdateSalPrnIC( this, pSetupData
);
1176 sal_uInt16
WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup
* pSetupData
)
1178 DWORD nRet
= ImplDeviceCaps( this, DC_BINS
, nullptr, pSetupData
);
1179 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1185 OUString
WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup
* pSetupData
, sal_uInt16 nPaperBin
)
1187 OUString aPaperBinName
;
1189 DWORD nBins
= ImplDeviceCaps( this, DC_BINNAMES
, nullptr, pSetupData
);
1190 if ( (nPaperBin
< nBins
) && (nBins
!= GDI_ERROR
) )
1192 auto pBuffer
= std::make_unique
<sal_Unicode
[]>(nBins
*24);
1193 DWORD nRet
= ImplDeviceCaps( this, DC_BINNAMES
, reinterpret_cast<BYTE
*>(pBuffer
.get()), pSetupData
);
1194 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1195 aPaperBinName
= OUString( pBuffer
.get() + (nPaperBin
*24) );
1198 return aPaperBinName
;
1201 sal_uInt16
WinSalInfoPrinter::GetPaperBinBySourceIndex( const ImplJobSetup
* pSetupData
, sal_uInt16 nPaperSource
)
1203 DWORD nBins
= ImplDeviceCaps( this, DC_BINNAMES
, nullptr, pSetupData
);
1204 if (nBins
!= GDI_ERROR
)
1206 auto pBuffer
= std::make_unique
<sal_uInt16
[]>(nBins
);
1207 nBins
= ImplDeviceCaps( this, DC_BINS
, reinterpret_cast<BYTE
*>(pBuffer
.get()), pSetupData
);
1208 if (nBins
!= GDI_ERROR
)
1210 for (DWORD nBin
= 0; nBin
< nBins
; ++nBin
)
1212 if (nPaperSource
== *(pBuffer
.get() + nBin
))
1220 sal_uInt16
WinSalInfoPrinter::GetSourceIndexByPaperBin(const ImplJobSetup
* pSetupData
, sal_uInt16 nPaperBin
)
1222 DWORD nBins
= ImplDeviceCaps( this, DC_BINNAMES
, nullptr, pSetupData
);
1223 if (nBins
!= GDI_ERROR
)
1225 auto pBuffer
= std::make_unique
<sal_uInt16
[]>(nBins
);
1226 nBins
= ImplDeviceCaps( this, DC_BINS
, reinterpret_cast<BYTE
*>(pBuffer
.get()), pSetupData
);
1227 if (nBins
!= GDI_ERROR
&& nBins
> nPaperBin
)
1229 return *(pBuffer
.get() + nPaperBin
);
1236 sal_uInt32
WinSalInfoPrinter::GetCapabilities( const ImplJobSetup
* pSetupData
, PrinterCapType nType
)
1242 case PrinterCapType::SupportDialog
:
1244 case PrinterCapType::Copies
:
1245 nRet
= ImplDeviceCaps( this, DC_COPIES
, nullptr, pSetupData
);
1246 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1249 case PrinterCapType::CollateCopies
:
1250 nRet
= ImplDeviceCaps( this, DC_COLLATE
, nullptr, pSetupData
);
1251 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1253 nRet
= ImplDeviceCaps( this, DC_COPIES
, nullptr, pSetupData
);
1254 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1259 case PrinterCapType::SetOrientation
:
1260 nRet
= ImplDeviceCaps( this, DC_ORIENTATION
, nullptr, pSetupData
);
1261 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1265 case PrinterCapType::SetPaperSize
:
1266 case PrinterCapType::SetPaper
:
1267 nRet
= ImplDeviceCaps( this, DC_PAPERS
, nullptr, pSetupData
);
1268 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1279 void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup
*,
1280 tools::Long
& rOutWidth
, tools::Long
& rOutHeight
,
1286 rOutWidth
= GetDeviceCaps( hDC
, HORZRES
);
1287 rOutHeight
= GetDeviceCaps( hDC
, VERTRES
);
1289 rPageOffset
.setX( GetDeviceCaps( hDC
, PHYSICALOFFSETX
) );
1290 rPageOffset
.setY( GetDeviceCaps( hDC
, PHYSICALOFFSETY
) );
1291 rPaperSize
.setWidth( GetDeviceCaps( hDC
, PHYSICALWIDTH
) );
1292 rPaperSize
.setHeight( GetDeviceCaps( hDC
, PHYSICALHEIGHT
) );
1296 std::unique_ptr
<SalPrinter
> WinSalInstance::CreatePrinter( SalInfoPrinter
* pInfoPrinter
)
1298 WinSalPrinter
* pPrinter
= new WinSalPrinter
;
1299 pPrinter
->mpInfoPrinter
= static_cast<WinSalInfoPrinter
*>(pInfoPrinter
);
1300 return std::unique_ptr
<SalPrinter
>(pPrinter
);
1303 static BOOL CALLBACK
SalPrintAbortProc( HDC hPrnDC
, int /* nError */ )
1305 SalData
* pSalData
= GetSalData();
1306 WinSalPrinter
* pPrinter
;
1310 // Ensure we handle the mutex which will be released in WinSalInstance::DoYield
1311 SolarMutexGuard aSolarMutexGuard
;
1315 bWhile
= Application::Reschedule( true );
1321 pPrinter
= pSalData
->mpFirstPrinter
;
1324 if( pPrinter
->mhDC
== hPrnDC
)
1327 pPrinter
= pPrinter
->mpNextPrinter
;
1330 if ( !pPrinter
|| pPrinter
->mbAbort
)
1338 static DEVMODEW
const * ImplSalSetCopies( DEVMODEW
const * pDevMode
, sal_uInt32 nCopies
, bool bCollate
)
1340 if ( pDevMode
&& (nCopies
> 1) )
1342 if ( nCopies
> 32765 )
1344 sal_uLong nDevSize
= pDevMode
->dmSize
+pDevMode
->dmDriverExtra
;
1345 LPDEVMODEW pNewDevMode
= static_cast<LPDEVMODEW
>(std::malloc( nDevSize
));
1346 assert(pNewDevMode
); // Don't handle OOM conditions
1347 memcpy( pNewDevMode
, pDevMode
, nDevSize
);
1348 pNewDevMode
->dmFields
|= DM_COPIES
;
1349 pNewDevMode
->dmCopies
= static_cast<short>(static_cast<sal_uInt16
>(nCopies
));
1350 pNewDevMode
->dmFields
|= DM_COLLATE
;
1352 pNewDevMode
->dmCollate
= DMCOLLATE_TRUE
;
1354 pNewDevMode
->dmCollate
= DMCOLLATE_FALSE
;
1364 WinSalPrinter::WinSalPrinter() :
1365 mpInfoPrinter( nullptr ),
1366 mpNextPrinter( nullptr ),
1368 mnError( SalPrinterError::NONE
),
1374 SalData
* pSalData
= GetSalData();
1375 // insert printer in printerlist
1376 mpNextPrinter
= pSalData
->mpFirstPrinter
;
1377 pSalData
->mpFirstPrinter
= this;
1380 WinSalPrinter::~WinSalPrinter()
1382 SalData
* pSalData
= GetSalData();
1384 // release DC if there is one still around because of AbortJob
1388 // explicitly reset(), so the mxGraphics's borrowed HDC defaults are
1389 // restored and WinSalGraphics's destructor won't work on a deleted HDC.
1394 // remove printer from printerlist
1395 if ( this == pSalData
->mpFirstPrinter
)
1396 pSalData
->mpFirstPrinter
= mpNextPrinter
;
1399 WinSalPrinter
* pTempPrinter
= pSalData
->mpFirstPrinter
;
1401 while( pTempPrinter
->mpNextPrinter
!= this )
1402 pTempPrinter
= pTempPrinter
->mpNextPrinter
;
1404 pTempPrinter
->mpNextPrinter
= mpNextPrinter
;
1408 void WinSalPrinter::markInvalid()
1413 // need wrappers for StarTocW/A to use structured exception handling
1414 // since SEH does not mix with standard exception handling's cleanup
1415 static int lcl_StartDocW1( HDC hDC
, DOCINFOW
const * pInfo
, WinSalPrinter
* pPrt
)
1418 CATCH_DRIVER_EX_BEGIN
;
1419 nRet
= ::StartDocW( hDC
, pInfo
);
1420 CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt
);
1424 static int lcl_StartDocW( HDC hDC
, DOCINFOW
const * pInfo
, WinSalPrinter
* pPrt
)
1426 //tdf#127547 - Freeze/crash in Microsoft Print to PDF dialog, if we try to paste while
1427 // executing the StartDocW method, Windows will call back into us on a separate thread,
1428 // where we will attempt to take the SolarMutex.
1429 SolarMutexReleaser aReleaser
;
1431 return lcl_StartDocW1(hDC
, pInfo
, pPrt
);
1434 bool WinSalPrinter::StartJob( const OUString
* pFileName
,
1435 const OUString
& rJobName
,
1440 ImplJobSetup
* pSetupData
)
1442 mnError
= SalPrinterError::NONE
;
1445 mbCollate
= bCollate
;
1447 DEVMODEW
const * pOrgDevModeW
= nullptr;
1448 DEVMODEW
const * pDevModeW
= nullptr;
1450 if ( pSetupData
&& pSetupData
->GetDriverData() )
1452 pOrgDevModeW
= SAL_DEVMODE_W( pSetupData
);
1453 pDevModeW
= ImplSalSetCopies( pOrgDevModeW
, nCopies
, bCollate
);
1456 // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
1457 sal_Unicode aDrvBuf
[4096];
1458 sal_Unicode aDevBuf
[4096];
1459 memcpy( aDrvBuf
, mpInfoPrinter
->maDriverName
.getStr(), (mpInfoPrinter
->maDriverName
.getLength()+1)*sizeof(sal_Unicode
));
1460 memcpy( aDevBuf
, mpInfoPrinter
->maDeviceName
.getStr(), (mpInfoPrinter
->maDeviceName
.getLength()+1)*sizeof(sal_Unicode
));
1461 hDC
= CreateDCW( o3tl::toW(aDrvBuf
),
1466 if ( pDevModeW
!= pOrgDevModeW
)
1467 std::free( const_cast<DEVMODEW
*>(pDevModeW
) );
1471 mnError
= SalPrinterError::General
;
1475 // make sure mhDC is set before the printer driver may call our abortproc
1477 if ( SetAbortProc( hDC
, SalPrintAbortProc
) <= 0 )
1479 mnError
= SalPrinterError::General
;
1483 mnError
= SalPrinterError::NONE
;
1486 // As the Telecom Balloon Fax driver tends to send messages repeatedly
1487 // we try to process first all, and then insert a dummy message
1488 for (int i
= 0; Application::Reschedule( true ) && i
<= 15; ++i
);
1489 bool const ret
= PostMessageW(GetSalData()->mpInstance
->mhComWnd
, SAL_MSG_DUMMY
, 0, 0);
1490 SAL_WARN_IF(!ret
, "vcl", "ERROR: PostMessage() failed!");
1492 // bring up a file chooser if printing to file port but no file name given
1493 OUString aOutFileName
;
1494 if( mpInfoPrinter
->maPortName
.equalsIgnoreAsciiCase( "FILE:" ) && (!pFileName
|| pFileName
->isEmpty()) )
1497 uno::Reference
< uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
1498 uno::Reference
< XFilePicker3
> xFilePicker
= FilePicker::createWithMode(xContext
, TemplateDescription::FILESAVE_SIMPLE
);
1500 if( xFilePicker
->execute() == ExecutableDialogResults::OK
)
1502 Sequence
< OUString
> aPathSeq( xFilePicker
->getSelectedFiles() );
1503 INetURLObject
aObj( aPathSeq
[0] );
1504 aOutFileName
= aObj
.PathToFileName();
1508 mnError
= SalPrinterError::Abort
;
1513 DOCINFOW aInfo
= {};
1514 aInfo
.cbSize
= sizeof( aInfo
);
1515 aInfo
.lpszDocName
= o3tl::toW(rJobName
.getStr());
1516 if ( pFileName
|| aOutFileName
.getLength() )
1518 if ( (pFileName
&& !pFileName
->isEmpty()) || aOutFileName
.getLength() )
1520 aInfo
.lpszOutput
= o3tl::toW((pFileName
&& !pFileName
->isEmpty()) ? pFileName
->getStr() : aOutFileName
.getStr());
1523 aInfo
.lpszOutput
= L
"FILE:";
1526 aInfo
.lpszOutput
= nullptr;
1528 // start Job, in the main thread
1529 int nRet
= vcl::solarthread::syncExecute([hDC
, this, &aInfo
]() -> int { return lcl_StartDocW(hDC
, &aInfo
, this); });
1533 DWORD nError
= GetLastError();
1534 if ( (nRet
== SP_USERABORT
) || (nRet
== SP_APPABORT
) || (nError
== ERROR_PRINT_CANCELLED
) || (nError
== ERROR_CANCELLED
) )
1535 mnError
= SalPrinterError::Abort
;
1537 mnError
= SalPrinterError::General
;
1544 void WinSalPrinter::DoEndDoc(HDC hDC
)
1546 CATCH_DRIVER_EX_BEGIN
;
1547 if( ::EndDoc( hDC
) <= 0 )
1549 CATCH_DRIVER_EX_END( "exception in EndDoc", this );
1552 bool WinSalPrinter::EndJob()
1559 // #i54419# Windows fax printer brings up a dialog in EndDoc
1560 // which text previously copied in soffice process can be
1561 // pasted to -> deadlock due to mutex not released.
1562 // it should be safe to release the yield mutex over the EndDoc
1563 // call, however the real solution is supposed to be the threading
1564 // framework yet to come.
1566 SolarMutexReleaser aReleaser
;
1576 SalGraphics
* WinSalPrinter::StartPage( ImplJobSetup
* pSetupData
, bool bNewJobData
)
1582 if ( pSetupData
&& pSetupData
->GetDriverData() && bNewJobData
)
1584 DEVMODEW
const * pOrgDevModeW
;
1585 DEVMODEW
const * pDevModeW
;
1586 pOrgDevModeW
= SAL_DEVMODE_W( pSetupData
);
1587 pDevModeW
= ImplSalSetCopies( pOrgDevModeW
, mnCopies
, mbCollate
);
1588 ResetDCW( hDC
, pDevModeW
);
1589 if ( pDevModeW
!= pOrgDevModeW
)
1590 std::free( const_cast<DEVMODEW
*>(pDevModeW
) );
1592 volatile int nRet
= 0;
1593 CATCH_DRIVER_EX_BEGIN
;
1594 nRet
= ::StartPage( hDC
);
1595 CATCH_DRIVER_EX_END( "exception in StartPage", this );
1600 mnError
= SalPrinterError::General
;
1604 // Hack to work around old PostScript printer drivers optimizing away empty pages
1605 // TODO: move into ImplCreateSalPrnGraphics()?
1606 HPEN hTempPen
= SelectPen( hDC
, GetStockPen( NULL_PEN
) );
1607 HBRUSH hTempBrush
= SelectBrush( hDC
, GetStockBrush( NULL_BRUSH
) );
1608 Rectangle( hDC
, -8000, -8000, -7999, -7999 );
1609 SelectPen( hDC
, hTempPen
);
1610 SelectBrush( hDC
, hTempBrush
);
1612 mxGraphics
.reset(ImplCreateSalPrnGraphics( hDC
));
1613 return mxGraphics
.get();
1616 void WinSalPrinter::EndPage()
1624 volatile int nRet
= 0;
1625 CATCH_DRIVER_EX_BEGIN
;
1626 nRet
= ::EndPage( hDC
);
1627 CATCH_DRIVER_EX_END( "exception in EndPage", this );
1632 mnError
= SalPrinterError::General
;
1636 SalPrinterError
WinSalPrinter::GetErrorCode()
1641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */