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