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 .
24 #include <osl/module.h>
26 #include <tools/urlobj.hxx>
28 #include <win/wincomp.hxx>
29 #include <win/saldata.hxx>
30 #include <win/salinst.h>
31 #include <win/salgdi.h>
32 #include <win/salframe.h>
33 #include <win/salprn.h>
35 #include <salptype.hxx>
39 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
40 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
41 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
42 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <com/sun/star/lang/XInitialization.hpp>
45 #include <comphelper/processfactory.hxx>
49 #if defined ( __MINGW32__ )
50 #include <sehandler.hxx>
53 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
54 #define CATCH_DRIVER_EX_BEGIN \
57 if (__builtin_setjmp(jmpbuf) == 0) \
59 han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER)
61 #define CATCH_DRIVER_EX_END(mes, p) \
64 #define CATCH_DRIVER_EX_END_2(mes) \
68 #define CATCH_DRIVER_EX_BEGIN \
71 #define CATCH_DRIVER_EX_END(mes, p) \
73 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
78 #define CATCH_DRIVER_EX_END_2(mes) \
80 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
86 using namespace com::sun::star
;
87 using namespace com::sun::star::uno
;
88 using namespace com::sun::star::lang
;
89 using namespace com::sun::star::ui::dialogs
;
91 static char aImplWindows
[] = "windows";
92 static char aImplDevice
[] = "device";
94 static DEVMODEW
const * SAL_DEVMODE_W( const ImplJobSetup
* pSetupData
)
96 DEVMODEW
const * pRet
= nullptr;
97 SalDriverData
const * pDrv
= reinterpret_cast<SalDriverData
const *>(pSetupData
->GetDriverData());
98 if( pSetupData
->GetDriverDataLen() >= sizeof(DEVMODEW
)+sizeof(SalDriverData
)-1 )
99 pRet
= reinterpret_cast<DEVMODEW
const *>((pSetupData
->GetDriverData()) + (pDrv
->mnDriverOffset
));
103 static PrintQueueFlags
ImplWinQueueStatusToSal( DWORD nWinStatus
)
105 PrintQueueFlags nStatus
= PrintQueueFlags::NONE
;
106 if ( nWinStatus
& PRINTER_STATUS_PAUSED
)
107 nStatus
|= PrintQueueFlags::Paused
;
108 if ( nWinStatus
& PRINTER_STATUS_ERROR
)
109 nStatus
|= PrintQueueFlags::Error
;
110 if ( nWinStatus
& PRINTER_STATUS_PENDING_DELETION
)
111 nStatus
|= PrintQueueFlags::PendingDeletion
;
112 if ( nWinStatus
& PRINTER_STATUS_PAPER_JAM
)
113 nStatus
|= PrintQueueFlags::PaperJam
;
114 if ( nWinStatus
& PRINTER_STATUS_PAPER_OUT
)
115 nStatus
|= PrintQueueFlags::PaperOut
;
116 if ( nWinStatus
& PRINTER_STATUS_MANUAL_FEED
)
117 nStatus
|= PrintQueueFlags::ManualFeed
;
118 if ( nWinStatus
& PRINTER_STATUS_PAPER_PROBLEM
)
119 nStatus
|= PrintQueueFlags::PaperProblem
;
120 if ( nWinStatus
& PRINTER_STATUS_OFFLINE
)
121 nStatus
|= PrintQueueFlags::Offline
;
122 if ( nWinStatus
& PRINTER_STATUS_IO_ACTIVE
)
123 nStatus
|= PrintQueueFlags::IOActive
;
124 if ( nWinStatus
& PRINTER_STATUS_BUSY
)
125 nStatus
|= PrintQueueFlags::Busy
;
126 if ( nWinStatus
& PRINTER_STATUS_PRINTING
)
127 nStatus
|= PrintQueueFlags::Printing
;
128 if ( nWinStatus
& PRINTER_STATUS_OUTPUT_BIN_FULL
)
129 nStatus
|= PrintQueueFlags::OutputBinFull
;
130 if ( nWinStatus
& PRINTER_STATUS_WAITING
)
131 nStatus
|= PrintQueueFlags::Waiting
;
132 if ( nWinStatus
& PRINTER_STATUS_PROCESSING
)
133 nStatus
|= PrintQueueFlags::Processing
;
134 if ( nWinStatus
& PRINTER_STATUS_INITIALIZING
)
135 nStatus
|= PrintQueueFlags::Initializing
;
136 if ( nWinStatus
& PRINTER_STATUS_WARMING_UP
)
137 nStatus
|= PrintQueueFlags::WarmingUp
;
138 if ( nWinStatus
& PRINTER_STATUS_TONER_LOW
)
139 nStatus
|= PrintQueueFlags::TonerLow
;
140 if ( nWinStatus
& PRINTER_STATUS_NO_TONER
)
141 nStatus
|= PrintQueueFlags::NoToner
;
142 if ( nWinStatus
& PRINTER_STATUS_PAGE_PUNT
)
143 nStatus
|= PrintQueueFlags::PagePunt
;
144 if ( nWinStatus
& PRINTER_STATUS_USER_INTERVENTION
)
145 nStatus
|= PrintQueueFlags::UserIntervention
;
146 if ( nWinStatus
& PRINTER_STATUS_OUT_OF_MEMORY
)
147 nStatus
|= PrintQueueFlags::OutOfMemory
;
148 if ( nWinStatus
& PRINTER_STATUS_DOOR_OPEN
)
149 nStatus
|= PrintQueueFlags::DoorOpen
;
150 if ( nWinStatus
& PRINTER_STATUS_SERVER_UNKNOWN
)
151 nStatus
|= PrintQueueFlags::StatusUnknown
;
152 if ( nWinStatus
& PRINTER_STATUS_POWER_SAVE
)
153 nStatus
|= PrintQueueFlags::PowerSave
;
154 if ( nStatus
== PrintQueueFlags::NONE
&& !(nWinStatus
& PRINTER_STATUS_NOT_AVAILABLE
) )
155 nStatus
|= PrintQueueFlags::Ready
;
160 void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList
* pList
)
165 EnumPrintersW( PRINTER_ENUM_LOCAL
| PRINTER_ENUM_CONNECTIONS
, nullptr, 4, nullptr, 0, &nBytes
, &nInfoPrn4
);
168 PRINTER_INFO_4W
* pWinInfo4
= static_cast<PRINTER_INFO_4W
*>(rtl_allocateMemory( nBytes
));
169 if ( EnumPrintersW( PRINTER_ENUM_LOCAL
| PRINTER_ENUM_CONNECTIONS
, nullptr, 4, reinterpret_cast<LPBYTE
>(pWinInfo4
), nBytes
, &nBytes
, &nInfoPrn4
) )
171 for ( i
= 0; i
< nInfoPrn4
; i
++ )
173 SalPrinterQueueInfo
* pInfo
= new SalPrinterQueueInfo
;
174 pInfo
->maPrinterName
= OUString( reinterpret_cast< const sal_Unicode
* >(pWinInfo4
[i
].pPrinterName
) );
175 pInfo
->mnStatus
= PrintQueueFlags::NONE
;
177 pInfo
->mpSysData
= nullptr;
181 rtl_freeMemory( pWinInfo4
);
185 void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo
* pInfo
)
187 HANDLE hPrinter
= nullptr;
188 LPWSTR pPrnName
= reinterpret_cast<LPWSTR
>(const_cast<sal_Unicode
*>(pInfo
->maPrinterName
.getStr()));
189 if( OpenPrinterW( pPrnName
, &hPrinter
, nullptr ) )
192 GetPrinterW( hPrinter
, 2, nullptr, 0, &nBytes
);
195 PRINTER_INFO_2W
* pWinInfo2
= static_cast<PRINTER_INFO_2W
*>(rtl_allocateMemory(nBytes
));
196 if( GetPrinterW( hPrinter
, 2, reinterpret_cast<LPBYTE
>(pWinInfo2
), nBytes
, &nBytes
) )
198 if( pWinInfo2
->pDriverName
)
199 pInfo
->maDriver
= OUString( reinterpret_cast< const sal_Unicode
* >(pWinInfo2
->pDriverName
) );
201 if ( pWinInfo2
->pPortName
)
202 aPortName
= OUString( reinterpret_cast< const sal_Unicode
* >(pWinInfo2
->pPortName
) );
203 // pLocation can be 0 (the Windows docu doesn't describe this)
204 if ( pWinInfo2
->pLocation
&& *pWinInfo2
->pLocation
)
205 pInfo
->maLocation
= OUString( reinterpret_cast< const sal_Unicode
* >(pWinInfo2
->pLocation
) );
207 pInfo
->maLocation
= aPortName
;
208 // pComment can be 0 (the Windows docu doesn't describe this)
209 if ( pWinInfo2
->pComment
)
210 pInfo
->maComment
= OUString( reinterpret_cast< const sal_Unicode
* >(pWinInfo2
->pComment
) );
211 pInfo
->mnStatus
= ImplWinQueueStatusToSal( pWinInfo2
->Status
);
212 pInfo
->mnJobs
= pWinInfo2
->cJobs
;
213 if( ! pInfo
->mpSysData
)
214 pInfo
->mpSysData
= new OUString(aPortName
);
216 rtl_freeMemory(pWinInfo2
);
218 ClosePrinter( hPrinter
);
222 void WinSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo
* pInfo
)
224 delete pInfo
->mpSysData
;
228 OUString
WinSalInstance::GetDefaultPrinter()
231 GetDefaultPrinterW( nullptr, &nChars
);
234 LPWSTR pStr
= static_cast<LPWSTR
>(rtl_allocateMemory(nChars
*sizeof(WCHAR
)));
236 if( GetDefaultPrinterW( pStr
, &nChars
) )
238 aDefPrt
= OUString(reinterpret_cast<sal_Unicode
* >(pStr
));
240 rtl_freeMemory( pStr
);
241 if( !aDefPrt
.isEmpty() )
245 // get default printer from win.ini
247 GetProfileStringA( aImplWindows
, aImplDevice
, "", szBuffer
, sizeof( szBuffer
) );
250 // search for printer name
251 char* pBuf
= szBuffer
;
253 while ( *pTmp
&& (*pTmp
!= ',') )
255 return ImplSalGetUniString( pBuf
, static_cast<sal_Int32
>(pTmp
-pBuf
) );
261 static DWORD
ImplDeviceCaps( WinSalInfoPrinter
* pPrinter
, WORD nCaps
,
262 BYTE
* pOutput
, const ImplJobSetup
* pSetupData
)
264 DEVMODEW
const * pDevMode
;
265 if ( !pSetupData
|| !pSetupData
->GetDriverData() )
268 pDevMode
= SAL_DEVMODE_W( pSetupData
);
270 return DeviceCapabilitiesW( reinterpret_cast<LPCWSTR
>(pPrinter
->maDeviceName
.getStr()),
271 reinterpret_cast<LPCWSTR
>(pPrinter
->maPortName
.getStr()),
272 nCaps
, reinterpret_cast<LPWSTR
>(pOutput
), pDevMode
);
275 static bool ImplTestSalJobSetup( WinSalInfoPrinter
* pPrinter
,
276 ImplJobSetup
* pSetupData
, bool bDelete
)
278 if ( pSetupData
&& pSetupData
->GetDriverData() )
280 // signature and size must fit to avoid using
281 // JobSetups from a wrong system
283 // initialize versions from jobsetup
284 // those will be overwritten with driver's version
285 DEVMODEW
const * pDevModeW
= nullptr;
286 LONG dmSpecVersion
= -1;
287 LONG dmDriverVersion
= -1;
288 SalDriverData
const * pSalDriverData
= reinterpret_cast<SalDriverData
const *>(pSetupData
->GetDriverData());
289 BYTE
const * pDriverData
= reinterpret_cast<BYTE
const *>(pSalDriverData
) + pSalDriverData
->mnDriverOffset
;
290 pDevModeW
= reinterpret_cast<DEVMODEW
const *>(pDriverData
);
292 long nSysJobSize
= -1;
293 if( pPrinter
&& pDevModeW
)
295 // just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
296 // this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
297 // can avoid potential driver crashes as their jobsetups are often not compatible
298 // #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
300 LPWSTR pPrinterNameW
= reinterpret_cast<LPWSTR
>(const_cast<sal_Unicode
*>(pPrinter
->maDeviceName
.getStr()));
301 if ( !OpenPrinterW( pPrinterNameW
, &hPrn
, nullptr ) )
304 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
305 if( hPrn
== HGDI_ERROR
)
308 nSysJobSize
= DocumentPropertiesW( nullptr, hPrn
,
310 nullptr, nullptr, 0 );
312 if( nSysJobSize
< 0 )
314 ClosePrinter( hPrn
);
317 DEVMODEW
*pBuffer
= static_cast<DEVMODEW
*>(_alloca( nSysJobSize
));
318 LONG nRet
= DocumentPropertiesW( nullptr, hPrn
,
320 pBuffer
, nullptr, DM_OUT_BUFFER
);
323 ClosePrinter( hPrn
);
327 // the spec version differs between the windows platforms, ie 98,NT,2000/XP
328 // this allows us to throw away printer settings from other platforms that might crash a buggy driver
329 // we check the driver version as well
330 dmSpecVersion
= pBuffer
->dmSpecVersion
;
331 dmDriverVersion
= pBuffer
->dmDriverVersion
;
333 ClosePrinter( hPrn
);
335 SalDriverData
const * pSetupDriverData
= reinterpret_cast<SalDriverData
const *>(pSetupData
->GetDriverData());
336 if ( (pSetupData
->GetSystem() == JOBSETUP_SYSTEM_WINDOWS
) &&
337 (pPrinter
->maDriverName
== pSetupData
->GetDriver()) &&
338 (pSetupData
->GetDriverDataLen() > sizeof( SalDriverData
)) &&
339 (long)(pSetupData
->GetDriverDataLen() - pSetupDriverData
->mnDriverOffset
) == nSysJobSize
&&
340 pSetupDriverData
->mnSysSignature
== SAL_DRIVERDATA_SYSSIGN
)
343 (dmSpecVersion
== pDevModeW
->dmSpecVersion
) &&
344 (dmDriverVersion
== pDevModeW
->dmDriverVersion
) )
349 rtl_freeMemory( const_cast<sal_uInt8
*>(pSetupData
->GetDriverData()) );
350 pSetupData
->SetDriverData( nullptr );
351 pSetupData
->SetDriverDataLen( 0 );
358 static bool ImplUpdateSalJobSetup( WinSalInfoPrinter
* pPrinter
, ImplJobSetup
* pSetupData
,
359 bool bIn
, WinSalFrame
* pVisibleDlgParent
)
362 LPWSTR pPrinterNameW
= reinterpret_cast<LPWSTR
>(const_cast<sal_Unicode
*>(pPrinter
->maDeviceName
.getStr()));
363 if ( !OpenPrinterW( pPrinterNameW
, &hPrn
, nullptr ) )
365 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
366 if( hPrn
== HGDI_ERROR
)
371 DWORD nMode
= DM_OUT_BUFFER
;
372 SalDriverData
* pOutBuffer
= nullptr;
373 BYTE
const * pInBuffer
= nullptr;
375 LONG nSysJobSize
= DocumentPropertiesW( hWnd
, hPrn
,
377 nullptr, nullptr, 0 );
378 if ( nSysJobSize
< 0 )
380 ClosePrinter( hPrn
);
385 const std::size_t nDriverDataLen
= sizeof(SalDriverData
) + nSysJobSize
-1;
386 pOutBuffer
= static_cast<SalDriverData
*>(rtl_allocateZeroMemory( nDriverDataLen
));
387 pOutBuffer
->mnSysSignature
= SAL_DRIVERDATA_SYSSIGN
;
388 // calculate driver data offset including structure padding
389 pOutBuffer
->mnDriverOffset
= sal::static_int_cast
<sal_uInt16
>(
390 reinterpret_cast<char*>(pOutBuffer
->maDriverData
) -
391 reinterpret_cast<char*>(pOutBuffer
) );
393 // check if we have a suitable input buffer
394 if ( bIn
&& ImplTestSalJobSetup( pPrinter
, pSetupData
, false ) )
396 pInBuffer
= pSetupData
->GetDriverData() + reinterpret_cast<SalDriverData
const *>(pSetupData
->GetDriverData())->mnDriverOffset
;
397 nMode
|= DM_IN_BUFFER
;
400 // check if the dialog should be shown
401 if ( pVisibleDlgParent
)
403 hWnd
= pVisibleDlgParent
->mhWnd
;
404 nMode
|= DM_IN_PROMPT
;
407 // Release mutex, in the other case we don't get paints and so on
408 sal_uLong nMutexCount
=0;
409 if ( pVisibleDlgParent
)
410 nMutexCount
= ImplSalReleaseYieldMutex();
412 BYTE
* pOutDevMode
= (reinterpret_cast<BYTE
*>(pOutBuffer
) + pOutBuffer
->mnDriverOffset
);
413 nRet
= DocumentPropertiesW( hWnd
, hPrn
,
415 reinterpret_cast<LPDEVMODEW
>(pOutDevMode
), reinterpret_cast<LPDEVMODEW
>(const_cast<BYTE
*>(pInBuffer
)), nMode
);
416 if ( pVisibleDlgParent
)
417 ImplSalAcquireYieldMutex( nMutexCount
);
418 ClosePrinter( hPrn
);
420 if( (nRet
< 0) || (pVisibleDlgParent
&& (nRet
== IDCANCEL
)) )
422 rtl_freeMemory( pOutBuffer
);
426 // fill up string buffers with 0 so they do not influence a JobSetup's memcmp
427 if( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmSize
>= 64 )
429 sal_Int32 nLen
= rtl_ustr_getLength( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmDeviceName
);
430 if ( sal::static_int_cast
<size_t>(nLen
) < SAL_N_ELEMENTS( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmDeviceName
) )
431 memset( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmDeviceName
+nLen
, 0, sizeof( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmDeviceName
)-(nLen
*sizeof(sal_Unicode
)) );
433 if( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmSize
>= 166 )
435 sal_Int32 nLen
= rtl_ustr_getLength( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmFormName
);
436 if ( sal::static_int_cast
<size_t>(nLen
) < SAL_N_ELEMENTS( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmFormName
) )
437 memset( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmFormName
+nLen
, 0, sizeof( reinterpret_cast<LPDEVMODEW
>(pOutDevMode
)->dmFormName
)-(nLen
*sizeof(sal_Unicode
)) );
441 if ( pSetupData
->GetDriverData() )
442 rtl_freeMemory( const_cast<sal_uInt8
*>(pSetupData
->GetDriverData()) );
443 pSetupData
->SetDriverDataLen( nDriverDataLen
);
444 pSetupData
->SetDriverData(reinterpret_cast<BYTE
*>(pOutBuffer
));
445 pSetupData
->SetSystem( JOBSETUP_SYSTEM_WINDOWS
);
450 static void ImplDevModeToJobSetup( WinSalInfoPrinter
* pPrinter
, ImplJobSetup
* pSetupData
, JobSetFlags nFlags
)
452 if ( !pSetupData
|| !pSetupData
->GetDriverData() )
455 DEVMODEW
const * pDevModeW
= SAL_DEVMODE_W(pSetupData
);
456 if( pDevModeW
== nullptr )
460 if ( nFlags
& JobSetFlags::ORIENTATION
)
462 if ( pDevModeW
->dmOrientation
== DMORIENT_PORTRAIT
)
463 pSetupData
->SetOrientation( Orientation::Portrait
);
464 else if ( pDevModeW
->dmOrientation
== DMORIENT_LANDSCAPE
)
465 pSetupData
->SetOrientation( Orientation::Landscape
);
469 if ( nFlags
& JobSetFlags::PAPERBIN
)
471 const DWORD nCount
= ImplDeviceCaps( pPrinter
, DC_BINS
, nullptr, pSetupData
);
473 if ( nCount
&& (nCount
!= GDI_ERROR
) )
475 WORD
* pBins
= static_cast<WORD
*>(rtl_allocateZeroMemory( nCount
*sizeof(WORD
) ));
476 ImplDeviceCaps( pPrinter
, DC_BINS
, reinterpret_cast<BYTE
*>(pBins
), pSetupData
);
477 pSetupData
->SetPaperBin( 0 );
479 // search the right bin and assign index to mnPaperBin
480 for( DWORD i
= 0; i
< nCount
; ++i
)
482 if( pDevModeW
->dmDefaultSource
== pBins
[ i
] )
484 pSetupData
->SetPaperBin( (sal_uInt16
)i
);
489 rtl_freeMemory( pBins
);
494 if ( nFlags
& JobSetFlags::PAPERSIZE
)
496 if( (pDevModeW
->dmFields
& (DM_PAPERWIDTH
|DM_PAPERLENGTH
)) == (DM_PAPERWIDTH
|DM_PAPERLENGTH
) )
498 pSetupData
->SetPaperWidth( pDevModeW
->dmPaperWidth
*10 );
499 pSetupData
->SetPaperHeight( pDevModeW
->dmPaperLength
*10 );
503 const DWORD nPaperCount
= ImplDeviceCaps( pPrinter
, DC_PAPERS
, nullptr, pSetupData
);
504 WORD
* pPapers
= nullptr;
505 const DWORD nPaperSizeCount
= ImplDeviceCaps( pPrinter
, DC_PAPERSIZE
, nullptr, pSetupData
);
506 POINT
* pPaperSizes
= nullptr;
507 if ( nPaperCount
&& (nPaperCount
!= GDI_ERROR
) )
509 pPapers
= static_cast<WORD
*>(rtl_allocateZeroMemory(nPaperCount
*sizeof(WORD
)));
510 ImplDeviceCaps( pPrinter
, DC_PAPERS
, reinterpret_cast<BYTE
*>(pPapers
), pSetupData
);
512 if ( nPaperSizeCount
&& (nPaperSizeCount
!= GDI_ERROR
) )
514 pPaperSizes
= static_cast<POINT
*>(rtl_allocateZeroMemory(nPaperSizeCount
*sizeof(POINT
)));
515 ImplDeviceCaps( pPrinter
, DC_PAPERSIZE
, reinterpret_cast<BYTE
*>(pPaperSizes
), pSetupData
);
517 if( nPaperSizeCount
== nPaperCount
&& pPaperSizes
&& pPapers
)
519 for( DWORD i
= 0; i
< nPaperCount
; ++i
)
521 if( pPapers
[ i
] == pDevModeW
->dmPaperSize
)
523 pSetupData
->SetPaperWidth( pPaperSizes
[ i
].x
*10 );
524 pSetupData
->SetPaperHeight( pPaperSizes
[ i
].y
*10 );
530 rtl_freeMemory( pPapers
);
532 rtl_freeMemory( pPaperSizes
);
534 switch( pDevModeW
->dmPaperSize
)
537 pSetupData
->SetPaperFormat( PAPER_LETTER
);
539 case DMPAPER_TABLOID
:
540 pSetupData
->SetPaperFormat( PAPER_TABLOID
);
543 pSetupData
->SetPaperFormat( PAPER_LEDGER
);
546 pSetupData
->SetPaperFormat( PAPER_LEGAL
);
548 case DMPAPER_STATEMENT
:
549 pSetupData
->SetPaperFormat( PAPER_STATEMENT
);
551 case DMPAPER_EXECUTIVE
:
552 pSetupData
->SetPaperFormat( PAPER_EXECUTIVE
);
555 pSetupData
->SetPaperFormat( PAPER_A3
);
558 pSetupData
->SetPaperFormat( PAPER_A4
);
561 pSetupData
->SetPaperFormat( PAPER_A5
);
563 //See http://wiki.openoffice.org/wiki/DefaultPaperSize
565 //http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
566 //DMPAPER_B4 12 B4 (JIS) 257 x 364 mm
567 //http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
568 //also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
569 //matches our Excel filter's belief about the matching XlPaperSize
572 //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
573 ////"DMPAPER_B4 12 B4 (JIS) 250 x 354"
574 //which is bogus as it's either JIS 257 x 364 or ISO 250 x 353
577 pSetupData
->SetPaperFormat( PAPER_B4_JIS
);
580 pSetupData
->SetPaperFormat( PAPER_B5_JIS
);
583 pSetupData
->SetPaperFormat( PAPER_QUARTO
);
586 pSetupData
->SetPaperFormat( PAPER_10x14
);
589 pSetupData
->SetPaperFormat( PAPER_LETTER
);
592 pSetupData
->SetPaperFormat( PAPER_ENV_9
);
595 pSetupData
->SetPaperFormat( PAPER_ENV_10
);
598 pSetupData
->SetPaperFormat( PAPER_ENV_11
);
601 pSetupData
->SetPaperFormat( PAPER_ENV_12
);
604 pSetupData
->SetPaperFormat( PAPER_ENV_14
);
607 pSetupData
->SetPaperFormat( PAPER_C
);
610 pSetupData
->SetPaperFormat( PAPER_D
);
613 pSetupData
->SetPaperFormat( PAPER_E
);
616 pSetupData
->SetPaperFormat( PAPER_ENV_DL
);
619 pSetupData
->SetPaperFormat( PAPER_ENV_C5
);
622 pSetupData
->SetPaperFormat( PAPER_ENV_C3
);
625 pSetupData
->SetPaperFormat( PAPER_ENV_C4
);
628 pSetupData
->SetPaperFormat( PAPER_ENV_C6
);
630 case DMPAPER_ENV_C65
:
631 pSetupData
->SetPaperFormat( PAPER_ENV_C65
);
633 case DMPAPER_ENV_ITALY
:
634 pSetupData
->SetPaperFormat( PAPER_ENV_ITALY
);
636 case DMPAPER_ENV_MONARCH
:
637 pSetupData
->SetPaperFormat( PAPER_ENV_MONARCH
);
639 case DMPAPER_ENV_PERSONAL
:
640 pSetupData
->SetPaperFormat( PAPER_ENV_PERSONAL
);
642 case DMPAPER_FANFOLD_US
:
643 pSetupData
->SetPaperFormat( PAPER_FANFOLD_US
);
645 case DMPAPER_FANFOLD_STD_GERMAN
:
646 pSetupData
->SetPaperFormat( PAPER_FANFOLD_DE
);
648 case DMPAPER_FANFOLD_LGL_GERMAN
:
649 pSetupData
->SetPaperFormat( PAPER_FANFOLD_LEGAL_DE
);
652 pSetupData
->SetPaperFormat( PAPER_B4_ISO
);
654 case DMPAPER_JAPANESE_POSTCARD
:
655 pSetupData
->SetPaperFormat( PAPER_POSTCARD_JP
);
658 pSetupData
->SetPaperFormat( PAPER_9x11
);
661 pSetupData
->SetPaperFormat( PAPER_10x11
);
664 pSetupData
->SetPaperFormat( PAPER_15x11
);
666 case DMPAPER_ENV_INVITE
:
667 pSetupData
->SetPaperFormat( PAPER_ENV_INVITE
);
670 pSetupData
->SetPaperFormat( PAPER_A_PLUS
);
673 pSetupData
->SetPaperFormat( PAPER_B_PLUS
);
675 case DMPAPER_LETTER_PLUS
:
676 pSetupData
->SetPaperFormat( PAPER_LETTER_PLUS
);
678 case DMPAPER_A4_PLUS
:
679 pSetupData
->SetPaperFormat( PAPER_A4_PLUS
);
682 pSetupData
->SetPaperFormat( PAPER_A2
);
684 case DMPAPER_DBL_JAPANESE_POSTCARD
:
685 pSetupData
->SetPaperFormat( PAPER_DOUBLEPOSTCARD_JP
);
688 pSetupData
->SetPaperFormat( PAPER_A6
);
691 pSetupData
->SetPaperFormat( PAPER_B6_JIS
);
694 pSetupData
->SetPaperFormat( PAPER_12x11
);
697 pSetupData
->SetPaperFormat( PAPER_USER
);
702 if( nFlags
& JobSetFlags::DUPLEXMODE
)
704 DuplexMode eDuplex
= DuplexMode::Unknown
;
705 if( (pDevModeW
->dmFields
& DM_DUPLEX
) )
707 if( pDevModeW
->dmDuplex
== DMDUP_SIMPLEX
)
708 eDuplex
= DuplexMode::Off
;
709 else if( pDevModeW
->dmDuplex
== DMDUP_VERTICAL
)
710 eDuplex
= DuplexMode::LongEdge
;
711 else if( pDevModeW
->dmDuplex
== DMDUP_HORIZONTAL
)
712 eDuplex
= DuplexMode::ShortEdge
;
714 pSetupData
->SetDuplexMode( eDuplex
);
718 static void ImplJobSetupToDevMode( WinSalInfoPrinter
* pPrinter
, const ImplJobSetup
* pSetupData
, JobSetFlags nFlags
)
720 if ( !pSetupData
|| !pSetupData
->GetDriverData() )
723 DEVMODEW
* pDevModeW
= const_cast<DEVMODEW
*>(SAL_DEVMODE_W(pSetupData
));
724 if( pDevModeW
== nullptr )
728 if ( nFlags
& JobSetFlags::ORIENTATION
)
730 pDevModeW
->dmFields
|= DM_ORIENTATION
;
731 if ( pSetupData
->GetOrientation() == Orientation::Portrait
)
732 pDevModeW
->dmOrientation
= DMORIENT_PORTRAIT
;
734 pDevModeW
->dmOrientation
= DMORIENT_LANDSCAPE
;
738 if ( nFlags
& JobSetFlags::PAPERBIN
)
740 const DWORD nCount
= ImplDeviceCaps( pPrinter
, DC_BINS
, nullptr, pSetupData
);
742 if ( nCount
&& (nCount
!= GDI_ERROR
) )
744 WORD
* pBins
= static_cast<WORD
*>(rtl_allocateZeroMemory(nCount
*sizeof(WORD
)));
745 ImplDeviceCaps( pPrinter
, DC_BINS
, reinterpret_cast<BYTE
*>(pBins
), pSetupData
);
746 pDevModeW
->dmFields
|= DM_DEFAULTSOURCE
;
747 pDevModeW
->dmDefaultSource
= pBins
[ pSetupData
->GetPaperBin() ];
748 rtl_freeMemory( pBins
);
753 if ( nFlags
& JobSetFlags::PAPERSIZE
)
755 pDevModeW
->dmFields
|= DM_PAPERSIZE
;
756 pDevModeW
->dmPaperWidth
= 0;
757 pDevModeW
->dmPaperLength
= 0;
759 switch( pSetupData
->GetPaperFormat() )
762 pDevModeW
->dmPaperSize
= DMPAPER_A2
;
765 pDevModeW
->dmPaperSize
= DMPAPER_A3
;
768 pDevModeW
->dmPaperSize
= DMPAPER_A4
;
771 pDevModeW
->dmPaperSize
= DMPAPER_A5
;
774 pDevModeW
->dmPaperSize
= DMPAPER_ISO_B4
;
777 pDevModeW
->dmPaperSize
= DMPAPER_LETTER
;
780 pDevModeW
->dmPaperSize
= DMPAPER_LEGAL
;
783 pDevModeW
->dmPaperSize
= DMPAPER_TABLOID
;
786 //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
787 //DMPAPER_ENV_B6 is documented as:
788 //"DMPAPER_ENV_B6 35 Envelope B6 176 x 125 mm"
789 //which is the wrong way around, it is surely 125 x 176, i.e.
790 //compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
791 //DMPAPER_ENV_B4 33 Envelope B4 250 x 353 mm
792 //DMPAPER_ENV_B5 34 Envelope B5 176 x 250 mm
794 pDevModeW
->dmPaperSize
= DMPAPER_ENV_B6
;
798 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C4
;
801 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C5
;
804 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C6
;
807 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C65
;
810 pDevModeW
->dmPaperSize
= DMPAPER_ENV_DL
;
813 pDevModeW
->dmPaperSize
= DMPAPER_CSHEET
;
816 pDevModeW
->dmPaperSize
= DMPAPER_DSHEET
;
819 pDevModeW
->dmPaperSize
= DMPAPER_ESHEET
;
821 case PAPER_EXECUTIVE
:
822 pDevModeW
->dmPaperSize
= DMPAPER_EXECUTIVE
;
824 case PAPER_FANFOLD_LEGAL_DE
:
825 pDevModeW
->dmPaperSize
= DMPAPER_FANFOLD_LGL_GERMAN
;
827 case PAPER_ENV_MONARCH
:
828 pDevModeW
->dmPaperSize
= DMPAPER_ENV_MONARCH
;
830 case PAPER_ENV_PERSONAL
:
831 pDevModeW
->dmPaperSize
= DMPAPER_ENV_PERSONAL
;
834 pDevModeW
->dmPaperSize
= DMPAPER_ENV_9
;
837 pDevModeW
->dmPaperSize
= DMPAPER_ENV_10
;
840 pDevModeW
->dmPaperSize
= DMPAPER_ENV_11
;
843 pDevModeW
->dmPaperSize
= DMPAPER_ENV_12
;
845 //See the comments on DMPAPER_B4 above
847 pDevModeW
->dmPaperSize
= DMPAPER_B4
;
850 pDevModeW
->dmPaperSize
= DMPAPER_B5
;
853 pDevModeW
->dmPaperSize
= DMPAPER_B6_JIS
;
856 pDevModeW
->dmPaperSize
= DMPAPER_LEDGER
;
858 case PAPER_STATEMENT
:
859 pDevModeW
->dmPaperSize
= DMPAPER_STATEMENT
;
862 pDevModeW
->dmPaperSize
= DMPAPER_10X14
;
865 pDevModeW
->dmPaperSize
= DMPAPER_ENV_14
;
868 pDevModeW
->dmPaperSize
= DMPAPER_ENV_C3
;
870 case PAPER_ENV_ITALY
:
871 pDevModeW
->dmPaperSize
= DMPAPER_ENV_ITALY
;
873 case PAPER_FANFOLD_US
:
874 pDevModeW
->dmPaperSize
= DMPAPER_FANFOLD_US
;
876 case PAPER_FANFOLD_DE
:
877 pDevModeW
->dmPaperSize
= DMPAPER_FANFOLD_STD_GERMAN
;
879 case PAPER_POSTCARD_JP
:
880 pDevModeW
->dmPaperSize
= DMPAPER_JAPANESE_POSTCARD
;
883 pDevModeW
->dmPaperSize
= DMPAPER_9X11
;
886 pDevModeW
->dmPaperSize
= DMPAPER_10X11
;
889 pDevModeW
->dmPaperSize
= DMPAPER_15X11
;
891 case PAPER_ENV_INVITE
:
892 pDevModeW
->dmPaperSize
= DMPAPER_ENV_INVITE
;
895 pDevModeW
->dmPaperSize
= DMPAPER_A_PLUS
;
898 pDevModeW
->dmPaperSize
= DMPAPER_B_PLUS
;
900 case PAPER_LETTER_PLUS
:
901 pDevModeW
->dmPaperSize
= DMPAPER_LETTER_PLUS
;
904 pDevModeW
->dmPaperSize
= DMPAPER_A4_PLUS
;
906 case PAPER_DOUBLEPOSTCARD_JP
:
907 pDevModeW
->dmPaperSize
= DMPAPER_DBL_JAPANESE_POSTCARD
;
910 pDevModeW
->dmPaperSize
= DMPAPER_A6
;
913 pDevModeW
->dmPaperSize
= DMPAPER_12X11
;
918 const DWORD nPaperCount
= ImplDeviceCaps( pPrinter
, DC_PAPERS
, nullptr, pSetupData
);
919 WORD
* pPapers
= nullptr;
920 const DWORD nPaperSizeCount
= ImplDeviceCaps( pPrinter
, DC_PAPERSIZE
, nullptr, pSetupData
);
921 POINT
* pPaperSizes
= nullptr;
922 DWORD nLandscapeAngle
= ImplDeviceCaps( pPrinter
, DC_ORIENTATION
, nullptr, pSetupData
);
923 if ( nPaperCount
&& (nPaperCount
!= GDI_ERROR
) )
925 pPapers
= static_cast<WORD
*>(rtl_allocateZeroMemory(nPaperCount
*sizeof(WORD
)));
926 ImplDeviceCaps( pPrinter
, DC_PAPERS
, reinterpret_cast<BYTE
*>(pPapers
), pSetupData
);
928 if ( nPaperSizeCount
&& (nPaperSizeCount
!= GDI_ERROR
) )
930 pPaperSizes
= static_cast<POINT
*>(rtl_allocateZeroMemory(nPaperSizeCount
*sizeof(POINT
)));
931 ImplDeviceCaps( pPrinter
, DC_PAPERSIZE
, reinterpret_cast<BYTE
*>(pPaperSizes
), pSetupData
);
933 if ( (nPaperSizeCount
== nPaperCount
) && pPapers
&& pPaperSizes
)
935 PaperInfo
aInfo(pSetupData
->GetPaperWidth(), pSetupData
->GetPaperHeight());
936 // compare paper formats and select a good match
937 for ( DWORD i
= 0; i
< nPaperCount
; ++i
)
939 if ( aInfo
.sloppyEqual(PaperInfo(pPaperSizes
[i
].x
*10, pPaperSizes
[i
].y
*10)))
946 // If the printer supports landscape orientation, check paper sizes again
947 // with landscape orientation. This is necessary as a printer driver provides
948 // all paper sizes with portrait orientation only!!
949 if ( !nPaper
&& nLandscapeAngle
!= 0 )
951 PaperInfo
aRotatedInfo(pSetupData
->GetPaperHeight(), pSetupData
->GetPaperWidth());
952 for ( DWORD i
= 0; i
< nPaperCount
; ++i
)
954 if ( aRotatedInfo
.sloppyEqual(PaperInfo(pPaperSizes
[i
].x
*10, pPaperSizes
[i
].y
*10)) )
963 pDevModeW
->dmPaperSize
= nPaper
;
968 pDevModeW
->dmFields
|= DM_PAPERLENGTH
| DM_PAPERWIDTH
;
969 pDevModeW
->dmPaperSize
= DMPAPER_USER
;
970 pDevModeW
->dmPaperWidth
= (short)(pSetupData
->GetPaperWidth()/10);
971 pDevModeW
->dmPaperLength
= (short)(pSetupData
->GetPaperHeight()/10);
975 rtl_freeMemory(pPapers
);
977 rtl_freeMemory(pPaperSizes
);
983 if( (nFlags
& JobSetFlags::DUPLEXMODE
) )
985 switch( pSetupData
->GetDuplexMode() )
987 case DuplexMode::Off
:
988 pDevModeW
->dmFields
|= DM_DUPLEX
;
989 pDevModeW
->dmDuplex
= DMDUP_SIMPLEX
;
991 case DuplexMode::ShortEdge
:
992 pDevModeW
->dmFields
|= DM_DUPLEX
;
993 pDevModeW
->dmDuplex
= DMDUP_HORIZONTAL
;
995 case DuplexMode::LongEdge
:
996 pDevModeW
->dmFields
|= DM_DUPLEX
;
997 pDevModeW
->dmDuplex
= DMDUP_VERTICAL
;
999 case DuplexMode::Unknown
:
1005 static HDC
ImplCreateICW_WithCatch( LPWSTR pDriver
,
1007 DEVMODEW
const * pDevMode
)
1010 CATCH_DRIVER_EX_BEGIN
;
1011 hDC
= CreateICW( pDriver
, pDevice
, nullptr, pDevMode
);
1012 CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
1016 static HDC
ImplCreateSalPrnIC( WinSalInfoPrinter
* pPrinter
, const ImplJobSetup
* pSetupData
)
1019 DEVMODEW
const * pDevMode
;
1020 if ( pSetupData
&& pSetupData
->GetDriverData() )
1021 pDevMode
= SAL_DEVMODE_W( pSetupData
);
1024 // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
1025 // pl: does this hold true for Unicode functions ?
1026 if( pPrinter
->maDriverName
.getLength() > 2048 || pPrinter
->maDeviceName
.getLength() > 2048 )
1028 sal_Unicode pDriverName
[ 4096 ];
1029 sal_Unicode pDeviceName
[ 4096 ];
1030 memcpy( pDriverName
, pPrinter
->maDriverName
.getStr(), pPrinter
->maDriverName
.getLength()*sizeof(sal_Unicode
));
1031 memset( pDriverName
+pPrinter
->maDriverName
.getLength(), 0, 32 );
1032 memcpy( pDeviceName
, pPrinter
->maDeviceName
.getStr(), pPrinter
->maDeviceName
.getLength()*sizeof(sal_Unicode
));
1033 memset( pDeviceName
+pPrinter
->maDeviceName
.getLength(), 0, 32 );
1034 hDC
= ImplCreateICW_WithCatch( reinterpret_cast< LPWSTR
>(pDriverName
),
1035 reinterpret_cast< LPCWSTR
>(pDeviceName
),
1040 static WinSalGraphics
* ImplCreateSalPrnGraphics( HDC hDC
)
1042 WinSalGraphics
* pGraphics
= new WinSalGraphics(WinSalGraphics::PRINTER
, false, nullptr, /* CHECKME */ nullptr);
1043 pGraphics
->SetLayout( SalLayoutFlags::NONE
);
1044 pGraphics
->setHDC(hDC
);
1045 pGraphics
->InitGraphics();
1049 static bool ImplUpdateSalPrnIC( WinSalInfoPrinter
* pPrinter
, const ImplJobSetup
* pSetupData
)
1051 HDC hNewDC
= ImplCreateSalPrnIC( pPrinter
, pSetupData
);
1055 if ( pPrinter
->mpGraphics
)
1057 pPrinter
->mpGraphics
->DeInitGraphics();
1058 DeleteDC( pPrinter
->mpGraphics
->getHDC() );
1059 delete pPrinter
->mpGraphics
;
1062 pPrinter
->mpGraphics
= ImplCreateSalPrnGraphics( hNewDC
);
1063 pPrinter
->mhDC
= hNewDC
;
1069 SalInfoPrinter
* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo
* pQueueInfo
,
1070 ImplJobSetup
* pSetupData
)
1072 WinSalInfoPrinter
* pPrinter
= new WinSalInfoPrinter
;
1073 if( ! pQueueInfo
->mpSysData
)
1074 GetPrinterQueueState( pQueueInfo
);
1075 pPrinter
->maDriverName
= pQueueInfo
->maDriver
;
1076 pPrinter
->maDeviceName
= pQueueInfo
->maPrinterName
;
1077 pPrinter
->maPortName
= pQueueInfo
->mpSysData
?
1078 *pQueueInfo
->mpSysData
1081 // check if the provided setup data match the actual printer
1082 ImplTestSalJobSetup( pPrinter
, pSetupData
, true );
1084 HDC hDC
= ImplCreateSalPrnIC( pPrinter
, pSetupData
);
1091 pPrinter
->mpGraphics
= ImplCreateSalPrnGraphics( hDC
);
1092 pPrinter
->mhDC
= hDC
;
1093 if ( !pSetupData
->GetDriverData() )
1094 ImplUpdateSalJobSetup( pPrinter
, pSetupData
, false, nullptr );
1095 ImplDevModeToJobSetup( pPrinter
, pSetupData
, JobSetFlags::ALL
);
1096 pSetupData
->SetSystem( JOBSETUP_SYSTEM_WINDOWS
);
1101 void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter
* pPrinter
)
1107 WinSalInfoPrinter::WinSalInfoPrinter() :
1108 mpGraphics( nullptr ),
1112 m_bPapersInit
= FALSE
;
1115 WinSalInfoPrinter::~WinSalInfoPrinter()
1119 mpGraphics
->DeInitGraphics();
1120 DeleteDC( mpGraphics
->getHDC() );
1125 void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup
* pSetupData
)
1127 m_aPaperFormats
.clear();
1129 DWORD nCount
= ImplDeviceCaps( this, DC_PAPERSIZE
, nullptr, pSetupData
);
1130 if( nCount
== GDI_ERROR
)
1135 POINT
* pPaperSizes
= static_cast<POINT
*>(rtl_allocateZeroMemory(nCount
*sizeof(POINT
)));
1136 ImplDeviceCaps( this, DC_PAPERSIZE
, reinterpret_cast<BYTE
*>(pPaperSizes
), pSetupData
);
1138 sal_Unicode
* pNamesBuffer
= static_cast<sal_Unicode
*>(rtl_allocateMemory(nCount
*64*sizeof(sal_Unicode
)));
1139 ImplDeviceCaps( this, DC_PAPERNAMES
, reinterpret_cast<BYTE
*>(pNamesBuffer
), pSetupData
);
1140 for( DWORD i
= 0; i
< nCount
; ++i
)
1142 PaperInfo
aInfo(pPaperSizes
[i
].x
* 10, pPaperSizes
[i
].y
* 10);
1143 m_aPaperFormats
.push_back( aInfo
);
1145 rtl_freeMemory( pNamesBuffer
);
1146 rtl_freeMemory( pPaperSizes
);
1149 m_bPapersInit
= true;
1152 int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup
* pSetupData
)
1154 const DWORD nRet
= ImplDeviceCaps( this, DC_ORIENTATION
, nullptr, pSetupData
);
1156 if( nRet
!= GDI_ERROR
)
1157 return static_cast<int>(nRet
) * 10;
1158 return 900; // guess
1161 SalGraphics
* WinSalInfoPrinter::AcquireGraphics()
1172 void WinSalInfoPrinter::ReleaseGraphics( SalGraphics
* )
1177 bool WinSalInfoPrinter::Setup( SalFrame
* pFrame
, ImplJobSetup
* pSetupData
)
1179 if ( ImplUpdateSalJobSetup( this, pSetupData
, true, static_cast<WinSalFrame
*>(pFrame
) ) )
1181 ImplDevModeToJobSetup( this, pSetupData
, JobSetFlags::ALL
);
1182 return ImplUpdateSalPrnIC( this, pSetupData
);
1188 bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup
* pSetupData
)
1190 if ( !ImplTestSalJobSetup( this, pSetupData
, false ) )
1192 return ImplUpdateSalPrnIC( this, pSetupData
);
1195 bool WinSalInfoPrinter::SetData( JobSetFlags nFlags
, ImplJobSetup
* pSetupData
)
1197 ImplJobSetupToDevMode( this, pSetupData
, nFlags
);
1198 if ( ImplUpdateSalJobSetup( this, pSetupData
, true, nullptr ) )
1200 ImplDevModeToJobSetup( this, pSetupData
, nFlags
);
1201 return ImplUpdateSalPrnIC( this, pSetupData
);
1207 sal_uLong
WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup
* pSetupData
)
1209 DWORD nRet
= ImplDeviceCaps( this, DC_BINS
, nullptr, pSetupData
);
1210 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1216 OUString
WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup
* pSetupData
, sal_uLong nPaperBin
)
1218 OUString aPaperBinName
;
1220 DWORD nBins
= ImplDeviceCaps( this, DC_BINNAMES
, nullptr, pSetupData
);
1221 if ( (nPaperBin
< nBins
) && (nBins
!= GDI_ERROR
) )
1223 sal_Unicode
* pBuffer
= new sal_Unicode
[nBins
*24];
1224 DWORD nRet
= ImplDeviceCaps( this, DC_BINNAMES
, reinterpret_cast<BYTE
*>(pBuffer
), pSetupData
);
1225 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1226 aPaperBinName
= OUString( pBuffer
+ (nPaperBin
*24) );
1230 return aPaperBinName
;
1233 sal_uInt32
WinSalInfoPrinter::GetCapabilities( const ImplJobSetup
* pSetupData
, PrinterCapType nType
)
1239 case PrinterCapType::SupportDialog
:
1241 case PrinterCapType::Copies
:
1242 nRet
= ImplDeviceCaps( this, DC_COPIES
, nullptr, pSetupData
);
1243 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1246 case PrinterCapType::CollateCopies
:
1247 nRet
= ImplDeviceCaps( this, DC_COLLATE
, nullptr, pSetupData
);
1248 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1250 nRet
= ImplDeviceCaps( this, DC_COPIES
, nullptr, pSetupData
);
1251 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1256 case PrinterCapType::SetOrientation
:
1257 nRet
= ImplDeviceCaps( this, DC_ORIENTATION
, nullptr, pSetupData
);
1258 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1262 case PrinterCapType::SetPaperBin
:
1263 nRet
= ImplDeviceCaps( this, DC_BINS
, nullptr, pSetupData
);
1264 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1268 case PrinterCapType::SetPaperSize
:
1269 case PrinterCapType::SetPaper
:
1270 nRet
= ImplDeviceCaps( this, DC_PAPERS
, nullptr, pSetupData
);
1271 if ( nRet
&& (nRet
!= GDI_ERROR
) )
1282 void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup
*,
1283 long& rOutWidth
, long& rOutHeight
,
1284 long& rPageOffX
, long& rPageOffY
,
1285 long& rPageWidth
, long& rPageHeight
)
1289 rOutWidth
= GetDeviceCaps( hDC
, HORZRES
);
1290 rOutHeight
= GetDeviceCaps( hDC
, VERTRES
);
1292 rPageOffX
= GetDeviceCaps( hDC
, PHYSICALOFFSETX
);
1293 rPageOffY
= GetDeviceCaps( hDC
, PHYSICALOFFSETY
);
1294 rPageWidth
= GetDeviceCaps( hDC
, PHYSICALWIDTH
);
1295 rPageHeight
= GetDeviceCaps( hDC
, PHYSICALHEIGHT
);
1299 SalPrinter
* WinSalInstance::CreatePrinter( SalInfoPrinter
* pInfoPrinter
)
1301 WinSalPrinter
* pPrinter
= new WinSalPrinter
;
1302 pPrinter
->mpInfoPrinter
= static_cast<WinSalInfoPrinter
*>(pInfoPrinter
);
1306 void WinSalInstance::DestroyPrinter( SalPrinter
* pPrinter
)
1311 BOOL CALLBACK
SalPrintAbortProc( HDC hPrnDC
, int /* nError */ )
1313 SalData
* pSalData
= GetSalData();
1314 WinSalPrinter
* pPrinter
;
1322 if ( PeekMessageW( &aMsg
, nullptr, 0, 0, PM_REMOVE
) )
1324 TranslateMessage( &aMsg
);
1325 DispatchMessageW( &aMsg
);
1334 pPrinter
= pSalData
->mpFirstPrinter
;
1337 if( pPrinter
->mhDC
== hPrnDC
)
1340 pPrinter
= pPrinter
->mpNextPrinter
;
1343 if ( !pPrinter
|| pPrinter
->mbAbort
)
1351 static DEVMODEW
const * ImplSalSetCopies( DEVMODEW
const * pDevMode
, sal_uLong nCopies
, bool bCollate
)
1353 if ( pDevMode
&& (nCopies
> 1) )
1355 if ( nCopies
> 32765 )
1357 sal_uLong nDevSize
= pDevMode
->dmSize
+pDevMode
->dmDriverExtra
;
1358 LPDEVMODEW pNewDevMode
= static_cast<LPDEVMODEW
>(rtl_allocateMemory( nDevSize
));
1359 memcpy( pNewDevMode
, pDevMode
, nDevSize
);
1360 pNewDevMode
->dmFields
|= DM_COPIES
;
1361 pNewDevMode
->dmCopies
= (short)(sal_uInt16
)nCopies
;
1362 pNewDevMode
->dmFields
|= DM_COLLATE
;
1364 pNewDevMode
->dmCollate
= DMCOLLATE_TRUE
;
1366 pNewDevMode
->dmCollate
= DMCOLLATE_FALSE
;
1376 WinSalPrinter::WinSalPrinter() :
1377 mpGraphics( nullptr ),
1378 mpInfoPrinter( nullptr ),
1379 mpNextPrinter( nullptr ),
1387 SalData
* pSalData
= GetSalData();
1388 // insert printer in printerlist
1389 mpNextPrinter
= pSalData
->mpFirstPrinter
;
1390 pSalData
->mpFirstPrinter
= this;
1393 WinSalPrinter::~WinSalPrinter()
1395 SalData
* pSalData
= GetSalData();
1397 // release DC if there is one still around because of AbortJob
1403 mpGraphics
->DeInitGraphics();
1410 // remove printer from printerlist
1411 if ( this == pSalData
->mpFirstPrinter
)
1412 pSalData
->mpFirstPrinter
= mpNextPrinter
;
1415 WinSalPrinter
* pTempPrinter
= pSalData
->mpFirstPrinter
;
1417 while( pTempPrinter
->mpNextPrinter
!= this )
1418 pTempPrinter
= pTempPrinter
->mpNextPrinter
;
1420 pTempPrinter
->mpNextPrinter
= mpNextPrinter
;
1425 void WinSalPrinter::markInvalid()
1430 // need wrappers for StarTocW/A to use structured exception handling
1431 // since SEH does not mix with standard exception handling's cleanup
1432 static int lcl_StartDocW( HDC hDC
, DOCINFOW
* pInfo
, WinSalPrinter
* pPrt
)
1436 CATCH_DRIVER_EX_BEGIN
;
1437 nRet
= ::StartDocW( hDC
, pInfo
);
1438 CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt
);
1442 bool WinSalPrinter::StartJob( const OUString
* pFileName
,
1443 const OUString
& rJobName
,
1448 ImplJobSetup
* pSetupData
)
1453 mbCollate
= bCollate
;
1455 DEVMODEW
const * pOrgDevModeW
= nullptr;
1456 DEVMODEW
const * pDevModeW
= nullptr;
1458 if ( pSetupData
&& pSetupData
->GetDriverData() )
1460 pOrgDevModeW
= SAL_DEVMODE_W( pSetupData
);
1461 pDevModeW
= ImplSalSetCopies( pOrgDevModeW
, nCopies
, bCollate
);
1464 // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
1465 sal_Unicode aDrvBuf
[4096];
1466 sal_Unicode aDevBuf
[4096];
1467 memcpy( aDrvBuf
, mpInfoPrinter
->maDriverName
.getStr(), (mpInfoPrinter
->maDriverName
.getLength()+1)*sizeof(sal_Unicode
));
1468 memcpy( aDevBuf
, mpInfoPrinter
->maDeviceName
.getStr(), (mpInfoPrinter
->maDeviceName
.getLength()+1)*sizeof(sal_Unicode
));
1469 hDC
= CreateDCW( reinterpret_cast<LPCWSTR
>(aDrvBuf
),
1470 reinterpret_cast<LPCWSTR
>(aDevBuf
),
1474 if ( pDevModeW
!= pOrgDevModeW
)
1475 rtl_freeMemory( const_cast<DEVMODEW
*>(pDevModeW
) );
1479 mnError
= SAL_PRINTER_ERROR_GENERALERROR
;
1483 // make sure mhDC is set before the printer driver may call our abortproc
1485 if ( SetAbortProc( hDC
, SalPrintAbortProc
) <= 0 )
1487 mnError
= SAL_PRINTER_ERROR_GENERALERROR
;
1494 // As the Telecom Balloon Fax driver tends to send messages repeatedly
1495 // we try to process first all, and then insert a dummy message
1502 if ( PeekMessageW( &aMsg
, nullptr, 0, 0, PM_REMOVE
) )
1504 TranslateMessage( &aMsg
);
1505 DispatchMessageW( &aMsg
);
1515 BOOL
const ret
= PostMessageW(GetSalData()->mpFirstInstance
->mhComWnd
, SAL_MSG_DUMMY
, 0, 0);
1516 SAL_WARN_IF(0 == ret
, "vcl", "ERROR: PostMessage() failed!");
1518 // bring up a file chooser if printing to file port but no file name given
1519 OUString aOutFileName
;
1520 if( mpInfoPrinter
->maPortName
.equalsIgnoreAsciiCase( "FILE:" ) && !(pFileName
&& !pFileName
->isEmpty()) )
1523 uno::Reference
< uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
1524 uno::Reference
< XFilePicker3
> xFilePicker
= FilePicker::createWithMode(xContext
, TemplateDescription::FILESAVE_SIMPLE
);
1526 if( xFilePicker
->execute() == ExecutableDialogResults::OK
)
1528 Sequence
< OUString
> aPathSeq( xFilePicker
->getSelectedFiles() );
1529 INetURLObject
aObj( aPathSeq
[0] );
1530 // we're using ansi calls (StartDocA) so convert the string
1531 aOutFileName
= aObj
.PathToFileName();
1535 mnError
= SAL_PRINTER_ERROR_ABORT
;
1541 memset( &aInfo
, 0, sizeof( DOCINFOW
) );
1542 aInfo
.cbSize
= sizeof( aInfo
);
1543 aInfo
.lpszDocName
= rJobName
.getStr();
1544 if ( pFileName
|| aOutFileName
.getLength() )
1546 if ( (pFileName
&& !pFileName
->isEmpty()) || aOutFileName
.getLength() )
1548 aInfo
.lpszOutput
= (pFileName
&& !pFileName
->isEmpty()) ? pFileName
->getStr() : aOutFileName
.getStr();
1551 aInfo
.lpszOutput
= L
"FILE:";
1554 aInfo
.lpszOutput
= nullptr;
1557 int nRet
= lcl_StartDocW( hDC
, &aInfo
, this );
1561 long nError
= GetLastError();
1562 if ( (nRet
== SP_USERABORT
) || (nRet
== SP_APPABORT
) || (nError
== ERROR_PRINT_CANCELLED
) || (nError
== ERROR_CANCELLED
) )
1563 mnError
= SAL_PRINTER_ERROR_ABORT
;
1565 mnError
= SAL_PRINTER_ERROR_GENERALERROR
;
1572 bool WinSalPrinter::EndJob()
1575 if ( isValid() && hDC
)
1579 mpGraphics
->DeInitGraphics();
1581 mpGraphics
= nullptr;
1584 // #i54419# Windows fax printer brings up a dialog in EndDoc
1585 // which text previously copied in soffice process can be
1586 // pasted to -> deadlock due to mutex not released.
1587 // it should be safe to release the yield mutex over the EndDoc
1588 // call, however the real solution is supposed to be the threading
1589 // framework yet to come.
1590 volatile sal_uLong nAcquire
= GetSalData()->mpFirstInstance
->ReleaseYieldMutex();
1591 CATCH_DRIVER_EX_BEGIN
;
1592 if( ::EndDoc( hDC
) <= 0 )
1594 CATCH_DRIVER_EX_END( "exception in EndDoc", this );
1596 GetSalData()->mpFirstInstance
->AcquireYieldMutex( nAcquire
);
1604 SalGraphics
* WinSalPrinter::StartPage( ImplJobSetup
* pSetupData
, bool bNewJobData
)
1606 if( ! isValid() || mhDC
== nullptr )
1610 if ( pSetupData
&& pSetupData
->GetDriverData() && bNewJobData
)
1612 DEVMODEW
const * pOrgDevModeW
;
1613 DEVMODEW
const * pDevModeW
;
1614 pOrgDevModeW
= SAL_DEVMODE_W( pSetupData
);
1615 pDevModeW
= ImplSalSetCopies( pOrgDevModeW
, mnCopies
, mbCollate
);
1616 ResetDCW( hDC
, pDevModeW
);
1617 if ( pDevModeW
!= pOrgDevModeW
)
1618 rtl_freeMemory( const_cast<DEVMODEW
*>(pDevModeW
) );
1620 volatile int nRet
= 0;
1621 CATCH_DRIVER_EX_BEGIN
;
1622 nRet
= ::StartPage( hDC
);
1623 CATCH_DRIVER_EX_END( "exception in StartPage", this );
1628 mnError
= SAL_PRINTER_ERROR_GENERALERROR
;
1632 // Hack to work around old PostScript printer drivers optimizing away empty pages
1633 // TODO: move into ImplCreateSalPrnGraphics()?
1634 HPEN hTempPen
= SelectPen( hDC
, GetStockPen( NULL_PEN
) );
1635 HBRUSH hTempBrush
= SelectBrush( hDC
, GetStockBrush( NULL_BRUSH
) );
1636 WIN_Rectangle( hDC
, -8000, -8000, -7999, -7999 );
1637 SelectPen( hDC
, hTempPen
);
1638 SelectBrush( hDC
, hTempBrush
);
1640 mpGraphics
= ImplCreateSalPrnGraphics( hDC
);
1644 void WinSalPrinter::EndPage()
1647 if ( hDC
&& mpGraphics
)
1649 mpGraphics
->DeInitGraphics();
1651 mpGraphics
= nullptr;
1657 volatile int nRet
= 0;
1658 CATCH_DRIVER_EX_BEGIN
;
1659 nRet
= ::EndPage( hDC
);
1660 CATCH_DRIVER_EX_END( "exception in EndPage", this );
1665 mnError
= SAL_PRINTER_ERROR_GENERALERROR
;
1669 sal_uLong
WinSalPrinter::GetErrorCode()
1674 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */