xref: /aoo42x/main/vcl/win/source/gdi/salprn.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <string.h>
32 
33 #include <osl/module.h>
34 
35 #include <tools/urlobj.hxx>
36 #include <tools/svwin.h>
37 #ifdef __MINGW32__
38 #include <excpt.h>
39 #endif
40 
41 #include <win/wincomp.hxx>
42 #include <win/saldata.hxx>
43 #include <win/salinst.h>
44 #include <win/salgdi.h>
45 #include <win/salframe.h>
46 #include <win/salprn.h>
47 
48 #include <salptype.hxx>
49 #include <print.h>
50 #include <jobset.h>
51 
52 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
53 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
54 #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
55 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
56 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
57 #include <com/sun/star/lang/XInitialization.hpp>
58 #include <comphelper/processfactory.hxx>
59 
60 #include <malloc.h>
61 
62 #ifdef __MINGW32__
63 #define CATCH_DRIVER_EX_BEGIN                                               \
64     jmp_buf jmpbuf;                                                         \
65     __SEHandler han;                                                        \
66     if (__builtin_setjmp(jmpbuf) == 0)                                      \
67     {                                                                       \
68         han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER)
69 
70 #define CATCH_DRIVER_EX_END(mes, p)                                         \
71     }                                                                       \
72     han.Reset()
73 #define CATCH_DRIVER_EX_END_2(mes)                                            \
74     }                                                                       \
75     han.Reset()
76 #else
77 #define CATCH_DRIVER_EX_BEGIN                                               \
78     __try                                                                   \
79     {
80 #define CATCH_DRIVER_EX_END(mes, p)                                         \
81     }                                                                       \
82     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
83     {                                                                       \
84         DBG_ERROR( mes );                                                   \
85         p->markInvalid();                                                   \
86     }
87 #define CATCH_DRIVER_EX_END_2(mes)                                         \
88     }                                                                       \
89     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
90     {                                                                       \
91         DBG_ERROR( mes );                                                   \
92     }
93 #endif
94 
95 
96 using namespace com::sun::star;
97 using namespace com::sun::star::uno;
98 using namespace com::sun::star::lang;
99 using namespace com::sun::star::ui::dialogs;
100 using namespace rtl;
101 
102 // =======================================================================
103 
104 static char aImplWindows[] = "windows";
105 static char aImplDevices[] = "devices";
106 static char aImplDevice[]  = "device";
107 
108 static LPDEVMODEA SAL_DEVMODE_A( const ImplJobSetup* pSetupData )
109 {
110     LPDEVMODEA pRet = NULL;
111     SalDriverData* pDrv = (SalDriverData*)pSetupData->mpDriverData;
112     if( pDrv->mnVersion == SAL_DRIVERDATA_VERSION_A &&
113         pSetupData->mnDriverDataLen >= sizeof(DEVMODEA)+sizeof(SalDriverData)-1
114         )
115         pRet = ((LPDEVMODEA)((pSetupData->mpDriverData) + (pDrv->mnDriverOffset)));
116     return pRet;
117 }
118 
119 static LPDEVMODEW SAL_DEVMODE_W( const ImplJobSetup* pSetupData )
120 {
121     LPDEVMODEW pRet = NULL;
122     SalDriverData* pDrv = (SalDriverData*)pSetupData->mpDriverData;
123     if( pDrv->mnVersion == SAL_DRIVERDATA_VERSION_W &&
124         pSetupData->mnDriverDataLen >= sizeof(DEVMODEW)+sizeof(SalDriverData)-1
125         )
126         pRet = ((LPDEVMODEW)((pSetupData->mpDriverData) + (pDrv->mnDriverOffset)));
127     return pRet;
128 }
129 
130 // =======================================================================
131 
132 static sal_uLong ImplWinQueueStatusToSal( DWORD nWinStatus )
133 {
134 	sal_uLong nStatus = 0;
135 	if ( nWinStatus & PRINTER_STATUS_PAUSED )
136 		nStatus |= QUEUE_STATUS_PAUSED;
137 	if ( nWinStatus & PRINTER_STATUS_ERROR )
138 		nStatus |= QUEUE_STATUS_ERROR;
139 	if ( nWinStatus & PRINTER_STATUS_PENDING_DELETION )
140 		nStatus |= QUEUE_STATUS_PENDING_DELETION;
141 	if ( nWinStatus & PRINTER_STATUS_PAPER_JAM )
142 		nStatus |= QUEUE_STATUS_PAPER_JAM;
143 	if ( nWinStatus & PRINTER_STATUS_PAPER_OUT )
144 		nStatus |= QUEUE_STATUS_PAPER_OUT;
145 	if ( nWinStatus & PRINTER_STATUS_MANUAL_FEED )
146 		nStatus |= QUEUE_STATUS_MANUAL_FEED;
147 	if ( nWinStatus & PRINTER_STATUS_PAPER_PROBLEM )
148 		nStatus |= QUEUE_STATUS_PAPER_PROBLEM;
149 	if ( nWinStatus & PRINTER_STATUS_OFFLINE )
150 		nStatus |= QUEUE_STATUS_OFFLINE;
151 	if ( nWinStatus & PRINTER_STATUS_IO_ACTIVE )
152 		nStatus |= QUEUE_STATUS_IO_ACTIVE;
153 	if ( nWinStatus & PRINTER_STATUS_BUSY )
154 		nStatus |= QUEUE_STATUS_BUSY;
155 	if ( nWinStatus & PRINTER_STATUS_PRINTING )
156 		nStatus |= QUEUE_STATUS_PRINTING;
157 	if ( nWinStatus & PRINTER_STATUS_OUTPUT_BIN_FULL )
158 		nStatus |= QUEUE_STATUS_OUTPUT_BIN_FULL;
159 	if ( nWinStatus & PRINTER_STATUS_WAITING )
160 		nStatus |= QUEUE_STATUS_WAITING;
161 	if ( nWinStatus & PRINTER_STATUS_PROCESSING )
162 		nStatus |= QUEUE_STATUS_PROCESSING;
163 	if ( nWinStatus & PRINTER_STATUS_INITIALIZING )
164 		nStatus |= QUEUE_STATUS_INITIALIZING;
165 	if ( nWinStatus & PRINTER_STATUS_WARMING_UP )
166 		nStatus |= QUEUE_STATUS_WARMING_UP;
167 	if ( nWinStatus & PRINTER_STATUS_TONER_LOW )
168 		nStatus |= QUEUE_STATUS_TONER_LOW;
169 	if ( nWinStatus & PRINTER_STATUS_NO_TONER )
170 		nStatus |= QUEUE_STATUS_NO_TONER;
171 	if ( nWinStatus & PRINTER_STATUS_PAGE_PUNT )
172 		nStatus |= QUEUE_STATUS_PAGE_PUNT;
173 	if ( nWinStatus & PRINTER_STATUS_USER_INTERVENTION )
174 		nStatus |= QUEUE_STATUS_USER_INTERVENTION;
175 	if ( nWinStatus & PRINTER_STATUS_OUT_OF_MEMORY )
176 		nStatus |= QUEUE_STATUS_OUT_OF_MEMORY;
177 	if ( nWinStatus & PRINTER_STATUS_DOOR_OPEN )
178 		nStatus |= QUEUE_STATUS_DOOR_OPEN;
179 	if ( nWinStatus & PRINTER_STATUS_SERVER_UNKNOWN )
180 		nStatus |= QUEUE_STATUS_SERVER_UNKNOWN;
181 	if ( nWinStatus & PRINTER_STATUS_POWER_SAVE )
182 		nStatus |= QUEUE_STATUS_POWER_SAVE;
183 	if ( !nStatus && !(nWinStatus & PRINTER_STATUS_NOT_AVAILABLE) )
184 		nStatus |= QUEUE_STATUS_READY;
185 	return nStatus;
186 }
187 
188 // -----------------------------------------------------------------------
189 
190 static void getPrinterQueueInfoOldStyle( ImplPrnQueueList* pList )
191 {
192 	DWORD			i;
193 	DWORD			n;
194 	DWORD			nBytes = 0;
195 	DWORD			nInfoPrn2;
196 	sal_Bool			bFound = FALSE;
197 	PRINTER_INFO_2* pWinInfo2 = NULL;
198 	PRINTER_INFO_2* pGetInfo2;
199 	EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &nBytes, &nInfoPrn2 );
200 	if ( nBytes )
201 	{
202 		pWinInfo2 = (PRINTER_INFO_2*) rtl_allocateMemory( nBytes );
203 		if ( EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes, &nInfoPrn2 ) )
204 		{
205 			pGetInfo2 = pWinInfo2;
206 			for ( i = 0; i < nInfoPrn2; i++ )
207 			{
208 				SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
209 				pInfo->maPrinterName = ImplSalGetUniString( pGetInfo2->pPrinterName );
210 				pInfo->maDriver 	 = ImplSalGetUniString( pGetInfo2->pDriverName );
211 				XubString aPortName;
212 				if ( pGetInfo2->pPortName )
213 					aPortName = ImplSalGetUniString( pGetInfo2->pPortName );
214 				// pLocation can be 0 (the Windows docu doesn't describe this)
215 				if ( pGetInfo2->pLocation && strlen( pGetInfo2->pLocation ) )
216 					pInfo->maLocation = ImplSalGetUniString( pGetInfo2->pLocation );
217 				else
218 					pInfo->maLocation = aPortName;
219 				// pComment can be 0 (the Windows docu doesn't describe this)
220 				if ( pGetInfo2->pComment )
221 					pInfo->maComment = ImplSalGetUniString( pGetInfo2->pComment );
222 				pInfo->mnStatus 	 = ImplWinQueueStatusToSal( pGetInfo2->Status );
223 				pInfo->mnJobs		 = pGetInfo2->cJobs;
224 				pInfo->mpSysData	 = new XubString( aPortName );
225 				pList->Add( pInfo );
226 				pGetInfo2++;
227 			}
228 
229 			bFound = TRUE;
230 		}
231 	}
232 
233 	// read printers from win.ini
234 	// TODO: MSDN: GetProfileString() should not be called from server
235 	// code because it is just there for WIN16 compatibility
236 	UINT	nSize = 4096;
237 	char*	pBuf = new char[nSize];
238 	UINT	nRead = GetProfileStringA( aImplDevices, NULL, "", pBuf, nSize );
239 	while ( nRead >= nSize-2 )
240 	{
241 		nSize += 2048;
242 		delete []pBuf;
243 		pBuf = new char[nSize];
244 		nRead = GetProfileStringA( aImplDevices, NULL, "", pBuf, nSize );
245 	}
246 
247 	// extract printer names from buffer and fill list
248 	char* pName = pBuf;
249 	while ( *pName )
250 	{
251 		char*	pPortName;
252 		char*	pTmp;
253 		char	aPortBuf[256];
254 		GetProfileStringA( aImplDevices, pName, "", aPortBuf, sizeof( aPortBuf ) );
255 
256 		pPortName = aPortBuf;
257 
258 		// create name
259 		xub_StrLen nNameLen = sal::static_int_cast<xub_StrLen>(strlen( pName ));
260 		XubString aName( ImplSalGetUniString( pName, nNameLen ) );
261 
262 		// get driver name
263 		pTmp = pPortName;
264 		while ( *pTmp != ',' )
265 			pTmp++;
266 		XubString aDriver( ImplSalGetUniString( pPortName, (sal_uInt16)(pTmp-pPortName) ) );
267 		pPortName = pTmp;
268 
269 		// get port names
270 		do
271 		{
272 			pPortName++;
273 			pTmp = pPortName;
274 			while ( *pTmp && (*pTmp != ',') )
275 				pTmp++;
276 
277 			String aPortName( ImplSalGetUniString( pPortName, (sal_uInt16)(pTmp-pPortName) ) );
278 
279 			// create new entry
280             // look up if printer was already found in first loop
281 			sal_Bool bAdd = TRUE;
282 			if ( pWinInfo2 )
283 			{
284 				pGetInfo2 = pWinInfo2;
285 				for ( n = 0; n < nInfoPrn2; n++ )
286 				{
287 					if ( aName.EqualsIgnoreCaseAscii( pGetInfo2->pPrinterName ) )
288 					{
289 						bAdd = FALSE;
290 						break;
291 					}
292 					pGetInfo2++;
293 				}
294 			}
295 			// if it's a new printer, add it
296 			if ( bAdd )
297 			{
298 				SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
299 				pInfo->maPrinterName = aName;
300 				pInfo->maDriver 	 = aDriver;
301 				pInfo->maLocation	 = aPortName;
302 				pInfo->mnStatus 	 = 0;
303 				pInfo->mnJobs		 = QUEUE_JOBS_DONTKNOW;
304 				pInfo->mpSysData	 = new XubString( aPortName );
305 				pList->Add( pInfo );
306 			}
307 		}
308 		while ( *pTmp == ',' );
309 
310 		pName += nNameLen + 1;
311 	}
312 
313 	delete []pBuf;
314 	rtl_freeMemory( pWinInfo2 );
315 }
316 
317 void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
318 {
319     if( ! aSalShlData.mbWPrinter )
320     {
321         getPrinterQueueInfoOldStyle( pList );
322         return;
323     }
324 	DWORD			i;
325 	DWORD			nBytes = 0;
326 	DWORD			nInfoPrn4 = 0;
327 	PRINTER_INFO_4W* pWinInfo4 = NULL;
328 	EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, NULL, 0, &nBytes, &nInfoPrn4 );
329 	if ( nBytes )
330 	{
331 		pWinInfo4 = (PRINTER_INFO_4W*) rtl_allocateMemory( nBytes );
332 		if ( EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, (LPBYTE)pWinInfo4, nBytes, &nBytes, &nInfoPrn4 ) )
333 		{
334 			for ( i = 0; i < nInfoPrn4; i++ )
335 			{
336 				SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
337 				pInfo->maPrinterName = UniString( reinterpret_cast< const sal_Unicode* >(pWinInfo4[i].pPrinterName) );
338 				pInfo->mnStatus 	 = 0;
339 				pInfo->mnJobs		 = 0;
340 				pInfo->mpSysData	 = NULL;
341 				pList->Add( pInfo );
342 			}
343 		}
344         rtl_freeMemory( pWinInfo4 );
345 	}
346 }
347 
348 // -----------------------------------------------------------------------
349 
350 static void getPrinterQueueStateOldStyle( SalPrinterQueueInfo* pInfo )
351 {
352 	DWORD				nBytes = 0;
353 	DWORD				nInfoRet;
354 	PRINTER_INFO_2* 	pWinInfo2;
355 	EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &nBytes, &nInfoRet );
356 	if ( nBytes )
357 	{
358 		pWinInfo2 = (PRINTER_INFO_2*) rtl_allocateMemory( nBytes );
359 		if ( EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes, &nInfoRet ) )
360 		{
361 			PRINTER_INFO_2* pGetInfo2 = pWinInfo2;
362 			for ( DWORD i = 0; i < nInfoRet; i++ )
363 			{
364 				if ( pInfo->maPrinterName.EqualsAscii( pGetInfo2->pPrinterName ) &&
365 					 ( pInfo->maDriver.Len() == 0 ||
366                        pInfo->maDriver.EqualsAscii( pGetInfo2->pDriverName ) )
367                        )
368 				{
369                     XubString aPortName;
370                     if ( pGetInfo2->pPortName )
371                         aPortName = ImplSalGetUniString( pGetInfo2->pPortName );
372                     // pLocation can be 0 (the Windows docu doesn't describe this)
373                     if ( pGetInfo2->pLocation && strlen( pGetInfo2->pLocation ) )
374                         pInfo->maLocation = ImplSalGetUniString( pGetInfo2->pLocation );
375                     else
376                         pInfo->maLocation = aPortName;
377                     // pComment can be 0 (the Windows docu doesn't describe this)
378                     if ( pGetInfo2->pComment )
379                         pInfo->maComment = ImplSalGetUniString( pGetInfo2->pComment );
380                     pInfo->mnStatus 	 = ImplWinQueueStatusToSal( pGetInfo2->Status );
381                     pInfo->mnJobs		 = pGetInfo2->cJobs;
382                     if( ! pInfo->mpSysData )
383                         pInfo->mpSysData	 = new XubString( aPortName );
384 					break;
385 				}
386 
387 				pGetInfo2++;
388 			}
389 		}
390 
391 		rtl_freeMemory( pWinInfo2 );
392 	}
393 }
394 
395 void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
396 {
397     if( ! aSalShlData.mbWPrinter )
398     {
399         getPrinterQueueStateOldStyle( pInfo );
400         return;
401     }
402 
403     HANDLE hPrinter = 0;
404     LPWSTR pPrnName = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pInfo->maPrinterName.GetBuffer()));
405     if( OpenPrinterW( pPrnName, &hPrinter, NULL ) )
406     {
407         DWORD				nBytes = 0;
408         GetPrinterW( hPrinter, 2, NULL, 0, &nBytes );
409         if( nBytes )
410         {
411             PRINTER_INFO_2W* pWinInfo2 = (PRINTER_INFO_2W*)rtl_allocateMemory(nBytes);
412             if( GetPrinterW( hPrinter, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes ) )
413             {
414                 if( pWinInfo2->pDriverName )
415                     pInfo->maDriver = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pDriverName) );
416                 XubString aPortName;
417                 if ( pWinInfo2->pPortName )
418                     aPortName = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pPortName) );
419                 // pLocation can be 0 (the Windows docu doesn't describe this)
420                 if ( pWinInfo2->pLocation && *pWinInfo2->pLocation )
421                     pInfo->maLocation = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pLocation) );
422                 else
423                     pInfo->maLocation = aPortName;
424                 // pComment can be 0 (the Windows docu doesn't describe this)
425                 if ( pWinInfo2->pComment )
426                     pInfo->maComment = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pComment) );
427                 pInfo->mnStatus 	 = ImplWinQueueStatusToSal( pWinInfo2->Status );
428                 pInfo->mnJobs		 = pWinInfo2->cJobs;
429                 if( ! pInfo->mpSysData )
430                     pInfo->mpSysData	 = new XubString( aPortName );
431             }
432             rtl_freeMemory(pWinInfo2);
433         }
434         ClosePrinter( hPrinter );
435     }
436 }
437 
438 // -----------------------------------------------------------------------
439 
440 void WinSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
441 {
442 	delete (String*)(pInfo->mpSysData);
443 	delete pInfo;
444 }
445 
446 // -----------------------------------------------------------------------
447 XubString WinSalInstance::GetDefaultPrinter()
448 {
449     static bool bGetDefPrtAPI = true;
450     static sal_Bool(WINAPI*pGetDefaultPrinter)(LPWSTR,LPDWORD) = NULL;
451     // try to use GetDefaultPrinter API (not available prior to W2000)
452     if( bGetDefPrtAPI )
453     {
454         bGetDefPrtAPI = false;
455         // check for W2k and XP
456         if( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && aSalShlData.maVersionInfo.dwMajorVersion >= 5 )
457         {
458             OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "winspool.drv" ) );
459             oslModule pLib = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
460             oslGenericFunction pFunc = NULL;
461             if( pLib )
462             {
463                 OUString queryFuncName( RTL_CONSTASCII_USTRINGPARAM( "GetDefaultPrinterW" ) );
464                 pFunc = osl_getFunctionSymbol( pLib, queryFuncName.pData );
465             }
466 
467             pGetDefaultPrinter = (sal_Bool(WINAPI*)(LPWSTR,LPDWORD)) pFunc;
468         }
469     }
470     if( pGetDefaultPrinter )
471     {
472         DWORD   nChars = 0;
473         pGetDefaultPrinter( NULL, &nChars );
474         if( nChars )
475         {
476             LPWSTR  pStr = (LPWSTR)rtl_allocateMemory(nChars*sizeof(WCHAR));
477             XubString aDefPrt;
478             if( pGetDefaultPrinter( pStr, &nChars ) )
479             {
480                 aDefPrt = reinterpret_cast<sal_Unicode* >(pStr);
481             }
482             rtl_freeMemory( pStr );
483             if( aDefPrt.Len() )
484                 return aDefPrt;
485         }
486     }
487 
488 	// get default printer from win.ini
489 	char szBuffer[256];
490 	GetProfileStringA( aImplWindows, aImplDevice, "", szBuffer, sizeof( szBuffer ) );
491 	if ( szBuffer[0] )
492 	{
493 		// Printername suchen
494 		char* pBuf = szBuffer;
495 		char* pTmp = pBuf;
496 		while ( *pTmp && (*pTmp != ',') )
497 			pTmp++;
498 		return ImplSalGetUniString( pBuf, (xub_StrLen)(pTmp-pBuf) );
499 	}
500 	else
501 		return XubString();
502 }
503 
504 // =======================================================================
505 
506 static DWORD ImplDeviceCaps( WinSalInfoPrinter* pPrinter, WORD nCaps,
507 							 BYTE* pOutput, const ImplJobSetup* pSetupData )
508 {
509     if( aSalShlData.mbWPrinter )
510     {
511         DEVMODEW* pDevMode;
512         if ( !pSetupData || !pSetupData->mpDriverData )
513             pDevMode = NULL;
514         else
515             pDevMode = SAL_DEVMODE_W( pSetupData );
516 
517         return DeviceCapabilitiesW( reinterpret_cast<LPCWSTR>(pPrinter->maDeviceName.GetBuffer()),
518                                     reinterpret_cast<LPCWSTR>(pPrinter->maPortName.GetBuffer()),
519                                     nCaps, (LPWSTR)pOutput, pDevMode );
520     }
521     else
522     {
523         DEVMODEA* pDevMode;
524         if ( !pSetupData || !pSetupData->mpDriverData )
525             pDevMode = NULL;
526         else
527             pDevMode = SAL_DEVMODE_A( pSetupData );
528 
529         return DeviceCapabilitiesA( ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
530                                 ImplSalGetWinAnsiString( pPrinter->maPortName, TRUE ).GetBuffer(),
531                                 nCaps, (LPSTR)pOutput, pDevMode );
532     }
533 }
534 
535 // -----------------------------------------------------------------------
536 
537 static sal_Bool ImplTestSalJobSetup( WinSalInfoPrinter* pPrinter,
538 								 ImplJobSetup* pSetupData, sal_Bool bDelete )
539 {
540 	if ( pSetupData && pSetupData->mpDriverData )
541 	{
542         // signature and size must fit to avoid using
543         // JobSetups from a wrong system
544 
545         // initialize versions from jobsetup
546         // those will be overwritten with driver's version
547         DEVMODEA* pDevModeA = NULL;
548         DEVMODEW* pDevModeW = NULL;
549         LONG dmSpecVersion = -1;
550         LONG dmDriverVersion = -1;
551         SalDriverData* pSalDriverData = (SalDriverData*)pSetupData->mpDriverData;
552         BYTE* pDriverData = ((BYTE*)pSalDriverData) + pSalDriverData->mnDriverOffset;
553         if( pSalDriverData->mnVersion == SAL_DRIVERDATA_VERSION_W )
554         {
555             if( aSalShlData.mbWPrinter )
556                 pDevModeW = (DEVMODEW*)pDriverData;
557         }
558         else if( pSalDriverData->mnVersion == SAL_DRIVERDATA_VERSION_A )
559         {
560             if( ! aSalShlData.mbWPrinter )
561                 pDevModeA = (DEVMODEA*)pDriverData;
562         }
563 
564         long nSysJobSize = -1;
565         if( pPrinter && ( pDevModeA || pDevModeW ) )
566         {
567             // just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
568             // this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
569             // can avoid potential driver crashes as their jobsetups are often not compatible
570             // #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
571             ByteString aPrinterNameA= ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE );
572             HANDLE hPrn;
573             LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.GetBuffer()));
574             if ( ! aSalShlData.mbWPrinter )
575             {
576                 if ( !OpenPrinterA( (LPSTR)aPrinterNameA.GetBuffer(), &hPrn, NULL ) )
577                     return FALSE;
578             }
579             else
580                 if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
581                     return FALSE;
582 
583             // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
584             if( hPrn == HGDI_ERROR )
585                 return FALSE;
586 
587             if( aSalShlData.mbWPrinter )
588             {
589                 nSysJobSize = DocumentPropertiesW( 0, hPrn,
590                                                    pPrinterNameW,
591                                                    NULL, NULL, 0 );
592             }
593             else
594             {
595                 nSysJobSize = DocumentPropertiesA( 0, hPrn,
596                                                    (LPSTR)aPrinterNameA.GetBuffer(),
597                                                    NULL, NULL, 0 );
598             }
599 
600             if( nSysJobSize < 0 )
601             {
602                 ClosePrinter( hPrn );
603                 return FALSE;
604             }
605             BYTE *pBuffer = (BYTE*)_alloca( nSysJobSize );
606             LONG nRet = -1;
607             if( aSalShlData.mbWPrinter )
608             {
609                 nRet = DocumentPropertiesW( 0, hPrn,
610                                             pPrinterNameW,
611                                             (LPDEVMODEW)pBuffer, NULL, DM_OUT_BUFFER );
612             }
613             else
614             {
615                 nRet = DocumentPropertiesA( 0, hPrn,
616                                             (LPSTR)aPrinterNameA.GetBuffer(),
617                                             (LPDEVMODEA)pBuffer, NULL, DM_OUT_BUFFER );
618             }
619             if( nRet < 0 )
620             {
621                 ClosePrinter( hPrn );
622                 return FALSE;
623             }
624 
625             // the spec version differs between the windows platforms, ie 98,NT,2000/XP
626             // this allows us to throw away printer settings from other platforms that might crash a buggy driver
627             // we check the driver version as well
628             dmSpecVersion = aSalShlData.mbWPrinter ? ((DEVMODEW*)pBuffer)->dmSpecVersion : ((DEVMODEA*)pBuffer)->dmSpecVersion;
629             dmDriverVersion = aSalShlData.mbWPrinter ? ((DEVMODEW*)pBuffer)->dmDriverVersion : ((DEVMODEA*)pBuffer)->dmDriverVersion;
630 
631             ClosePrinter( hPrn );
632         }
633         SalDriverData* pSetupDriverData = (SalDriverData*)(pSetupData->mpDriverData);
634 		if ( (pSetupData->mnSystem == JOBSETUP_SYSTEM_WINDOWS) &&
635              (pPrinter->maDriverName == pSetupData->maDriver) &&
636 			 (pSetupData->mnDriverDataLen > sizeof( SalDriverData )) &&
637              (long)(pSetupData->mnDriverDataLen - pSetupDriverData->mnDriverOffset) == nSysJobSize &&
638 			 pSetupDriverData->mnSysSignature == SAL_DRIVERDATA_SYSSIGN )
639         {
640             if( pDevModeA &&
641                 (dmSpecVersion == pDevModeA->dmSpecVersion) &&
642                 (dmDriverVersion == pDevModeA->dmDriverVersion) )
643                 return TRUE;
644             if( pDevModeW &&
645                 (dmSpecVersion == pDevModeW->dmSpecVersion) &&
646                 (dmDriverVersion == pDevModeW->dmDriverVersion) )
647                 return TRUE;
648         }
649 		if ( bDelete )
650 		{
651 			rtl_freeMemory( pSetupData->mpDriverData );
652 			pSetupData->mpDriverData = NULL;
653 			pSetupData->mnDriverDataLen = 0;
654 		}
655 	}
656 
657 	return FALSE;
658 }
659 
660 // -----------------------------------------------------------------------
661 
662 static sal_Bool ImplUpdateSalJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData,
663 								   sal_Bool bIn, WinSalFrame* pVisibleDlgParent )
664 {
665     ByteString aPrinterNameA = ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE );
666     HANDLE hPrn;
667     LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.GetBuffer()));
668     if( aSalShlData.mbWPrinter )
669     {
670         if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
671             return FALSE;
672     }
673     else
674     {
675         if ( !OpenPrinterA( (LPSTR)aPrinterNameA.GetBuffer(), &hPrn, NULL ) )
676             return FALSE;
677     }
678     // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
679     if( hPrn == HGDI_ERROR )
680         return FALSE;
681 
682 	LONG			nRet;
683 	LONG			nSysJobSize = -1;
684 	HWND			hWnd = 0;
685 	DWORD			nMode = DM_OUT_BUFFER;
686 	sal_uLong			nDriverDataLen = 0;
687 	SalDriverData*	pOutBuffer = NULL;
688     BYTE*           pInBuffer = NULL;
689 
690     if( aSalShlData.mbWPrinter )
691     {
692         nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
693                                            pPrinterNameW,
694                                            NULL, NULL, 0 );
695     }
696     else
697         nSysJobSize = DocumentPropertiesA( hWnd, hPrn,
698                                            (LPSTR)ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
699                                            NULL, NULL, 0 );
700 	if ( nSysJobSize < 0 )
701 	{
702 		ClosePrinter( hPrn );
703 		return FALSE;
704 	}
705 
706 	// Outputbuffer anlegen
707 	nDriverDataLen				= sizeof(SalDriverData) + nSysJobSize-1;
708 	pOutBuffer					= (SalDriverData*)rtl_allocateZeroMemory( nDriverDataLen );
709 	pOutBuffer->mnSysSignature	= SAL_DRIVERDATA_SYSSIGN;
710 	pOutBuffer->mnVersion		= aSalShlData.mbWPrinter ? SAL_DRIVERDATA_VERSION_W : SAL_DRIVERDATA_VERSION_A;
711     // calculate driver data offset including structure padding
712 	pOutBuffer->mnDriverOffset	= sal::static_int_cast<sal_uInt16>(
713                                     (char*)pOutBuffer->maDriverData -
714                                     (char*)pOutBuffer );
715 
716 	// Testen, ob wir einen geeigneten Inputbuffer haben
717 	if ( bIn && ImplTestSalJobSetup( pPrinter, pSetupData, FALSE ) )
718 	{
719 		pInBuffer = (BYTE*)pSetupData->mpDriverData + ((SalDriverData*)pSetupData->mpDriverData)->mnDriverOffset;
720 		nMode |= DM_IN_BUFFER;
721 	}
722 
723 	// Testen, ob Dialog angezeigt werden soll
724 	if ( pVisibleDlgParent )
725 	{
726 		hWnd = pVisibleDlgParent->mhWnd;
727 		nMode |= DM_IN_PROMPT;
728 	}
729 
730 	// Release mutex, in the other case we don't get paints and so on
731     sal_uLong nMutexCount=0;
732     if ( pVisibleDlgParent )
733         nMutexCount = ImplSalReleaseYieldMutex();
734 
735     BYTE* pOutDevMode = (((BYTE*)pOutBuffer) + pOutBuffer->mnDriverOffset);
736     if( aSalShlData.mbWPrinter )
737     {
738         nRet = DocumentPropertiesW( hWnd, hPrn,
739                                     pPrinterNameW,
740                                     (LPDEVMODEW)pOutDevMode, (LPDEVMODEW)pInBuffer, nMode );
741     }
742     else
743     {
744         nRet = DocumentPropertiesA( hWnd, hPrn,
745                                     (LPSTR)ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
746                                     (LPDEVMODEA)pOutDevMode, (LPDEVMODEA)pInBuffer, nMode );
747     }
748     if ( pVisibleDlgParent )
749         ImplSalAcquireYieldMutex( nMutexCount );
750 	ClosePrinter( hPrn );
751 
752 	if( (nRet < 0) || (pVisibleDlgParent && (nRet == IDCANCEL)) )
753 	{
754 		rtl_freeMemory( pOutBuffer );
755 		return FALSE;
756 	}
757 
758     // fill up string buffers with 0 so they do not influence a JobSetup's memcmp
759     if( aSalShlData.mbWPrinter )
760     {
761         if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 64 )
762         {
763             sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmDeviceName );
764             if ( nLen < sizeof( ((LPDEVMODEW)pOutDevMode)->dmDeviceName )/sizeof(sal_Unicode) )
765                 memset( ((LPDEVMODEW)pOutDevMode)->dmDeviceName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmDeviceName )-(nLen*sizeof(sal_Unicode)) );
766         }
767         if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 166 )
768         {
769             sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmFormName );
770             if ( nLen < sizeof( ((LPDEVMODEW)pOutDevMode)->dmFormName )/sizeof(sal_Unicode) )
771                 memset( ((LPDEVMODEW)pOutDevMode)->dmFormName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmFormName )-(nLen*sizeof(sal_Unicode)) );
772         }
773     }
774     else
775     {
776         if( ((LPDEVMODEA)pOutDevMode)->dmSize >= 32 )
777         {
778             sal_Int32 nLen = strlen( (const char*)((LPDEVMODEA)pOutDevMode)->dmDeviceName );
779             if ( nLen < sizeof( ((LPDEVMODEA)pOutDevMode)->dmDeviceName ) )
780                 memset( ((LPDEVMODEA)pOutDevMode)->dmDeviceName+nLen, 0, sizeof( ((LPDEVMODEA)pOutDevMode)->dmDeviceName )-nLen );
781         }
782         if( ((LPDEVMODEA)pOutDevMode)->dmSize >= 102 )
783         {
784             sal_Int32 nLen = strlen( (const char*)((LPDEVMODEA)pOutDevMode)->dmFormName );
785             if ( nLen < sizeof( ((LPDEVMODEA)pOutDevMode)->dmFormName ) )
786                 memset( ((LPDEVMODEA)pOutDevMode)->dmFormName+nLen, 0, sizeof( ((LPDEVMODEA)pOutDevMode)->dmFormName )-nLen );
787         }
788     }
789 
790 	// update data
791 	if ( pSetupData->mpDriverData )
792 		rtl_freeMemory( pSetupData->mpDriverData );
793 	pSetupData->mnDriverDataLen = nDriverDataLen;
794 	pSetupData->mpDriverData	= (BYTE*)pOutBuffer;
795 	pSetupData->mnSystem		= JOBSETUP_SYSTEM_WINDOWS;
796 
797 	return TRUE;
798 }
799 
800 // -----------------------------------------------------------------------
801 
802 #define DECLARE_DEVMODE( i )\
803     DEVMODEA* pDevModeA = SAL_DEVMODE_A(i);\
804     DEVMODEW* pDevModeW = SAL_DEVMODE_W(i);\
805     if( pDevModeA == NULL && pDevModeW == NULL )\
806         return
807 
808 #define CHOOSE_DEVMODE(i)\
809     (pDevModeW ? pDevModeW->i : pDevModeA->i)
810 
811 static void ImplDevModeToJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, sal_uLong nFlags )
812 {
813 	if ( !pSetupData || !pSetupData->mpDriverData )
814 		return;
815 
816     DECLARE_DEVMODE( pSetupData );
817 
818 	// Orientation
819 	if ( nFlags & SAL_JOBSET_ORIENTATION )
820 	{
821 		if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_PORTRAIT )
822 			pSetupData->meOrientation = ORIENTATION_PORTRAIT;
823 		else if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_LANDSCAPE )
824 			pSetupData->meOrientation = ORIENTATION_LANDSCAPE;
825 	}
826 
827 	// PaperBin
828 	if ( nFlags & SAL_JOBSET_PAPERBIN )
829 	{
830 		sal_uLong nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
831 
832 		if ( nCount && (nCount != GDI_ERROR) )
833 		{
834 			WORD* pBins = (WORD*)rtl_allocateZeroMemory( nCount*sizeof(WORD) );
835 			ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
836 			pSetupData->mnPaperBin = 0;
837 
838 			// search the right bin and assign index to mnPaperBin
839 			for( sal_uLong i = 0; i < nCount; i++ )
840 			{
841 				if( CHOOSE_DEVMODE(dmDefaultSource) == pBins[ i ] )
842 				{
843 					pSetupData->mnPaperBin = (sal_uInt16)i;
844 					break;
845 				}
846 			}
847 
848 			rtl_freeMemory( pBins );
849 		}
850 	}
851 
852 	// PaperSize
853 	if ( nFlags & SAL_JOBSET_PAPERSIZE )
854 	{
855 		if( (CHOOSE_DEVMODE(dmFields) & (DM_PAPERWIDTH|DM_PAPERLENGTH)) == (DM_PAPERWIDTH|DM_PAPERLENGTH) )
856 		{
857 		    pSetupData->mnPaperWidth  = CHOOSE_DEVMODE(dmPaperWidth)*10;
858 		    pSetupData->mnPaperHeight = CHOOSE_DEVMODE(dmPaperLength)*10;
859 		}
860 		else
861 		{
862 			sal_uLong	nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
863 			WORD*	pPapers = NULL;
864 			sal_uLong	nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
865 			POINT*	pPaperSizes = NULL;
866 			if ( nPaperCount && (nPaperCount != GDI_ERROR) )
867 			{
868 				pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
869 				ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
870 			}
871 			if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
872 			{
873 				pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
874 				ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
875 			}
876 			if( nPaperSizeCount == nPaperCount && pPaperSizes && pPapers )
877 			{
878 				for( sal_uLong i = 0; i < nPaperCount; i++ )
879 				{
880 					if( pPapers[ i ] == CHOOSE_DEVMODE(dmPaperSize) )
881 					{
882 						pSetupData->mnPaperWidth  = pPaperSizes[ i ].x*10;
883 						pSetupData->mnPaperHeight = pPaperSizes[ i ].y*10;
884 						break;
885 					}
886 				}
887 			}
888 			if( pPapers )
889 				rtl_freeMemory( pPapers );
890 			if( pPaperSizes )
891 				rtl_freeMemory( pPaperSizes );
892 		}
893 		switch( CHOOSE_DEVMODE(dmPaperSize) )
894 		{
895 			case( DMPAPER_LETTER ):
896 				pSetupData->mePaperFormat = PAPER_LETTER;
897 				break;
898 			case( DMPAPER_TABLOID ):
899 				pSetupData->mePaperFormat = PAPER_TABLOID;
900 				break;
901 			case( DMPAPER_LEDGER ):
902 				pSetupData->mePaperFormat = PAPER_LEDGER;
903 				break;
904 			case( DMPAPER_LEGAL ):
905 				pSetupData->mePaperFormat = PAPER_LEGAL;
906 				break;
907 			case( DMPAPER_STATEMENT ):
908 				pSetupData->mePaperFormat = PAPER_STATEMENT;
909 				break;
910 			case( DMPAPER_EXECUTIVE ):
911 				pSetupData->mePaperFormat = PAPER_EXECUTIVE;
912 				break;
913 			case( DMPAPER_A3 ):
914 				pSetupData->mePaperFormat = PAPER_A3;
915 				break;
916 			case( DMPAPER_A4 ):
917 				pSetupData->mePaperFormat = PAPER_A4;
918 				break;
919 			case( DMPAPER_A5 ):
920 				pSetupData->mePaperFormat = PAPER_A5;
921 				break;
922 			//See http://wiki.services.openoffice.org/wiki/DefaultPaperSize
923 			//i.e.
924 			//http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
925 			//DMPAPER_B4	12	B4 (JIS) 257 x 364 mm
926 			//http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
927 			//also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
928 			//matches our Excel filter's belief about the matching XlPaperSize
929 			//enumeration.
930 			//
931 			//http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
932 			////"DMPAPER_B4 	12 	B4 (JIS) 250 x 354"
933 			//which is bogus as it's either JIS 257 × 364 or ISO 250 × 353
934 			//(cmc)
935 			case( DMPAPER_B4 ):
936 				pSetupData->mePaperFormat = PAPER_B4_JIS;
937 				break;
938 			case( DMPAPER_B5 ):
939 				pSetupData->mePaperFormat = PAPER_B5_JIS;
940 				break;
941 			case( DMPAPER_QUARTO ):
942 				pSetupData->mePaperFormat = PAPER_QUARTO;
943 				break;
944 			case( DMPAPER_10X14 ):
945 				pSetupData->mePaperFormat = PAPER_10x14;
946 				break;
947 			case( DMPAPER_NOTE ):
948 				pSetupData->mePaperFormat = PAPER_LETTER;
949 				break;
950 			case( DMPAPER_ENV_9 ):
951 				pSetupData->mePaperFormat = PAPER_ENV_9;
952 				break;
953 			case( DMPAPER_ENV_10 ):
954 				pSetupData->mePaperFormat = PAPER_ENV_10;
955 				break;
956 			case( DMPAPER_ENV_11 ):
957 				pSetupData->mePaperFormat = PAPER_ENV_11;
958 				break;
959 			case( DMPAPER_ENV_12 ):
960 				pSetupData->mePaperFormat = PAPER_ENV_12;
961 				break;
962 			case( DMPAPER_ENV_14 ):
963 				pSetupData->mePaperFormat = PAPER_ENV_14;
964 				break;
965 			case( DMPAPER_CSHEET ):
966 				pSetupData->mePaperFormat = PAPER_C;
967 				break;
968 			case( DMPAPER_DSHEET ):
969 				pSetupData->mePaperFormat = PAPER_D;
970 				break;
971 			case( DMPAPER_ESHEET ):
972 				pSetupData->mePaperFormat = PAPER_E;
973 				break;
974 			case( DMPAPER_ENV_DL):
975 				pSetupData->mePaperFormat = PAPER_ENV_DL;
976 				break;
977 			case( DMPAPER_ENV_C5):
978 				pSetupData->mePaperFormat = PAPER_ENV_C5;
979 				break;
980 			case( DMPAPER_ENV_C3):
981 				pSetupData->mePaperFormat = PAPER_ENV_C3;
982 				break;
983 			case( DMPAPER_ENV_C4):
984 				pSetupData->mePaperFormat = PAPER_ENV_C4;
985 				break;
986 			case( DMPAPER_ENV_C6):
987 				pSetupData->mePaperFormat = PAPER_ENV_C6;
988 				break;
989 			case( DMPAPER_ENV_C65):
990 				pSetupData->mePaperFormat = PAPER_ENV_C65;
991 				break;
992 			case( DMPAPER_ENV_ITALY ):
993 				pSetupData->mePaperFormat = PAPER_ENV_ITALY;
994 				break;
995 			case( DMPAPER_ENV_MONARCH ):
996 				pSetupData->mePaperFormat = PAPER_ENV_MONARCH;
997 				break;
998 			case( DMPAPER_ENV_PERSONAL ):
999 				pSetupData->mePaperFormat = PAPER_ENV_PERSONAL;
1000 				break;
1001 			case( DMPAPER_FANFOLD_US ):
1002 				pSetupData->mePaperFormat = PAPER_FANFOLD_US;
1003 				break;
1004 			case( DMPAPER_FANFOLD_STD_GERMAN ):
1005 				pSetupData->mePaperFormat = PAPER_FANFOLD_DE;
1006 				break;
1007 			case( DMPAPER_FANFOLD_LGL_GERMAN ):
1008 				pSetupData->mePaperFormat = PAPER_FANFOLD_LEGAL_DE;
1009 				break;
1010 			case( DMPAPER_ISO_B4 ):
1011 				pSetupData->mePaperFormat = PAPER_B4_ISO;
1012 				break;
1013 			case( DMPAPER_JAPANESE_POSTCARD ):
1014 				pSetupData->mePaperFormat = PAPER_POSTCARD_JP;
1015 				break;
1016 			case( DMPAPER_9X11 ):
1017 				pSetupData->mePaperFormat = PAPER_9x11;
1018 				break;
1019 			case( DMPAPER_10X11 ):
1020 				pSetupData->mePaperFormat = PAPER_10x11;
1021 				break;
1022 			case( DMPAPER_15X11 ):
1023 				pSetupData->mePaperFormat = PAPER_15x11;
1024 				break;
1025 			case( DMPAPER_ENV_INVITE ):
1026 				pSetupData->mePaperFormat = PAPER_ENV_INVITE;
1027 				break;
1028 			case( DMPAPER_A_PLUS ):
1029 				pSetupData->mePaperFormat = PAPER_A_PLUS;
1030 				break;
1031 			case( DMPAPER_B_PLUS ):
1032 				pSetupData->mePaperFormat = PAPER_B_PLUS;
1033 				break;
1034 			case( DMPAPER_LETTER_PLUS ):
1035 				pSetupData->mePaperFormat = PAPER_LETTER_PLUS;
1036 				break;
1037 			case( DMPAPER_A4_PLUS ):
1038 				pSetupData->mePaperFormat = PAPER_A4_PLUS;
1039 				break;
1040 			case( DMPAPER_A2 ):
1041 				pSetupData->mePaperFormat = PAPER_A2;
1042 				break;
1043 			case( DMPAPER_DBL_JAPANESE_POSTCARD ):
1044 				pSetupData->mePaperFormat = PAPER_DOUBLEPOSTCARD_JP;
1045 				break;
1046 			case( DMPAPER_A6 ):
1047 				pSetupData->mePaperFormat = PAPER_A6;
1048 				break;
1049 			case( DMPAPER_B6_JIS ):
1050 				pSetupData->mePaperFormat = PAPER_B6_JIS;
1051 				break;
1052 			case( DMPAPER_12X11 ):
1053 				pSetupData->mePaperFormat = PAPER_12x11;
1054 				break;
1055 			default:
1056 				pSetupData->mePaperFormat = PAPER_USER;
1057 				break;
1058 		}
1059 	}
1060 
1061     if( nFlags & SAL_JOBSET_DUPLEXMODE )
1062     {
1063         DuplexMode eDuplex = DUPLEX_UNKNOWN;
1064         if( (CHOOSE_DEVMODE(dmFields) & DM_DUPLEX) )
1065         {
1066             if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_SIMPLEX )
1067                 eDuplex = DUPLEX_OFF;
1068             else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_VERTICAL )
1069                 eDuplex = DUPLEX_LONGEDGE;
1070             else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_HORIZONTAL )
1071                 eDuplex = DUPLEX_SHORTEDGE;
1072         }
1073         pSetupData->meDuplexMode = eDuplex;
1074     }
1075 }
1076 
1077 // -----------------------------------------------------------------------
1078 
1079 static void ImplJobSetupToDevMode( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, sal_uLong nFlags )
1080 {
1081 	if ( !pSetupData || !pSetupData->mpDriverData )
1082 		return;
1083 
1084     DECLARE_DEVMODE( pSetupData );
1085 
1086 	// Orientation
1087 	if ( nFlags & SAL_JOBSET_ORIENTATION )
1088 	{
1089 		CHOOSE_DEVMODE(dmFields) |= DM_ORIENTATION;
1090 		if ( pSetupData->meOrientation == ORIENTATION_PORTRAIT )
1091 			CHOOSE_DEVMODE(dmOrientation) = DMORIENT_PORTRAIT;
1092 		else
1093 			CHOOSE_DEVMODE(dmOrientation) = DMORIENT_LANDSCAPE;
1094 	}
1095 
1096 	// PaperBin
1097 	if ( nFlags & SAL_JOBSET_PAPERBIN )
1098 	{
1099 		sal_uLong nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
1100 
1101 		if ( nCount && (nCount != GDI_ERROR) )
1102 		{
1103 			WORD* pBins = (WORD*)rtl_allocateZeroMemory(nCount*sizeof(WORD));
1104 			ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
1105 			CHOOSE_DEVMODE(dmFields) |= DM_DEFAULTSOURCE;
1106 			CHOOSE_DEVMODE(dmDefaultSource) = pBins[ pSetupData->mnPaperBin ];
1107 			rtl_freeMemory( pBins );
1108 		}
1109 	}
1110 
1111 	// PaperSize
1112 	if ( nFlags & SAL_JOBSET_PAPERSIZE )
1113 	{
1114 		CHOOSE_DEVMODE(dmFields)		|= DM_PAPERSIZE;
1115 		CHOOSE_DEVMODE(dmPaperWidth)	 = 0;
1116 		CHOOSE_DEVMODE(dmPaperLength)    = 0;
1117 
1118 		switch( pSetupData->mePaperFormat )
1119 		{
1120 			case( PAPER_A2 ):
1121 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A2;
1122 				break;
1123 			case( PAPER_A3 ):
1124 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A3;
1125 				break;
1126 			case( PAPER_A4 ):
1127 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4;
1128 				break;
1129 			case( PAPER_A5 ):
1130 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A5;
1131 				break;
1132 			case( PAPER_B4_ISO):
1133 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ISO_B4;
1134 				break;
1135 			case( PAPER_LETTER ):
1136 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER;
1137 				break;
1138 			case( PAPER_LEGAL ):
1139 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEGAL;
1140 				break;
1141 			case( PAPER_TABLOID ):
1142 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_TABLOID;
1143 				break;
1144 #if 0
1145 			//http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
1146 			//DMPAPER_ENV_B6 is documented as:
1147 			//"DMPAPER_ENV_B6 	35 	Envelope B6 176 x 125 mm"
1148 			//which is the wrong way around, it is surely 125 x 176, i.e.
1149 			//compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
1150 			//DMPAPER_ENV_B4 	33 	Envelope B4 250 x 353 mm
1151 			//DMPAPER_ENV_B5 	34 	Envelope B5 176 x 250 mm
1152 			case( PAPER_B6_ISO ):
1153 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_B6;
1154 				break;
1155 #endif
1156 			case( PAPER_ENV_C4 ):
1157 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C4;
1158 				break;
1159 			case( PAPER_ENV_C5 ):
1160 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C5;
1161 				break;
1162 			case( PAPER_ENV_C6 ):
1163 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C6;
1164 				break;
1165 			case( PAPER_ENV_C65 ):
1166 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C65;
1167 				break;
1168 			case( PAPER_ENV_DL ):
1169 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_DL;
1170 				break;
1171 			case( PAPER_C ):
1172 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_CSHEET;
1173 				break;
1174 			case( PAPER_D ):
1175 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DSHEET;
1176 				break;
1177 			case( PAPER_E ):
1178 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ESHEET;
1179 				break;
1180 			case( PAPER_EXECUTIVE ):
1181 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_EXECUTIVE;
1182 				break;
1183 			case( PAPER_FANFOLD_LEGAL_DE ):
1184 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_LGL_GERMAN;
1185 				break;
1186 			case( PAPER_ENV_MONARCH ):
1187 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_MONARCH;
1188 				break;
1189 			case( PAPER_ENV_PERSONAL ):
1190 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_PERSONAL;
1191 				break;
1192 			case( PAPER_ENV_9 ):
1193 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_9;
1194 				break;
1195 			case( PAPER_ENV_10 ):
1196 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_10;
1197 				break;
1198 			case( PAPER_ENV_11 ):
1199 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_11;
1200 				break;
1201 			case( PAPER_ENV_12 ):
1202 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_12;
1203 				break;
1204 			//See the comments on DMPAPER_B4 above
1205 			case( PAPER_B4_JIS ):
1206 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B4;
1207 				break;
1208 			case( PAPER_B5_JIS ):
1209 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B5;
1210 				break;
1211 			case( PAPER_B6_JIS ):
1212 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B6_JIS;
1213 				break;
1214 			case( PAPER_LEDGER ):
1215 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEDGER;
1216 				break;
1217 			case( PAPER_STATEMENT ):
1218 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_STATEMENT;
1219 				break;
1220 			case( PAPER_10x14 ):
1221 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X14;
1222 				break;
1223 			case( PAPER_ENV_14 ):
1224 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_14;
1225 				break;
1226 			case( PAPER_ENV_C3 ):
1227 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C3;
1228 				break;
1229 			case( PAPER_ENV_ITALY ):
1230 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_ITALY;
1231 				break;
1232 			case( PAPER_FANFOLD_US ):
1233 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_US;
1234 				break;
1235 			case( PAPER_FANFOLD_DE ):
1236 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_STD_GERMAN;
1237 				break;
1238 			case( PAPER_POSTCARD_JP ):
1239 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_JAPANESE_POSTCARD;
1240 				break;
1241 			case( PAPER_9x11 ):
1242 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_9X11;
1243 				break;
1244 			case( PAPER_10x11 ):
1245 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X11;
1246 				break;
1247 			case( PAPER_15x11 ):
1248 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_15X11;
1249 				break;
1250 			case( PAPER_ENV_INVITE ):
1251 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_INVITE;
1252 				break;
1253 			case( PAPER_A_PLUS ):
1254 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A_PLUS;
1255 				break;
1256 			case( PAPER_B_PLUS ):
1257 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B_PLUS;
1258 				break;
1259 			case( PAPER_LETTER_PLUS ):
1260 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER_PLUS;
1261 				break;
1262 			case( PAPER_A4_PLUS ):
1263 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4_PLUS;
1264 				break;
1265 			case( PAPER_DOUBLEPOSTCARD_JP ):
1266 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DBL_JAPANESE_POSTCARD;
1267 				break;
1268 			case( PAPER_A6 ):
1269 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A6;
1270 				break;
1271 			case( PAPER_12x11 ):
1272 				CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_12X11;
1273 				break;
1274 			default:
1275 			{
1276 				short	nPaper = 0;
1277 				sal_uLong	nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
1278 				WORD*	pPapers = NULL;
1279 				sal_uLong	nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
1280 				POINT*	pPaperSizes = NULL;
1281 				DWORD	nLandscapeAngle = ImplDeviceCaps( pPrinter, DC_ORIENTATION, NULL, pSetupData );
1282 				if ( nPaperCount && (nPaperCount != GDI_ERROR) )
1283 				{
1284 					pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
1285 					ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
1286 				}
1287 				if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
1288 				{
1289 					pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
1290 					ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
1291 				}
1292 				if ( (nPaperSizeCount == nPaperCount) && pPapers && pPaperSizes )
1293 				{
1294                     PaperInfo aInfo(pSetupData->mnPaperWidth, pSetupData->mnPaperHeight);
1295 					// compare paper formats and select a good match
1296 					for ( sal_uLong i = 0; i < nPaperCount; i++ )
1297 					{
1298 						if ( aInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)))
1299 						{
1300 							nPaper = pPapers[i];
1301 							break;
1302 						}
1303 					}
1304 
1305 					// If the printer supports landscape orientation, check paper sizes again
1306 					// with landscape orientation. This is necessary as a printer driver provides
1307 					// all paper sizes with portrait orientation only!!
1308 					if ( !nPaper && nLandscapeAngle != 0 )
1309 					{
1310                         PaperInfo aRotatedInfo(pSetupData->mnPaperHeight, pSetupData->mnPaperWidth);
1311 						for ( sal_uLong i = 0; i < nPaperCount; i++ )
1312 						{
1313 							if ( aRotatedInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)) )
1314 							{
1315 								nPaper = pPapers[i];
1316 								break;
1317 							}
1318 						}
1319 					}
1320 
1321 					if ( nPaper )
1322 						CHOOSE_DEVMODE(dmPaperSize) = nPaper;
1323 				}
1324 
1325 				if ( !nPaper )
1326 				{
1327 					CHOOSE_DEVMODE(dmFields)	   |= DM_PAPERLENGTH | DM_PAPERWIDTH;
1328 					CHOOSE_DEVMODE(dmPaperSize)    	= DMPAPER_USER;
1329 					CHOOSE_DEVMODE(dmPaperWidth)	= (short)(pSetupData->mnPaperWidth/10);
1330 					CHOOSE_DEVMODE(dmPaperLength)   = (short)(pSetupData->mnPaperHeight/10);
1331 				}
1332 
1333 				if ( pPapers )
1334 					rtl_freeMemory(pPapers);
1335 				if ( pPaperSizes )
1336 					rtl_freeMemory(pPaperSizes);
1337 
1338 				break;
1339 			}
1340 		}
1341 	}
1342     if( (nFlags & SAL_JOBSET_DUPLEXMODE) )
1343     {
1344         switch( pSetupData->meDuplexMode )
1345         {
1346         case DUPLEX_OFF:
1347             CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
1348             CHOOSE_DEVMODE(dmDuplex) = DMDUP_SIMPLEX;
1349             break;
1350         case DUPLEX_SHORTEDGE:
1351             CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
1352             CHOOSE_DEVMODE(dmDuplex) = DMDUP_HORIZONTAL;
1353             break;
1354         case DUPLEX_LONGEDGE:
1355             CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
1356             CHOOSE_DEVMODE(dmDuplex) = DMDUP_VERTICAL;
1357             break;
1358         case DUPLEX_UNKNOWN:
1359             break;
1360         }
1361     }
1362 }
1363 
1364 // -----------------------------------------------------------------------
1365 
1366 static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
1367 	                                LPCWSTR pDevice,
1368                                     LPDEVMODEW pDevMode )
1369 {
1370     HDC hDC = 0;
1371 	CATCH_DRIVER_EX_BEGIN;
1372     hDC = CreateICW( pDriver, pDevice, 0, pDevMode );
1373 	CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
1374     return hDC;
1375 }
1376 
1377 static HDC ImplCreateICA_WithCatch( char* pDriver,
1378 	                                char* pDevice,
1379                                     LPDEVMODEA pDevMode )
1380 {
1381     HDC hDC = 0;
1382 	CATCH_DRIVER_EX_BEGIN;
1383     hDC = CreateICA( pDriver, pDevice, 0, pDevMode );
1384 	CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
1385     return hDC;
1386 }
1387 
1388 
1389 static HDC ImplCreateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
1390 {
1391     HDC hDC = 0;
1392     if( aSalShlData.mbWPrinter )
1393     {
1394         LPDEVMODEW pDevMode;
1395         if ( pSetupData && pSetupData->mpDriverData )
1396             pDevMode = SAL_DEVMODE_W( pSetupData );
1397         else
1398             pDevMode = NULL;
1399         // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
1400         // pl: does this hold true for Unicode functions ?
1401         if( pPrinter->maDriverName.Len() > 2048 || pPrinter->maDeviceName.Len() > 2048 )
1402             return 0;
1403         sal_Unicode pDriverName[ 4096 ];
1404         sal_Unicode pDeviceName[ 4096 ];
1405         rtl_copyMemory( pDriverName, pPrinter->maDriverName.GetBuffer(), pPrinter->maDriverName.Len()*sizeof(sal_Unicode));
1406         memset( pDriverName+pPrinter->maDriverName.Len(), 0, 32 );
1407         rtl_copyMemory( pDeviceName, pPrinter->maDeviceName.GetBuffer(), pPrinter->maDeviceName.Len()*sizeof(sal_Unicode));
1408         memset( pDeviceName+pPrinter->maDeviceName.Len(), 0, 32 );
1409         hDC = ImplCreateICW_WithCatch( reinterpret_cast< LPWSTR >(pDriverName),
1410                                        reinterpret_cast< LPCWSTR >(pDeviceName),
1411                                        pDevMode );
1412     }
1413     else
1414     {
1415         LPDEVMODEA pDevMode;
1416         if ( pSetupData && pSetupData->mpDriverData )
1417             pDevMode = SAL_DEVMODE_A( pSetupData );
1418         else
1419             pDevMode = NULL;
1420         // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
1421         ByteString aDriver ( ImplSalGetWinAnsiString( pPrinter->maDriverName, TRUE ) );
1422         ByteString aDevice ( ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ) );
1423         int n = aDriver.Len() > aDevice.Len() ? aDriver.Len() : aDevice.Len();
1424             // #125813# under some circumstances many printer drivers really
1425         // seem to have a problem with the names and their conversions.
1426         // We need to get on to of this, but haven't been able to reproduce
1427         // the problem yet. Put the names on the stack so we get them
1428         // with an eventual crash report.
1429         if( n >= 2048 )
1430             return 0;
1431         n += 2048;
1432         char lpszDriverName[ 4096 ];
1433         char lpszDeviceName[ 4096 ];
1434         strncpy( lpszDriverName, aDriver.GetBuffer(), n );
1435         strncpy( lpszDeviceName, aDevice.GetBuffer(), n );
1436         // HDU: the crashes usually happen in a MBCS to unicode conversion,
1437         // so I suspect the MBCS string's end is not properly recognized.
1438         // The longest MBCS encoding I'm aware of has six bytes per code
1439         // => add a couple of zeroes...
1440         memset( lpszDriverName+aDriver.Len(), 0, 16 );
1441         memset( lpszDeviceName+aDevice.Len(), 0, 16 );
1442         hDC = ImplCreateICA_WithCatch( lpszDriverName,
1443                                        lpszDeviceName,
1444                                        pDevMode );
1445     }
1446     return hDC;
1447 }
1448 
1449 // -----------------------------------------------------------------------
1450 
1451 static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC )
1452 {
1453 	WinSalGraphics* pGraphics = new WinSalGraphics;
1454     pGraphics->SetLayout( 0 );
1455 	pGraphics->mhDC		= hDC;
1456 	pGraphics->mhWnd 	= 0;
1457 	pGraphics->mbPrinter = TRUE;
1458 	pGraphics->mbVirDev	= FALSE;
1459 	pGraphics->mbWindow	= FALSE;
1460 	pGraphics->mbScreen	= FALSE;
1461 	ImplSalInitGraphics( pGraphics );
1462 	return pGraphics;
1463 }
1464 
1465 // -----------------------------------------------------------------------
1466 
1467 static sal_Bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
1468 {
1469 	HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1470 	if ( !hNewDC )
1471 		return FALSE;
1472 
1473 	if ( pPrinter->mpGraphics )
1474 	{
1475 		ImplSalDeInitGraphics( pPrinter->mpGraphics );
1476 		DeleteDC( pPrinter->mpGraphics->mhDC );
1477 		delete pPrinter->mpGraphics;
1478 	}
1479 
1480 	pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hNewDC );
1481 	pPrinter->mhDC		= hNewDC;
1482 
1483 	return TRUE;
1484 }
1485 
1486 // =======================================================================
1487 
1488 SalInfoPrinter* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
1489                                                    ImplJobSetup* pSetupData )
1490 {
1491 	WinSalInfoPrinter* pPrinter = new WinSalInfoPrinter;
1492     if( ! pQueueInfo->mpSysData )
1493         GetPrinterQueueState( pQueueInfo );
1494 	pPrinter->maDriverName	= pQueueInfo->maDriver;
1495 	pPrinter->maDeviceName	= pQueueInfo->maPrinterName;
1496 	pPrinter->maPortName	= pQueueInfo->mpSysData ?
1497                                 *(String*)(pQueueInfo->mpSysData)
1498                               : String();
1499 
1500     // check if the provided setup data match the actual printer
1501 	ImplTestSalJobSetup( pPrinter, pSetupData, TRUE );
1502 
1503 	HDC hDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
1504 	if ( !hDC )
1505 	{
1506 		delete pPrinter;
1507 		return NULL;
1508 	}
1509 
1510     pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hDC );
1511 	pPrinter->mhDC		= hDC;
1512 	if ( !pSetupData->mpDriverData )
1513 		ImplUpdateSalJobSetup( pPrinter, pSetupData, FALSE, NULL );
1514 	ImplDevModeToJobSetup( pPrinter, pSetupData, SAL_JOBSET_ALL );
1515 	pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
1516 
1517 	return pPrinter;
1518 }
1519 
1520 // -----------------------------------------------------------------------
1521 
1522 void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
1523 {
1524 	delete pPrinter;
1525 }
1526 
1527 // =======================================================================
1528 
1529 WinSalInfoPrinter::WinSalInfoPrinter() :
1530     mpGraphics( NULL ),
1531     mhDC( 0 ),
1532     mbGraphics( FALSE )
1533 {
1534     m_bPapersInit = FALSE;
1535 }
1536 
1537 // -----------------------------------------------------------------------
1538 
1539 WinSalInfoPrinter::~WinSalInfoPrinter()
1540 {
1541 	if ( mpGraphics )
1542 	{
1543 		ImplSalDeInitGraphics( mpGraphics );
1544 		DeleteDC( mpGraphics->mhDC );
1545 		delete mpGraphics;
1546 	}
1547 }
1548 
1549 // -----------------------------------------------------------------------
1550 
1551 void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
1552 {
1553     m_aPaperFormats.clear();
1554 
1555     DWORD nCount = ImplDeviceCaps( this, DC_PAPERSIZE, NULL, pSetupData );
1556     if( nCount == GDI_ERROR )
1557         nCount = 0;
1558 
1559     POINT* pPaperSizes = NULL;
1560     if( nCount )
1561 	{
1562 		pPaperSizes = (POINT*)rtl_allocateZeroMemory(nCount*sizeof(POINT));
1563 		ImplDeviceCaps( this, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
1564 
1565         if( aSalShlData.mbWPrinter )
1566         {
1567             sal_Unicode* pNamesBuffer = (sal_Unicode*)rtl_allocateMemory(nCount*64*sizeof(sal_Unicode));
1568             ImplDeviceCaps( this, DC_PAPERNAMES, (BYTE*)pNamesBuffer, pSetupData );
1569             for( DWORD i = 0; i < nCount; ++i )
1570             {
1571                 PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
1572                 m_aPaperFormats.push_back( aInfo );
1573             }
1574             rtl_freeMemory( pNamesBuffer );
1575         }
1576         else
1577         {
1578             char* pNamesBuffer = (char*)rtl_allocateMemory(nCount*64);
1579             ImplDeviceCaps( this, DC_PAPERNAMES, (BYTE*)pNamesBuffer, pSetupData );
1580             for( DWORD i = 0; i < nCount; ++i )
1581             {
1582                 PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
1583                 m_aPaperFormats.push_back( aInfo );
1584             }
1585             rtl_freeMemory( pNamesBuffer );
1586         }
1587         rtl_freeMemory( pPaperSizes );
1588 	}
1589 
1590     m_bPapersInit = true;
1591 }
1592 
1593 // -----------------------------------------------------------------------
1594 
1595 int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
1596 {
1597     int nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
1598 
1599     if( nRet != GDI_ERROR )
1600         return nRet * 10;
1601     else
1602         return 900; // guess
1603 }
1604 
1605 // -----------------------------------------------------------------------
1606 
1607 SalGraphics* WinSalInfoPrinter::GetGraphics()
1608 {
1609 	if ( mbGraphics )
1610 		return NULL;
1611 
1612 	if ( mpGraphics )
1613 		mbGraphics = TRUE;
1614 
1615 	return mpGraphics;
1616 }
1617 
1618 // -----------------------------------------------------------------------
1619 
1620 void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
1621 {
1622 	mbGraphics = FALSE;
1623 }
1624 
1625 // -----------------------------------------------------------------------
1626 
1627 sal_Bool WinSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pSetupData )
1628 {
1629 	if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, static_cast<WinSalFrame*>(pFrame) ) )
1630 	{
1631 		ImplDevModeToJobSetup( this, pSetupData, SAL_JOBSET_ALL );
1632 		return ImplUpdateSalPrnIC( this, pSetupData );
1633 	}
1634 
1635 	return FALSE;
1636 }
1637 
1638 // -----------------------------------------------------------------------
1639 
1640 sal_Bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
1641 {
1642 	if ( !ImplTestSalJobSetup( this, pSetupData, FALSE ) )
1643 		return FALSE;
1644 	return ImplUpdateSalPrnIC( this, pSetupData );
1645 }
1646 
1647 // -----------------------------------------------------------------------
1648 
1649 sal_Bool WinSalInfoPrinter::SetData( sal_uLong nFlags, ImplJobSetup* pSetupData )
1650 {
1651 	ImplJobSetupToDevMode( this, pSetupData, nFlags );
1652 	if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, NULL ) )
1653 	{
1654 		ImplDevModeToJobSetup( this, pSetupData, nFlags );
1655 		return ImplUpdateSalPrnIC( this, pSetupData );
1656 	}
1657 
1658 	return FALSE;
1659 }
1660 
1661 // -----------------------------------------------------------------------
1662 
1663 sal_uLong WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
1664 {
1665 	DWORD nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
1666 	if ( nRet && (nRet != GDI_ERROR) )
1667 		return nRet;
1668 	else
1669 		return 0;
1670 }
1671 
1672 // -----------------------------------------------------------------------
1673 
1674 XubString WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pSetupData, sal_uLong nPaperBin )
1675 {
1676 	XubString aPaperBinName;
1677 
1678 	DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, NULL, pSetupData );
1679 	if ( (nPaperBin < nBins) && (nBins != GDI_ERROR) )
1680 	{
1681         if( aSalShlData.mbWPrinter )
1682         {
1683             sal_Unicode* pBuffer = new sal_Unicode[nBins*24];
1684             DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, (BYTE*)pBuffer, pSetupData );
1685             if ( nRet && (nRet != GDI_ERROR) )
1686                 aPaperBinName = pBuffer + (nPaperBin*24);
1687             delete [] pBuffer;
1688         }
1689         else
1690         {
1691             char* pBuffer = new char[nBins*24];
1692             DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, (BYTE*)pBuffer, pSetupData );
1693             if ( nRet && (nRet != GDI_ERROR) )
1694                 aPaperBinName = ImplSalGetUniString( (const char*)(pBuffer + (nPaperBin*24)) );
1695             delete [] pBuffer;
1696         }
1697 	}
1698 
1699 	return aPaperBinName;
1700 }
1701 
1702 // -----------------------------------------------------------------------
1703 
1704 sal_uLong WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, sal_uInt16 nType )
1705 {
1706 	DWORD nRet;
1707 
1708 	switch ( nType )
1709 	{
1710 		case PRINTER_CAPABILITIES_SUPPORTDIALOG:
1711 			return TRUE;
1712 		case PRINTER_CAPABILITIES_COPIES:
1713 			nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
1714 			if ( nRet && (nRet != GDI_ERROR) )
1715 				return nRet;
1716 			return 0;
1717 		case PRINTER_CAPABILITIES_COLLATECOPIES:
1718 			if ( aSalShlData.mbW40 )
1719 			{
1720 				nRet = ImplDeviceCaps( this, DC_COLLATE, NULL, pSetupData );
1721 				if ( nRet && (nRet != GDI_ERROR) )
1722 				{
1723 					nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
1724 					if ( nRet && (nRet != GDI_ERROR) )
1725 						 return nRet;
1726 				}
1727 			}
1728 			return 0;
1729 
1730 		case PRINTER_CAPABILITIES_SETORIENTATION:
1731 			nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
1732 			if ( nRet && (nRet != GDI_ERROR) )
1733 				return TRUE;
1734 			return FALSE;
1735 
1736 		case PRINTER_CAPABILITIES_SETPAPERBIN:
1737 			nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
1738 			if ( nRet && (nRet != GDI_ERROR) )
1739 				return TRUE;
1740 			return FALSE;
1741 
1742 		case PRINTER_CAPABILITIES_SETPAPERSIZE:
1743 		case PRINTER_CAPABILITIES_SETPAPER:
1744 			nRet = ImplDeviceCaps( this, DC_PAPERS, NULL, pSetupData );
1745 			if ( nRet && (nRet != GDI_ERROR) )
1746 				return TRUE;
1747 			return FALSE;
1748 	}
1749 
1750 	return 0;
1751 }
1752 
1753 // -----------------------------------------------------------------------
1754 
1755 void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
1756 								  long& rOutWidth, long& rOutHeight,
1757 								  long& rPageOffX, long& rPageOffY,
1758 								  long& rPageWidth, long& rPageHeight )
1759 {
1760 	HDC hDC = mhDC;
1761 
1762 	rOutWidth	= GetDeviceCaps( hDC, HORZRES );
1763 	rOutHeight	= GetDeviceCaps( hDC, VERTRES );
1764 
1765 	rPageOffX	= GetDeviceCaps( hDC, PHYSICALOFFSETX );
1766 	rPageOffY	= GetDeviceCaps( hDC, PHYSICALOFFSETY );
1767 	rPageWidth	= GetDeviceCaps( hDC, PHYSICALWIDTH );
1768 	rPageHeight = GetDeviceCaps( hDC, PHYSICALHEIGHT );
1769 }
1770 
1771 // =======================================================================
1772 
1773 SalPrinter* WinSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
1774 {
1775 	WinSalPrinter* pPrinter = new WinSalPrinter;
1776 	pPrinter->mpInfoPrinter = static_cast<WinSalInfoPrinter*>(pInfoPrinter);
1777 	return pPrinter;
1778 }
1779 
1780 // -----------------------------------------------------------------------
1781 
1782 void WinSalInstance::DestroyPrinter( SalPrinter* pPrinter )
1783 {
1784 	delete pPrinter;
1785 }
1786 
1787 // =======================================================================
1788 
1789 BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
1790 {
1791 	SalData*	pSalData = GetSalData();
1792 	WinSalPrinter* pPrinter;
1793 	sal_Bool		bWhile = TRUE;
1794 	int 		i = 0;
1795 
1796 	do
1797 	{
1798 		// Messages verarbeiten
1799 		MSG aMsg;
1800 		if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
1801 		{
1802             if ( !ImplInterceptChildWindowKeyDown( aMsg ) )
1803             {
1804                 TranslateMessage( &aMsg );
1805                 ImplDispatchMessage( &aMsg );
1806             }
1807 			i++;
1808 			if ( i > 15 )
1809 				bWhile = FALSE;
1810 		}
1811 		else
1812 			bWhile = FALSE;
1813 
1814 		pPrinter = pSalData->mpFirstPrinter;
1815 		while ( pPrinter )
1816 		{
1817 			if( pPrinter->mhDC == hPrnDC )
1818 				break;
1819 
1820 			pPrinter = pPrinter->mpNextPrinter;
1821 		}
1822 
1823 		if ( !pPrinter || pPrinter->mbAbort )
1824 			return FALSE;
1825 	}
1826 	while ( bWhile );
1827 
1828 	return TRUE;
1829 }
1830 
1831 // -----------------------------------------------------------------------
1832 
1833 static LPDEVMODEA ImplSalSetCopies( LPDEVMODEA pDevMode, sal_uLong nCopies, sal_Bool bCollate )
1834 {
1835 	LPDEVMODEA pNewDevMode = pDevMode;
1836 	if ( pDevMode && (nCopies > 1) )
1837 	{
1838 		if ( nCopies > 32765 )
1839 			nCopies = 32765;
1840 		sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
1841 		pNewDevMode = (LPDEVMODEA)rtl_allocateMemory( nDevSize );
1842 		memcpy( pNewDevMode, pDevMode, nDevSize );
1843 		pDevMode = pNewDevMode;
1844 		pDevMode->dmFields |= DM_COPIES;
1845 		pDevMode->dmCopies	= (short)(sal_uInt16)nCopies;
1846 		if ( aSalShlData.mbW40 )
1847 		{
1848 			pDevMode->dmFields |= DM_COLLATE;
1849 			if ( bCollate )
1850 				pDevMode->dmCollate = DMCOLLATE_TRUE;
1851 			else
1852 				pDevMode->dmCollate = DMCOLLATE_FALSE;
1853 		}
1854 	}
1855 
1856 	return pNewDevMode;
1857 }
1858 
1859 static LPDEVMODEW ImplSalSetCopies( LPDEVMODEW pDevMode, sal_uLong nCopies, sal_Bool bCollate )
1860 {
1861 	LPDEVMODEW pNewDevMode = pDevMode;
1862 	if ( pDevMode && (nCopies > 1) )
1863 	{
1864 		if ( nCopies > 32765 )
1865 			nCopies = 32765;
1866 		sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
1867 		pNewDevMode = (LPDEVMODEW)rtl_allocateMemory( nDevSize );
1868 		memcpy( pNewDevMode, pDevMode, nDevSize );
1869 		pDevMode = pNewDevMode;
1870 		pDevMode->dmFields |= DM_COPIES;
1871 		pDevMode->dmCopies	= (short)(sal_uInt16)nCopies;
1872 		if ( aSalShlData.mbW40 )
1873 		{
1874 			pDevMode->dmFields |= DM_COLLATE;
1875 			if ( bCollate )
1876 				pDevMode->dmCollate = DMCOLLATE_TRUE;
1877 			else
1878 				pDevMode->dmCollate = DMCOLLATE_FALSE;
1879 		}
1880 	}
1881 
1882 	return pNewDevMode;
1883 }
1884 
1885 // -----------------------------------------------------------------------
1886 
1887 WinSalPrinter::WinSalPrinter() :
1888     mpGraphics( NULL ),
1889     mpInfoPrinter( NULL ),
1890     mpNextPrinter( NULL ),
1891     mhDC( 0 ),
1892     mnError( 0 ),
1893     mnCopies( 0 ),
1894     mbCollate( FALSE ),
1895     mbAbort( FALSE ),
1896     mbValid( true )
1897 {
1898 	SalData* pSalData = GetSalData();
1899 	// insert printer in printerlist
1900 	mpNextPrinter = pSalData->mpFirstPrinter;
1901 	pSalData->mpFirstPrinter = this;
1902 }
1903 
1904 // -----------------------------------------------------------------------
1905 
1906 WinSalPrinter::~WinSalPrinter()
1907 {
1908 	SalData* pSalData = GetSalData();
1909 
1910     // release DC if there is one still around because of AbortJob
1911 	HDC hDC = mhDC;
1912 	if ( hDC )
1913 	{
1914 		if ( mpGraphics )
1915 		{
1916 			ImplSalDeInitGraphics( mpGraphics );
1917 			delete mpGraphics;
1918 		}
1919 
1920 		DeleteDC( hDC );
1921 	}
1922 
1923 	// remove printer from printerlist
1924 	if ( this == pSalData->mpFirstPrinter )
1925 		pSalData->mpFirstPrinter = mpNextPrinter;
1926 	else
1927 	{
1928 		WinSalPrinter* pTempPrinter = pSalData->mpFirstPrinter;
1929 
1930 		while( pTempPrinter->mpNextPrinter != this )
1931 			pTempPrinter = pTempPrinter->mpNextPrinter;
1932 
1933 		pTempPrinter->mpNextPrinter = mpNextPrinter;
1934 	}
1935     mbValid = false;
1936 }
1937 
1938 // -----------------------------------------------------------------------
1939 
1940 void WinSalPrinter::markInvalid()
1941 {
1942     mbValid = false;
1943 }
1944 
1945 // -----------------------------------------------------------------------
1946 
1947 // need wrappers for StarTocW/A to use structured exception handling
1948 // since SEH does not mix with standard exception handling's cleanup
1949 static int lcl_StartDocW( HDC hDC, DOCINFOW* pInfo, WinSalPrinter* pPrt )
1950 {
1951     int nRet = 0;
1952     CATCH_DRIVER_EX_BEGIN;
1953     nRet = ::StartDocW( hDC, pInfo );
1954     CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
1955     return nRet;
1956 }
1957 
1958 static int lcl_StartDocA( HDC hDC, DOCINFOA* pInfo, WinSalPrinter* pPrt )
1959 {
1960     int nRet = 0;
1961     CATCH_DRIVER_EX_BEGIN;
1962     nRet = ::StartDocA( hDC, pInfo );
1963     CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
1964     return nRet;
1965 }
1966 
1967 sal_Bool WinSalPrinter::StartJob( const XubString* pFileName,
1968 						   const XubString& rJobName,
1969 						   const XubString&,
1970 						   sal_uLong nCopies,
1971                            bool bCollate,
1972                            bool /*bDirect*/,
1973 						   ImplJobSetup* pSetupData )
1974 {
1975 	mnError		= 0;
1976 	mbAbort		= FALSE;
1977 	mnCopies		= nCopies;
1978 	mbCollate 	= bCollate;
1979 
1980 	LPDEVMODEA	pOrgDevModeA = NULL;
1981 	LPDEVMODEA	pDevModeA = NULL;
1982 	LPDEVMODEW	pOrgDevModeW = NULL;
1983 	LPDEVMODEW	pDevModeW = NULL;
1984     HDC hDC = 0;
1985     if( aSalShlData.mbWPrinter )
1986     {
1987         if ( pSetupData && pSetupData->mpDriverData )
1988         {
1989             pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
1990             pDevModeW = ImplSalSetCopies( pOrgDevModeW, nCopies, bCollate );
1991         }
1992         else
1993             pDevModeW = NULL;
1994 
1995         // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
1996         sal_Unicode aDrvBuf[4096];
1997         sal_Unicode aDevBuf[4096];
1998         rtl_copyMemory( aDrvBuf, mpInfoPrinter->maDriverName.GetBuffer(), (mpInfoPrinter->maDriverName.Len()+1)*sizeof(sal_Unicode));
1999         rtl_copyMemory( aDevBuf, mpInfoPrinter->maDeviceName.GetBuffer(), (mpInfoPrinter->maDeviceName.Len()+1)*sizeof(sal_Unicode));
2000         hDC = CreateDCW( reinterpret_cast<LPCWSTR>(aDrvBuf),
2001                          reinterpret_cast<LPCWSTR>(aDevBuf),
2002                          NULL,
2003                          pDevModeW );
2004 
2005         if ( pDevModeW != pOrgDevModeW )
2006             rtl_freeMemory( pDevModeW );
2007     }
2008     else
2009     {
2010         if ( pSetupData && pSetupData->mpDriverData )
2011         {
2012             pOrgDevModeA = SAL_DEVMODE_A( pSetupData );
2013             pDevModeA = ImplSalSetCopies( pOrgDevModeA, nCopies, bCollate );
2014         }
2015         else
2016             pDevModeA = NULL;
2017 
2018         // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
2019         ByteString aDriver ( ImplSalGetWinAnsiString( mpInfoPrinter->maDriverName, TRUE ) );
2020         ByteString aDevice ( ImplSalGetWinAnsiString( mpInfoPrinter->maDeviceName, TRUE ) );
2021         int n = aDriver.Len() > aDevice.Len() ? aDriver.Len() : aDevice.Len();
2022         n += 2048;
2023         char *lpszDriverName = new char[n];
2024         char *lpszDeviceName = new char[n];
2025         strncpy( lpszDriverName, aDriver.GetBuffer(), n );
2026         strncpy( lpszDeviceName, aDevice.GetBuffer(), n );
2027         hDC = CreateDCA( lpszDriverName,
2028                          lpszDeviceName,
2029                          NULL,
2030                          pDevModeA );
2031 
2032         delete [] lpszDriverName;
2033         delete [] lpszDeviceName;
2034 
2035         if ( pDevModeA != pOrgDevModeA )
2036             rtl_freeMemory( pDevModeA );
2037     }
2038 
2039 	if ( !hDC )
2040 	{
2041 		mnError = SAL_PRINTER_ERROR_GENERALERROR;
2042 		return FALSE;
2043 	}
2044 
2045     // make sure mhDC is set before the printer driver may call our abortproc
2046     mhDC = hDC;
2047 	if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
2048 	{
2049 		mnError = SAL_PRINTER_ERROR_GENERALERROR;
2050 		return FALSE;
2051 	}
2052 
2053 	mnError	= 0;
2054 	mbAbort	= FALSE;
2055 
2056 	// Wegen Telocom Balloon Fax-Treiber, der uns unsere Messages
2057 	// ansonsten oefters schickt, versuchen wir vorher alle
2058 	// zu verarbeiten und dann eine Dummy-Message reinstellen
2059 	sal_Bool bWhile = TRUE;
2060 	int  i = 0;
2061 	do
2062 	{
2063 		// Messages verarbeiten
2064 		MSG aMsg;
2065 		if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
2066 		{
2067             if ( !ImplInterceptChildWindowKeyDown( aMsg ) )
2068             {
2069                 TranslateMessage( &aMsg );
2070                 ImplDispatchMessage( &aMsg );
2071             }
2072 
2073 			i++;
2074 			if ( i > 15 )
2075 				bWhile = FALSE;
2076 		}
2077 		else
2078 			bWhile = FALSE;
2079 	}
2080 	while ( bWhile );
2081 	ImplPostMessage( GetSalData()->mpFirstInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0 );
2082 
2083     // bring up a file choser if printing to file port but no file name given
2084     OUString aOutFileName;
2085     if( mpInfoPrinter->maPortName.EqualsIgnoreCaseAscii( "FILE:" ) && !(pFileName && pFileName->Len()) )
2086     {
2087 
2088         uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
2089         if( xFactory.is() )
2090         {
2091             uno::Reference< XFilePicker > xFilePicker( xFactory->createInstance(
2092                 OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FilePicker" ) ) ),
2093                 UNO_QUERY );
2094             DBG_ASSERT( xFilePicker.is(), "could not get FilePicker service" );
2095 
2096             uno::Reference< XInitialization > xInit( xFilePicker, UNO_QUERY );
2097             uno::Reference< XFilterManager > xFilterMgr( xFilePicker, UNO_QUERY );
2098             if( xInit.is() && xFilePicker.is() && xFilterMgr.is() )
2099             {
2100                 Sequence< Any > aServiceType( 1 );
2101                 aServiceType[0] <<= TemplateDescription::FILESAVE_SIMPLE;
2102                 xInit->initialize( aServiceType );
2103                 if( xFilePicker->execute() == ExecutableDialogResults::OK )
2104                 {
2105                     Sequence< OUString > aPathSeq( xFilePicker->getFiles() );
2106 				    INetURLObject aObj( aPathSeq[0] );
2107                     // we're using ansi calls (StartDocA) so convert the string
2108                     aOutFileName = aObj.PathToFileName();
2109                 }
2110                 else
2111                 {
2112                     mnError = SAL_PRINTER_ERROR_ABORT;
2113                     return FALSE;
2114                 }
2115             }
2116         }
2117     }
2118 
2119     if( aSalShlData.mbWPrinter )
2120     {
2121         DOCINFOW aInfo;
2122         memset( &aInfo, 0, sizeof( DOCINFOW ) );
2123         aInfo.cbSize = sizeof( aInfo );
2124         aInfo.lpszDocName = (LPWSTR)rJobName.GetBuffer();
2125         if ( pFileName || aOutFileName.getLength() )
2126         {
2127             if ( (pFileName && pFileName->Len()) || aOutFileName.getLength() )
2128             {
2129                 aInfo.lpszOutput = (LPWSTR)( (pFileName && pFileName->Len()) ? pFileName->GetBuffer() : aOutFileName.getStr());
2130             }
2131             else
2132                 aInfo.lpszOutput = L"FILE:";
2133         }
2134         else
2135             aInfo.lpszOutput = NULL;
2136 
2137         // start Job
2138         int nRet = lcl_StartDocW( hDC, &aInfo, this );
2139 
2140         if ( nRet <= 0 )
2141         {
2142             long nError = GetLastError();
2143             if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
2144                 mnError = SAL_PRINTER_ERROR_ABORT;
2145             else
2146                 mnError = SAL_PRINTER_ERROR_GENERALERROR;
2147             return FALSE;
2148         }
2149     }
2150     else
2151     {
2152         // Both strings must exist, if StartJob() is called
2153         ByteString aJobName( ImplSalGetWinAnsiString( rJobName, TRUE ) );
2154         ByteString aFileName;
2155 
2156         DOCINFOA aInfo;
2157         memset( &aInfo, 0, sizeof( DOCINFOA ) );
2158         aInfo.cbSize = sizeof( aInfo );
2159         aInfo.lpszDocName = (LPCSTR)aJobName.GetBuffer();
2160         if ( pFileName || aOutFileName.getLength() )
2161         {
2162             if ( pFileName->Len() || aOutFileName.getLength() )
2163             {
2164                 aFileName = ImplSalGetWinAnsiString( pFileName ? *pFileName : static_cast<const XubString>(aOutFileName), TRUE );
2165                 aInfo.lpszOutput = (LPCSTR)aFileName.GetBuffer();
2166             }
2167             else
2168                 aInfo.lpszOutput = "FILE:";
2169         }
2170         else
2171             aInfo.lpszOutput = NULL;
2172 
2173         // start Job
2174         int nRet = lcl_StartDocA( hDC, &aInfo, this );
2175         if ( nRet <= 0 )
2176         {
2177             long nError = GetLastError();
2178             if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
2179                 mnError = SAL_PRINTER_ERROR_ABORT;
2180             else
2181                 mnError = SAL_PRINTER_ERROR_GENERALERROR;
2182             return FALSE;
2183         }
2184     }
2185 
2186 	return TRUE;
2187 }
2188 
2189 // -----------------------------------------------------------------------
2190 
2191 sal_Bool WinSalPrinter::EndJob()
2192 {
2193 	DWORD err = 0;
2194 	HDC hDC = mhDC;
2195 	if ( isValid() && hDC )
2196 	{
2197 		if ( mpGraphics )
2198 		{
2199 			ImplSalDeInitGraphics( mpGraphics );
2200 			delete mpGraphics;
2201 			mpGraphics = NULL;
2202 		}
2203 
2204         // #i54419# Windows fax printer brings up a dialog in EndDoc
2205         // which text previously copied in soffice process can be
2206         // pasted to -> deadlock due to mutex not released.
2207         // it should be safe to release the yield mutex over the EndDoc
2208         // call, however the real solution is supposed to be the threading
2209         // framework yet to come.
2210         SalData* pSalData = GetSalData();
2211 		sal_uLong nAcquire = pSalData->mpFirstInstance->ReleaseYieldMutex();
2212         CATCH_DRIVER_EX_BEGIN;
2213         if( ::EndDoc( hDC ) <= 0 )
2214             err = GetLastError();
2215         CATCH_DRIVER_EX_END( "exception in EndDoc", this );
2216 
2217 		pSalData->mpFirstInstance->AcquireYieldMutex( nAcquire );
2218 		DeleteDC( hDC );
2219         mhDC = 0;
2220 	}
2221 
2222 	return TRUE;
2223 }
2224 
2225 // -----------------------------------------------------------------------
2226 
2227 sal_Bool WinSalPrinter::AbortJob()
2228 {
2229 	mbAbort = TRUE;
2230 
2231 	// Abort asyncron ausloesen
2232 	HDC hDC = mhDC;
2233 	if ( hDC )
2234 	{
2235 		SalData* pSalData = GetSalData();
2236 		ImplPostMessage( pSalData->mpFirstInstance->mhComWnd,
2237 						 SAL_MSG_PRINTABORTJOB, (WPARAM)hDC, 0 );
2238 	}
2239 
2240 	return TRUE;
2241 }
2242 
2243 // -----------------------------------------------------------------------
2244 
2245 void ImplSalPrinterAbortJobAsync( HDC hPrnDC )
2246 {
2247 	SalData*	pSalData = GetSalData();
2248 	WinSalPrinter* pPrinter = pSalData->mpFirstPrinter;
2249 
2250 	// Feststellen, ob Printer noch existiert
2251 	while ( pPrinter )
2252 	{
2253 		if ( pPrinter->mhDC == hPrnDC )
2254 			break;
2255 
2256 		pPrinter = pPrinter->mpNextPrinter;
2257 	}
2258 
2259 	// Wenn Printer noch existiert, dann den Job abbrechen
2260 	if ( pPrinter )
2261 	{
2262 		HDC hDC = pPrinter->mhDC;
2263 		if ( hDC )
2264 		{
2265 			if ( pPrinter->mpGraphics )
2266 			{
2267 				ImplSalDeInitGraphics( pPrinter->mpGraphics );
2268 				delete pPrinter->mpGraphics;
2269 				pPrinter->mpGraphics = NULL;
2270 			}
2271 
2272             CATCH_DRIVER_EX_BEGIN;
2273             ::AbortDoc( hDC );
2274             CATCH_DRIVER_EX_END( "exception in AbortDoc", pPrinter );
2275 
2276 			DeleteDC( hDC );
2277             pPrinter->mhDC = 0;
2278 		}
2279 	}
2280 }
2281 
2282 // -----------------------------------------------------------------------
2283 
2284 SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, sal_Bool bNewJobData )
2285 {
2286     if( ! isValid() || mhDC == 0 )
2287         return NULL;
2288 
2289 	HDC hDC = mhDC;
2290 	if ( pSetupData && pSetupData->mpDriverData && bNewJobData )
2291 	{
2292         if( aSalShlData.mbWPrinter )
2293         {
2294             LPDEVMODEW	pOrgDevModeW;
2295             LPDEVMODEW	pDevModeW;
2296             pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
2297             pDevModeW = ImplSalSetCopies( pOrgDevModeW, mnCopies, mbCollate );
2298             ResetDCW( hDC, pDevModeW );
2299             if ( pDevModeW != pOrgDevModeW )
2300                 rtl_freeMemory( pDevModeW );
2301         }
2302         else
2303         {
2304             LPDEVMODEA	pOrgDevModeA;
2305             LPDEVMODEA	pDevModeA;
2306             pOrgDevModeA = SAL_DEVMODE_A( pSetupData );
2307             pDevModeA = ImplSalSetCopies( pOrgDevModeA, mnCopies, mbCollate );
2308             ResetDCA( hDC, pDevModeA );
2309             if ( pDevModeA != pOrgDevModeA )
2310                 rtl_freeMemory( pDevModeA );
2311         }
2312 	}
2313 	int nRet = 0;
2314     CATCH_DRIVER_EX_BEGIN;
2315     nRet = ::StartPage( hDC );
2316     CATCH_DRIVER_EX_END( "exception in StartPage", this );
2317 
2318 	if ( nRet <= 0 )
2319 	{
2320 		GetLastError();
2321 		mnError = SAL_PRINTER_ERROR_GENERALERROR;
2322 		return NULL;
2323 	}
2324 
2325 	// Hack to work around old PostScript printer drivers optimizing away empty pages
2326     // TODO: move into ImplCreateSalPrnGraphics()?
2327 	HPEN	hTempPen = SelectPen( hDC, GetStockPen( NULL_PEN ) );
2328 	HBRUSH	hTempBrush = SelectBrush( hDC, GetStockBrush( NULL_BRUSH ) );
2329 	WIN_Rectangle( hDC, -8000, -8000, -7999, -7999 );
2330 	SelectPen( hDC, hTempPen );
2331 	SelectBrush( hDC, hTempBrush );
2332 
2333     mpGraphics = ImplCreateSalPrnGraphics( hDC );
2334     return mpGraphics;
2335 }
2336 
2337 // -----------------------------------------------------------------------
2338 
2339 sal_Bool WinSalPrinter::EndPage()
2340 {
2341 	HDC hDC = mhDC;
2342 	if ( hDC && mpGraphics )
2343 	{
2344 		ImplSalDeInitGraphics( mpGraphics );
2345 		delete mpGraphics;
2346 		mpGraphics = NULL;
2347 	}
2348 
2349     if( ! isValid() )
2350         return FALSE;
2351 
2352 	int nRet = 0;
2353     CATCH_DRIVER_EX_BEGIN;
2354     nRet = ::EndPage( hDC );
2355     CATCH_DRIVER_EX_END( "exception in EndPage", this );
2356 
2357 	if ( nRet > 0 )
2358 		return TRUE;
2359 	else
2360 	{
2361 		GetLastError();
2362 		mnError = SAL_PRINTER_ERROR_GENERALERROR;
2363 		return FALSE;
2364 	}
2365 }
2366 
2367 // -----------------------------------------------------------------------
2368 
2369 sal_uLong WinSalPrinter::GetErrorCode()
2370 {
2371 	return mnError;
2372 }
2373