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