build fix
[LibreOffice.git] / vcl / win / gdi / salprn.cxx
blobdb54dd0069f04a4ec32a9f1a9092994c3965b0f5
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 <string.h>
22 #include <svsys.h>
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>
36 #include <print.h>
37 #include <jobset.h>
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>
47 #include <malloc.h>
49 #if defined ( __MINGW32__ )
50 #include <sehandler.hxx>
51 #endif
53 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
54 #define CATCH_DRIVER_EX_BEGIN \
55 jmp_buf jmpbuf; \
56 __SEHandler han; \
57 if (__builtin_setjmp(jmpbuf) == 0) \
58 { \
59 han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER)
61 #define CATCH_DRIVER_EX_END(mes, p) \
62 } \
63 han.Reset()
64 #define CATCH_DRIVER_EX_END_2(mes) \
65 } \
66 han.Reset()
67 #else
68 #define CATCH_DRIVER_EX_BEGIN \
69 __try \
71 #define CATCH_DRIVER_EX_END(mes, p) \
72 } \
73 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
74 { \
75 OSL_FAIL( mes ); \
76 p->markInvalid(); \
78 #define CATCH_DRIVER_EX_END_2(mes) \
79 } \
80 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
81 { \
82 OSL_FAIL( mes ); \
84 #endif
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));
100 return pRet;
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;
156 return nStatus;
160 void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
162 DWORD i;
163 DWORD nBytes = 0;
164 DWORD nInfoPrn4 = 0;
165 EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, nullptr, 0, &nBytes, &nInfoPrn4 );
166 if ( nBytes )
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;
176 pInfo->mnJobs = 0;
177 pInfo->mpSysData = nullptr;
178 pList->Add( pInfo );
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 ) )
191 DWORD nBytes = 0;
192 GetPrinterW( hPrinter, 2, nullptr, 0, &nBytes );
193 if( 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) );
200 OUString aPortName;
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) );
206 else
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;
225 delete pInfo;
228 OUString WinSalInstance::GetDefaultPrinter()
230 DWORD nChars = 0;
231 GetDefaultPrinterW( nullptr, &nChars );
232 if( nChars )
234 LPWSTR pStr = static_cast<LPWSTR>(rtl_allocateMemory(nChars*sizeof(WCHAR)));
235 OUString aDefPrt;
236 if( GetDefaultPrinterW( pStr, &nChars ) )
238 aDefPrt = OUString(reinterpret_cast<sal_Unicode* >(pStr));
240 rtl_freeMemory( pStr );
241 if( !aDefPrt.isEmpty() )
242 return aDefPrt;
245 // get default printer from win.ini
246 char szBuffer[256];
247 GetProfileStringA( aImplWindows, aImplDevice, "", szBuffer, sizeof( szBuffer ) );
248 if ( szBuffer[0] )
250 // search for printer name
251 char* pBuf = szBuffer;
252 char* pTmp = pBuf;
253 while ( *pTmp && (*pTmp != ',') )
254 pTmp++;
255 return ImplSalGetUniString( pBuf, static_cast<sal_Int32>(pTmp-pBuf) );
257 else
258 return OUString();
261 static DWORD ImplDeviceCaps( WinSalInfoPrinter* pPrinter, WORD nCaps,
262 BYTE* pOutput, const ImplJobSetup* pSetupData )
264 DEVMODEW const * pDevMode;
265 if ( !pSetupData || !pSetupData->GetDriverData() )
266 pDevMode = nullptr;
267 else
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#
299 HANDLE hPrn;
300 LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.getStr()));
301 if ( !OpenPrinterW( pPrinterNameW, &hPrn, nullptr ) )
302 return FALSE;
304 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
305 if( hPrn == HGDI_ERROR )
306 return FALSE;
308 nSysJobSize = DocumentPropertiesW( nullptr, hPrn,
309 pPrinterNameW,
310 nullptr, nullptr, 0 );
312 if( nSysJobSize < 0 )
314 ClosePrinter( hPrn );
315 return FALSE;
317 DEVMODEW *pBuffer = static_cast<DEVMODEW*>(_alloca( nSysJobSize ));
318 LONG nRet = DocumentPropertiesW( nullptr, hPrn,
319 pPrinterNameW,
320 pBuffer, nullptr, DM_OUT_BUFFER );
321 if( nRet < 0 )
323 ClosePrinter( hPrn );
324 return FALSE;
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 )
342 if( pDevModeW &&
343 (dmSpecVersion == pDevModeW->dmSpecVersion) &&
344 (dmDriverVersion == pDevModeW->dmDriverVersion) )
345 return TRUE;
347 if ( bDelete )
349 rtl_freeMemory( const_cast<sal_uInt8*>(pSetupData->GetDriverData()) );
350 pSetupData->SetDriverData( nullptr );
351 pSetupData->SetDriverDataLen( 0 );
355 return FALSE;
358 static bool ImplUpdateSalJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData,
359 bool bIn, WinSalFrame* pVisibleDlgParent )
361 HANDLE hPrn;
362 LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.getStr()));
363 if ( !OpenPrinterW( pPrinterNameW, &hPrn, nullptr ) )
364 return FALSE;
365 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
366 if( hPrn == HGDI_ERROR )
367 return FALSE;
369 LONG nRet;
370 HWND hWnd = nullptr;
371 DWORD nMode = DM_OUT_BUFFER;
372 SalDriverData* pOutBuffer = nullptr;
373 BYTE const * pInBuffer = nullptr;
375 LONG nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
376 pPrinterNameW,
377 nullptr, nullptr, 0 );
378 if ( nSysJobSize < 0 )
380 ClosePrinter( hPrn );
381 return FALSE;
384 // make Outputbuffer
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,
414 pPrinterNameW,
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 );
423 return FALSE;
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)) );
440 // update data
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 );
447 return TRUE;
450 static void ImplDevModeToJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, JobSetFlags nFlags )
452 if ( !pSetupData || !pSetupData->GetDriverData() )
453 return;
455 DEVMODEW const * pDevModeW = SAL_DEVMODE_W(pSetupData);
456 if( pDevModeW == nullptr )
457 return;
459 // Orientation
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 );
468 // PaperBin
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 );
485 break;
489 rtl_freeMemory( pBins );
493 // PaperSize
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 );
501 else
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 );
525 break;
529 if( pPapers )
530 rtl_freeMemory( pPapers );
531 if( pPaperSizes )
532 rtl_freeMemory( pPaperSizes );
534 switch( pDevModeW->dmPaperSize )
536 case DMPAPER_LETTER:
537 pSetupData->SetPaperFormat( PAPER_LETTER );
538 break;
539 case DMPAPER_TABLOID:
540 pSetupData->SetPaperFormat( PAPER_TABLOID );
541 break;
542 case DMPAPER_LEDGER:
543 pSetupData->SetPaperFormat( PAPER_LEDGER );
544 break;
545 case DMPAPER_LEGAL:
546 pSetupData->SetPaperFormat( PAPER_LEGAL );
547 break;
548 case DMPAPER_STATEMENT:
549 pSetupData->SetPaperFormat( PAPER_STATEMENT );
550 break;
551 case DMPAPER_EXECUTIVE:
552 pSetupData->SetPaperFormat( PAPER_EXECUTIVE );
553 break;
554 case DMPAPER_A3:
555 pSetupData->SetPaperFormat( PAPER_A3 );
556 break;
557 case DMPAPER_A4:
558 pSetupData->SetPaperFormat( PAPER_A4 );
559 break;
560 case DMPAPER_A5:
561 pSetupData->SetPaperFormat( PAPER_A5 );
562 break;
563 //See http://wiki.openoffice.org/wiki/DefaultPaperSize
564 //i.e.
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
570 //enumeration.
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
575 //(cmc)
576 case DMPAPER_B4:
577 pSetupData->SetPaperFormat( PAPER_B4_JIS );
578 break;
579 case DMPAPER_B5:
580 pSetupData->SetPaperFormat( PAPER_B5_JIS );
581 break;
582 case DMPAPER_QUARTO:
583 pSetupData->SetPaperFormat( PAPER_QUARTO );
584 break;
585 case DMPAPER_10X14:
586 pSetupData->SetPaperFormat( PAPER_10x14 );
587 break;
588 case DMPAPER_NOTE:
589 pSetupData->SetPaperFormat( PAPER_LETTER );
590 break;
591 case DMPAPER_ENV_9:
592 pSetupData->SetPaperFormat( PAPER_ENV_9 );
593 break;
594 case DMPAPER_ENV_10:
595 pSetupData->SetPaperFormat( PAPER_ENV_10 );
596 break;
597 case DMPAPER_ENV_11:
598 pSetupData->SetPaperFormat( PAPER_ENV_11 );
599 break;
600 case DMPAPER_ENV_12:
601 pSetupData->SetPaperFormat( PAPER_ENV_12 );
602 break;
603 case DMPAPER_ENV_14:
604 pSetupData->SetPaperFormat( PAPER_ENV_14 );
605 break;
606 case DMPAPER_CSHEET:
607 pSetupData->SetPaperFormat( PAPER_C );
608 break;
609 case DMPAPER_DSHEET:
610 pSetupData->SetPaperFormat( PAPER_D );
611 break;
612 case DMPAPER_ESHEET:
613 pSetupData->SetPaperFormat( PAPER_E );
614 break;
615 case DMPAPER_ENV_DL:
616 pSetupData->SetPaperFormat( PAPER_ENV_DL );
617 break;
618 case DMPAPER_ENV_C5:
619 pSetupData->SetPaperFormat( PAPER_ENV_C5 );
620 break;
621 case DMPAPER_ENV_C3:
622 pSetupData->SetPaperFormat( PAPER_ENV_C3 );
623 break;
624 case DMPAPER_ENV_C4:
625 pSetupData->SetPaperFormat( PAPER_ENV_C4 );
626 break;
627 case DMPAPER_ENV_C6:
628 pSetupData->SetPaperFormat( PAPER_ENV_C6 );
629 break;
630 case DMPAPER_ENV_C65:
631 pSetupData->SetPaperFormat( PAPER_ENV_C65 );
632 break;
633 case DMPAPER_ENV_ITALY:
634 pSetupData->SetPaperFormat( PAPER_ENV_ITALY );
635 break;
636 case DMPAPER_ENV_MONARCH:
637 pSetupData->SetPaperFormat( PAPER_ENV_MONARCH );
638 break;
639 case DMPAPER_ENV_PERSONAL:
640 pSetupData->SetPaperFormat( PAPER_ENV_PERSONAL );
641 break;
642 case DMPAPER_FANFOLD_US:
643 pSetupData->SetPaperFormat( PAPER_FANFOLD_US );
644 break;
645 case DMPAPER_FANFOLD_STD_GERMAN:
646 pSetupData->SetPaperFormat( PAPER_FANFOLD_DE );
647 break;
648 case DMPAPER_FANFOLD_LGL_GERMAN:
649 pSetupData->SetPaperFormat( PAPER_FANFOLD_LEGAL_DE );
650 break;
651 case DMPAPER_ISO_B4:
652 pSetupData->SetPaperFormat( PAPER_B4_ISO );
653 break;
654 case DMPAPER_JAPANESE_POSTCARD:
655 pSetupData->SetPaperFormat( PAPER_POSTCARD_JP );
656 break;
657 case DMPAPER_9X11:
658 pSetupData->SetPaperFormat( PAPER_9x11 );
659 break;
660 case DMPAPER_10X11:
661 pSetupData->SetPaperFormat( PAPER_10x11 );
662 break;
663 case DMPAPER_15X11:
664 pSetupData->SetPaperFormat( PAPER_15x11 );
665 break;
666 case DMPAPER_ENV_INVITE:
667 pSetupData->SetPaperFormat( PAPER_ENV_INVITE );
668 break;
669 case DMPAPER_A_PLUS:
670 pSetupData->SetPaperFormat( PAPER_A_PLUS );
671 break;
672 case DMPAPER_B_PLUS:
673 pSetupData->SetPaperFormat( PAPER_B_PLUS );
674 break;
675 case DMPAPER_LETTER_PLUS:
676 pSetupData->SetPaperFormat( PAPER_LETTER_PLUS );
677 break;
678 case DMPAPER_A4_PLUS:
679 pSetupData->SetPaperFormat( PAPER_A4_PLUS );
680 break;
681 case DMPAPER_A2:
682 pSetupData->SetPaperFormat( PAPER_A2 );
683 break;
684 case DMPAPER_DBL_JAPANESE_POSTCARD:
685 pSetupData->SetPaperFormat( PAPER_DOUBLEPOSTCARD_JP );
686 break;
687 case DMPAPER_A6:
688 pSetupData->SetPaperFormat( PAPER_A6 );
689 break;
690 case DMPAPER_B6_JIS:
691 pSetupData->SetPaperFormat( PAPER_B6_JIS );
692 break;
693 case DMPAPER_12X11:
694 pSetupData->SetPaperFormat( PAPER_12x11 );
695 break;
696 default:
697 pSetupData->SetPaperFormat( PAPER_USER );
698 break;
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() )
721 return;
723 DEVMODEW* pDevModeW = const_cast<DEVMODEW *>(SAL_DEVMODE_W(pSetupData));
724 if( pDevModeW == nullptr )
725 return;
727 // Orientation
728 if ( nFlags & JobSetFlags::ORIENTATION )
730 pDevModeW->dmFields |= DM_ORIENTATION;
731 if ( pSetupData->GetOrientation() == Orientation::Portrait )
732 pDevModeW->dmOrientation = DMORIENT_PORTRAIT;
733 else
734 pDevModeW->dmOrientation = DMORIENT_LANDSCAPE;
737 // PaperBin
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 );
752 // PaperSize
753 if ( nFlags & JobSetFlags::PAPERSIZE )
755 pDevModeW->dmFields |= DM_PAPERSIZE;
756 pDevModeW->dmPaperWidth = 0;
757 pDevModeW->dmPaperLength = 0;
759 switch( pSetupData->GetPaperFormat() )
761 case PAPER_A2:
762 pDevModeW->dmPaperSize = DMPAPER_A2;
763 break;
764 case PAPER_A3:
765 pDevModeW->dmPaperSize = DMPAPER_A3;
766 break;
767 case PAPER_A4:
768 pDevModeW->dmPaperSize = DMPAPER_A4;
769 break;
770 case PAPER_A5:
771 pDevModeW->dmPaperSize = DMPAPER_A5;
772 break;
773 case PAPER_B4_ISO:
774 pDevModeW->dmPaperSize = DMPAPER_ISO_B4;
775 break;
776 case PAPER_LETTER:
777 pDevModeW->dmPaperSize = DMPAPER_LETTER;
778 break;
779 case PAPER_LEGAL:
780 pDevModeW->dmPaperSize = DMPAPER_LEGAL;
781 break;
782 case PAPER_TABLOID:
783 pDevModeW->dmPaperSize = DMPAPER_TABLOID;
784 break;
785 #if 0
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
793 case PAPER_B6_ISO:
794 pDevModeW->dmPaperSize = DMPAPER_ENV_B6;
795 break;
796 #endif
797 case PAPER_ENV_C4:
798 pDevModeW->dmPaperSize = DMPAPER_ENV_C4;
799 break;
800 case PAPER_ENV_C5:
801 pDevModeW->dmPaperSize = DMPAPER_ENV_C5;
802 break;
803 case PAPER_ENV_C6:
804 pDevModeW->dmPaperSize = DMPAPER_ENV_C6;
805 break;
806 case PAPER_ENV_C65:
807 pDevModeW->dmPaperSize = DMPAPER_ENV_C65;
808 break;
809 case PAPER_ENV_DL:
810 pDevModeW->dmPaperSize = DMPAPER_ENV_DL;
811 break;
812 case PAPER_C:
813 pDevModeW->dmPaperSize = DMPAPER_CSHEET;
814 break;
815 case PAPER_D:
816 pDevModeW->dmPaperSize = DMPAPER_DSHEET;
817 break;
818 case PAPER_E:
819 pDevModeW->dmPaperSize = DMPAPER_ESHEET;
820 break;
821 case PAPER_EXECUTIVE:
822 pDevModeW->dmPaperSize = DMPAPER_EXECUTIVE;
823 break;
824 case PAPER_FANFOLD_LEGAL_DE:
825 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_LGL_GERMAN;
826 break;
827 case PAPER_ENV_MONARCH:
828 pDevModeW->dmPaperSize = DMPAPER_ENV_MONARCH;
829 break;
830 case PAPER_ENV_PERSONAL:
831 pDevModeW->dmPaperSize = DMPAPER_ENV_PERSONAL;
832 break;
833 case PAPER_ENV_9:
834 pDevModeW->dmPaperSize = DMPAPER_ENV_9;
835 break;
836 case PAPER_ENV_10:
837 pDevModeW->dmPaperSize = DMPAPER_ENV_10;
838 break;
839 case PAPER_ENV_11:
840 pDevModeW->dmPaperSize = DMPAPER_ENV_11;
841 break;
842 case PAPER_ENV_12:
843 pDevModeW->dmPaperSize = DMPAPER_ENV_12;
844 break;
845 //See the comments on DMPAPER_B4 above
846 case PAPER_B4_JIS:
847 pDevModeW->dmPaperSize = DMPAPER_B4;
848 break;
849 case PAPER_B5_JIS:
850 pDevModeW->dmPaperSize = DMPAPER_B5;
851 break;
852 case PAPER_B6_JIS:
853 pDevModeW->dmPaperSize = DMPAPER_B6_JIS;
854 break;
855 case PAPER_LEDGER:
856 pDevModeW->dmPaperSize = DMPAPER_LEDGER;
857 break;
858 case PAPER_STATEMENT:
859 pDevModeW->dmPaperSize = DMPAPER_STATEMENT;
860 break;
861 case PAPER_10x14:
862 pDevModeW->dmPaperSize = DMPAPER_10X14;
863 break;
864 case PAPER_ENV_14:
865 pDevModeW->dmPaperSize = DMPAPER_ENV_14;
866 break;
867 case PAPER_ENV_C3:
868 pDevModeW->dmPaperSize = DMPAPER_ENV_C3;
869 break;
870 case PAPER_ENV_ITALY:
871 pDevModeW->dmPaperSize = DMPAPER_ENV_ITALY;
872 break;
873 case PAPER_FANFOLD_US:
874 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_US;
875 break;
876 case PAPER_FANFOLD_DE:
877 pDevModeW->dmPaperSize = DMPAPER_FANFOLD_STD_GERMAN;
878 break;
879 case PAPER_POSTCARD_JP:
880 pDevModeW->dmPaperSize = DMPAPER_JAPANESE_POSTCARD;
881 break;
882 case PAPER_9x11:
883 pDevModeW->dmPaperSize = DMPAPER_9X11;
884 break;
885 case PAPER_10x11:
886 pDevModeW->dmPaperSize = DMPAPER_10X11;
887 break;
888 case PAPER_15x11:
889 pDevModeW->dmPaperSize = DMPAPER_15X11;
890 break;
891 case PAPER_ENV_INVITE:
892 pDevModeW->dmPaperSize = DMPAPER_ENV_INVITE;
893 break;
894 case PAPER_A_PLUS:
895 pDevModeW->dmPaperSize = DMPAPER_A_PLUS;
896 break;
897 case PAPER_B_PLUS:
898 pDevModeW->dmPaperSize = DMPAPER_B_PLUS;
899 break;
900 case PAPER_LETTER_PLUS:
901 pDevModeW->dmPaperSize = DMPAPER_LETTER_PLUS;
902 break;
903 case PAPER_A4_PLUS:
904 pDevModeW->dmPaperSize = DMPAPER_A4_PLUS;
905 break;
906 case PAPER_DOUBLEPOSTCARD_JP:
907 pDevModeW->dmPaperSize = DMPAPER_DBL_JAPANESE_POSTCARD;
908 break;
909 case PAPER_A6:
910 pDevModeW->dmPaperSize = DMPAPER_A6;
911 break;
912 case PAPER_12x11:
913 pDevModeW->dmPaperSize = DMPAPER_12X11;
914 break;
915 default:
917 short nPaper = 0;
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)))
941 nPaper = pPapers[i];
942 break;
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)) )
956 nPaper = pPapers[i];
957 break;
962 if ( nPaper )
963 pDevModeW->dmPaperSize = nPaper;
966 if ( !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);
974 if ( pPapers )
975 rtl_freeMemory(pPapers);
976 if ( pPaperSizes )
977 rtl_freeMemory(pPaperSizes);
979 break;
983 if( (nFlags & JobSetFlags::DUPLEXMODE) )
985 switch( pSetupData->GetDuplexMode() )
987 case DuplexMode::Off:
988 pDevModeW->dmFields |= DM_DUPLEX;
989 pDevModeW->dmDuplex = DMDUP_SIMPLEX;
990 break;
991 case DuplexMode::ShortEdge:
992 pDevModeW->dmFields |= DM_DUPLEX;
993 pDevModeW->dmDuplex = DMDUP_HORIZONTAL;
994 break;
995 case DuplexMode::LongEdge:
996 pDevModeW->dmFields |= DM_DUPLEX;
997 pDevModeW->dmDuplex = DMDUP_VERTICAL;
998 break;
999 case DuplexMode::Unknown:
1000 break;
1005 static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
1006 LPCWSTR pDevice,
1007 DEVMODEW const * pDevMode )
1009 HDC hDC = nullptr;
1010 CATCH_DRIVER_EX_BEGIN;
1011 hDC = CreateICW( pDriver, pDevice, nullptr, pDevMode );
1012 CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
1013 return hDC;
1016 static HDC ImplCreateSalPrnIC( WinSalInfoPrinter* pPrinter, const ImplJobSetup* pSetupData )
1018 HDC hDC = nullptr;
1019 DEVMODEW const * pDevMode;
1020 if ( pSetupData && pSetupData->GetDriverData() )
1021 pDevMode = SAL_DEVMODE_W( pSetupData );
1022 else
1023 pDevMode = nullptr;
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 )
1027 return nullptr;
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),
1036 pDevMode );
1037 return hDC;
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();
1046 return pGraphics;
1049 static bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, const ImplJobSetup* pSetupData )
1051 HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1052 if ( !hNewDC )
1053 return FALSE;
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;
1065 return TRUE;
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
1079 : OUString();
1081 // check if the provided setup data match the actual printer
1082 ImplTestSalJobSetup( pPrinter, pSetupData, true );
1084 HDC hDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1085 if ( !hDC )
1087 delete pPrinter;
1088 return nullptr;
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 );
1098 return pPrinter;
1101 void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
1103 delete pPrinter;
1107 WinSalInfoPrinter::WinSalInfoPrinter() :
1108 mpGraphics( nullptr ),
1109 mhDC( nullptr ),
1110 mbGraphics( FALSE )
1112 m_bPapersInit = FALSE;
1115 WinSalInfoPrinter::~WinSalInfoPrinter()
1117 if ( mpGraphics )
1119 mpGraphics->DeInitGraphics();
1120 DeleteDC( mpGraphics->getHDC() );
1121 delete mpGraphics;
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 )
1131 nCount = 0;
1133 if( nCount )
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()
1163 if ( mbGraphics )
1164 return nullptr;
1166 if ( mpGraphics )
1167 mbGraphics = TRUE;
1169 return mpGraphics;
1172 void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
1174 mbGraphics = FALSE;
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 );
1185 return FALSE;
1188 bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
1190 if ( !ImplTestSalJobSetup( this, pSetupData, false ) )
1191 return 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 );
1204 return FALSE;
1207 sal_uLong WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
1209 DWORD nRet = ImplDeviceCaps( this, DC_BINS, nullptr, pSetupData );
1210 if ( nRet && (nRet != GDI_ERROR) )
1211 return nRet;
1212 else
1213 return 0;
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) );
1227 delete [] pBuffer;
1230 return aPaperBinName;
1233 sal_uInt32 WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, PrinterCapType nType )
1235 DWORD nRet;
1237 switch ( nType )
1239 case PrinterCapType::SupportDialog:
1240 return TRUE;
1241 case PrinterCapType::Copies:
1242 nRet = ImplDeviceCaps( this, DC_COPIES, nullptr, pSetupData );
1243 if ( nRet && (nRet != GDI_ERROR) )
1244 return nRet;
1245 return 0;
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) )
1252 return nRet;
1254 return 0;
1256 case PrinterCapType::SetOrientation:
1257 nRet = ImplDeviceCaps( this, DC_ORIENTATION, nullptr, pSetupData );
1258 if ( nRet && (nRet != GDI_ERROR) )
1259 return TRUE;
1260 return FALSE;
1262 case PrinterCapType::SetPaperBin:
1263 nRet = ImplDeviceCaps( this, DC_BINS, nullptr, pSetupData );
1264 if ( nRet && (nRet != GDI_ERROR) )
1265 return TRUE;
1266 return FALSE;
1268 case PrinterCapType::SetPaperSize:
1269 case PrinterCapType::SetPaper:
1270 nRet = ImplDeviceCaps( this, DC_PAPERS, nullptr, pSetupData );
1271 if ( nRet && (nRet != GDI_ERROR) )
1272 return TRUE;
1273 return FALSE;
1275 default:
1276 break;
1279 return 0;
1282 void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
1283 long& rOutWidth, long& rOutHeight,
1284 long& rPageOffX, long& rPageOffY,
1285 long& rPageWidth, long& rPageHeight )
1287 HDC hDC = mhDC;
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);
1303 return pPrinter;
1306 void WinSalInstance::DestroyPrinter( SalPrinter* pPrinter )
1308 delete pPrinter;
1311 BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
1313 SalData* pSalData = GetSalData();
1314 WinSalPrinter* pPrinter;
1315 bool bWhile = TRUE;
1316 int i = 0;
1320 // process messages
1321 MSG aMsg;
1322 if ( PeekMessageW( &aMsg, nullptr, 0, 0, PM_REMOVE ) )
1324 TranslateMessage( &aMsg );
1325 DispatchMessageW( &aMsg );
1327 i++;
1328 if ( i > 15 )
1329 bWhile = FALSE;
1331 else
1332 bWhile = FALSE;
1334 pPrinter = pSalData->mpFirstPrinter;
1335 while ( pPrinter )
1337 if( pPrinter->mhDC == hPrnDC )
1338 break;
1340 pPrinter = pPrinter->mpNextPrinter;
1343 if ( !pPrinter || pPrinter->mbAbort )
1344 return FALSE;
1346 while ( bWhile );
1348 return TRUE;
1351 static DEVMODEW const * ImplSalSetCopies( DEVMODEW const * pDevMode, sal_uLong nCopies, bool bCollate )
1353 if ( pDevMode && (nCopies > 1) )
1355 if ( nCopies > 32765 )
1356 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;
1363 if ( bCollate )
1364 pNewDevMode->dmCollate = DMCOLLATE_TRUE;
1365 else
1366 pNewDevMode->dmCollate = DMCOLLATE_FALSE;
1367 return pNewDevMode;
1369 else
1371 return pDevMode;
1376 WinSalPrinter::WinSalPrinter() :
1377 mpGraphics( nullptr ),
1378 mpInfoPrinter( nullptr ),
1379 mpNextPrinter( nullptr ),
1380 mhDC( nullptr ),
1381 mnError( 0 ),
1382 mnCopies( 0 ),
1383 mbCollate( FALSE ),
1384 mbAbort( FALSE ),
1385 mbValid( true )
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
1398 HDC hDC = mhDC;
1399 if ( hDC )
1401 if ( mpGraphics )
1403 mpGraphics->DeInitGraphics();
1404 delete mpGraphics;
1407 DeleteDC( hDC );
1410 // remove printer from printerlist
1411 if ( this == pSalData->mpFirstPrinter )
1412 pSalData->mpFirstPrinter = mpNextPrinter;
1413 else
1415 WinSalPrinter* pTempPrinter = pSalData->mpFirstPrinter;
1417 while( pTempPrinter->mpNextPrinter != this )
1418 pTempPrinter = pTempPrinter->mpNextPrinter;
1420 pTempPrinter->mpNextPrinter = mpNextPrinter;
1422 mbValid = false;
1425 void WinSalPrinter::markInvalid()
1427 mbValid = false;
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 )
1434 (void) pPrt;
1435 int nRet = 0;
1436 CATCH_DRIVER_EX_BEGIN;
1437 nRet = ::StartDocW( hDC, pInfo );
1438 CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
1439 return nRet;
1442 bool WinSalPrinter::StartJob( const OUString* pFileName,
1443 const OUString& rJobName,
1444 const OUString&,
1445 sal_uInt32 nCopies,
1446 bool bCollate,
1447 bool /*bDirect*/,
1448 ImplJobSetup* pSetupData )
1450 mnError = 0;
1451 mbAbort = FALSE;
1452 mnCopies = nCopies;
1453 mbCollate = bCollate;
1455 DEVMODEW const * pOrgDevModeW = nullptr;
1456 DEVMODEW const * pDevModeW = nullptr;
1457 HDC hDC = 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),
1471 nullptr,
1472 pDevModeW );
1474 if ( pDevModeW != pOrgDevModeW )
1475 rtl_freeMemory( const_cast<DEVMODEW *>(pDevModeW) );
1477 if ( !hDC )
1479 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1480 return FALSE;
1483 // make sure mhDC is set before the printer driver may call our abortproc
1484 mhDC = hDC;
1485 if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
1487 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1488 return FALSE;
1491 mnError = 0;
1492 mbAbort = FALSE;
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
1496 bool bWhile = TRUE;
1497 int i = 0;
1500 // process messages
1501 MSG aMsg;
1502 if ( PeekMessageW( &aMsg, nullptr, 0, 0, PM_REMOVE ) )
1504 TranslateMessage( &aMsg );
1505 DispatchMessageW( &aMsg );
1507 i++;
1508 if ( i > 15 )
1509 bWhile = FALSE;
1511 else
1512 bWhile = FALSE;
1514 while ( bWhile );
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();
1533 else
1535 mnError = SAL_PRINTER_ERROR_ABORT;
1536 return FALSE;
1540 DOCINFOW aInfo;
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();
1550 else
1551 aInfo.lpszOutput = L"FILE:";
1553 else
1554 aInfo.lpszOutput = nullptr;
1556 // start Job
1557 int nRet = lcl_StartDocW( hDC, &aInfo, this );
1559 if ( nRet <= 0 )
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;
1564 else
1565 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1566 return FALSE;
1569 return TRUE;
1572 bool WinSalPrinter::EndJob()
1574 HDC hDC = mhDC;
1575 if ( isValid() && hDC )
1577 if ( mpGraphics )
1579 mpGraphics->DeInitGraphics();
1580 delete mpGraphics;
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 )
1593 GetLastError();
1594 CATCH_DRIVER_EX_END( "exception in EndDoc", this );
1596 GetSalData()->mpFirstInstance->AcquireYieldMutex( nAcquire );
1597 DeleteDC( hDC );
1598 mhDC = nullptr;
1601 return TRUE;
1604 SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, bool bNewJobData )
1606 if( ! isValid() || mhDC == nullptr )
1607 return nullptr;
1609 HDC hDC = mhDC;
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 );
1625 if ( nRet <= 0 )
1627 GetLastError();
1628 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1629 return nullptr;
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 );
1641 return mpGraphics;
1644 void WinSalPrinter::EndPage()
1646 HDC hDC = mhDC;
1647 if ( hDC && mpGraphics )
1649 mpGraphics->DeInitGraphics();
1650 delete mpGraphics;
1651 mpGraphics = nullptr;
1654 if( ! isValid() )
1655 return;
1657 volatile int nRet = 0;
1658 CATCH_DRIVER_EX_BEGIN;
1659 nRet = ::EndPage( hDC );
1660 CATCH_DRIVER_EX_END( "exception in EndPage", this );
1662 if ( nRet <= 0 )
1664 GetLastError();
1665 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1669 sal_uLong WinSalPrinter::GetErrorCode()
1671 return mnError;
1674 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */