Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/win/gdi/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 58 kB image not shown  

Quelle  salprn.cxx   Sprache: C

 
/* -*- 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 .
 */


#include <sal/config.h>
#include <sal/log.hxx>
#include <osl/diagnose.h>

#include <memory>
#include <vector>
#include <string.h>

#include <svsys.h>

#include <osl/module.h>
#include <o3tl/char16_t2wchar_t.hxx>

#include <tools/urlobj.hxx>

#include <vcl/weld.hxx>
#include <vcl/QueueInfo.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 <comphelper/windowsdebugoutput.hxx>

#include <vcl/threadex.hxx>

#include <malloc.h>

#include <winspool.h>
#if defined GetDefaultPrinter
#  undef GetDefaultPrinter
#endif
#if defined SetPrinterData
#  undef SetPrinterData
#endif

#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 );                                                   \
    }

using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::ui::dialogs;

static DEVMODEW const * SAL_DEVMODE_W( const ImplJobSetup* pSetupData )
{
    DEVMODEW const * pRet = nullptr;
    SalDriverData const * pDrv = reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData());
    if( pSetupData->GetDriverDataLen() >= sizeof(DEVMODEW)+sizeof(SalDriverData)-1 )
        pRet = reinterpret_cast<DEVMODEW const *>((pSetupData->GetDriverData()) + (pDrv->mnDriverOffset));
    return pRet;
}

static PrintQueueFlags ImplWinQueueStatusToSal( DWORD nWinStatus )
{
    PrintQueueFlags nStatus = PrintQueueFlags::NONE;
    if ( nWinStatus & PRINTER_STATUS_PAUSED )
        nStatus |= PrintQueueFlags::Paused;
    if ( nWinStatus & PRINTER_STATUS_ERROR )
        nStatus |= PrintQueueFlags::Error;
    if ( nWinStatus & PRINTER_STATUS_PENDING_DELETION )
        nStatus |= PrintQueueFlags::PendingDeletion;
    if ( nWinStatus & PRINTER_STATUS_PAPER_JAM )
        nStatus |= PrintQueueFlags::PaperJam;
    if ( nWinStatus & PRINTER_STATUS_PAPER_OUT )
        nStatus |= PrintQueueFlags::PaperOut;
    if ( nWinStatus & PRINTER_STATUS_MANUAL_FEED )
        nStatus |= PrintQueueFlags::ManualFeed;
    if ( nWinStatus & PRINTER_STATUS_PAPER_PROBLEM )
        nStatus |= PrintQueueFlags::PaperProblem;
    if ( nWinStatus & PRINTER_STATUS_OFFLINE )
        nStatus |= PrintQueueFlags::Offline;
    if ( nWinStatus & PRINTER_STATUS_IO_ACTIVE )
        nStatus |= PrintQueueFlags::IOActive;
    if ( nWinStatus & PRINTER_STATUS_BUSY )
        nStatus |= PrintQueueFlags::Busy;
    if ( nWinStatus & PRINTER_STATUS_PRINTING )
        nStatus |= PrintQueueFlags::Printing;
    if ( nWinStatus & PRINTER_STATUS_OUTPUT_BIN_FULL )
        nStatus |= PrintQueueFlags::OutputBinFull;
    if ( nWinStatus & PRINTER_STATUS_WAITING )
        nStatus |= PrintQueueFlags::Waiting;
    if ( nWinStatus & PRINTER_STATUS_PROCESSING )
        nStatus |= PrintQueueFlags::Processing;
    if ( nWinStatus & PRINTER_STATUS_INITIALIZING )
        nStatus |= PrintQueueFlags::Initializing;
    if ( nWinStatus & PRINTER_STATUS_WARMING_UP )
        nStatus |= PrintQueueFlags::WarmingUp;
    if ( nWinStatus & PRINTER_STATUS_TONER_LOW )
        nStatus |= PrintQueueFlags::TonerLow;
    if ( nWinStatus & PRINTER_STATUS_NO_TONER )
        nStatus |= PrintQueueFlags::NoToner;
    if ( nWinStatus & PRINTER_STATUS_PAGE_PUNT )
        nStatus |= PrintQueueFlags::PagePunt;
    if ( nWinStatus & PRINTER_STATUS_USER_INTERVENTION )
        nStatus |= PrintQueueFlags::UserIntervention;
    if ( nWinStatus & PRINTER_STATUS_OUT_OF_MEMORY )
        nStatus |= PrintQueueFlags::OutOfMemory;
    if ( nWinStatus & PRINTER_STATUS_DOOR_OPEN )
        nStatus |= PrintQueueFlags::DoorOpen;
    if ( nWinStatus & PRINTER_STATUS_SERVER_UNKNOWN )
        nStatus |= PrintQueueFlags::StatusUnknown;
    if ( nWinStatus & PRINTER_STATUS_POWER_SAVE )
        nStatus |= PrintQueueFlags::PowerSave;
    if ( nStatus == PrintQueueFlags::NONE && !(nWinStatus & PRINTER_STATUS_NOT_AVAILABLE) )
        nStatus |= PrintQueueFlags::Ready;
    return nStatus;
}


void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
{
    DWORD           i;
    DWORD           nBytes = 0;
    DWORD           nInfoPrn4 = 0;
    EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, nullptr, 0, &nBytes,&nbsp;&nInfoPrn4 );
    if ( !nBytes )
        return;

    PRINTER_INFO_4W* pWinInfo4 = static_cast<PRINTER_INFO_4W*>(std::malloc( nBytes ));
    assert(pWinInfo4 && "Don't handle OOM conditions");
    if ( EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, reinterpret_cast<LPBYTE>(pWinInfo4), nBytes, &nBytes, &nInfoPrn4 ) )
    {
        for ( i = 0; i < nInfoPrn4; i++ )
        {
            std::unique_ptr<SalPrinterQueueInfo> pInfo(new SalPrinterQueueInfo);
            pInfo->maPrinterName = o3tl::toU(pWinInfo4[i].pPrinterName);
            pInfo->mnStatus      = PrintQueueFlags::NONE;
            pInfo->mnJobs        = 0;
            pList->Add( std::move(pInfo) );
        }
    }
    std::free( pWinInfo4 );
}

void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
{
    HANDLE hPrinter = nullptr;
    LPWSTR pPrnName = const_cast<LPWSTR>(o3tl::toW(pInfo->maPrinterName.getStr()));
    if( !OpenPrinterW( pPrnName, &hPrinter, nullptr ) )
        return;

    DWORD               nBytes = 0;
    GetPrinterW( hPrinter, 2, nullptr, 0, &nBytes );
    if( nBytes )
    {
        PRINTER_INFO_2W* pWinInfo2 = static_cast<PRINTER_INFO_2W*>(std::malloc(nBytes));
        assert(pWinInfo2 && "Don't handle OOM conditions");
        if( GetPrinterW( hPrinter, 2, reinterpret_cast<LPBYTE>(pWinInfo2), nBytes, &nBytes ) )
        {
            if( pWinInfo2->pDriverName )
                pInfo->maDriver = o3tl::toU(pWinInfo2->pDriverName);
            OUString aPortName;
            if ( pWinInfo2->pPortName )
                aPortName = o3tl::toU(pWinInfo2->pPortName);
            // pLocation can be 0 (the Windows docu doesn't describe this)
            if ( pWinInfo2->pLocation && *pWinInfo2->pLocation )
                pInfo->maLocation = o3tl::toU(pWinInfo2->pLocation);
            else
                pInfo->maLocation = aPortName;
            // pComment can be 0 (the Windows docu doesn't describe this)
            if ( pWinInfo2->pComment )
                pInfo->maComment = o3tl::toU(pWinInfo2->pComment);
            pInfo->mnStatus      = ImplWinQueueStatusToSal( pWinInfo2->Status );
            pInfo->mnJobs        = pWinInfo2->cJobs;
            if( ! pInfo->moPortName )
                pInfo->moPortName = aPortName;
        }
        std::free(pWinInfo2);
    }
    ClosePrinter( hPrinter );
}

OUString WinSalInstance::GetDefaultPrinter()
{
    DWORD   nChars = 0;
    GetDefaultPrinterW( nullptr, &nChars );
    if( nChars )
    {
        std::vector<WCHAR> pStr(nChars);
        if (GetDefaultPrinterW(pStr.data(), &nChars))
            return OUString(o3tl::toU(pStr.data()));
    }
    return OUString();
}

static DWORD ImplDeviceCaps( WinSalInfoPrinter const * pPrinter, WORD nCaps,
                             BYTE* pOutput, const ImplJobSetup* pSetupData )
{
    DEVMODEW const * pDevMode;
    if ( !pSetupData || !pSetupData->GetDriverData() )
        pDevMode = nullptr;
    else
        pDevMode = SAL_DEVMODE_W( pSetupData );

    return DeviceCapabilitiesW( o3tl::toW(pPrinter->maDeviceName.getStr()),
                                o3tl::toW(pPrinter->maPortName.getStr()),
                                nCaps, reinterpret_cast<LPWSTR>(pOutput), pDevMode );
}

static bool ImplTestSalJobSetup( WinSalInfoPrinter const * pPrinter,
                                 ImplJobSetup* pSetupData, bool bDelete )
{
    if ( !pSetupData || !pSetupData->GetDriverData() )
        return false;

    // 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 const * pDevModeW = nullptr;
    LONG dmSpecVersion = -1;
    LONG dmDriverVersion = -1;
    SalDriverData const * pSalDriverData = reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData());
    BYTE const * pDriverData = reinterpret_cast<BYTE const *>(pSalDriverData) + pSalDriverData->mnDriverOffset;
    pDevModeW = reinterpret_cast<DEVMODEW const *>(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 = const_cast<LPWSTR>(o3tl::toW(pPrinter->maDeviceName.getStr()));
        if ( !OpenPrinterW( pPrinterNameW, &hPrn, nullptr ) )
            return false;

        // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
        if( hPrn == HGDI_ERROR )
            return false;

        nSysJobSize = DocumentPropertiesW( nullptr, hPrn,
                                           pPrinterNameW,
                                           nullptr, nullptr, 0 );

        if( nSysJobSize < 0 )
        {
            ClosePrinter( hPrn );
            return false;
        }
        DEVMODEW *pBuffer = static_cast<DEVMODEW*>(_alloca( nSysJobSize ));
        LONG nRet = DocumentPropertiesW( nullptr, hPrn,
                                    pPrinterNameW,
                                    pBuffer, nullptr, 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 = pBuffer->dmSpecVersion;
        dmDriverVersion = pBuffer->dmDriverVersion;

        ClosePrinter( hPrn );
    }
    SalDriverData const * pSetupDriverData = reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData());
    if ( (pSetupData->GetSystem() == JOBSETUP_SYSTEM_WINDOWS) &&
         (pPrinter && pPrinter->maDriverName == pSetupData->GetDriver()) &&
         (pSetupData->GetDriverDataLen() > sizeof( SalDriverData )) &&
         static_cast<tools::Long>(pSetupData->GetDriverDataLen() - pSetupDriverData->mnDriverOffset) == nSysJobSize &&
         pSetupDriverData->mnSysSignature == SAL_DRIVERDATA_SYSSIGN )
    {
        if( pDevModeW &&
            (dmSpecVersion == pDevModeW->dmSpecVersion) &&
            (dmDriverVersion == pDevModeW->dmDriverVersion) )
            return true;
    }
    if ( bDelete )
    {
        pSetupData->SetDriverData( nullptr, 0 );
    }

    return false;
}

static bool ImplUpdateSalJobSetup( WinSalInfoPrinter const * pPrinter, ImplJobSetup* pSetupData,
                                   bool bIn, weld::Window* pVisibleDlgParent )
{
    HANDLE hPrn;
    LPWSTR pPrinterNameW = const_cast<LPWSTR>(o3tl::toW(pPrinter->maDeviceName.getStr()));
    if ( !OpenPrinterW( pPrinterNameW, &hPrn, nullptr ) )
        return false;
    // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
    if( hPrn == HGDI_ERROR )
        return false;

    LONG            nRet;
    HWND            hWnd = nullptr;
    DWORD           nMode = DM_OUT_BUFFER;
    std::unique_ptr<sal_uInt8[]> pDriverData;
    SalDriverData*  pOutBuffer = nullptr;
    BYTE const *    pInBuffer = nullptr;

    LONG nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
                                       pPrinterNameW,
                                       nullptr, nullptr, 0 );
    if ( nSysJobSize < 0 )
    {
        ClosePrinter( hPrn );
        return false;
    }

    // make Outputbuffer
    const std::size_t nDriverDataLen = sizeof(SalDriverData) + nSysJobSize-1;
    pDriverData = std::make_unique<sal_uInt8[]>( nDriverDataLen );
    memset(pDriverData.get(), 0, nDriverDataLen);
    pOutBuffer = reinterpret_cast<SalDriverData*>(pDriverData.get());
    pOutBuffer->mnSysSignature  = SAL_DRIVERDATA_SYSSIGN;
    // calculate driver data offset including structure padding
    pOutBuffer->mnDriverOffset  = sal::static_int_cast<sal_uInt16>(
                                    reinterpret_cast<char*>(pOutBuffer->maDriverData) -
                                    reinterpret_cast<char*>(pOutBuffer) );

    // check if we have a suitable input buffer
    if ( bIn && ImplTestSalJobSetup( pPrinter, pSetupData, false ) )
    {
        pInBuffer = pSetupData->GetDriverData() + reinterpret_cast<SalDriverData const *>(pSetupData->GetDriverData())->mnDriverOffset;
        nMode |= DM_IN_BUFFER;
    }

    // check if the dialog should be shown
    if ( pVisibleDlgParent )
    {
        hWnd = pVisibleDlgParent->get_system_data().hWnd;
        nMode |= DM_IN_PROMPT;
    }

    // Release mutex, in the other case we don't get paints and so on
    sal_uInt32 nMutexCount = 0;
    WinSalInstance* pInst = GetSalData()->mpInstance;
    if ( pInst && pVisibleDlgParent )
        nMutexCount = pInst->ReleaseYieldMutex(true);

    BYTE* pOutDevMode = reinterpret_cast<BYTE*>(pOutBuffer) + pOutBuffer->mnDriverOffset;
    nRet = DocumentPropertiesW( hWnd, hPrn,
                                pPrinterNameW,
                                reinterpret_cast<LPDEVMODEW>(pOutDevMode), reinterpret_cast<LPDEVMODEW>(const_cast<BYTE *>(pInBuffer)), nMode );
    if ( pInst && pVisibleDlgParent )
        pInst->AcquireYieldMutex( nMutexCount );
    ClosePrinter( hPrn );

    if( (nRet < 0) || (pVisibleDlgParent && (nRet == IDCANCEL)) )
        return false;

    // fill up string buffers with 0 so they do not influence a JobSetup's memcmp
    ifreinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmSize >= 64 )
    {
        sal_Int32 nLen = rtl_ustr_getLength( o3tl::toU(reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmDeviceName) );
        if ( sal::static_int_cast<size_t>(nLen) < SAL_N_ELEMENTS( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmDeviceName ) )
            memset( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmDeviceName+nLen, 0, sizeofreinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmDeviceName )-(nLen*sizeof(sal_Unicode)) );
    }
    ifreinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmSize >= 166 )
    {
        sal_Int32 nLen = rtl_ustr_getLength( o3tl::toU(reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmFormName) );
        if ( sal::static_int_cast<size_t>(nLen) < SAL_N_ELEMENTS( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmFormName ) )
            memset( reinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmFormName+nLen, 0, sizeofreinterpret_cast<LPDEVMODEW>(pOutDevMode)->dmFormName )-(nLen*sizeof(sal_Unicode)) );
    }

    // update data
    pSetupData->SetDriverData(std::move(pDriverData), nDriverDataLen);
    pSetupData->SetSystem( JOBSETUP_SYSTEM_WINDOWS );

    return true;
}

static void ImplDevModeToJobSetup( WinSalInfoPrinter const * pPrinter, ImplJobSetup* pSetupData, JobSetFlags nFlags )
{
    if ( !pSetupData || !pSetupData->GetDriverData() )
        return;

    DEVMODEW const * pDevModeW = SAL_DEVMODE_W(pSetupData);
    if( pDevModeW == nullptr )
        return;

    // Orientation
    if ( nFlags & JobSetFlags::ORIENTATION )
    {
        if ( pDevModeW->dmOrientation == DMORIENT_PORTRAIT )
            pSetupData->SetOrientation( Orientation::Portrait );
        else if ( pDevModeW->dmOrientation == DMORIENT_LANDSCAPE )
            pSetupData->SetOrientation( Orientation::Landscape );
    }

    // PaperBin
    if ( nFlags & JobSetFlags::PAPERBIN )
    {
        const DWORD nCount = ImplDeviceCaps( pPrinter, DC_BINS, nullptr, pSetupData );

        if ( nCount && (nCount != GDI_ERROR) )
        {
            WORD* pBins = static_cast<WORD*>(rtl_allocateZeroMemory( nCount*sizeof(WORD) ));
            ImplDeviceCaps( pPrinter, DC_BINS, reinterpret_cast<BYTE*>(pBins), pSetupData );
            pSetupData->SetPaperBin( 0 );

            // search the right bin and assign index to mnPaperBin
            for( DWORD i = 0; i < nCount; ++i )
            {
                if( pDevModeW->dmDefaultSource == pBins[ i ] )
                {
                    pSetupData->SetPaperBin( static_cast<sal_uInt16>(i) );
                    break;
                }
            }

            std::free( pBins );
        }
    }

    // PaperSize
    if ( nFlags & JobSetFlags::PAPERSIZE )
    {
        if( (pDevModeW->dmFields & (DM_PAPERWIDTH|DM_PAPERLENGTH)) == (DM_PAPERWIDTH|DM_PAPERLENGTH) )
        {
            pSetupData->SetPaperWidth( pDevModeW->dmPaperWidth*10 );
            pSetupData->SetPaperHeight( pDevModeW->dmPaperLength*10 );
        }
        else
        {
            const DWORD nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, nullptr, pSetupData );
            WORD*   pPapers = nullptr;
            const DWORD nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, nullptr, pSetupData );
            POINT*  pPaperSizes = nullptr;
            if ( nPaperCount && (nPaperCount != GDI_ERROR) )
            {
                pPapers = static_cast<WORD*>(rtl_allocateZeroMemory(nPaperCount*sizeof(WORD)));
                ImplDeviceCaps( pPrinter, DC_PAPERS, reinterpret_cast<BYTE*>(pPapers), pSetupData );
            }
            if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
            {
                pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT)));
                ImplDeviceCaps( pPrinter, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );
            }
            if( nPaperSizeCount == nPaperCount && pPaperSizes && pPapers )
            {
                for( DWORD i = 0; i < nPaperCount; ++i )
                {
                    if( pPapers[ i ] == pDevModeW->dmPaperSize )
                    {
                        pSetupData->SetPaperWidth( pPaperSizes[ i ].x*10 );
                        pSetupData->SetPaperHeight( pPaperSizes[ i ].y*10 );
                        break;
                    }
                }
            }
            if( pPapers )
                std::free( pPapers );
            if( pPaperSizes )
                std::free( pPaperSizes );
        }
        switch( pDevModeW->dmPaperSize )
        {
            case DMPAPER_LETTER:
                pSetupData->SetPaperFormat( PAPER_LETTER );
                break;
            case DMPAPER_TABLOID:
                pSetupData->SetPaperFormat( PAPER_TABLOID );
                break;
            case DMPAPER_LEDGER:
                pSetupData->SetPaperFormat( PAPER_LEDGER );
                break;
            case DMPAPER_LEGAL:
                pSetupData->SetPaperFormat( PAPER_LEGAL );
                break;
            case DMPAPER_STATEMENT:
                pSetupData->SetPaperFormat( PAPER_STATEMENT );
                break;
            case DMPAPER_EXECUTIVE:
                pSetupData->SetPaperFormat( PAPER_EXECUTIVE );
                break;
            case DMPAPER_A3:
                pSetupData->SetPaperFormat( PAPER_A3 );
                break;
            case DMPAPER_A4:
                pSetupData->SetPaperFormat( PAPER_A4 );
                break;
            case DMPAPER_A5:
                pSetupData->SetPaperFormat( PAPER_A5 );
                break;
            //See http://wiki.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 x 364 or ISO 250 x 353
            //(cmc)
            case DMPAPER_B4:
                pSetupData->SetPaperFormat( PAPER_B4_JIS );
                break;
            case DMPAPER_B5:
                pSetupData->SetPaperFormat( PAPER_B5_JIS );
                break;
            case DMPAPER_QUARTO:
                pSetupData->SetPaperFormat( PAPER_QUARTO );
                break;
            case DMPAPER_10X14:
                pSetupData->SetPaperFormat( PAPER_10x14 );
                break;
            case DMPAPER_NOTE:
                pSetupData->SetPaperFormat( PAPER_LETTER );
                break;
            case DMPAPER_ENV_9:
                pSetupData->SetPaperFormat( PAPER_ENV_9 );
                break;
            case DMPAPER_ENV_10:
                pSetupData->SetPaperFormat( PAPER_ENV_10 );
                break;
            case DMPAPER_ENV_11:
                pSetupData->SetPaperFormat( PAPER_ENV_11 );
                break;
            case DMPAPER_ENV_12:
                pSetupData->SetPaperFormat( PAPER_ENV_12 );
                break;
            case DMPAPER_ENV_14:
                pSetupData->SetPaperFormat( PAPER_ENV_14 );
                break;
            case DMPAPER_CSHEET:
                pSetupData->SetPaperFormat( PAPER_C );
                break;
            case DMPAPER_DSHEET:
                pSetupData->SetPaperFormat( PAPER_D );
                break;
            case DMPAPER_ESHEET:
                pSetupData->SetPaperFormat( PAPER_E );
                break;
            case DMPAPER_ENV_DL:
                pSetupData->SetPaperFormat( PAPER_ENV_DL );
                break;
            case DMPAPER_ENV_C5:
                pSetupData->SetPaperFormat( PAPER_ENV_C5 );
                break;
            case DMPAPER_ENV_C3:
                pSetupData->SetPaperFormat( PAPER_ENV_C3 );
                break;
            case DMPAPER_ENV_C4:
                pSetupData->SetPaperFormat( PAPER_ENV_C4 );
                break;
            case DMPAPER_ENV_C6:
                pSetupData->SetPaperFormat( PAPER_ENV_C6 );
                break;
            case DMPAPER_ENV_C65:
                pSetupData->SetPaperFormat( PAPER_ENV_C65 );
                break;
            case DMPAPER_ENV_ITALY:
                pSetupData->SetPaperFormat( PAPER_ENV_ITALY );
                break;
            case DMPAPER_ENV_MONARCH:
                pSetupData->SetPaperFormat( PAPER_ENV_MONARCH );
                break;
            case DMPAPER_ENV_PERSONAL:
                pSetupData->SetPaperFormat( PAPER_ENV_PERSONAL );
                break;
            case DMPAPER_FANFOLD_US:
                pSetupData->SetPaperFormat( PAPER_FANFOLD_US );
                break;
            case DMPAPER_FANFOLD_STD_GERMAN:
                pSetupData->SetPaperFormat( PAPER_FANFOLD_DE );
                break;
            case DMPAPER_FANFOLD_LGL_GERMAN:
                pSetupData->SetPaperFormat( PAPER_FANFOLD_LEGAL_DE );
                break;
            case DMPAPER_ISO_B4:
                pSetupData->SetPaperFormat( PAPER_B4_ISO );
                break;
            case DMPAPER_JAPANESE_POSTCARD:
                pSetupData->SetPaperFormat( PAPER_POSTCARD_JP );
                break;
            case DMPAPER_9X11:
                pSetupData->SetPaperFormat( PAPER_9x11 );
                break;
            case DMPAPER_10X11:
                pSetupData->SetPaperFormat( PAPER_10x11 );
                break;
            case DMPAPER_15X11:
                pSetupData->SetPaperFormat( PAPER_15x11 );
                break;
            case DMPAPER_ENV_INVITE:
                pSetupData->SetPaperFormat( PAPER_ENV_INVITE );
                break;
            case DMPAPER_A_PLUS:
                pSetupData->SetPaperFormat( PAPER_A_PLUS );
                break;
            case DMPAPER_B_PLUS:
                pSetupData->SetPaperFormat( PAPER_B_PLUS );
                break;
            case DMPAPER_LETTER_PLUS:
                pSetupData->SetPaperFormat( PAPER_LETTER_PLUS );
                break;
            case DMPAPER_A4_PLUS:
                pSetupData->SetPaperFormat( PAPER_A4_PLUS );
                break;
            case DMPAPER_A2:
                pSetupData->SetPaperFormat( PAPER_A2 );
                break;
            case DMPAPER_DBL_JAPANESE_POSTCARD:
                pSetupData->SetPaperFormat( PAPER_DOUBLEPOSTCARD_JP );
                break;
            case DMPAPER_A6:
                pSetupData->SetPaperFormat( PAPER_A6 );
                break;
            case DMPAPER_B6_JIS:
                pSetupData->SetPaperFormat( PAPER_B6_JIS );
                break;
            case DMPAPER_12X11:
                pSetupData->SetPaperFormat( PAPER_12x11 );
                break;
            default:
                pSetupData->SetPaperFormat( PAPER_USER );
                break;
        }
    }

    if( nFlags & JobSetFlags::DUPLEXMODE )
    {
        DuplexMode eDuplex = DuplexMode::Unknown;
        if( pDevModeW->dmFields & DM_DUPLEX )
        {
            if( pDevModeW->dmDuplex == DMDUP_SIMPLEX )
                eDuplex = DuplexMode::Off;
            else if( pDevModeW->dmDuplex == DMDUP_VERTICAL )
                eDuplex = DuplexMode::LongEdge;
            else if( pDevModeW->dmDuplex == DMDUP_HORIZONTAL )
                eDuplex = DuplexMode::ShortEdge;
        }
        pSetupData->SetDuplexMode( eDuplex );
    }
}

static void ImplJobSetupToDevMode( WinSalInfoPrinter const * pPrinter, const ImplJobSetup* pSetupData, JobSetFlags nFlags )
{
    if ( !pSetupData || !pSetupData->GetDriverData() )
        return;

    DEVMODEW* pDevModeW = const_cast<DEVMODEW *>(SAL_DEVMODE_W(pSetupData));
    if( pDevModeW == nullptr )
        return;

    // Orientation
    if ( nFlags & JobSetFlags::ORIENTATION )
    {
        pDevModeW->dmFields |= DM_ORIENTATION;
        if ( pSetupData->GetOrientation() == Orientation::Portrait )
            pDevModeW->dmOrientation = DMORIENT_PORTRAIT;
        else
            pDevModeW->dmOrientation = DMORIENT_LANDSCAPE;
    }

    // PaperBin
    if ( nFlags & JobSetFlags::PAPERBIN )
    {
        const DWORD nCount = ImplDeviceCaps( pPrinter, DC_BINS, nullptr, pSetupData );

        if ( nCount && (nCount != GDI_ERROR) )
        {
            WORD* pBins = static_cast<WORD*>(rtl_allocateZeroMemory(nCount*sizeof(WORD)));
            ImplDeviceCaps( pPrinter, DC_BINS, reinterpret_cast<BYTE*>(pBins), pSetupData );
            pDevModeW->dmFields |= DM_DEFAULTSOURCE;
            pDevModeW->dmDefaultSource = pBins[ pSetupData->GetPaperBin() ];
            std::free( pBins );
        }
    }

    // PaperSize
    if ( nFlags & JobSetFlags::PAPERSIZE )
    {
        pDevModeW->dmFields        |= DM_PAPERSIZE;
        pDevModeW->dmPaperWidth     = 0;
        pDevModeW->dmPaperLength    = 0;

        switch( pSetupData->GetPaperFormat() )
        {
            case PAPER_A2:
                pDevModeW->dmPaperSize = DMPAPER_A2;
                break;
            case PAPER_A3:
                pDevModeW->dmPaperSize = DMPAPER_A3;
                break;
            case PAPER_A4:
                pDevModeW->dmPaperSize = DMPAPER_A4;
                break;
            case PAPER_A5:
                pDevModeW->dmPaperSize = DMPAPER_A5;
                break;
            case PAPER_B4_ISO:
                pDevModeW->dmPaperSize = DMPAPER_ISO_B4;
                break;
            case PAPER_LETTER:
                pDevModeW->dmPaperSize = DMPAPER_LETTER;
                break;
            case PAPER_LEGAL:
                pDevModeW->dmPaperSize = DMPAPER_LEGAL;
                break;
            case PAPER_TABLOID:
                pDevModeW->dmPaperSize = DMPAPER_TABLOID;
                break;

            // 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_ENV_C4:
                pDevModeW->dmPaperSize = DMPAPER_ENV_C4;
                break;
            case PAPER_ENV_C5:
                pDevModeW->dmPaperSize = DMPAPER_ENV_C5;
                break;
            case PAPER_ENV_C6:
                pDevModeW->dmPaperSize = DMPAPER_ENV_C6;
                break;
            case PAPER_ENV_C65:
                pDevModeW->dmPaperSize = DMPAPER_ENV_C65;
                break;
            case PAPER_ENV_DL:
                pDevModeW->dmPaperSize = DMPAPER_ENV_DL;
                break;
            case PAPER_C:
                pDevModeW->dmPaperSize = DMPAPER_CSHEET;
                break;
            case PAPER_D:
                pDevModeW->dmPaperSize = DMPAPER_DSHEET;
                break;
            case PAPER_E:
                pDevModeW->dmPaperSize = DMPAPER_ESHEET;
                break;
            case PAPER_EXECUTIVE:
                pDevModeW->dmPaperSize = DMPAPER_EXECUTIVE;
                break;
            case PAPER_FANFOLD_LEGAL_DE:
                pDevModeW->dmPaperSize = DMPAPER_FANFOLD_LGL_GERMAN;
                break;
            case PAPER_ENV_MONARCH:
                pDevModeW->dmPaperSize = DMPAPER_ENV_MONARCH;
                break;
            case PAPER_ENV_PERSONAL:
                pDevModeW->dmPaperSize = DMPAPER_ENV_PERSONAL;
                break;
            case PAPER_ENV_9:
                pDevModeW->dmPaperSize = DMPAPER_ENV_9;
                break;
            case PAPER_ENV_10:
                pDevModeW->dmPaperSize = DMPAPER_ENV_10;
                break;
            case PAPER_ENV_11:
                pDevModeW->dmPaperSize = DMPAPER_ENV_11;
                break;
            case PAPER_ENV_12:
                pDevModeW->dmPaperSize = DMPAPER_ENV_12;
                break;
            //See the comments on DMPAPER_B4 above
            case PAPER_B4_JIS:
                pDevModeW->dmPaperSize = DMPAPER_B4;
                break;
            case PAPER_B5_JIS:
                pDevModeW->dmPaperSize = DMPAPER_B5;
                break;
            case PAPER_B6_JIS:
                pDevModeW->dmPaperSize = DMPAPER_B6_JIS;
                break;
            case PAPER_LEDGER:
                pDevModeW->dmPaperSize = DMPAPER_LEDGER;
                break;
            case PAPER_STATEMENT:
                pDevModeW->dmPaperSize = DMPAPER_STATEMENT;
                break;
            case PAPER_10x14:
                pDevModeW->dmPaperSize = DMPAPER_10X14;
                break;
            case PAPER_ENV_14:
                pDevModeW->dmPaperSize = DMPAPER_ENV_14;
                break;
            case PAPER_ENV_C3:
                pDevModeW->dmPaperSize = DMPAPER_ENV_C3;
                break;
            case PAPER_ENV_ITALY:
                pDevModeW->dmPaperSize = DMPAPER_ENV_ITALY;
                break;
            case PAPER_FANFOLD_US:
                pDevModeW->dmPaperSize = DMPAPER_FANFOLD_US;
                break;
            case PAPER_FANFOLD_DE:
                pDevModeW->dmPaperSize = DMPAPER_FANFOLD_STD_GERMAN;
                break;
            case PAPER_POSTCARD_JP:
                pDevModeW->dmPaperSize = DMPAPER_JAPANESE_POSTCARD;
                break;
            case PAPER_9x11:
                pDevModeW->dmPaperSize = DMPAPER_9X11;
                break;
            case PAPER_10x11:
                pDevModeW->dmPaperSize = DMPAPER_10X11;
                break;
            case PAPER_15x11:
                pDevModeW->dmPaperSize = DMPAPER_15X11;
                break;
            case PAPER_ENV_INVITE:
                pDevModeW->dmPaperSize = DMPAPER_ENV_INVITE;
                break;
            case PAPER_A_PLUS:
                pDevModeW->dmPaperSize = DMPAPER_A_PLUS;
                break;
            case PAPER_B_PLUS:
                pDevModeW->dmPaperSize = DMPAPER_B_PLUS;
                break;
            case PAPER_LETTER_PLUS:
                pDevModeW->dmPaperSize = DMPAPER_LETTER_PLUS;
                break;
            case PAPER_A4_PLUS:
                pDevModeW->dmPaperSize = DMPAPER_A4_PLUS;
                break;
            case PAPER_DOUBLEPOSTCARD_JP:
                pDevModeW->dmPaperSize = DMPAPER_DBL_JAPANESE_POSTCARD;
                break;
            case PAPER_A6:
                pDevModeW->dmPaperSize = DMPAPER_A6;
                break;
            case PAPER_12x11:
                pDevModeW->dmPaperSize = DMPAPER_12X11;
                break;
            default:
            {
                short   nPaper = 0;
                const DWORD nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, nullptr, pSetupData );
                WORD*   pPapers = nullptr;
                const DWORD nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, nullptr, pSetupData );
                POINT*  pPaperSizes = nullptr;
                DWORD   nLandscapeAngle = ImplDeviceCaps( pPrinter, DC_ORIENTATION, nullptr, pSetupData );
                if ( nPaperCount && (nPaperCount != GDI_ERROR) )
                {
                    pPapers = static_cast<WORD*>(rtl_allocateZeroMemory(nPaperCount*sizeof(WORD)));
                    ImplDeviceCaps( pPrinter, DC_PAPERS, reinterpret_cast<BYTE*>(pPapers), pSetupData );
                }
                if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
                {
                    pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT)));
                    ImplDeviceCaps( pPrinter, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );
                }
                if ( (nPaperSizeCount == nPaperCount) && pPapers && pPaperSizes )
                {
                    PaperInfo aInfo(pSetupData->GetPaperWidth(), pSetupData->GetPaperHeight());
                    // compare paper formats and select a good match
                    for ( DWORD 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->GetPaperHeight(), pSetupData->GetPaperWidth());
                        for ( DWORD i = 0; i < nPaperCount; ++i )
                        {
                            if ( aRotatedInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)) )
                            {
                                nPaper = pPapers[i];
                                break;
                            }
                        }
                    }

                    if ( nPaper )
                        pDevModeW->dmPaperSize = nPaper;
                }

                if ( !nPaper )
                {
                    pDevModeW->dmFields       |= DM_PAPERLENGTH | DM_PAPERWIDTH;
                    pDevModeW->dmPaperSize     = DMPAPER_USER;
                    pDevModeW->dmPaperWidth    = static_cast<short>(pSetupData->GetPaperWidth()/10);
                    pDevModeW->dmPaperLength   = static_cast<short>(pSetupData->GetPaperHeight()/10);
                }

                if ( pPapers )
                    std::free(pPapers);
                if ( pPaperSizes )
                    std::free(pPaperSizes);

                break;
            }
        }
    }
    if( nFlags & JobSetFlags::DUPLEXMODE )
    {
        switch( pSetupData->GetDuplexMode() )
        {
        case DuplexMode::Off:
            pDevModeW->dmFields |= DM_DUPLEX;
            pDevModeW->dmDuplex = DMDUP_SIMPLEX;
            break;
        case DuplexMode::ShortEdge:
            pDevModeW->dmFields |= DM_DUPLEX;
            pDevModeW->dmDuplex = DMDUP_HORIZONTAL;
            break;
        case DuplexMode::LongEdge:
            pDevModeW->dmFields |= DM_DUPLEX;
            pDevModeW->dmDuplex = DMDUP_VERTICAL;
            break;
        case DuplexMode::Unknown:
            break;
        }
    }
}

static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
                                    LPCWSTR pDevice,
                                    DEVMODEW const * pDevMode )
{
    HDC hDC = nullptr;
    CATCH_DRIVER_EX_BEGIN;
    hDC = CreateICW( pDriver, pDevice, nullptr, pDevMode );
    CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
    return hDC;
}

static HDC ImplCreateSalPrnIC( WinSalInfoPrinter const * pPrinter, const ImplJobSetup* pSetupData )
{
    HDC hDC = nullptr;
    DEVMODEW const * pDevMode;
    if ( pSetupData && pSetupData->GetDriverData() )
        pDevMode = SAL_DEVMODE_W( pSetupData );
    else
        pDevMode = nullptr;
    // #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 nullptr;
    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( o3tl::toW(pDriverName),
                                   o3tl::toW(pDeviceName),
                                   pDevMode );
    return hDC;
}

static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC )
{
    WinSalGraphics* pGraphics = new WinSalGraphics(WinSalGraphics::PRINTER, false, nullptr/* CHECKME */ nullptr);
    pGraphics->SetLayout( SalLayoutFlags::NONE );
    pGraphics->setHDC(hDC);
    return pGraphics;
}

static bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, const ImplJobSetup* pSetupData )
{
    HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
    if ( !hNewDC )
        return false;

    pPrinter->setHDC(hNewDC);
    return true;
}


SalInfoPrinter* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
                                                   ImplJobSetup* pSetupData )
{
    WinSalInfoPrinter* pPrinter = new WinSalInfoPrinter;
    if( ! pQueueInfo->moPortName )
        GetPrinterQueueState( pQueueInfo );
    pPrinter->maDriverName  = pQueueInfo->maDriver;
    pPrinter->maDeviceName  = pQueueInfo->maPrinterName;
    pPrinter->maPortName    = pQueueInfo->moPortName ? *pQueueInfo->moPortName : 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 nullptr;
    }

    pPrinter->setHDC(hDC);
    if ( !pSetupData->GetDriverData() )
        ImplUpdateSalJobSetup( pPrinter, pSetupData, false, nullptr );
    ImplDevModeToJobSetup( pPrinter, pSetupData, JobSetFlags::ALL );
    pSetupData->SetSystem( JOBSETUP_SYSTEM_WINDOWS );

    return pPrinter;
}

void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
{
    delete pPrinter;
}


WinSalInfoPrinter::WinSalInfoPrinter() :
    m_hDC(nullptr),
    m_pGraphics(nullptr),
    m_bGraphics(false)
{
    m_bPapersInit = false;
}

WinSalInfoPrinter::~WinSalInfoPrinter()
{
    setHDC(nullptr);
}

void WinSalInfoPrinter::setHDC(HDC hNewDC)
{
    assert(!m_bGraphics);

    if (m_hDC)
    {
        assert(!m_pGraphics || m_hDC == m_pGraphics->getHDC());
        delete m_pGraphics;
        m_pGraphics = nullptr;
        DeleteDC(m_hDC);
    }

    m_hDC = hNewDC;
}

void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
{
    m_aPaperFormats.clear();

    DWORD nCount = ImplDeviceCaps( this, DC_PAPERSIZE, nullptr, pSetupData );
    if( nCount == GDI_ERROR )
        nCount = 0;

    if( nCount )
    {
        POINT* pPaperSizes = static_cast<POINT*>(rtl_allocateZeroMemory(nCount*sizeof(POINT)));
        ImplDeviceCaps( this, DC_PAPERSIZE, reinterpret_cast<BYTE*>(pPaperSizes), pSetupData );

        sal_Unicode* pNamesBuffer = static_cast<sal_Unicode*>(std::malloc(nCount*64*sizeof(sal_Unicode)));
        ImplDeviceCaps( this, DC_PAPERNAMES, reinterpret_cast<BYTE*>(pNamesBuffer), pSetupData );

        SAL_INFO("vcl.print""DC_PAPERSIZE sizes (mm) from printer: " << DC_PAPERSIZE_array_to_string(pPaperSizes, nCount));

        for( DWORD i = 0; i < nCount; ++i )
        {
            PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
            m_aPaperFormats.push_back( aInfo );
        }
        std::free( pNamesBuffer );
        std::free( pPaperSizes );
    }

    m_bPapersInit = true;
}

int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
{
    const DWORD nRet = ImplDeviceCaps( this, DC_ORIENTATION, nullptr, pSetupData );

    if( nRet != GDI_ERROR )
        return static_cast<int>(nRet) * 10;
    return 900; // guess
}

SalGraphics* WinSalInfoPrinter::AcquireGraphics()
{
    assert(m_hDC);
    if (m_bGraphics)
        return nullptr;

    if (!m_pGraphics)
        m_pGraphics = ImplCreateSalPrnGraphics(m_hDC);
    if (m_pGraphics)
        m_bGraphics = true;

    return m_pGraphics;
}

void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
{
    m_bGraphics = false;
}

bool WinSalInfoPrinter::Setup(weld::Window* pFrame, ImplJobSetup* pSetupData)
{
    if ( ImplUpdateSalJobSetup(this, pSetupData, true, pFrame))
    {
        ImplDevModeToJobSetup( this, pSetupData, JobSetFlags::ALL );
        return ImplUpdateSalPrnIC( this, pSetupData );
    }

    return false;
}

bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
{
    if ( !ImplTestSalJobSetup( this, pSetupData, false ) )
        return false;
    return ImplUpdateSalPrnIC( this, pSetupData );
}

bool WinSalInfoPrinter::SetData( JobSetFlags nFlags, ImplJobSetup* pSetupData )
{
    ImplJobSetupToDevMode( this, pSetupData, nFlags );
    if ( ImplUpdateSalJobSetup( this, pSetupData, true, nullptr ) )
    {
        ImplDevModeToJobSetup( this, pSetupData, nFlags );
        return ImplUpdateSalPrnIC( this, pSetupData );
    }

    return false;
}

sal_uInt16 WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
{
    DWORD nRet = ImplDeviceCaps( this, DC_BINS, nullptr, pSetupData );
    if ( nRet && (nRet != GDI_ERROR) )
        return nRet;
    else
        return 0;
}

OUString WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pSetupData, sal_uInt16 nPaperBin )
{
    OUString aPaperBinName;

    DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, nullptr, pSetupData );
    if ( (nPaperBin < nBins) && (nBins != GDI_ERROR) )
    {
        auto pBuffer = std::make_unique<sal_Unicode[]>(nBins*24);
        DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, reinterpret_cast<BYTE*>(pBuffer.get()), pSetupData );
        if ( nRet && (nRet != GDI_ERROR) )
            aPaperBinName = OUString( pBuffer.get() + (nPaperBin*24) );
    }

    return aPaperBinName;
}

sal_uInt16 WinSalInfoPrinter::GetPaperBinBySourceIndex( const ImplJobSetup* pSetupData, sal_uInt16 nPaperSource )
{
    DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, nullptr, pSetupData );
    if (nBins == GDI_ERROR)
        return 0xffff;

    auto pBuffer = std::make_unique<sal_uInt16[]>(nBins);
    nBins = ImplDeviceCaps( this, DC_BINS, reinterpret_cast<BYTE*>(pBuffer.get()), pSetupData );
    if (nBins != GDI_ERROR)
    {
        for (DWORD nBin = 0; nBin < nBins; ++nBin)
        {
            if (nPaperSource == *(pBuffer.get() + nBin))
                return nBin;
        }
    }
    return 0xffff;
}

sal_uInt16  WinSalInfoPrinter::GetSourceIndexByPaperBin(const ImplJobSetup* pSetupData, sal_uInt16 nPaperBin)
{
    DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, nullptr, pSetupData );
    if (nBins == GDI_ERROR)
        return 0;

    auto pBuffer = std::make_unique<sal_uInt16[]>(nBins);
    nBins = ImplDeviceCaps( this, DC_BINS, reinterpret_cast<BYTE*>(pBuffer.get()), pSetupData );
    if (nBins != GDI_ERROR && nBins > nPaperBin)
    {
        return *(pBuffer.get() + nPaperBin);
    }
    return 0;
}


sal_uInt32 WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, PrinterCapType nType )
{
    DWORD nRet;

    switch ( nType )
    {
        case PrinterCapType::SupportDialog:
            return TRUE;
        case PrinterCapType::Copies:
            nRet = ImplDeviceCaps( this, DC_COPIES, nullptr, pSetupData );
            if ( nRet && (nRet != GDI_ERROR) )
                return nRet;
            return 0;
        case PrinterCapType::CollateCopies:
            nRet = ImplDeviceCaps( this, DC_COLLATE, nullptr, pSetupData );
            if ( nRet && (nRet != GDI_ERROR) )
            {
                nRet = ImplDeviceCaps( this, DC_COPIES, nullptr, pSetupData );
                if ( nRet && (nRet != GDI_ERROR) )
                    return nRet;
            }
            return 0;

        case PrinterCapType::SetOrientation:
            nRet = ImplDeviceCaps( this, DC_ORIENTATION, nullptr, pSetupData );
            if ( nRet && (nRet != GDI_ERROR) )
                return TRUE;
            return FALSE;

        case PrinterCapType::SetPaperSize:
        case PrinterCapType::SetPaper:
            nRet = ImplDeviceCaps( this, DC_PAPERS, nullptr, pSetupData );
            if ( nRet && (nRet != GDI_ERROR) )
                return TRUE;
            return FALSE;

        default:
            break;
    }

    return 0;
}

void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
                                  tools::Long& rOutWidth, tools::Long& rOutHeight,
                                  Point& rPageOffset,
                                  Size& rPaperSize )
{
    HDC hDC = m_hDC;

    rOutWidth   = GetDeviceCaps( hDC, HORZRES );
    rOutHeight  = GetDeviceCaps( hDC, VERTRES );

    rPageOffset.setX( GetDeviceCaps( hDC, PHYSICALOFFSETX ) );
    rPageOffset.setY( GetDeviceCaps( hDC, PHYSICALOFFSETY ) );
    rPaperSize.setWidth( GetDeviceCaps( hDC, PHYSICALWIDTH ) );
    rPaperSize.setHeight( GetDeviceCaps( hDC, PHYSICALHEIGHT ) );
}


std::unique_ptr<SalPrinter> WinSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
{
    WinSalPrinter* pPrinter = new WinSalPrinter;
    pPrinter->mpInfoPrinter = static_cast<WinSalInfoPrinter*>(pInfoPrinter);
    return std::unique_ptr<SalPrinter>(pPrinter);
}

static BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
{
    SalData*    pSalData = GetSalData();
    WinSalPrinter* pPrinter;
    int         i = 0;
    bool        bWhile = true;

    // Ensure we handle the mutex which will be released in WinSalInstance::DoYield
    SolarMutexGuard aSolarMutexGuard;
    do
    {
        // process messages
        bWhile = Application::Reschedule( true );
        if (i > 15)
            bWhile = false;
        else
            ++i;

        pPrinter = pSalData->mpFirstPrinter;
        while ( pPrinter )
        {
            if( pPrinter->mhDC == hPrnDC )
                break;

            pPrinter = pPrinter->mpNextPrinter;
        }

        if ( !pPrinter || pPrinter->mbAbort )
            return FALSE;
    }
    while ( bWhile );

    return TRUE;
}

static DEVMODEW const * ImplSalSetCopies( DEVMODEW const * pDevMode, sal_uInt32 nCopies, bool bCollate )
{
    if ( !pDevMode || (nCopies <= 1) )
        return pDevMode;

    if ( nCopies > 32765 )
        nCopies = 32765;
    sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
    LPDEVMODEW pNewDevMode = static_cast<LPDEVMODEW>(std::malloc( nDevSize ));
    assert(pNewDevMode); // Don't handle OOM conditions
    memcpy( pNewDevMode, pDevMode, nDevSize );
    pNewDevMode->dmFields |= DM_COPIES;
    pNewDevMode->dmCopies  = static_cast<short>(static_cast<sal_uInt16>(nCopies));
    pNewDevMode->dmFields |= DM_COLLATE;
    if ( bCollate )
        pNewDevMode->dmCollate = DMCOLLATE_TRUE;
    else
        pNewDevMode->dmCollate = DMCOLLATE_FALSE;
    return pNewDevMode;
}


WinSalPrinter::WinSalPrinter() :
    mpInfoPrinter( nullptr ),
    mpNextPrinter( nullptr ),
    mhDC( nullptr ),
    mnError( SalPrinterError::NONE ),
    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 )
    {
        // explicitly reset(), so the mxGraphics's borrowed HDC defaults are
        // restored and WinSalGraphics's destructor won't work on a deleted HDC.
        mxGraphics.reset();
        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;
    }
}

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_StartDocW1( HDC hDC, DOCINFOW const * pInfo, WinSalPrinter* pPrt )
{
    int nRet = 0;
    CATCH_DRIVER_EX_BEGIN;
    nRet = ::StartDocW( hDC, pInfo );
    CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
    return nRet;
}

static int lcl_StartDocW( HDC hDC, DOCINFOW const * pInfo, WinSalPrinter* pPrt )
{
    //tdf#127547 - Freeze/crash in Microsoft Print to PDF dialog, if we try to paste while
    // executing the StartDocW method, Windows will call back into us on a separate thread,
    // where we will attempt to take the SolarMutex.
    SolarMutexReleaser aReleaser;

    return lcl_StartDocW1(hDC, pInfo, pPrt);
}

bool WinSalPrinter::StartJob( const OUString* pFileName,
                           const OUString& rJobName,
                           const OUString&,
                           sal_uInt32 nCopies,
                           bool bCollate,
                           bool /*bDirect*/,
                           ImplJobSetup* pSetupData )
{
    mnError     = SalPrinterError::NONE;
    mbAbort     = false;
    mnCopies        = nCopies;
    mbCollate   = bCollate;

    DEVMODEW const * pOrgDevModeW = nullptr;
    DEVMODEW const * pDevModeW = nullptr;
    HDC hDC = nullptr;
    if ( pSetupData && pSetupData->GetDriverData() )
    {
        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( o3tl::toW(aDrvBuf),
                     o3tl::toW(aDevBuf),
                     nullptr,
                     pDevModeW );

    if ( pDevModeW != pOrgDevModeW )
        std::free( const_cast<DEVMODEW *>(pDevModeW) );

    if ( !hDC )
    {
        mnError = SalPrinterError::General;
        return false;
    }

    // make sure mhDC is set before the printer driver may call our abortproc
    mhDC = hDC;
    if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
    {
        mnError = SalPrinterError::General;
        return false;
    }

    mnError = SalPrinterError::NONE;
    mbAbort = false;

    // As the Telecom Balloon Fax driver tends to send messages repeatedly
    // we try to process first all, and then insert a dummy message
    for (int i = 0; Application::Reschedule( true ) && i <= 15; ++i);
    bool const ret = PostMessageW(GetSalData()->mpInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0);
    SAL_WARN_IF(!ret, "vcl""ERROR: PostMessage() failed!");

    // bring up a file chooser if printing to file port but no file name given
    OUString aOutFileName;
    if( mpInfoPrinter->maPortName.equalsIgnoreAsciiCase( "FILE:" ) && (!pFileName || pFileName->isEmpty()) )
    {

        uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
        uno::Reference< XFilePicker3 > xFilePicker = FilePicker::createWithMode(xContext, TemplateDescription::FILESAVE_SIMPLE);

        if( xFilePicker->execute() == ExecutableDialogResults::OK )
        {
            Sequence< OUString > aPathSeq( xFilePicker->getSelectedFiles() );
            INetURLObject aObj( aPathSeq[0] );
            aOutFileName = aObj.PathToFileName();
        }
        else
        {
            mnError = SalPrinterError::Abort;
            return false;
        }
    }

    DOCINFOW aInfo = {};
    aInfo.cbSize = sizeof( aInfo );
    aInfo.lpszDocName = o3tl::toW(rJobName.getStr());
    if ( pFileName || aOutFileName.getLength() )
    {
        if ( (pFileName && !pFileName->isEmpty()) || aOutFileName.getLength() )
        {
            aInfo.lpszOutput = o3tl::toW((pFileName && !pFileName->isEmpty()) ? pFileName->getStr() : aOutFileName.getStr());
        }
        else
            aInfo.lpszOutput = L"FILE:";
    }
    else
        aInfo.lpszOutput = nullptr;

    // start Job, in the main thread
    int nRet = vcl::solarthread::syncExecute([hDC, this, &aInfo]() -> int { return lcl_StartDocW(hDC, &aInfo, this); });

    if ( nRet <= 0 )
    {
        DWORD nError = GetLastError();
        if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
            mnError = SalPrinterError::Abort;
        else
            mnError = SalPrinterError::General;
        return false;
    }

    return true;
}

void WinSalPrinter::DoEndDoc(HDC hDC)
{
    CATCH_DRIVER_EX_BEGIN;
    if( ::EndDoc( hDC ) <= 0 )
        GetLastError();
    CATCH_DRIVER_EX_END( "exception in EndDoc"this );
}

bool WinSalPrinter::EndJob()
{
    HDC hDC = mhDC;
    if (!isValid())
        return true;

    mxGraphics.reset();

    // #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.
    {
        SolarMutexReleaser aReleaser;
        DoEndDoc( hDC );
    }
    DeleteDC( hDC );
    mhDC = nullptr;

    return true;
}

SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, bool bNewJobData )
{
    if (!isValid())
        return nullptr;

    HDC hDC = mhDC;
    if ( pSetupData && pSetupData->GetDriverData() && bNewJobData )
    {
        DEVMODEW const * pOrgDevModeW;
        DEVMODEW const * pDevModeW;
        pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
        pDevModeW = ImplSalSetCopies( pOrgDevModeW, mnCopies, mbCollate );
        ResetDCW( hDC, pDevModeW );
        if ( pDevModeW != pOrgDevModeW )
            std::free( const_cast<DEVMODEW *>(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 = SalPrinterError::General;
        return nullptr;
    }

    // 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 ) );
    Rectangle( hDC, -8000, -8000, -7999, -7999 );
    SelectPen( hDC, hTempPen );
    SelectBrush( hDC, hTempBrush );

    mxGraphics.reset(ImplCreateSalPrnGraphics( hDC ));
    return mxGraphics.get();
}

void WinSalPrinter::EndPage()
{
    mxGraphics.reset();

    if (!isValid())
        return;

    HDC hDC = mhDC;
    volatile int nRet = 0;
    CATCH_DRIVER_EX_BEGIN;
    nRet = ::EndPage( hDC );
    CATCH_DRIVER_EX_END( "exception in EndPage"this );

    if ( nRet <= 0 )
    {
        GetLastError();
        mnError = SalPrinterError::General;
    }
}

SalPrinterError WinSalPrinter::GetErrorCode()
{
    return mnError;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=95 H=95 G=94

¤ Dauer der Verarbeitung: 0.24 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.