office-gobmx/vcl/win/source/gdi/salprn.cxx
Noel Grandin 4b51374a70 fdo#46808, Adapt ui::dialogs::FilePicker UNO service to new style
Change-Id: I1cafbfc53994e5d74241042dbd1d292ddbda67d5
2013-02-12 10:14:45 +02:00

1830 lines
64 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#define WINVER 0x0500
#include <string.h>
#include <svsys.h>
#include <osl/module.h>
#include <tools/urlobj.hxx>
#include <win/wincomp.hxx>
#include <win/saldata.hxx>
#include <win/salinst.h>
#include <win/salgdi.h>
#include <win/salframe.h>
#include <win/salprn.h>
#include <salptype.hxx>
#include <print.h>
#include <jobset.h>
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
#include <com/sun/star/ui/dialogs/FilePicker.hpp>
#include <com/sun/star/ui/dialogs/XFilterManager.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <comphelper/processfactory.hxx>
#include <malloc.h>
#ifdef __MINGW32__
#include <sehandler.hxx>
#endif
#ifdef __MINGW32__
#define CATCH_DRIVER_EX_BEGIN \
jmp_buf jmpbuf; \
__SEHandler han; \
if (__builtin_setjmp(jmpbuf) == 0) \
{ \
han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER)
#define CATCH_DRIVER_EX_END(mes, p) \
} \
han.Reset()
#define CATCH_DRIVER_EX_END_2(mes) \
} \
han.Reset()
#else
#define CATCH_DRIVER_EX_BEGIN \
__try \
{
#define CATCH_DRIVER_EX_END(mes, p) \
} \
__except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
{ \
OSL_FAIL( mes ); \
p->markInvalid(); \
}
#define CATCH_DRIVER_EX_END_2(mes) \
} \
__except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
{ \
OSL_FAIL( mes ); \
}
#endif
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::ui::dialogs;
using ::rtl::OUString;
// =======================================================================
static char aImplWindows[] = "windows";
static char aImplDevice[] = "device";
static LPDEVMODEW SAL_DEVMODE_W( const ImplJobSetup* pSetupData )
{
LPDEVMODEW pRet = NULL;
SalDriverData* pDrv = (SalDriverData*)pSetupData->mpDriverData;
if( pSetupData->mnDriverDataLen >= sizeof(DEVMODEW)+sizeof(SalDriverData)-1 )
pRet = ((LPDEVMODEW)((pSetupData->mpDriverData) + (pDrv->mnDriverOffset)));
return pRet;
}
// =======================================================================
static sal_uLong ImplWinQueueStatusToSal( DWORD nWinStatus )
{
sal_uLong nStatus = 0;
if ( nWinStatus & PRINTER_STATUS_PAUSED )
nStatus |= QUEUE_STATUS_PAUSED;
if ( nWinStatus & PRINTER_STATUS_ERROR )
nStatus |= QUEUE_STATUS_ERROR;
if ( nWinStatus & PRINTER_STATUS_PENDING_DELETION )
nStatus |= QUEUE_STATUS_PENDING_DELETION;
if ( nWinStatus & PRINTER_STATUS_PAPER_JAM )
nStatus |= QUEUE_STATUS_PAPER_JAM;
if ( nWinStatus & PRINTER_STATUS_PAPER_OUT )
nStatus |= QUEUE_STATUS_PAPER_OUT;
if ( nWinStatus & PRINTER_STATUS_MANUAL_FEED )
nStatus |= QUEUE_STATUS_MANUAL_FEED;
if ( nWinStatus & PRINTER_STATUS_PAPER_PROBLEM )
nStatus |= QUEUE_STATUS_PAPER_PROBLEM;
if ( nWinStatus & PRINTER_STATUS_OFFLINE )
nStatus |= QUEUE_STATUS_OFFLINE;
if ( nWinStatus & PRINTER_STATUS_IO_ACTIVE )
nStatus |= QUEUE_STATUS_IO_ACTIVE;
if ( nWinStatus & PRINTER_STATUS_BUSY )
nStatus |= QUEUE_STATUS_BUSY;
if ( nWinStatus & PRINTER_STATUS_PRINTING )
nStatus |= QUEUE_STATUS_PRINTING;
if ( nWinStatus & PRINTER_STATUS_OUTPUT_BIN_FULL )
nStatus |= QUEUE_STATUS_OUTPUT_BIN_FULL;
if ( nWinStatus & PRINTER_STATUS_WAITING )
nStatus |= QUEUE_STATUS_WAITING;
if ( nWinStatus & PRINTER_STATUS_PROCESSING )
nStatus |= QUEUE_STATUS_PROCESSING;
if ( nWinStatus & PRINTER_STATUS_INITIALIZING )
nStatus |= QUEUE_STATUS_INITIALIZING;
if ( nWinStatus & PRINTER_STATUS_WARMING_UP )
nStatus |= QUEUE_STATUS_WARMING_UP;
if ( nWinStatus & PRINTER_STATUS_TONER_LOW )
nStatus |= QUEUE_STATUS_TONER_LOW;
if ( nWinStatus & PRINTER_STATUS_NO_TONER )
nStatus |= QUEUE_STATUS_NO_TONER;
if ( nWinStatus & PRINTER_STATUS_PAGE_PUNT )
nStatus |= QUEUE_STATUS_PAGE_PUNT;
if ( nWinStatus & PRINTER_STATUS_USER_INTERVENTION )
nStatus |= QUEUE_STATUS_USER_INTERVENTION;
if ( nWinStatus & PRINTER_STATUS_OUT_OF_MEMORY )
nStatus |= QUEUE_STATUS_OUT_OF_MEMORY;
if ( nWinStatus & PRINTER_STATUS_DOOR_OPEN )
nStatus |= QUEUE_STATUS_DOOR_OPEN;
if ( nWinStatus & PRINTER_STATUS_SERVER_UNKNOWN )
nStatus |= QUEUE_STATUS_SERVER_UNKNOWN;
if ( nWinStatus & PRINTER_STATUS_POWER_SAVE )
nStatus |= QUEUE_STATUS_POWER_SAVE;
if ( !nStatus && !(nWinStatus & PRINTER_STATUS_NOT_AVAILABLE) )
nStatus |= QUEUE_STATUS_READY;
return nStatus;
}
// -----------------------------------------------------------------------
void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
{
DWORD i;
DWORD nBytes = 0;
DWORD nInfoPrn4 = 0;
EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, NULL, 0, &nBytes, &nInfoPrn4 );
if ( nBytes )
{
PRINTER_INFO_4W* pWinInfo4 = (PRINTER_INFO_4W*) rtl_allocateMemory( nBytes );
if ( EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, (LPBYTE)pWinInfo4, nBytes, &nBytes, &nInfoPrn4 ) )
{
for ( i = 0; i < nInfoPrn4; i++ )
{
SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
pInfo->maPrinterName = rtl::OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo4[i].pPrinterName) );
pInfo->mnStatus = 0;
pInfo->mnJobs = 0;
pInfo->mpSysData = NULL;
pList->Add( pInfo );
}
}
rtl_freeMemory( pWinInfo4 );
}
}
// -----------------------------------------------------------------------
void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
{
HANDLE hPrinter = 0;
LPWSTR pPrnName = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pInfo->maPrinterName.getStr()));
if( OpenPrinterW( pPrnName, &hPrinter, NULL ) )
{
DWORD nBytes = 0;
GetPrinterW( hPrinter, 2, NULL, 0, &nBytes );
if( nBytes )
{
PRINTER_INFO_2W* pWinInfo2 = (PRINTER_INFO_2W*)rtl_allocateMemory(nBytes);
if( GetPrinterW( hPrinter, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes ) )
{
if( pWinInfo2->pDriverName )
pInfo->maDriver = rtl::OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pDriverName) );
XubString aPortName;
if ( pWinInfo2->pPortName )
aPortName = rtl::OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pPortName) );
// pLocation can be 0 (the Windows docu doesn't describe this)
if ( pWinInfo2->pLocation && *pWinInfo2->pLocation )
pInfo->maLocation = rtl::OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pLocation) );
else
pInfo->maLocation = aPortName;
// pComment can be 0 (the Windows docu doesn't describe this)
if ( pWinInfo2->pComment )
pInfo->maComment = rtl::OUString( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pComment) );
pInfo->mnStatus = ImplWinQueueStatusToSal( pWinInfo2->Status );
pInfo->mnJobs = pWinInfo2->cJobs;
if( ! pInfo->mpSysData )
pInfo->mpSysData = new rtl::OUString(aPortName);
}
rtl_freeMemory(pWinInfo2);
}
ClosePrinter( hPrinter );
}
}
// -----------------------------------------------------------------------
void WinSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
{
delete pInfo->mpSysData;
delete pInfo;
}
// -----------------------------------------------------------------------
rtl::OUString WinSalInstance::GetDefaultPrinter()
{
DWORD nChars = 0;
GetDefaultPrinterW( NULL, &nChars );
if( nChars )
{
LPWSTR pStr = (LPWSTR)rtl_allocateMemory(nChars*sizeof(WCHAR));
XubString aDefPrt;
if( GetDefaultPrinterW( pStr, &nChars ) )
{
aDefPrt = reinterpret_cast<sal_Unicode* >(pStr);
}
rtl_freeMemory( pStr );
if( aDefPrt.Len() )
return aDefPrt;
}
// get default printer from win.ini
char szBuffer[256];
GetProfileStringA( aImplWindows, aImplDevice, "", szBuffer, sizeof( szBuffer ) );
if ( szBuffer[0] )
{
// Printername suchen
char* pBuf = szBuffer;
char* pTmp = pBuf;
while ( *pTmp && (*pTmp != ',') )
pTmp++;
return ImplSalGetUniString( pBuf, (xub_StrLen)(pTmp-pBuf) );
}
else
return rtl::OUString();
}
// =======================================================================
static DWORD ImplDeviceCaps( WinSalInfoPrinter* pPrinter, WORD nCaps,
BYTE* pOutput, const ImplJobSetup* pSetupData )
{
DEVMODEW* pDevMode;
if ( !pSetupData || !pSetupData->mpDriverData )
pDevMode = NULL;
else
pDevMode = SAL_DEVMODE_W( pSetupData );
return DeviceCapabilitiesW( reinterpret_cast<LPCWSTR>(pPrinter->maDeviceName.getStr()),
reinterpret_cast<LPCWSTR>(pPrinter->maPortName.getStr()),
nCaps, (LPWSTR)pOutput, pDevMode );
}
// -----------------------------------------------------------------------
static sal_Bool ImplTestSalJobSetup( WinSalInfoPrinter* pPrinter,
ImplJobSetup* pSetupData, sal_Bool bDelete )
{
if ( pSetupData && pSetupData->mpDriverData )
{
// signature and size must fit to avoid using
// JobSetups from a wrong system
// initialize versions from jobsetup
// those will be overwritten with driver's version
DEVMODEW* pDevModeW = NULL;
LONG dmSpecVersion = -1;
LONG dmDriverVersion = -1;
SalDriverData* pSalDriverData = (SalDriverData*)pSetupData->mpDriverData;
BYTE* pDriverData = ((BYTE*)pSalDriverData) + pSalDriverData->mnDriverOffset;
pDevModeW = (DEVMODEW*)pDriverData;
long nSysJobSize = -1;
if( pPrinter && pDevModeW )
{
// just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
// this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
// can avoid potential driver crashes as their jobsetups are often not compatible
// #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
HANDLE hPrn;
LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.getStr()));
if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
return FALSE;
// #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
if( hPrn == HGDI_ERROR )
return FALSE;
nSysJobSize = DocumentPropertiesW( 0, hPrn,
pPrinterNameW,
NULL, NULL, 0 );
if( nSysJobSize < 0 )
{
ClosePrinter( hPrn );
return FALSE;
}
BYTE *pBuffer = (BYTE*)_alloca( nSysJobSize );
LONG nRet = DocumentPropertiesW( 0, hPrn,
pPrinterNameW,
(LPDEVMODEW)pBuffer, NULL, DM_OUT_BUFFER );
if( nRet < 0 )
{
ClosePrinter( hPrn );
return FALSE;
}
// the spec version differs between the windows platforms, ie 98,NT,2000/XP
// this allows us to throw away printer settings from other platforms that might crash a buggy driver
// we check the driver version as well
dmSpecVersion = ((DEVMODEW*)pBuffer)->dmSpecVersion;
dmDriverVersion = ((DEVMODEW*)pBuffer)->dmDriverVersion;
ClosePrinter( hPrn );
}
SalDriverData* pSetupDriverData = (SalDriverData*)(pSetupData->mpDriverData);
if ( (pSetupData->mnSystem == JOBSETUP_SYSTEM_WINDOWS) &&
(pPrinter->maDriverName == pSetupData->maDriver) &&
(pSetupData->mnDriverDataLen > sizeof( SalDriverData )) &&
(long)(pSetupData->mnDriverDataLen - pSetupDriverData->mnDriverOffset) == nSysJobSize &&
pSetupDriverData->mnSysSignature == SAL_DRIVERDATA_SYSSIGN )
{
if( pDevModeW &&
(dmSpecVersion == pDevModeW->dmSpecVersion) &&
(dmDriverVersion == pDevModeW->dmDriverVersion) )
return TRUE;
}
if ( bDelete )
{
rtl_freeMemory( pSetupData->mpDriverData );
pSetupData->mpDriverData = NULL;
pSetupData->mnDriverDataLen = 0;
}
}
return FALSE;
}
// -----------------------------------------------------------------------
static sal_Bool ImplUpdateSalJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData,
sal_Bool bIn, WinSalFrame* pVisibleDlgParent )
{
HANDLE hPrn;
LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.getStr()));
if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
return FALSE;
// #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
if( hPrn == HGDI_ERROR )
return FALSE;
LONG nRet;
HWND hWnd = 0;
DWORD nMode = DM_OUT_BUFFER;
sal_uLong nDriverDataLen = 0;
SalDriverData* pOutBuffer = NULL;
BYTE* pInBuffer = NULL;
LONG nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
pPrinterNameW,
NULL, NULL, 0 );
if ( nSysJobSize < 0 )
{
ClosePrinter( hPrn );
return FALSE;
}
// Outputbuffer anlegen
nDriverDataLen = sizeof(SalDriverData) + nSysJobSize-1;
pOutBuffer = (SalDriverData*)rtl_allocateZeroMemory( nDriverDataLen );
pOutBuffer->mnSysSignature = SAL_DRIVERDATA_SYSSIGN;
// calculate driver data offset including structure padding
pOutBuffer->mnDriverOffset = sal::static_int_cast<sal_uInt16>(
(char*)pOutBuffer->maDriverData -
(char*)pOutBuffer );
// Testen, ob wir einen geeigneten Inputbuffer haben
if ( bIn && ImplTestSalJobSetup( pPrinter, pSetupData, FALSE ) )
{
pInBuffer = (BYTE*)pSetupData->mpDriverData + ((SalDriverData*)pSetupData->mpDriverData)->mnDriverOffset;
nMode |= DM_IN_BUFFER;
}
// Testen, ob Dialog angezeigt werden soll
if ( pVisibleDlgParent )
{
hWnd = pVisibleDlgParent->mhWnd;
nMode |= DM_IN_PROMPT;
}
// Release mutex, in the other case we don't get paints and so on
sal_uLong nMutexCount=0;
if ( pVisibleDlgParent )
nMutexCount = ImplSalReleaseYieldMutex();
BYTE* pOutDevMode = (((BYTE*)pOutBuffer) + pOutBuffer->mnDriverOffset);
nRet = DocumentPropertiesW( hWnd, hPrn,
pPrinterNameW,
(LPDEVMODEW)pOutDevMode, (LPDEVMODEW)pInBuffer, nMode );
if ( pVisibleDlgParent )
ImplSalAcquireYieldMutex( nMutexCount );
ClosePrinter( hPrn );
if( (nRet < 0) || (pVisibleDlgParent && (nRet == IDCANCEL)) )
{
rtl_freeMemory( pOutBuffer );
return FALSE;
}
// fill up string buffers with 0 so they do not influence a JobSetup's memcmp
if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 64 )
{
sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmDeviceName );
if ( sal::static_int_cast<size_t>(nLen) < SAL_N_ELEMENTS( ((LPDEVMODEW)pOutDevMode)->dmDeviceName ) )
memset( ((LPDEVMODEW)pOutDevMode)->dmDeviceName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmDeviceName )-(nLen*sizeof(sal_Unicode)) );
}
if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 166 )
{
sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmFormName );
if ( sal::static_int_cast<size_t>(nLen) < SAL_N_ELEMENTS( ((LPDEVMODEW)pOutDevMode)->dmFormName ) )
memset( ((LPDEVMODEW)pOutDevMode)->dmFormName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmFormName )-(nLen*sizeof(sal_Unicode)) );
}
// update data
if ( pSetupData->mpDriverData )
rtl_freeMemory( pSetupData->mpDriverData );
pSetupData->mnDriverDataLen = nDriverDataLen;
pSetupData->mpDriverData = (BYTE*)pOutBuffer;
pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
return TRUE;
}
// -----------------------------------------------------------------------
#define DECLARE_DEVMODE( i )\
DEVMODEW* pDevModeW = SAL_DEVMODE_W(i);\
if( pDevModeW == NULL )\
return
#define CHOOSE_DEVMODE(i)\
(pDevModeW->i)
static void ImplDevModeToJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, sal_uLong nFlags )
{
if ( !pSetupData || !pSetupData->mpDriverData )
return;
DECLARE_DEVMODE( pSetupData );
// Orientation
if ( nFlags & SAL_JOBSET_ORIENTATION )
{
if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_PORTRAIT )
pSetupData->meOrientation = ORIENTATION_PORTRAIT;
else if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_LANDSCAPE )
pSetupData->meOrientation = ORIENTATION_LANDSCAPE;
}
// PaperBin
if ( nFlags & SAL_JOBSET_PAPERBIN )
{
sal_uLong nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
if ( nCount && (nCount != GDI_ERROR) )
{
WORD* pBins = (WORD*)rtl_allocateZeroMemory( nCount*sizeof(WORD) );
ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
pSetupData->mnPaperBin = 0;
// search the right bin and assign index to mnPaperBin
for( sal_uLong i = 0; i < nCount; i++ )
{
if( CHOOSE_DEVMODE(dmDefaultSource) == pBins[ i ] )
{
pSetupData->mnPaperBin = (sal_uInt16)i;
break;
}
}
rtl_freeMemory( pBins );
}
}
// PaperSize
if ( nFlags & SAL_JOBSET_PAPERSIZE )
{
if( (CHOOSE_DEVMODE(dmFields) & (DM_PAPERWIDTH|DM_PAPERLENGTH)) == (DM_PAPERWIDTH|DM_PAPERLENGTH) )
{
pSetupData->mnPaperWidth = CHOOSE_DEVMODE(dmPaperWidth)*10;
pSetupData->mnPaperHeight = CHOOSE_DEVMODE(dmPaperLength)*10;
}
else
{
sal_uLong nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
WORD* pPapers = NULL;
sal_uLong nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
POINT* pPaperSizes = NULL;
if ( nPaperCount && (nPaperCount != GDI_ERROR) )
{
pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
}
if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
{
pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
}
if( nPaperSizeCount == nPaperCount && pPaperSizes && pPapers )
{
for( sal_uLong i = 0; i < nPaperCount; i++ )
{
if( pPapers[ i ] == CHOOSE_DEVMODE(dmPaperSize) )
{
pSetupData->mnPaperWidth = pPaperSizes[ i ].x*10;
pSetupData->mnPaperHeight = pPaperSizes[ i ].y*10;
break;
}
}
}
if( pPapers )
rtl_freeMemory( pPapers );
if( pPaperSizes )
rtl_freeMemory( pPaperSizes );
}
switch( CHOOSE_DEVMODE(dmPaperSize) )
{
case( DMPAPER_LETTER ):
pSetupData->mePaperFormat = PAPER_LETTER;
break;
case( DMPAPER_TABLOID ):
pSetupData->mePaperFormat = PAPER_TABLOID;
break;
case( DMPAPER_LEDGER ):
pSetupData->mePaperFormat = PAPER_LEDGER;
break;
case( DMPAPER_LEGAL ):
pSetupData->mePaperFormat = PAPER_LEGAL;
break;
case( DMPAPER_STATEMENT ):
pSetupData->mePaperFormat = PAPER_STATEMENT;
break;
case( DMPAPER_EXECUTIVE ):
pSetupData->mePaperFormat = PAPER_EXECUTIVE;
break;
case( DMPAPER_A3 ):
pSetupData->mePaperFormat = PAPER_A3;
break;
case( DMPAPER_A4 ):
pSetupData->mePaperFormat = PAPER_A4;
break;
case( DMPAPER_A5 ):
pSetupData->mePaperFormat = PAPER_A5;
break;
//See http://wiki.services.openoffice.org/wiki/DefaultPaperSize
//i.e.
//http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
//DMPAPER_B4 12 B4 (JIS) 257 x 364 mm
//http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
//also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
//matches our Excel filter's belief about the matching XlPaperSize
//enumeration.
//
//http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
////"DMPAPER_B4 12 B4 (JIS) 250 x 354"
//which is bogus as it's either JIS 257 × 364 or ISO 250 × 353
//(cmc)
case( DMPAPER_B4 ):
pSetupData->mePaperFormat = PAPER_B4_JIS;
break;
case( DMPAPER_B5 ):
pSetupData->mePaperFormat = PAPER_B5_JIS;
break;
case( DMPAPER_QUARTO ):
pSetupData->mePaperFormat = PAPER_QUARTO;
break;
case( DMPAPER_10X14 ):
pSetupData->mePaperFormat = PAPER_10x14;
break;
case( DMPAPER_NOTE ):
pSetupData->mePaperFormat = PAPER_LETTER;
break;
case( DMPAPER_ENV_9 ):
pSetupData->mePaperFormat = PAPER_ENV_9;
break;
case( DMPAPER_ENV_10 ):
pSetupData->mePaperFormat = PAPER_ENV_10;
break;
case( DMPAPER_ENV_11 ):
pSetupData->mePaperFormat = PAPER_ENV_11;
break;
case( DMPAPER_ENV_12 ):
pSetupData->mePaperFormat = PAPER_ENV_12;
break;
case( DMPAPER_ENV_14 ):
pSetupData->mePaperFormat = PAPER_ENV_14;
break;
case( DMPAPER_CSHEET ):
pSetupData->mePaperFormat = PAPER_C;
break;
case( DMPAPER_DSHEET ):
pSetupData->mePaperFormat = PAPER_D;
break;
case( DMPAPER_ESHEET ):
pSetupData->mePaperFormat = PAPER_E;
break;
case( DMPAPER_ENV_DL):
pSetupData->mePaperFormat = PAPER_ENV_DL;
break;
case( DMPAPER_ENV_C5):
pSetupData->mePaperFormat = PAPER_ENV_C5;
break;
case( DMPAPER_ENV_C3):
pSetupData->mePaperFormat = PAPER_ENV_C3;
break;
case( DMPAPER_ENV_C4):
pSetupData->mePaperFormat = PAPER_ENV_C4;
break;
case( DMPAPER_ENV_C6):
pSetupData->mePaperFormat = PAPER_ENV_C6;
break;
case( DMPAPER_ENV_C65):
pSetupData->mePaperFormat = PAPER_ENV_C65;
break;
case( DMPAPER_ENV_ITALY ):
pSetupData->mePaperFormat = PAPER_ENV_ITALY;
break;
case( DMPAPER_ENV_MONARCH ):
pSetupData->mePaperFormat = PAPER_ENV_MONARCH;
break;
case( DMPAPER_ENV_PERSONAL ):
pSetupData->mePaperFormat = PAPER_ENV_PERSONAL;
break;
case( DMPAPER_FANFOLD_US ):
pSetupData->mePaperFormat = PAPER_FANFOLD_US;
break;
case( DMPAPER_FANFOLD_STD_GERMAN ):
pSetupData->mePaperFormat = PAPER_FANFOLD_DE;
break;
case( DMPAPER_FANFOLD_LGL_GERMAN ):
pSetupData->mePaperFormat = PAPER_FANFOLD_LEGAL_DE;
break;
case( DMPAPER_ISO_B4 ):
pSetupData->mePaperFormat = PAPER_B4_ISO;
break;
case( DMPAPER_JAPANESE_POSTCARD ):
pSetupData->mePaperFormat = PAPER_POSTCARD_JP;
break;
case( DMPAPER_9X11 ):
pSetupData->mePaperFormat = PAPER_9x11;
break;
case( DMPAPER_10X11 ):
pSetupData->mePaperFormat = PAPER_10x11;
break;
case( DMPAPER_15X11 ):
pSetupData->mePaperFormat = PAPER_15x11;
break;
case( DMPAPER_ENV_INVITE ):
pSetupData->mePaperFormat = PAPER_ENV_INVITE;
break;
case( DMPAPER_A_PLUS ):
pSetupData->mePaperFormat = PAPER_A_PLUS;
break;
case( DMPAPER_B_PLUS ):
pSetupData->mePaperFormat = PAPER_B_PLUS;
break;
case( DMPAPER_LETTER_PLUS ):
pSetupData->mePaperFormat = PAPER_LETTER_PLUS;
break;
case( DMPAPER_A4_PLUS ):
pSetupData->mePaperFormat = PAPER_A4_PLUS;
break;
case( DMPAPER_A2 ):
pSetupData->mePaperFormat = PAPER_A2;
break;
case( DMPAPER_DBL_JAPANESE_POSTCARD ):
pSetupData->mePaperFormat = PAPER_DOUBLEPOSTCARD_JP;
break;
case( DMPAPER_A6 ):
pSetupData->mePaperFormat = PAPER_A6;
break;
case( DMPAPER_B6_JIS ):
pSetupData->mePaperFormat = PAPER_B6_JIS;
break;
case( DMPAPER_12X11 ):
pSetupData->mePaperFormat = PAPER_12x11;
break;
default:
pSetupData->mePaperFormat = PAPER_USER;
break;
}
}
if( nFlags & SAL_JOBSET_DUPLEXMODE )
{
DuplexMode eDuplex = DUPLEX_UNKNOWN;
if( (CHOOSE_DEVMODE(dmFields) & DM_DUPLEX) )
{
if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_SIMPLEX )
eDuplex = DUPLEX_OFF;
else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_VERTICAL )
eDuplex = DUPLEX_LONGEDGE;
else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_HORIZONTAL )
eDuplex = DUPLEX_SHORTEDGE;
}
pSetupData->meDuplexMode = eDuplex;
}
}
// -----------------------------------------------------------------------
static void ImplJobSetupToDevMode( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, sal_uLong nFlags )
{
if ( !pSetupData || !pSetupData->mpDriverData )
return;
DECLARE_DEVMODE( pSetupData );
// Orientation
if ( nFlags & SAL_JOBSET_ORIENTATION )
{
CHOOSE_DEVMODE(dmFields) |= DM_ORIENTATION;
if ( pSetupData->meOrientation == ORIENTATION_PORTRAIT )
CHOOSE_DEVMODE(dmOrientation) = DMORIENT_PORTRAIT;
else
CHOOSE_DEVMODE(dmOrientation) = DMORIENT_LANDSCAPE;
}
// PaperBin
if ( nFlags & SAL_JOBSET_PAPERBIN )
{
sal_uLong nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
if ( nCount && (nCount != GDI_ERROR) )
{
WORD* pBins = (WORD*)rtl_allocateZeroMemory(nCount*sizeof(WORD));
ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
CHOOSE_DEVMODE(dmFields) |= DM_DEFAULTSOURCE;
CHOOSE_DEVMODE(dmDefaultSource) = pBins[ pSetupData->mnPaperBin ];
rtl_freeMemory( pBins );
}
}
// PaperSize
if ( nFlags & SAL_JOBSET_PAPERSIZE )
{
CHOOSE_DEVMODE(dmFields) |= DM_PAPERSIZE;
CHOOSE_DEVMODE(dmPaperWidth) = 0;
CHOOSE_DEVMODE(dmPaperLength) = 0;
switch( pSetupData->mePaperFormat )
{
case( PAPER_A2 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A2;
break;
case( PAPER_A3 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A3;
break;
case( PAPER_A4 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4;
break;
case( PAPER_A5 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A5;
break;
case( PAPER_B4_ISO):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ISO_B4;
break;
case( PAPER_LETTER ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER;
break;
case( PAPER_LEGAL ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEGAL;
break;
case( PAPER_TABLOID ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_TABLOID;
break;
#if 0
//http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
//DMPAPER_ENV_B6 is documented as:
//"DMPAPER_ENV_B6 35 Envelope B6 176 x 125 mm"
//which is the wrong way around, it is surely 125 x 176, i.e.
//compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
//DMPAPER_ENV_B4 33 Envelope B4 250 x 353 mm
//DMPAPER_ENV_B5 34 Envelope B5 176 x 250 mm
case( PAPER_B6_ISO ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_B6;
break;
#endif
case( PAPER_ENV_C4 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C4;
break;
case( PAPER_ENV_C5 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C5;
break;
case( PAPER_ENV_C6 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C6;
break;
case( PAPER_ENV_C65 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C65;
break;
case( PAPER_ENV_DL ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_DL;
break;
case( PAPER_C ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_CSHEET;
break;
case( PAPER_D ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DSHEET;
break;
case( PAPER_E ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ESHEET;
break;
case( PAPER_EXECUTIVE ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_EXECUTIVE;
break;
case( PAPER_FANFOLD_LEGAL_DE ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_LGL_GERMAN;
break;
case( PAPER_ENV_MONARCH ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_MONARCH;
break;
case( PAPER_ENV_PERSONAL ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_PERSONAL;
break;
case( PAPER_ENV_9 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_9;
break;
case( PAPER_ENV_10 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_10;
break;
case( PAPER_ENV_11 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_11;
break;
case( PAPER_ENV_12 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_12;
break;
//See the comments on DMPAPER_B4 above
case( PAPER_B4_JIS ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B4;
break;
case( PAPER_B5_JIS ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B5;
break;
case( PAPER_B6_JIS ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B6_JIS;
break;
case( PAPER_LEDGER ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEDGER;
break;
case( PAPER_STATEMENT ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_STATEMENT;
break;
case( PAPER_10x14 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X14;
break;
case( PAPER_ENV_14 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_14;
break;
case( PAPER_ENV_C3 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C3;
break;
case( PAPER_ENV_ITALY ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_ITALY;
break;
case( PAPER_FANFOLD_US ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_US;
break;
case( PAPER_FANFOLD_DE ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_STD_GERMAN;
break;
case( PAPER_POSTCARD_JP ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_JAPANESE_POSTCARD;
break;
case( PAPER_9x11 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_9X11;
break;
case( PAPER_10x11 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X11;
break;
case( PAPER_15x11 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_15X11;
break;
case( PAPER_ENV_INVITE ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_INVITE;
break;
case( PAPER_A_PLUS ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A_PLUS;
break;
case( PAPER_B_PLUS ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B_PLUS;
break;
case( PAPER_LETTER_PLUS ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER_PLUS;
break;
case( PAPER_A4_PLUS ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4_PLUS;
break;
case( PAPER_DOUBLEPOSTCARD_JP ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DBL_JAPANESE_POSTCARD;
break;
case( PAPER_A6 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A6;
break;
case( PAPER_12x11 ):
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_12X11;
break;
default:
{
short nPaper = 0;
sal_uLong nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
WORD* pPapers = NULL;
sal_uLong nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
POINT* pPaperSizes = NULL;
DWORD nLandscapeAngle = ImplDeviceCaps( pPrinter, DC_ORIENTATION, NULL, pSetupData );
if ( nPaperCount && (nPaperCount != GDI_ERROR) )
{
pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
}
if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
{
pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
}
if ( (nPaperSizeCount == nPaperCount) && pPapers && pPaperSizes )
{
PaperInfo aInfo(pSetupData->mnPaperWidth, pSetupData->mnPaperHeight);
// compare paper formats and select a good match
for ( sal_uLong i = 0; i < nPaperCount; i++ )
{
if ( aInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)))
{
nPaper = pPapers[i];
break;
}
}
// If the printer supports landscape orientation, check paper sizes again
// with landscape orientation. This is necessary as a printer driver provides
// all paper sizes with portrait orientation only!!
if ( !nPaper && nLandscapeAngle != 0 )
{
PaperInfo aRotatedInfo(pSetupData->mnPaperHeight, pSetupData->mnPaperWidth);
for ( sal_uLong i = 0; i < nPaperCount; i++ )
{
if ( aRotatedInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)) )
{
nPaper = pPapers[i];
break;
}
}
}
if ( nPaper )
CHOOSE_DEVMODE(dmPaperSize) = nPaper;
}
if ( !nPaper )
{
CHOOSE_DEVMODE(dmFields) |= DM_PAPERLENGTH | DM_PAPERWIDTH;
CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_USER;
CHOOSE_DEVMODE(dmPaperWidth) = (short)(pSetupData->mnPaperWidth/10);
CHOOSE_DEVMODE(dmPaperLength) = (short)(pSetupData->mnPaperHeight/10);
}
if ( pPapers )
rtl_freeMemory(pPapers);
if ( pPaperSizes )
rtl_freeMemory(pPaperSizes);
break;
}
}
}
if( (nFlags & SAL_JOBSET_DUPLEXMODE) )
{
switch( pSetupData->meDuplexMode )
{
case DUPLEX_OFF:
CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
CHOOSE_DEVMODE(dmDuplex) = DMDUP_SIMPLEX;
break;
case DUPLEX_SHORTEDGE:
CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
CHOOSE_DEVMODE(dmDuplex) = DMDUP_HORIZONTAL;
break;
case DUPLEX_LONGEDGE:
CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
CHOOSE_DEVMODE(dmDuplex) = DMDUP_VERTICAL;
break;
case DUPLEX_UNKNOWN:
break;
}
}
}
// -----------------------------------------------------------------------
static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
LPCWSTR pDevice,
LPDEVMODEW pDevMode )
{
HDC hDC = 0;
CATCH_DRIVER_EX_BEGIN;
hDC = CreateICW( pDriver, pDevice, 0, pDevMode );
CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
return hDC;
}
static HDC ImplCreateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
{
HDC hDC = 0;
LPDEVMODEW pDevMode;
if ( pSetupData && pSetupData->mpDriverData )
pDevMode = SAL_DEVMODE_W( pSetupData );
else
pDevMode = NULL;
// #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
// pl: does this hold true for Unicode functions ?
if( pPrinter->maDriverName.getLength() > 2048 || pPrinter->maDeviceName.getLength() > 2048 )
return 0;
sal_Unicode pDriverName[ 4096 ];
sal_Unicode pDeviceName[ 4096 ];
memcpy( pDriverName, pPrinter->maDriverName.getStr(), pPrinter->maDriverName.getLength()*sizeof(sal_Unicode));
memset( pDriverName+pPrinter->maDriverName.getLength(), 0, 32 );
memcpy( pDeviceName, pPrinter->maDeviceName.getStr(), pPrinter->maDeviceName.getLength()*sizeof(sal_Unicode));
memset( pDeviceName+pPrinter->maDeviceName.getLength(), 0, 32 );
hDC = ImplCreateICW_WithCatch( reinterpret_cast< LPWSTR >(pDriverName),
reinterpret_cast< LPCWSTR >(pDeviceName),
pDevMode );
return hDC;
}
// -----------------------------------------------------------------------
static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC )
{
WinSalGraphics* pGraphics = new WinSalGraphics;
pGraphics->SetLayout( 0 );
pGraphics->mhDC = hDC;
pGraphics->mhWnd = 0;
pGraphics->mbPrinter = TRUE;
pGraphics->mbVirDev = FALSE;
pGraphics->mbWindow = FALSE;
pGraphics->mbScreen = FALSE;
ImplSalInitGraphics( pGraphics );
return pGraphics;
}
// -----------------------------------------------------------------------
static sal_Bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
{
HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
if ( !hNewDC )
return FALSE;
if ( pPrinter->mpGraphics )
{
ImplSalDeInitGraphics( pPrinter->mpGraphics );
DeleteDC( pPrinter->mpGraphics->mhDC );
delete pPrinter->mpGraphics;
}
pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hNewDC );
pPrinter->mhDC = hNewDC;
return TRUE;
}
// =======================================================================
SalInfoPrinter* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
ImplJobSetup* pSetupData )
{
WinSalInfoPrinter* pPrinter = new WinSalInfoPrinter;
if( ! pQueueInfo->mpSysData )
GetPrinterQueueState( pQueueInfo );
pPrinter->maDriverName = pQueueInfo->maDriver;
pPrinter->maDeviceName = pQueueInfo->maPrinterName;
pPrinter->maPortName = pQueueInfo->mpSysData ?
*pQueueInfo->mpSysData
: rtl::OUString();
// check if the provided setup data match the actual printer
ImplTestSalJobSetup( pPrinter, pSetupData, TRUE );
HDC hDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
if ( !hDC )
{
delete pPrinter;
return NULL;
}
pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hDC );
pPrinter->mhDC = hDC;
if ( !pSetupData->mpDriverData )
ImplUpdateSalJobSetup( pPrinter, pSetupData, FALSE, NULL );
ImplDevModeToJobSetup( pPrinter, pSetupData, SAL_JOBSET_ALL );
pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
return pPrinter;
}
// -----------------------------------------------------------------------
void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
{
delete pPrinter;
}
// =======================================================================
WinSalInfoPrinter::WinSalInfoPrinter() :
mpGraphics( NULL ),
mhDC( 0 ),
mbGraphics( FALSE )
{
m_bPapersInit = FALSE;
}
// -----------------------------------------------------------------------
WinSalInfoPrinter::~WinSalInfoPrinter()
{
if ( mpGraphics )
{
ImplSalDeInitGraphics( mpGraphics );
DeleteDC( mpGraphics->mhDC );
delete mpGraphics;
}
}
// -----------------------------------------------------------------------
void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
{
m_aPaperFormats.clear();
DWORD nCount = ImplDeviceCaps( this, DC_PAPERSIZE, NULL, pSetupData );
if( nCount == GDI_ERROR )
nCount = 0;
if( nCount )
{
POINT* pPaperSizes = (POINT*)rtl_allocateZeroMemory(nCount*sizeof(POINT));
ImplDeviceCaps( this, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
sal_Unicode* pNamesBuffer = (sal_Unicode*)rtl_allocateMemory(nCount*64*sizeof(sal_Unicode));
ImplDeviceCaps( this, DC_PAPERNAMES, (BYTE*)pNamesBuffer, pSetupData );
for( DWORD i = 0; i < nCount; ++i )
{
PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
m_aPaperFormats.push_back( aInfo );
}
rtl_freeMemory( pNamesBuffer );
rtl_freeMemory( pPaperSizes );
}
m_bPapersInit = true;
}
// -----------------------------------------------------------------------
int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
{
int nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
if( nRet != sal::static_int_cast<int>( GDI_ERROR ) )
return nRet * 10;
else
return 900; // guess
}
// -----------------------------------------------------------------------
SalGraphics* WinSalInfoPrinter::GetGraphics()
{
if ( mbGraphics )
return NULL;
if ( mpGraphics )
mbGraphics = TRUE;
return mpGraphics;
}
// -----------------------------------------------------------------------
void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
{
mbGraphics = FALSE;
}
// -----------------------------------------------------------------------
sal_Bool WinSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pSetupData )
{
if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, static_cast<WinSalFrame*>(pFrame) ) )
{
ImplDevModeToJobSetup( this, pSetupData, SAL_JOBSET_ALL );
return ImplUpdateSalPrnIC( this, pSetupData );
}
return FALSE;
}
// -----------------------------------------------------------------------
sal_Bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
{
if ( !ImplTestSalJobSetup( this, pSetupData, FALSE ) )
return FALSE;
return ImplUpdateSalPrnIC( this, pSetupData );
}
// -----------------------------------------------------------------------
sal_Bool WinSalInfoPrinter::SetData( sal_uLong nFlags, ImplJobSetup* pSetupData )
{
ImplJobSetupToDevMode( this, pSetupData, nFlags );
if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, NULL ) )
{
ImplDevModeToJobSetup( this, pSetupData, nFlags );
return ImplUpdateSalPrnIC( this, pSetupData );
}
return FALSE;
}
// -----------------------------------------------------------------------
sal_uLong WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
{
DWORD nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
if ( nRet && (nRet != GDI_ERROR) )
return nRet;
else
return 0;
}
// -----------------------------------------------------------------------
rtl::OUString WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pSetupData, sal_uLong nPaperBin )
{
XubString aPaperBinName;
DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, NULL, pSetupData );
if ( (nPaperBin < nBins) && (nBins != GDI_ERROR) )
{
sal_Unicode* pBuffer = new sal_Unicode[nBins*24];
DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, (BYTE*)pBuffer, pSetupData );
if ( nRet && (nRet != GDI_ERROR) )
aPaperBinName = pBuffer + (nPaperBin*24);
delete [] pBuffer;
}
return aPaperBinName;
}
// -----------------------------------------------------------------------
sal_uLong WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, sal_uInt16 nType )
{
DWORD nRet;
switch ( nType )
{
case PRINTER_CAPABILITIES_SUPPORTDIALOG:
return TRUE;
case PRINTER_CAPABILITIES_COPIES:
nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
if ( nRet && (nRet != GDI_ERROR) )
return nRet;
return 0;
case PRINTER_CAPABILITIES_COLLATECOPIES:
nRet = ImplDeviceCaps( this, DC_COLLATE, NULL, pSetupData );
if ( nRet && (nRet != GDI_ERROR) )
{
nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
if ( nRet && (nRet != GDI_ERROR) )
return nRet;
}
return 0;
case PRINTER_CAPABILITIES_SETORIENTATION:
nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
if ( nRet && (nRet != GDI_ERROR) )
return TRUE;
return FALSE;
case PRINTER_CAPABILITIES_SETPAPERBIN:
nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
if ( nRet && (nRet != GDI_ERROR) )
return TRUE;
return FALSE;
case PRINTER_CAPABILITIES_SETPAPERSIZE:
case PRINTER_CAPABILITIES_SETPAPER:
nRet = ImplDeviceCaps( this, DC_PAPERS, NULL, pSetupData );
if ( nRet && (nRet != GDI_ERROR) )
return TRUE;
return FALSE;
}
return 0;
}
// -----------------------------------------------------------------------
void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
long& rOutWidth, long& rOutHeight,
long& rPageOffX, long& rPageOffY,
long& rPageWidth, long& rPageHeight )
{
HDC hDC = mhDC;
rOutWidth = GetDeviceCaps( hDC, HORZRES );
rOutHeight = GetDeviceCaps( hDC, VERTRES );
rPageOffX = GetDeviceCaps( hDC, PHYSICALOFFSETX );
rPageOffY = GetDeviceCaps( hDC, PHYSICALOFFSETY );
rPageWidth = GetDeviceCaps( hDC, PHYSICALWIDTH );
rPageHeight = GetDeviceCaps( hDC, PHYSICALHEIGHT );
}
// =======================================================================
SalPrinter* WinSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
{
WinSalPrinter* pPrinter = new WinSalPrinter;
pPrinter->mpInfoPrinter = static_cast<WinSalInfoPrinter*>(pInfoPrinter);
return pPrinter;
}
// -----------------------------------------------------------------------
void WinSalInstance::DestroyPrinter( SalPrinter* pPrinter )
{
delete pPrinter;
}
// =======================================================================
BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
{
SalData* pSalData = GetSalData();
WinSalPrinter* pPrinter;
sal_Bool bWhile = TRUE;
int i = 0;
do
{
// Messages verarbeiten
MSG aMsg;
if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &aMsg );
ImplDispatchMessage( &aMsg );
i++;
if ( i > 15 )
bWhile = FALSE;
}
else
bWhile = FALSE;
pPrinter = pSalData->mpFirstPrinter;
while ( pPrinter )
{
if( pPrinter->mhDC == hPrnDC )
break;
pPrinter = pPrinter->mpNextPrinter;
}
if ( !pPrinter || pPrinter->mbAbort )
return FALSE;
}
while ( bWhile );
return TRUE;
}
// -----------------------------------------------------------------------
static LPDEVMODEW ImplSalSetCopies( LPDEVMODEW pDevMode, sal_uLong nCopies, sal_Bool bCollate )
{
LPDEVMODEW pNewDevMode = pDevMode;
if ( pDevMode && (nCopies > 1) )
{
if ( nCopies > 32765 )
nCopies = 32765;
sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
pNewDevMode = (LPDEVMODEW)rtl_allocateMemory( nDevSize );
memcpy( pNewDevMode, pDevMode, nDevSize );
pDevMode = pNewDevMode;
pDevMode->dmFields |= DM_COPIES;
pDevMode->dmCopies = (short)(sal_uInt16)nCopies;
pDevMode->dmFields |= DM_COLLATE;
if ( bCollate )
pDevMode->dmCollate = DMCOLLATE_TRUE;
else
pDevMode->dmCollate = DMCOLLATE_FALSE;
}
return pNewDevMode;
}
// -----------------------------------------------------------------------
WinSalPrinter::WinSalPrinter() :
mpGraphics( NULL ),
mpInfoPrinter( NULL ),
mpNextPrinter( NULL ),
mhDC( 0 ),
mnError( 0 ),
mnCopies( 0 ),
mbCollate( FALSE ),
mbAbort( FALSE ),
mbValid( true )
{
SalData* pSalData = GetSalData();
// insert printer in printerlist
mpNextPrinter = pSalData->mpFirstPrinter;
pSalData->mpFirstPrinter = this;
}
// -----------------------------------------------------------------------
WinSalPrinter::~WinSalPrinter()
{
SalData* pSalData = GetSalData();
// release DC if there is one still around because of AbortJob
HDC hDC = mhDC;
if ( hDC )
{
if ( mpGraphics )
{
ImplSalDeInitGraphics( mpGraphics );
delete mpGraphics;
}
DeleteDC( hDC );
}
// remove printer from printerlist
if ( this == pSalData->mpFirstPrinter )
pSalData->mpFirstPrinter = mpNextPrinter;
else
{
WinSalPrinter* pTempPrinter = pSalData->mpFirstPrinter;
while( pTempPrinter->mpNextPrinter != this )
pTempPrinter = pTempPrinter->mpNextPrinter;
pTempPrinter->mpNextPrinter = mpNextPrinter;
}
mbValid = false;
}
// -----------------------------------------------------------------------
void WinSalPrinter::markInvalid()
{
mbValid = false;
}
// -----------------------------------------------------------------------
// need wrappers for StarTocW/A to use structured exception handling
// since SEH does not mix with standard exception handling's cleanup
static int lcl_StartDocW( HDC hDC, DOCINFOW* pInfo, WinSalPrinter* pPrt )
{
(void) pPrt;
int nRet = 0;
CATCH_DRIVER_EX_BEGIN;
nRet = ::StartDocW( hDC, pInfo );
CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
return nRet;
}
sal_Bool WinSalPrinter::StartJob( const rtl::OUString* pFileName,
const rtl::OUString& rJobName,
const rtl::OUString&,
sal_uLong nCopies,
bool bCollate,
bool /*bDirect*/,
ImplJobSetup* pSetupData )
{
mnError = 0;
mbAbort = FALSE;
mnCopies = nCopies;
mbCollate = bCollate;
LPDEVMODEW pOrgDevModeW = NULL;
LPDEVMODEW pDevModeW = NULL;
HDC hDC = 0;
if ( pSetupData && pSetupData->mpDriverData )
{
pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
pDevModeW = ImplSalSetCopies( pOrgDevModeW, nCopies, bCollate );
}
// #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
sal_Unicode aDrvBuf[4096];
sal_Unicode aDevBuf[4096];
memcpy( aDrvBuf, mpInfoPrinter->maDriverName.getStr(), (mpInfoPrinter->maDriverName.getLength()+1)*sizeof(sal_Unicode));
memcpy( aDevBuf, mpInfoPrinter->maDeviceName.getStr(), (mpInfoPrinter->maDeviceName.getLength()+1)*sizeof(sal_Unicode));
hDC = CreateDCW( reinterpret_cast<LPCWSTR>(aDrvBuf),
reinterpret_cast<LPCWSTR>(aDevBuf),
NULL,
pDevModeW );
if ( pDevModeW != pOrgDevModeW )
rtl_freeMemory( pDevModeW );
if ( !hDC )
{
mnError = SAL_PRINTER_ERROR_GENERALERROR;
return FALSE;
}
// make sure mhDC is set before the printer driver may call our abortproc
mhDC = hDC;
if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
{
mnError = SAL_PRINTER_ERROR_GENERALERROR;
return FALSE;
}
mnError = 0;
mbAbort = FALSE;
// Wegen Telocom Balloon Fax-Treiber, der uns unsere Messages
// ansonsten oefters schickt, versuchen wir vorher alle
// zu verarbeiten und dann eine Dummy-Message reinstellen
sal_Bool bWhile = TRUE;
int i = 0;
do
{
// Messages verarbeiten
MSG aMsg;
if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &aMsg );
ImplDispatchMessage( &aMsg );
i++;
if ( i > 15 )
bWhile = FALSE;
}
else
bWhile = FALSE;
}
while ( bWhile );
ImplPostMessage( GetSalData()->mpFirstInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0 );
// bring up a file choser if printing to file port but no file name given
OUString aOutFileName;
if( mpInfoPrinter->maPortName.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "FILE:" ) ) && !(pFileName && !pFileName->isEmpty()) )
{
uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
uno::Reference< XFilePicker3 > xFilePicker = FilePicker::createDefault(xContext);
uno::Reference< XInitialization > xInit( xFilePicker, UNO_QUERY );
uno::Reference< XFilterManager > xFilterMgr( xFilePicker, UNO_QUERY );
if( xInit.is() && xFilePicker.is() && xFilterMgr.is() )
{
Sequence< Any > aServiceType( 1 );
aServiceType[0] <<= TemplateDescription::FILESAVE_SIMPLE;
xInit->initialize( aServiceType );
if( xFilePicker->execute() == ExecutableDialogResults::OK )
{
Sequence< OUString > aPathSeq( xFilePicker->getFiles() );
INetURLObject aObj( aPathSeq[0] );
// we're using ansi calls (StartDocA) so convert the string
aOutFileName = aObj.PathToFileName();
}
else
{
mnError = SAL_PRINTER_ERROR_ABORT;
return FALSE;
}
}
}
DOCINFOW aInfo;
memset( &aInfo, 0, sizeof( DOCINFOW ) );
aInfo.cbSize = sizeof( aInfo );
aInfo.lpszDocName = (LPWSTR)rJobName.getStr();
if ( pFileName || aOutFileName.getLength() )
{
if ( (pFileName && !pFileName->isEmpty()) || aOutFileName.getLength() )
{
aInfo.lpszOutput = (LPWSTR)( (pFileName && !pFileName->isEmpty()) ? pFileName->getStr() : aOutFileName.getStr());
}
else
aInfo.lpszOutput = L"FILE:";
}
else
aInfo.lpszOutput = NULL;
// start Job
int nRet = lcl_StartDocW( hDC, &aInfo, this );
if ( nRet <= 0 )
{
long nError = GetLastError();
if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
mnError = SAL_PRINTER_ERROR_ABORT;
else
mnError = SAL_PRINTER_ERROR_GENERALERROR;
return FALSE;
}
return TRUE;
}
// -----------------------------------------------------------------------
sal_Bool WinSalPrinter::EndJob()
{
HDC hDC = mhDC;
if ( isValid() && hDC )
{
if ( mpGraphics )
{
ImplSalDeInitGraphics( mpGraphics );
delete mpGraphics;
mpGraphics = NULL;
}
// #i54419# Windows fax printer brings up a dialog in EndDoc
// which text previously copied in soffice process can be
// pasted to -> deadlock due to mutex not released.
// it should be safe to release the yield mutex over the EndDoc
// call, however the real solution is supposed to be the threading
// framework yet to come.
volatile sal_uLong nAcquire = GetSalData()->mpFirstInstance->ReleaseYieldMutex();
CATCH_DRIVER_EX_BEGIN;
if( ::EndDoc( hDC ) <= 0 )
GetLastError();
CATCH_DRIVER_EX_END( "exception in EndDoc", this );
GetSalData()->mpFirstInstance->AcquireYieldMutex( nAcquire );
DeleteDC( hDC );
mhDC = 0;
}
return TRUE;
}
// -----------------------------------------------------------------------
sal_Bool WinSalPrinter::AbortJob()
{
mbAbort = TRUE;
// Abort asyncron ausloesen
HDC hDC = mhDC;
if ( hDC )
{
SalData* pSalData = GetSalData();
ImplPostMessage( pSalData->mpFirstInstance->mhComWnd,
SAL_MSG_PRINTABORTJOB, (WPARAM)hDC, 0 );
}
return TRUE;
}
// -----------------------------------------------------------------------
void ImplSalPrinterAbortJobAsync( HDC hPrnDC )
{
SalData* pSalData = GetSalData();
WinSalPrinter* pPrinter = pSalData->mpFirstPrinter;
// Feststellen, ob Printer noch existiert
while ( pPrinter )
{
if ( pPrinter->mhDC == hPrnDC )
break;
pPrinter = pPrinter->mpNextPrinter;
}
// Wenn Printer noch existiert, dann den Job abbrechen
if ( pPrinter )
{
HDC hDC = pPrinter->mhDC;
if ( hDC )
{
if ( pPrinter->mpGraphics )
{
ImplSalDeInitGraphics( pPrinter->mpGraphics );
delete pPrinter->mpGraphics;
pPrinter->mpGraphics = NULL;
}
CATCH_DRIVER_EX_BEGIN;
::AbortDoc( hDC );
CATCH_DRIVER_EX_END( "exception in AbortDoc", pPrinter );
DeleteDC( hDC );
pPrinter->mhDC = 0;
}
}
}
// -----------------------------------------------------------------------
SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, sal_Bool bNewJobData )
{
if( ! isValid() || mhDC == 0 )
return NULL;
HDC hDC = mhDC;
if ( pSetupData && pSetupData->mpDriverData && bNewJobData )
{
LPDEVMODEW pOrgDevModeW;
LPDEVMODEW pDevModeW;
pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
pDevModeW = ImplSalSetCopies( pOrgDevModeW, mnCopies, mbCollate );
ResetDCW( hDC, pDevModeW );
if ( pDevModeW != pOrgDevModeW )
rtl_freeMemory( pDevModeW );
}
volatile int nRet = 0;
CATCH_DRIVER_EX_BEGIN;
nRet = ::StartPage( hDC );
CATCH_DRIVER_EX_END( "exception in StartPage", this );
if ( nRet <= 0 )
{
GetLastError();
mnError = SAL_PRINTER_ERROR_GENERALERROR;
return NULL;
}
// Hack to work around old PostScript printer drivers optimizing away empty pages
// TODO: move into ImplCreateSalPrnGraphics()?
HPEN hTempPen = SelectPen( hDC, GetStockPen( NULL_PEN ) );
HBRUSH hTempBrush = SelectBrush( hDC, GetStockBrush( NULL_BRUSH ) );
WIN_Rectangle( hDC, -8000, -8000, -7999, -7999 );
SelectPen( hDC, hTempPen );
SelectBrush( hDC, hTempBrush );
mpGraphics = ImplCreateSalPrnGraphics( hDC );
return mpGraphics;
}
// -----------------------------------------------------------------------
sal_Bool WinSalPrinter::EndPage()
{
HDC hDC = mhDC;
if ( hDC && mpGraphics )
{
ImplSalDeInitGraphics( mpGraphics );
delete mpGraphics;
mpGraphics = NULL;
}
if( ! isValid() )
return FALSE;
volatile int nRet = 0;
CATCH_DRIVER_EX_BEGIN;
nRet = ::EndPage( hDC );
CATCH_DRIVER_EX_END( "exception in EndPage", this );
if ( nRet > 0 )
return TRUE;
else
{
GetLastError();
mnError = SAL_PRINTER_ERROR_GENERALERROR;
return FALSE;
}
}
// -----------------------------------------------------------------------
sal_uLong WinSalPrinter::GetErrorCode()
{
return mnError;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */