xref: /AOO41X/main/vcl/win/source/gdi/salprn.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
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