Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / win / source / gdi / salprn.cxx
blobc0705fee03e42f017b10b730f568bf0a66e44fdf
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 LPDEVMODEW SAL_DEVMODE_W( const ImplJobSetup* pSetupData )
96 LPDEVMODEW pRet = NULL;
97 SalDriverData* pDrv = (SalDriverData*)pSetupData->mpDriverData;
98 if( pSetupData->mnDriverDataLen >= sizeof(DEVMODEW)+sizeof(SalDriverData)-1 )
99 pRet = ((LPDEVMODEW)((pSetupData->mpDriverData) + (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;
159 // - WinSalInstance -
161 void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
163 DWORD i;
164 DWORD nBytes = 0;
165 DWORD nInfoPrn4 = 0;
166 EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, NULL, 0, &nBytes, &nInfoPrn4 );
167 if ( nBytes )
169 PRINTER_INFO_4W* pWinInfo4 = (PRINTER_INFO_4W*) rtl_allocateMemory( nBytes );
170 if ( EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, (LPBYTE)pWinInfo4, nBytes, &nBytes, &nInfoPrn4 ) )
172 for ( i = 0; i < nInfoPrn4; i++ )
174 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
175 pInfo->maPrinterName = OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo4[i].pPrinterName) );
176 pInfo->mnStatus = PrintQueueFlags::NONE;
177 pInfo->mnJobs = 0;
178 pInfo->mpSysData = NULL;
179 pList->Add( pInfo );
182 rtl_freeMemory( pWinInfo4 );
186 void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
188 HANDLE hPrinter = 0;
189 LPWSTR pPrnName = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pInfo->maPrinterName.getStr()));
190 if( OpenPrinterW( pPrnName, &hPrinter, NULL ) )
192 DWORD nBytes = 0;
193 GetPrinterW( hPrinter, 2, NULL, 0, &nBytes );
194 if( nBytes )
196 PRINTER_INFO_2W* pWinInfo2 = (PRINTER_INFO_2W*)rtl_allocateMemory(nBytes);
197 if( GetPrinterW( hPrinter, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes ) )
199 if( pWinInfo2->pDriverName )
200 pInfo->maDriver = OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pDriverName) );
201 OUString aPortName;
202 if ( pWinInfo2->pPortName )
203 aPortName = OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pPortName) );
204 // pLocation can be 0 (the Windows docu doesn't describe this)
205 if ( pWinInfo2->pLocation && *pWinInfo2->pLocation )
206 pInfo->maLocation = OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pLocation) );
207 else
208 pInfo->maLocation = aPortName;
209 // pComment can be 0 (the Windows docu doesn't describe this)
210 if ( pWinInfo2->pComment )
211 pInfo->maComment = OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pComment) );
212 pInfo->mnStatus = ImplWinQueueStatusToSal( pWinInfo2->Status );
213 pInfo->mnJobs = pWinInfo2->cJobs;
214 if( ! pInfo->mpSysData )
215 pInfo->mpSysData = new OUString(aPortName);
217 rtl_freeMemory(pWinInfo2);
219 ClosePrinter( hPrinter );
223 void WinSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
225 delete pInfo->mpSysData;
226 delete pInfo;
229 OUString WinSalInstance::GetDefaultPrinter()
231 DWORD nChars = 0;
232 GetDefaultPrinterW( NULL, &nChars );
233 if( nChars )
235 LPWSTR pStr = (LPWSTR)rtl_allocateMemory(nChars*sizeof(WCHAR));
236 OUString aDefPrt;
237 if( GetDefaultPrinterW( pStr, &nChars ) )
239 aDefPrt = OUString(reinterpret_cast<sal_Unicode* >(pStr));
241 rtl_freeMemory( pStr );
242 if( !aDefPrt.isEmpty() )
243 return aDefPrt;
246 // get default printer from win.ini
247 char szBuffer[256];
248 GetProfileStringA( aImplWindows, aImplDevice, "", szBuffer, sizeof( szBuffer ) );
249 if ( szBuffer[0] )
251 // search for printer name
252 char* pBuf = szBuffer;
253 char* pTmp = pBuf;
254 while ( *pTmp && (*pTmp != ',') )
255 pTmp++;
256 return ImplSalGetUniString( pBuf, static_cast<sal_Int32>(pTmp-pBuf) );
258 else
259 return OUString();
262 static DWORD ImplDeviceCaps( WinSalInfoPrinter* pPrinter, WORD nCaps,
263 BYTE* pOutput, const ImplJobSetup* pSetupData )
265 DEVMODEW* pDevMode;
266 if ( !pSetupData || !pSetupData->mpDriverData )
267 pDevMode = NULL;
268 else
269 pDevMode = SAL_DEVMODE_W( pSetupData );
271 return DeviceCapabilitiesW( reinterpret_cast<LPCWSTR>(pPrinter->maDeviceName.getStr()),
272 reinterpret_cast<LPCWSTR>(pPrinter->maPortName.getStr()),
273 nCaps, (LPWSTR)pOutput, pDevMode );
276 static bool ImplTestSalJobSetup( WinSalInfoPrinter* pPrinter,
277 ImplJobSetup* pSetupData, bool bDelete )
279 if ( pSetupData && pSetupData->mpDriverData )
281 // signature and size must fit to avoid using
282 // JobSetups from a wrong system
284 // initialize versions from jobsetup
285 // those will be overwritten with driver's version
286 DEVMODEW* pDevModeW = NULL;
287 LONG dmSpecVersion = -1;
288 LONG dmDriverVersion = -1;
289 SalDriverData* pSalDriverData = (SalDriverData*)pSetupData->mpDriverData;
290 BYTE* pDriverData = ((BYTE*)pSalDriverData) + pSalDriverData->mnDriverOffset;
291 pDevModeW = (DEVMODEW*)pDriverData;
293 long nSysJobSize = -1;
294 if( pPrinter && pDevModeW )
296 // just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
297 // this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
298 // can avoid potential driver crashes as their jobsetups are often not compatible
299 // #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
300 HANDLE hPrn;
301 LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.getStr()));
302 if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
303 return FALSE;
305 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
306 if( hPrn == HGDI_ERROR )
307 return FALSE;
309 nSysJobSize = DocumentPropertiesW( 0, hPrn,
310 pPrinterNameW,
311 NULL, NULL, 0 );
313 if( nSysJobSize < 0 )
315 ClosePrinter( hPrn );
316 return FALSE;
318 BYTE *pBuffer = (BYTE*)_alloca( nSysJobSize );
319 LONG nRet = DocumentPropertiesW( 0, hPrn,
320 pPrinterNameW,
321 (LPDEVMODEW)pBuffer, NULL, DM_OUT_BUFFER );
322 if( nRet < 0 )
324 ClosePrinter( hPrn );
325 return FALSE;
328 // the spec version differs between the windows platforms, ie 98,NT,2000/XP
329 // this allows us to throw away printer settings from other platforms that might crash a buggy driver
330 // we check the driver version as well
331 dmSpecVersion = ((DEVMODEW*)pBuffer)->dmSpecVersion;
332 dmDriverVersion = ((DEVMODEW*)pBuffer)->dmDriverVersion;
334 ClosePrinter( hPrn );
336 SalDriverData* pSetupDriverData = (SalDriverData*)(pSetupData->mpDriverData);
337 if ( (pSetupData->mnSystem == JOBSETUP_SYSTEM_WINDOWS) &&
338 (pPrinter->maDriverName == pSetupData->maDriver) &&
339 (pSetupData->mnDriverDataLen > sizeof( SalDriverData )) &&
340 (long)(pSetupData->mnDriverDataLen - pSetupDriverData->mnDriverOffset) == nSysJobSize &&
341 pSetupDriverData->mnSysSignature == SAL_DRIVERDATA_SYSSIGN )
343 if( pDevModeW &&
344 (dmSpecVersion == pDevModeW->dmSpecVersion) &&
345 (dmDriverVersion == pDevModeW->dmDriverVersion) )
346 return TRUE;
348 if ( bDelete )
350 rtl_freeMemory( pSetupData->mpDriverData );
351 pSetupData->mpDriverData = NULL;
352 pSetupData->mnDriverDataLen = 0;
356 return FALSE;
359 static bool ImplUpdateSalJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData,
360 bool bIn, WinSalFrame* pVisibleDlgParent )
362 HANDLE hPrn;
363 LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.getStr()));
364 if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
365 return FALSE;
366 // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
367 if( hPrn == HGDI_ERROR )
368 return FALSE;
370 LONG nRet;
371 HWND hWnd = 0;
372 DWORD nMode = DM_OUT_BUFFER;
373 sal_uLong nDriverDataLen = 0;
374 SalDriverData* pOutBuffer = NULL;
375 BYTE* pInBuffer = NULL;
377 LONG nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
378 pPrinterNameW,
379 NULL, NULL, 0 );
380 if ( nSysJobSize < 0 )
382 ClosePrinter( hPrn );
383 return FALSE;
386 // make Outputbuffer
387 nDriverDataLen = sizeof(SalDriverData) + nSysJobSize-1;
388 pOutBuffer = (SalDriverData*)rtl_allocateZeroMemory( nDriverDataLen );
389 pOutBuffer->mnSysSignature = SAL_DRIVERDATA_SYSSIGN;
390 // calculate driver data offset including structure padding
391 pOutBuffer->mnDriverOffset = sal::static_int_cast<sal_uInt16>(
392 (char*)pOutBuffer->maDriverData -
393 (char*)pOutBuffer );
395 // check if we have a suitable input buffer
396 if ( bIn && ImplTestSalJobSetup( pPrinter, pSetupData, FALSE ) )
398 pInBuffer = (BYTE*)pSetupData->mpDriverData + ((SalDriverData*)pSetupData->mpDriverData)->mnDriverOffset;
399 nMode |= DM_IN_BUFFER;
402 // check if the dialog should be shown
403 if ( pVisibleDlgParent )
405 hWnd = pVisibleDlgParent->mhWnd;
406 nMode |= DM_IN_PROMPT;
409 // Release mutex, in the other case we don't get paints and so on
410 sal_uLong nMutexCount=0;
411 if ( pVisibleDlgParent )
412 nMutexCount = ImplSalReleaseYieldMutex();
414 BYTE* pOutDevMode = (((BYTE*)pOutBuffer) + pOutBuffer->mnDriverOffset);
415 nRet = DocumentPropertiesW( hWnd, hPrn,
416 pPrinterNameW,
417 (LPDEVMODEW)pOutDevMode, (LPDEVMODEW)pInBuffer, nMode );
418 if ( pVisibleDlgParent )
419 ImplSalAcquireYieldMutex( nMutexCount );
420 ClosePrinter( hPrn );
422 if( (nRet < 0) || (pVisibleDlgParent && (nRet == IDCANCEL)) )
424 rtl_freeMemory( pOutBuffer );
425 return FALSE;
428 // fill up string buffers with 0 so they do not influence a JobSetup's memcmp
429 if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 64 )
431 sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmDeviceName );
432 if ( sal::static_int_cast<size_t>(nLen) < SAL_N_ELEMENTS( ((LPDEVMODEW)pOutDevMode)->dmDeviceName ) )
433 memset( ((LPDEVMODEW)pOutDevMode)->dmDeviceName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmDeviceName )-(nLen*sizeof(sal_Unicode)) );
435 if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 166 )
437 sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmFormName );
438 if ( sal::static_int_cast<size_t>(nLen) < SAL_N_ELEMENTS( ((LPDEVMODEW)pOutDevMode)->dmFormName ) )
439 memset( ((LPDEVMODEW)pOutDevMode)->dmFormName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmFormName )-(nLen*sizeof(sal_Unicode)) );
442 // update data
443 if ( pSetupData->mpDriverData )
444 rtl_freeMemory( pSetupData->mpDriverData );
445 pSetupData->mnDriverDataLen = nDriverDataLen;
446 pSetupData->mpDriverData = (BYTE*)pOutBuffer;
447 pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
449 return TRUE;
452 #define DECLARE_DEVMODE( i )\
453 DEVMODEW* pDevModeW = SAL_DEVMODE_W(i);\
454 if( pDevModeW == NULL )\
455 return
457 #define CHOOSE_DEVMODE(i)\
458 (pDevModeW->i)
460 static void ImplDevModeToJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, sal_uLong nFlags )
462 if ( !pSetupData || !pSetupData->mpDriverData )
463 return;
465 DECLARE_DEVMODE( pSetupData );
467 // Orientation
468 if ( nFlags & SAL_JOBSET_ORIENTATION )
470 if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_PORTRAIT )
471 pSetupData->meOrientation = ORIENTATION_PORTRAIT;
472 else if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_LANDSCAPE )
473 pSetupData->meOrientation = ORIENTATION_LANDSCAPE;
476 // PaperBin
477 if ( nFlags & SAL_JOBSET_PAPERBIN )
479 sal_uLong nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
481 if ( nCount && (nCount != GDI_ERROR) )
483 WORD* pBins = (WORD*)rtl_allocateZeroMemory( nCount*sizeof(WORD) );
484 ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
485 pSetupData->mnPaperBin = 0;
487 // search the right bin and assign index to mnPaperBin
488 for( sal_uLong i = 0; i < nCount; i++ )
490 if( CHOOSE_DEVMODE(dmDefaultSource) == pBins[ i ] )
492 pSetupData->mnPaperBin = (sal_uInt16)i;
493 break;
497 rtl_freeMemory( pBins );
501 // PaperSize
502 if ( nFlags & SAL_JOBSET_PAPERSIZE )
504 if( (CHOOSE_DEVMODE(dmFields) & (DM_PAPERWIDTH|DM_PAPERLENGTH)) == (DM_PAPERWIDTH|DM_PAPERLENGTH) )
506 pSetupData->mnPaperWidth = CHOOSE_DEVMODE(dmPaperWidth)*10;
507 pSetupData->mnPaperHeight = CHOOSE_DEVMODE(dmPaperLength)*10;
509 else
511 sal_uLong nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
512 WORD* pPapers = NULL;
513 sal_uLong nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
514 POINT* pPaperSizes = NULL;
515 if ( nPaperCount && (nPaperCount != GDI_ERROR) )
517 pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
518 ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
520 if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
522 pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
523 ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
525 if( nPaperSizeCount == nPaperCount && pPaperSizes && pPapers )
527 for( sal_uLong i = 0; i < nPaperCount; i++ )
529 if( pPapers[ i ] == CHOOSE_DEVMODE(dmPaperSize) )
531 pSetupData->mnPaperWidth = pPaperSizes[ i ].x*10;
532 pSetupData->mnPaperHeight = pPaperSizes[ i ].y*10;
533 break;
537 if( pPapers )
538 rtl_freeMemory( pPapers );
539 if( pPaperSizes )
540 rtl_freeMemory( pPaperSizes );
542 switch( CHOOSE_DEVMODE(dmPaperSize) )
544 case( DMPAPER_LETTER ):
545 pSetupData->mePaperFormat = PAPER_LETTER;
546 break;
547 case( DMPAPER_TABLOID ):
548 pSetupData->mePaperFormat = PAPER_TABLOID;
549 break;
550 case( DMPAPER_LEDGER ):
551 pSetupData->mePaperFormat = PAPER_LEDGER;
552 break;
553 case( DMPAPER_LEGAL ):
554 pSetupData->mePaperFormat = PAPER_LEGAL;
555 break;
556 case( DMPAPER_STATEMENT ):
557 pSetupData->mePaperFormat = PAPER_STATEMENT;
558 break;
559 case( DMPAPER_EXECUTIVE ):
560 pSetupData->mePaperFormat = PAPER_EXECUTIVE;
561 break;
562 case( DMPAPER_A3 ):
563 pSetupData->mePaperFormat = PAPER_A3;
564 break;
565 case( DMPAPER_A4 ):
566 pSetupData->mePaperFormat = PAPER_A4;
567 break;
568 case( DMPAPER_A5 ):
569 pSetupData->mePaperFormat = PAPER_A5;
570 break;
571 //See http://wiki.openoffice.org/wiki/DefaultPaperSize
572 //i.e.
573 //http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
574 //DMPAPER_B4 12 B4 (JIS) 257 x 364 mm
575 //http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
576 //also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
577 //matches our Excel filter's belief about the matching XlPaperSize
578 //enumeration.
580 //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
581 ////"DMPAPER_B4 12 B4 (JIS) 250 x 354"
582 //which is bogus as it's either JIS 257 x 364 or ISO 250 x 353
583 //(cmc)
584 case( DMPAPER_B4 ):
585 pSetupData->mePaperFormat = PAPER_B4_JIS;
586 break;
587 case( DMPAPER_B5 ):
588 pSetupData->mePaperFormat = PAPER_B5_JIS;
589 break;
590 case( DMPAPER_QUARTO ):
591 pSetupData->mePaperFormat = PAPER_QUARTO;
592 break;
593 case( DMPAPER_10X14 ):
594 pSetupData->mePaperFormat = PAPER_10x14;
595 break;
596 case( DMPAPER_NOTE ):
597 pSetupData->mePaperFormat = PAPER_LETTER;
598 break;
599 case( DMPAPER_ENV_9 ):
600 pSetupData->mePaperFormat = PAPER_ENV_9;
601 break;
602 case( DMPAPER_ENV_10 ):
603 pSetupData->mePaperFormat = PAPER_ENV_10;
604 break;
605 case( DMPAPER_ENV_11 ):
606 pSetupData->mePaperFormat = PAPER_ENV_11;
607 break;
608 case( DMPAPER_ENV_12 ):
609 pSetupData->mePaperFormat = PAPER_ENV_12;
610 break;
611 case( DMPAPER_ENV_14 ):
612 pSetupData->mePaperFormat = PAPER_ENV_14;
613 break;
614 case( DMPAPER_CSHEET ):
615 pSetupData->mePaperFormat = PAPER_C;
616 break;
617 case( DMPAPER_DSHEET ):
618 pSetupData->mePaperFormat = PAPER_D;
619 break;
620 case( DMPAPER_ESHEET ):
621 pSetupData->mePaperFormat = PAPER_E;
622 break;
623 case( DMPAPER_ENV_DL):
624 pSetupData->mePaperFormat = PAPER_ENV_DL;
625 break;
626 case( DMPAPER_ENV_C5):
627 pSetupData->mePaperFormat = PAPER_ENV_C5;
628 break;
629 case( DMPAPER_ENV_C3):
630 pSetupData->mePaperFormat = PAPER_ENV_C3;
631 break;
632 case( DMPAPER_ENV_C4):
633 pSetupData->mePaperFormat = PAPER_ENV_C4;
634 break;
635 case( DMPAPER_ENV_C6):
636 pSetupData->mePaperFormat = PAPER_ENV_C6;
637 break;
638 case( DMPAPER_ENV_C65):
639 pSetupData->mePaperFormat = PAPER_ENV_C65;
640 break;
641 case( DMPAPER_ENV_ITALY ):
642 pSetupData->mePaperFormat = PAPER_ENV_ITALY;
643 break;
644 case( DMPAPER_ENV_MONARCH ):
645 pSetupData->mePaperFormat = PAPER_ENV_MONARCH;
646 break;
647 case( DMPAPER_ENV_PERSONAL ):
648 pSetupData->mePaperFormat = PAPER_ENV_PERSONAL;
649 break;
650 case( DMPAPER_FANFOLD_US ):
651 pSetupData->mePaperFormat = PAPER_FANFOLD_US;
652 break;
653 case( DMPAPER_FANFOLD_STD_GERMAN ):
654 pSetupData->mePaperFormat = PAPER_FANFOLD_DE;
655 break;
656 case( DMPAPER_FANFOLD_LGL_GERMAN ):
657 pSetupData->mePaperFormat = PAPER_FANFOLD_LEGAL_DE;
658 break;
659 case( DMPAPER_ISO_B4 ):
660 pSetupData->mePaperFormat = PAPER_B4_ISO;
661 break;
662 case( DMPAPER_JAPANESE_POSTCARD ):
663 pSetupData->mePaperFormat = PAPER_POSTCARD_JP;
664 break;
665 case( DMPAPER_9X11 ):
666 pSetupData->mePaperFormat = PAPER_9x11;
667 break;
668 case( DMPAPER_10X11 ):
669 pSetupData->mePaperFormat = PAPER_10x11;
670 break;
671 case( DMPAPER_15X11 ):
672 pSetupData->mePaperFormat = PAPER_15x11;
673 break;
674 case( DMPAPER_ENV_INVITE ):
675 pSetupData->mePaperFormat = PAPER_ENV_INVITE;
676 break;
677 case( DMPAPER_A_PLUS ):
678 pSetupData->mePaperFormat = PAPER_A_PLUS;
679 break;
680 case( DMPAPER_B_PLUS ):
681 pSetupData->mePaperFormat = PAPER_B_PLUS;
682 break;
683 case( DMPAPER_LETTER_PLUS ):
684 pSetupData->mePaperFormat = PAPER_LETTER_PLUS;
685 break;
686 case( DMPAPER_A4_PLUS ):
687 pSetupData->mePaperFormat = PAPER_A4_PLUS;
688 break;
689 case( DMPAPER_A2 ):
690 pSetupData->mePaperFormat = PAPER_A2;
691 break;
692 case( DMPAPER_DBL_JAPANESE_POSTCARD ):
693 pSetupData->mePaperFormat = PAPER_DOUBLEPOSTCARD_JP;
694 break;
695 case( DMPAPER_A6 ):
696 pSetupData->mePaperFormat = PAPER_A6;
697 break;
698 case( DMPAPER_B6_JIS ):
699 pSetupData->mePaperFormat = PAPER_B6_JIS;
700 break;
701 case( DMPAPER_12X11 ):
702 pSetupData->mePaperFormat = PAPER_12x11;
703 break;
704 default:
705 pSetupData->mePaperFormat = PAPER_USER;
706 break;
710 if( nFlags & SAL_JOBSET_DUPLEXMODE )
712 DuplexMode eDuplex = DUPLEX_UNKNOWN;
713 if( (CHOOSE_DEVMODE(dmFields) & DM_DUPLEX) )
715 if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_SIMPLEX )
716 eDuplex = DUPLEX_OFF;
717 else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_VERTICAL )
718 eDuplex = DUPLEX_LONGEDGE;
719 else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_HORIZONTAL )
720 eDuplex = DUPLEX_SHORTEDGE;
722 pSetupData->meDuplexMode = eDuplex;
726 static void ImplJobSetupToDevMode( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, sal_uLong nFlags )
728 if ( !pSetupData || !pSetupData->mpDriverData )
729 return;
731 DECLARE_DEVMODE( pSetupData );
733 // Orientation
734 if ( nFlags & SAL_JOBSET_ORIENTATION )
736 CHOOSE_DEVMODE(dmFields) |= DM_ORIENTATION;
737 if ( pSetupData->meOrientation == ORIENTATION_PORTRAIT )
738 CHOOSE_DEVMODE(dmOrientation) = DMORIENT_PORTRAIT;
739 else
740 CHOOSE_DEVMODE(dmOrientation) = DMORIENT_LANDSCAPE;
743 // PaperBin
744 if ( nFlags & SAL_JOBSET_PAPERBIN )
746 sal_uLong nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
748 if ( nCount && (nCount != GDI_ERROR) )
750 WORD* pBins = (WORD*)rtl_allocateZeroMemory(nCount*sizeof(WORD));
751 ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
752 CHOOSE_DEVMODE(dmFields) |= DM_DEFAULTSOURCE;
753 CHOOSE_DEVMODE(dmDefaultSource) = pBins[ pSetupData->mnPaperBin ];
754 rtl_freeMemory( pBins );
758 // PaperSize
759 if ( nFlags & SAL_JOBSET_PAPERSIZE )
761 CHOOSE_DEVMODE(dmFields) |= DM_PAPERSIZE;
762 CHOOSE_DEVMODE(dmPaperWidth) = 0;
763 CHOOSE_DEVMODE(dmPaperLength) = 0;
765 switch( pSetupData->mePaperFormat )
767 case( PAPER_A2 ):
768 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A2;
769 break;
770 case( PAPER_A3 ):
771 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A3;
772 break;
773 case( PAPER_A4 ):
774 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4;
775 break;
776 case( PAPER_A5 ):
777 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A5;
778 break;
779 case( PAPER_B4_ISO):
780 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ISO_B4;
781 break;
782 case( PAPER_LETTER ):
783 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER;
784 break;
785 case( PAPER_LEGAL ):
786 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEGAL;
787 break;
788 case( PAPER_TABLOID ):
789 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_TABLOID;
790 break;
791 #if 0
792 //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
793 //DMPAPER_ENV_B6 is documented as:
794 //"DMPAPER_ENV_B6 35 Envelope B6 176 x 125 mm"
795 //which is the wrong way around, it is surely 125 x 176, i.e.
796 //compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
797 //DMPAPER_ENV_B4 33 Envelope B4 250 x 353 mm
798 //DMPAPER_ENV_B5 34 Envelope B5 176 x 250 mm
799 case( PAPER_B6_ISO ):
800 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_B6;
801 break;
802 #endif
803 case( PAPER_ENV_C4 ):
804 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C4;
805 break;
806 case( PAPER_ENV_C5 ):
807 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C5;
808 break;
809 case( PAPER_ENV_C6 ):
810 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C6;
811 break;
812 case( PAPER_ENV_C65 ):
813 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C65;
814 break;
815 case( PAPER_ENV_DL ):
816 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_DL;
817 break;
818 case( PAPER_C ):
819 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_CSHEET;
820 break;
821 case( PAPER_D ):
822 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DSHEET;
823 break;
824 case( PAPER_E ):
825 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ESHEET;
826 break;
827 case( PAPER_EXECUTIVE ):
828 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_EXECUTIVE;
829 break;
830 case( PAPER_FANFOLD_LEGAL_DE ):
831 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_LGL_GERMAN;
832 break;
833 case( PAPER_ENV_MONARCH ):
834 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_MONARCH;
835 break;
836 case( PAPER_ENV_PERSONAL ):
837 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_PERSONAL;
838 break;
839 case( PAPER_ENV_9 ):
840 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_9;
841 break;
842 case( PAPER_ENV_10 ):
843 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_10;
844 break;
845 case( PAPER_ENV_11 ):
846 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_11;
847 break;
848 case( PAPER_ENV_12 ):
849 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_12;
850 break;
851 //See the comments on DMPAPER_B4 above
852 case( PAPER_B4_JIS ):
853 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B4;
854 break;
855 case( PAPER_B5_JIS ):
856 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B5;
857 break;
858 case( PAPER_B6_JIS ):
859 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B6_JIS;
860 break;
861 case( PAPER_LEDGER ):
862 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEDGER;
863 break;
864 case( PAPER_STATEMENT ):
865 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_STATEMENT;
866 break;
867 case( PAPER_10x14 ):
868 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X14;
869 break;
870 case( PAPER_ENV_14 ):
871 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_14;
872 break;
873 case( PAPER_ENV_C3 ):
874 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C3;
875 break;
876 case( PAPER_ENV_ITALY ):
877 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_ITALY;
878 break;
879 case( PAPER_FANFOLD_US ):
880 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_US;
881 break;
882 case( PAPER_FANFOLD_DE ):
883 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_STD_GERMAN;
884 break;
885 case( PAPER_POSTCARD_JP ):
886 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_JAPANESE_POSTCARD;
887 break;
888 case( PAPER_9x11 ):
889 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_9X11;
890 break;
891 case( PAPER_10x11 ):
892 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X11;
893 break;
894 case( PAPER_15x11 ):
895 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_15X11;
896 break;
897 case( PAPER_ENV_INVITE ):
898 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_INVITE;
899 break;
900 case( PAPER_A_PLUS ):
901 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A_PLUS;
902 break;
903 case( PAPER_B_PLUS ):
904 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B_PLUS;
905 break;
906 case( PAPER_LETTER_PLUS ):
907 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER_PLUS;
908 break;
909 case( PAPER_A4_PLUS ):
910 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4_PLUS;
911 break;
912 case( PAPER_DOUBLEPOSTCARD_JP ):
913 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DBL_JAPANESE_POSTCARD;
914 break;
915 case( PAPER_A6 ):
916 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A6;
917 break;
918 case( PAPER_12x11 ):
919 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_12X11;
920 break;
921 default:
923 short nPaper = 0;
924 sal_uLong nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
925 WORD* pPapers = NULL;
926 sal_uLong nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
927 POINT* pPaperSizes = NULL;
928 DWORD nLandscapeAngle = ImplDeviceCaps( pPrinter, DC_ORIENTATION, NULL, pSetupData );
929 if ( nPaperCount && (nPaperCount != GDI_ERROR) )
931 pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
932 ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
934 if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
936 pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
937 ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
939 if ( (nPaperSizeCount == nPaperCount) && pPapers && pPaperSizes )
941 PaperInfo aInfo(pSetupData->mnPaperWidth, pSetupData->mnPaperHeight);
942 // compare paper formats and select a good match
943 for ( sal_uLong i = 0; i < nPaperCount; i++ )
945 if ( aInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)))
947 nPaper = pPapers[i];
948 break;
952 // If the printer supports landscape orientation, check paper sizes again
953 // with landscape orientation. This is necessary as a printer driver provides
954 // all paper sizes with portrait orientation only!!
955 if ( !nPaper && nLandscapeAngle != 0 )
957 PaperInfo aRotatedInfo(pSetupData->mnPaperHeight, pSetupData->mnPaperWidth);
958 for ( sal_uLong i = 0; i < nPaperCount; i++ )
960 if ( aRotatedInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)) )
962 nPaper = pPapers[i];
963 break;
968 if ( nPaper )
969 CHOOSE_DEVMODE(dmPaperSize) = nPaper;
972 if ( !nPaper )
974 CHOOSE_DEVMODE(dmFields) |= DM_PAPERLENGTH | DM_PAPERWIDTH;
975 CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_USER;
976 CHOOSE_DEVMODE(dmPaperWidth) = (short)(pSetupData->mnPaperWidth/10);
977 CHOOSE_DEVMODE(dmPaperLength) = (short)(pSetupData->mnPaperHeight/10);
980 if ( pPapers )
981 rtl_freeMemory(pPapers);
982 if ( pPaperSizes )
983 rtl_freeMemory(pPaperSizes);
985 break;
989 if( (nFlags & SAL_JOBSET_DUPLEXMODE) )
991 switch( pSetupData->meDuplexMode )
993 case DUPLEX_OFF:
994 CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
995 CHOOSE_DEVMODE(dmDuplex) = DMDUP_SIMPLEX;
996 break;
997 case DUPLEX_SHORTEDGE:
998 CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
999 CHOOSE_DEVMODE(dmDuplex) = DMDUP_HORIZONTAL;
1000 break;
1001 case DUPLEX_LONGEDGE:
1002 CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
1003 CHOOSE_DEVMODE(dmDuplex) = DMDUP_VERTICAL;
1004 break;
1005 case DUPLEX_UNKNOWN:
1006 break;
1011 static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
1012 LPCWSTR pDevice,
1013 LPDEVMODEW pDevMode )
1015 HDC hDC = 0;
1016 CATCH_DRIVER_EX_BEGIN;
1017 hDC = CreateICW( pDriver, pDevice, 0, pDevMode );
1018 CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
1019 return hDC;
1022 static HDC ImplCreateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
1024 HDC hDC = 0;
1025 LPDEVMODEW pDevMode;
1026 if ( pSetupData && pSetupData->mpDriverData )
1027 pDevMode = SAL_DEVMODE_W( pSetupData );
1028 else
1029 pDevMode = NULL;
1030 // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
1031 // pl: does this hold true for Unicode functions ?
1032 if( pPrinter->maDriverName.getLength() > 2048 || pPrinter->maDeviceName.getLength() > 2048 )
1033 return 0;
1034 sal_Unicode pDriverName[ 4096 ];
1035 sal_Unicode pDeviceName[ 4096 ];
1036 memcpy( pDriverName, pPrinter->maDriverName.getStr(), pPrinter->maDriverName.getLength()*sizeof(sal_Unicode));
1037 memset( pDriverName+pPrinter->maDriverName.getLength(), 0, 32 );
1038 memcpy( pDeviceName, pPrinter->maDeviceName.getStr(), pPrinter->maDeviceName.getLength()*sizeof(sal_Unicode));
1039 memset( pDeviceName+pPrinter->maDeviceName.getLength(), 0, 32 );
1040 hDC = ImplCreateICW_WithCatch( reinterpret_cast< LPWSTR >(pDriverName),
1041 reinterpret_cast< LPCWSTR >(pDeviceName),
1042 pDevMode );
1043 return hDC;
1046 static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC )
1048 WinSalGraphics* pGraphics = new WinSalGraphics(WinSalGraphics::PRINTER, false, 0, /* CHECKME */ NULL);
1049 pGraphics->SetLayout( SalLayoutFlags::NONE );
1050 pGraphics->setHDC(hDC);
1051 pGraphics->InitGraphics();
1052 return pGraphics;
1055 static bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
1057 HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1058 if ( !hNewDC )
1059 return FALSE;
1061 if ( pPrinter->mpGraphics )
1063 pPrinter->mpGraphics->DeInitGraphics();
1064 DeleteDC( pPrinter->mpGraphics->getHDC() );
1065 delete pPrinter->mpGraphics;
1068 pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hNewDC );
1069 pPrinter->mhDC = hNewDC;
1071 return TRUE;
1074 // - WinSalInstance -
1076 SalInfoPrinter* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
1077 ImplJobSetup* pSetupData )
1079 WinSalInfoPrinter* pPrinter = new WinSalInfoPrinter;
1080 if( ! pQueueInfo->mpSysData )
1081 GetPrinterQueueState( pQueueInfo );
1082 pPrinter->maDriverName = pQueueInfo->maDriver;
1083 pPrinter->maDeviceName = pQueueInfo->maPrinterName;
1084 pPrinter->maPortName = pQueueInfo->mpSysData ?
1085 *pQueueInfo->mpSysData
1086 : OUString();
1088 // check if the provided setup data match the actual printer
1089 ImplTestSalJobSetup( pPrinter, pSetupData, TRUE );
1091 HDC hDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1092 if ( !hDC )
1094 delete pPrinter;
1095 return NULL;
1098 pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hDC );
1099 pPrinter->mhDC = hDC;
1100 if ( !pSetupData->mpDriverData )
1101 ImplUpdateSalJobSetup( pPrinter, pSetupData, FALSE, NULL );
1102 ImplDevModeToJobSetup( pPrinter, pSetupData, SAL_JOBSET_ALL );
1103 pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
1105 return pPrinter;
1108 void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
1110 delete pPrinter;
1113 // - WinSalInfoPrinter -
1115 WinSalInfoPrinter::WinSalInfoPrinter() :
1116 mpGraphics( NULL ),
1117 mhDC( 0 ),
1118 mbGraphics( FALSE )
1120 m_bPapersInit = FALSE;
1123 WinSalInfoPrinter::~WinSalInfoPrinter()
1125 if ( mpGraphics )
1127 mpGraphics->DeInitGraphics();
1128 DeleteDC( mpGraphics->getHDC() );
1129 delete mpGraphics;
1133 void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
1135 m_aPaperFormats.clear();
1137 DWORD nCount = ImplDeviceCaps( this, DC_PAPERSIZE, NULL, pSetupData );
1138 if( nCount == GDI_ERROR )
1139 nCount = 0;
1141 if( nCount )
1143 POINT* pPaperSizes = (POINT*)rtl_allocateZeroMemory(nCount*sizeof(POINT));
1144 ImplDeviceCaps( this, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
1146 sal_Unicode* pNamesBuffer = (sal_Unicode*)rtl_allocateMemory(nCount*64*sizeof(sal_Unicode));
1147 ImplDeviceCaps( this, DC_PAPERNAMES, (BYTE*)pNamesBuffer, pSetupData );
1148 for( DWORD i = 0; i < nCount; ++i )
1150 PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
1151 m_aPaperFormats.push_back( aInfo );
1153 rtl_freeMemory( pNamesBuffer );
1154 rtl_freeMemory( pPaperSizes );
1157 m_bPapersInit = true;
1160 int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
1162 int nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
1164 if( nRet != sal::static_int_cast<int>( GDI_ERROR ) )
1165 return nRet * 10;
1166 else
1167 return 900; // guess
1170 SalGraphics* WinSalInfoPrinter::AcquireGraphics()
1172 if ( mbGraphics )
1173 return NULL;
1175 if ( mpGraphics )
1176 mbGraphics = TRUE;
1178 return mpGraphics;
1181 void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
1183 mbGraphics = FALSE;
1186 bool WinSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pSetupData )
1188 if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, static_cast<WinSalFrame*>(pFrame) ) )
1190 ImplDevModeToJobSetup( this, pSetupData, SAL_JOBSET_ALL );
1191 return ImplUpdateSalPrnIC( this, pSetupData );
1194 return FALSE;
1197 bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
1199 if ( !ImplTestSalJobSetup( this, pSetupData, FALSE ) )
1200 return FALSE;
1201 return ImplUpdateSalPrnIC( this, pSetupData );
1204 bool WinSalInfoPrinter::SetData( sal_uLong nFlags, ImplJobSetup* pSetupData )
1206 ImplJobSetupToDevMode( this, pSetupData, nFlags );
1207 if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, NULL ) )
1209 ImplDevModeToJobSetup( this, pSetupData, nFlags );
1210 return ImplUpdateSalPrnIC( this, pSetupData );
1213 return FALSE;
1216 sal_uLong WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
1218 DWORD nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
1219 if ( nRet && (nRet != GDI_ERROR) )
1220 return nRet;
1221 else
1222 return 0;
1225 OUString WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pSetupData, sal_uLong nPaperBin )
1227 OUString aPaperBinName;
1229 DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, NULL, pSetupData );
1230 if ( (nPaperBin < nBins) && (nBins != GDI_ERROR) )
1232 sal_Unicode* pBuffer = new sal_Unicode[nBins*24];
1233 DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, (BYTE*)pBuffer, pSetupData );
1234 if ( nRet && (nRet != GDI_ERROR) )
1235 aPaperBinName = OUString( pBuffer + (nPaperBin*24) );
1236 delete [] pBuffer;
1239 return aPaperBinName;
1242 sal_uLong WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, sal_uInt16 nType )
1244 DWORD nRet;
1246 switch ( nType )
1248 case PRINTER_CAPABILITIES_SUPPORTDIALOG:
1249 return TRUE;
1250 case PRINTER_CAPABILITIES_COPIES:
1251 nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
1252 if ( nRet && (nRet != GDI_ERROR) )
1253 return nRet;
1254 return 0;
1255 case PRINTER_CAPABILITIES_COLLATECOPIES:
1256 nRet = ImplDeviceCaps( this, DC_COLLATE, NULL, pSetupData );
1257 if ( nRet && (nRet != GDI_ERROR) )
1259 nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
1260 if ( nRet && (nRet != GDI_ERROR) )
1261 return nRet;
1263 return 0;
1265 case PRINTER_CAPABILITIES_SETORIENTATION:
1266 nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
1267 if ( nRet && (nRet != GDI_ERROR) )
1268 return TRUE;
1269 return FALSE;
1271 case PRINTER_CAPABILITIES_SETPAPERBIN:
1272 nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
1273 if ( nRet && (nRet != GDI_ERROR) )
1274 return TRUE;
1275 return FALSE;
1277 case PRINTER_CAPABILITIES_SETPAPERSIZE:
1278 case PRINTER_CAPABILITIES_SETPAPER:
1279 nRet = ImplDeviceCaps( this, DC_PAPERS, NULL, pSetupData );
1280 if ( nRet && (nRet != GDI_ERROR) )
1281 return TRUE;
1282 return FALSE;
1285 return 0;
1288 void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
1289 long& rOutWidth, long& rOutHeight,
1290 long& rPageOffX, long& rPageOffY,
1291 long& rPageWidth, long& rPageHeight )
1293 HDC hDC = mhDC;
1295 rOutWidth = GetDeviceCaps( hDC, HORZRES );
1296 rOutHeight = GetDeviceCaps( hDC, VERTRES );
1298 rPageOffX = GetDeviceCaps( hDC, PHYSICALOFFSETX );
1299 rPageOffY = GetDeviceCaps( hDC, PHYSICALOFFSETY );
1300 rPageWidth = GetDeviceCaps( hDC, PHYSICALWIDTH );
1301 rPageHeight = GetDeviceCaps( hDC, PHYSICALHEIGHT );
1304 // - WinSalInstance -
1306 SalPrinter* WinSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
1308 WinSalPrinter* pPrinter = new WinSalPrinter;
1309 pPrinter->mpInfoPrinter = static_cast<WinSalInfoPrinter*>(pInfoPrinter);
1310 return pPrinter;
1313 void WinSalInstance::DestroyPrinter( SalPrinter* pPrinter )
1315 delete pPrinter;
1318 BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
1320 SalData* pSalData = GetSalData();
1321 WinSalPrinter* pPrinter;
1322 bool bWhile = TRUE;
1323 int i = 0;
1327 // process messages
1328 MSG aMsg;
1329 if ( PeekMessageW( &aMsg, 0, 0, 0, PM_REMOVE ) )
1331 TranslateMessage( &aMsg );
1332 DispatchMessageW( &aMsg );
1334 i++;
1335 if ( i > 15 )
1336 bWhile = FALSE;
1338 else
1339 bWhile = FALSE;
1341 pPrinter = pSalData->mpFirstPrinter;
1342 while ( pPrinter )
1344 if( pPrinter->mhDC == hPrnDC )
1345 break;
1347 pPrinter = pPrinter->mpNextPrinter;
1350 if ( !pPrinter || pPrinter->mbAbort )
1351 return FALSE;
1353 while ( bWhile );
1355 return TRUE;
1358 static LPDEVMODEW ImplSalSetCopies( LPDEVMODEW pDevMode, sal_uLong nCopies, bool bCollate )
1360 LPDEVMODEW pNewDevMode = pDevMode;
1361 if ( pDevMode && (nCopies > 1) )
1363 if ( nCopies > 32765 )
1364 nCopies = 32765;
1365 sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
1366 pNewDevMode = (LPDEVMODEW)rtl_allocateMemory( nDevSize );
1367 memcpy( pNewDevMode, pDevMode, nDevSize );
1368 pDevMode = pNewDevMode;
1369 pDevMode->dmFields |= DM_COPIES;
1370 pDevMode->dmCopies = (short)(sal_uInt16)nCopies;
1371 pDevMode->dmFields |= DM_COLLATE;
1372 if ( bCollate )
1373 pDevMode->dmCollate = DMCOLLATE_TRUE;
1374 else
1375 pDevMode->dmCollate = DMCOLLATE_FALSE;
1378 return pNewDevMode;
1381 // - WinSalPrinter -
1383 WinSalPrinter::WinSalPrinter() :
1384 mpGraphics( NULL ),
1385 mpInfoPrinter( NULL ),
1386 mpNextPrinter( NULL ),
1387 mhDC( 0 ),
1388 mnError( 0 ),
1389 mnCopies( 0 ),
1390 mbCollate( FALSE ),
1391 mbAbort( FALSE ),
1392 mbValid( true )
1394 SalData* pSalData = GetSalData();
1395 // insert printer in printerlist
1396 mpNextPrinter = pSalData->mpFirstPrinter;
1397 pSalData->mpFirstPrinter = this;
1400 WinSalPrinter::~WinSalPrinter()
1402 SalData* pSalData = GetSalData();
1404 // release DC if there is one still around because of AbortJob
1405 HDC hDC = mhDC;
1406 if ( hDC )
1408 if ( mpGraphics )
1410 mpGraphics->DeInitGraphics();
1411 delete mpGraphics;
1414 DeleteDC( hDC );
1417 // remove printer from printerlist
1418 if ( this == pSalData->mpFirstPrinter )
1419 pSalData->mpFirstPrinter = mpNextPrinter;
1420 else
1422 WinSalPrinter* pTempPrinter = pSalData->mpFirstPrinter;
1424 while( pTempPrinter->mpNextPrinter != this )
1425 pTempPrinter = pTempPrinter->mpNextPrinter;
1427 pTempPrinter->mpNextPrinter = mpNextPrinter;
1429 mbValid = false;
1432 void WinSalPrinter::markInvalid()
1434 mbValid = false;
1437 // need wrappers for StarTocW/A to use structured exception handling
1438 // since SEH does not mix with standard exception handling's cleanup
1439 static int lcl_StartDocW( HDC hDC, DOCINFOW* pInfo, WinSalPrinter* pPrt )
1441 (void) pPrt;
1442 int nRet = 0;
1443 CATCH_DRIVER_EX_BEGIN;
1444 nRet = ::StartDocW( hDC, pInfo );
1445 CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
1446 return nRet;
1449 bool WinSalPrinter::StartJob( const OUString* pFileName,
1450 const OUString& rJobName,
1451 const OUString&,
1452 sal_uLong nCopies,
1453 bool bCollate,
1454 bool /*bDirect*/,
1455 ImplJobSetup* pSetupData )
1457 mnError = 0;
1458 mbAbort = FALSE;
1459 mnCopies = nCopies;
1460 mbCollate = bCollate;
1462 LPDEVMODEW pOrgDevModeW = NULL;
1463 LPDEVMODEW pDevModeW = NULL;
1464 HDC hDC = 0;
1465 if ( pSetupData && pSetupData->mpDriverData )
1467 pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
1468 pDevModeW = ImplSalSetCopies( pOrgDevModeW, nCopies, bCollate );
1471 // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
1472 sal_Unicode aDrvBuf[4096];
1473 sal_Unicode aDevBuf[4096];
1474 memcpy( aDrvBuf, mpInfoPrinter->maDriverName.getStr(), (mpInfoPrinter->maDriverName.getLength()+1)*sizeof(sal_Unicode));
1475 memcpy( aDevBuf, mpInfoPrinter->maDeviceName.getStr(), (mpInfoPrinter->maDeviceName.getLength()+1)*sizeof(sal_Unicode));
1476 hDC = CreateDCW( reinterpret_cast<LPCWSTR>(aDrvBuf),
1477 reinterpret_cast<LPCWSTR>(aDevBuf),
1478 NULL,
1479 pDevModeW );
1481 if ( pDevModeW != pOrgDevModeW )
1482 rtl_freeMemory( pDevModeW );
1484 if ( !hDC )
1486 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1487 return FALSE;
1490 // make sure mhDC is set before the printer driver may call our abortproc
1491 mhDC = hDC;
1492 if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
1494 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1495 return FALSE;
1498 mnError = 0;
1499 mbAbort = FALSE;
1501 // As the Telocom Balloon Fax driver tends to send messages repeatedly
1502 // we try to process first all, and then insert a dummy message
1503 bool bWhile = TRUE;
1504 int i = 0;
1507 // process messages
1508 MSG aMsg;
1509 if ( PeekMessageW( &aMsg, 0, 0, 0, PM_REMOVE ) )
1511 TranslateMessage( &aMsg );
1512 DispatchMessageW( &aMsg );
1514 i++;
1515 if ( i > 15 )
1516 bWhile = FALSE;
1518 else
1519 bWhile = FALSE;
1521 while ( bWhile );
1522 PostMessageW( GetSalData()->mpFirstInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0 );
1524 // bring up a file choser if printing to file port but no file name given
1525 OUString aOutFileName;
1526 if( mpInfoPrinter->maPortName.equalsIgnoreAsciiCase( "FILE:" ) && !(pFileName && !pFileName->isEmpty()) )
1529 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1530 uno::Reference< XFilePicker3 > xFilePicker = FilePicker::createWithMode(xContext, TemplateDescription::FILESAVE_SIMPLE);
1532 if( xFilePicker->execute() == ExecutableDialogResults::OK )
1534 Sequence< OUString > aPathSeq( xFilePicker->getFiles() );
1535 INetURLObject aObj( aPathSeq[0] );
1536 // we're using ansi calls (StartDocA) so convert the string
1537 aOutFileName = aObj.PathToFileName();
1539 else
1541 mnError = SAL_PRINTER_ERROR_ABORT;
1542 return FALSE;
1546 DOCINFOW aInfo;
1547 memset( &aInfo, 0, sizeof( DOCINFOW ) );
1548 aInfo.cbSize = sizeof( aInfo );
1549 aInfo.lpszDocName = (LPWSTR)rJobName.getStr();
1550 if ( pFileName || aOutFileName.getLength() )
1552 if ( (pFileName && !pFileName->isEmpty()) || aOutFileName.getLength() )
1554 aInfo.lpszOutput = (LPWSTR)( (pFileName && !pFileName->isEmpty()) ? pFileName->getStr() : aOutFileName.getStr());
1556 else
1557 aInfo.lpszOutput = L"FILE:";
1559 else
1560 aInfo.lpszOutput = NULL;
1562 // start Job
1563 int nRet = lcl_StartDocW( hDC, &aInfo, this );
1565 if ( nRet <= 0 )
1567 long nError = GetLastError();
1568 if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
1569 mnError = SAL_PRINTER_ERROR_ABORT;
1570 else
1571 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1572 return FALSE;
1575 return TRUE;
1578 bool WinSalPrinter::EndJob()
1580 HDC hDC = mhDC;
1581 if ( isValid() && hDC )
1583 if ( mpGraphics )
1585 mpGraphics->DeInitGraphics();
1586 delete mpGraphics;
1587 mpGraphics = NULL;
1590 // #i54419# Windows fax printer brings up a dialog in EndDoc
1591 // which text previously copied in soffice process can be
1592 // pasted to -> deadlock due to mutex not released.
1593 // it should be safe to release the yield mutex over the EndDoc
1594 // call, however the real solution is supposed to be the threading
1595 // framework yet to come.
1596 volatile sal_uLong nAcquire = GetSalData()->mpFirstInstance->ReleaseYieldMutex();
1597 CATCH_DRIVER_EX_BEGIN;
1598 if( ::EndDoc( hDC ) <= 0 )
1599 GetLastError();
1600 CATCH_DRIVER_EX_END( "exception in EndDoc", this );
1602 GetSalData()->mpFirstInstance->AcquireYieldMutex( nAcquire );
1603 DeleteDC( hDC );
1604 mhDC = 0;
1607 return TRUE;
1610 bool WinSalPrinter::AbortJob()
1612 mbAbort = TRUE;
1614 // trigger Abort asynchronously
1615 HDC hDC = mhDC;
1616 if ( hDC )
1618 SalData* pSalData = GetSalData();
1619 PostMessageW( pSalData->mpFirstInstance->mhComWnd,
1620 SAL_MSG_PRINTABORTJOB, (WPARAM)hDC, 0 );
1623 return TRUE;
1626 void ImplSalPrinterAbortJobAsync( HDC hPrnDC )
1628 SalData* pSalData = GetSalData();
1629 WinSalPrinter* pPrinter = pSalData->mpFirstPrinter;
1631 // check if printer still exists
1632 while ( pPrinter )
1634 if ( pPrinter->mhDC == hPrnDC )
1635 break;
1637 pPrinter = pPrinter->mpNextPrinter;
1640 // if printer still exists, cancel the job
1641 if ( pPrinter )
1643 HDC hDC = pPrinter->mhDC;
1644 if ( hDC )
1646 if ( pPrinter->mpGraphics )
1648 pPrinter->mpGraphics->DeInitGraphics();
1649 delete pPrinter->mpGraphics;
1650 pPrinter->mpGraphics = NULL;
1653 CATCH_DRIVER_EX_BEGIN;
1654 ::AbortDoc( hDC );
1655 CATCH_DRIVER_EX_END( "exception in AbortDoc", pPrinter );
1657 DeleteDC( hDC );
1658 pPrinter->mhDC = 0;
1663 SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, bool bNewJobData )
1665 if( ! isValid() || mhDC == 0 )
1666 return NULL;
1668 HDC hDC = mhDC;
1669 if ( pSetupData && pSetupData->mpDriverData && bNewJobData )
1671 LPDEVMODEW pOrgDevModeW;
1672 LPDEVMODEW pDevModeW;
1673 pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
1674 pDevModeW = ImplSalSetCopies( pOrgDevModeW, mnCopies, mbCollate );
1675 ResetDCW( hDC, pDevModeW );
1676 if ( pDevModeW != pOrgDevModeW )
1677 rtl_freeMemory( pDevModeW );
1679 volatile int nRet = 0;
1680 CATCH_DRIVER_EX_BEGIN;
1681 nRet = ::StartPage( hDC );
1682 CATCH_DRIVER_EX_END( "exception in StartPage", this );
1684 if ( nRet <= 0 )
1686 GetLastError();
1687 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1688 return NULL;
1691 // Hack to work around old PostScript printer drivers optimizing away empty pages
1692 // TODO: move into ImplCreateSalPrnGraphics()?
1693 HPEN hTempPen = SelectPen( hDC, GetStockPen( NULL_PEN ) );
1694 HBRUSH hTempBrush = SelectBrush( hDC, GetStockBrush( NULL_BRUSH ) );
1695 WIN_Rectangle( hDC, -8000, -8000, -7999, -7999 );
1696 SelectPen( hDC, hTempPen );
1697 SelectBrush( hDC, hTempBrush );
1699 mpGraphics = ImplCreateSalPrnGraphics( hDC );
1700 return mpGraphics;
1703 bool WinSalPrinter::EndPage()
1705 HDC hDC = mhDC;
1706 if ( hDC && mpGraphics )
1708 mpGraphics->DeInitGraphics();
1709 delete mpGraphics;
1710 mpGraphics = NULL;
1713 if( ! isValid() )
1714 return FALSE;
1716 volatile int nRet = 0;
1717 CATCH_DRIVER_EX_BEGIN;
1718 nRet = ::EndPage( hDC );
1719 CATCH_DRIVER_EX_END( "exception in EndPage", this );
1721 if ( nRet > 0 )
1722 return TRUE;
1723 else
1725 GetLastError();
1726 mnError = SAL_PRINTER_ERROR_GENERALERROR;
1727 return FALSE;
1731 sal_uLong WinSalPrinter::GetErrorCode()
1733 return mnError;
1736 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */