/* -*- 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 <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/util/CloseVetoException.hpp>
#include <com/sun/star/util/XCloseable.hpp>
#include <com/sun/star/util/XCloseBroadcaster.hpp>
#include <com/sun/star/util/XCloseListener.hpp>
#include <com/sun/star/frame/XFrame.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <cppuhelper/implbase.hxx>
#include <comphelper/processfactory.hxx>
#include <prewin.h>
#include <postwin.h>
#include <math.h>
#include <tools/stream.hxx>
#include <tools/helpers.hxx>
#include <osl/mutex.hxx>
#include <osl/module.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/sysdata.hxx>
#include "scanner.hxx"
#include <twain/twain.h>
using namespace ::com::sun::star;
#define TWAIN_EVENT_NONE 0x00000000UL
#define TWAIN_EVENT_QUIT 0x00000001UL
#define TWAIN_EVENT_SCANNING 0x00000002UL
#define TWAIN_EVENT_XFER 0x00000004UL
#define PFUNC (*pDSM)
#define PTWAINMSG MSG*
#define FIXTODOUBLE( nFix ) (static_cast<double>(nFix.Whole)+static_cast<double>(nFix.Frac)/65536.)
#define FIXTOLONG( nFix ) (static_cast<long>(floor(FIXTODOUBLE(nFix)+0.5)))
#define TWAIN_FUNCNAME "DSM_Entry"
#if defined(TWH_64BIT)
# define TWAIN_LIBNAME "TWAINDSM.DLL"
#else
# define TWAIN_LIBNAME "TWAIN_32.DLL"
#endif
enum TwainState
{
TWAIN_STATE_NONE = 0,
TWAIN_STATE_SCANNING = 1,
TWAIN_STATE_DONE = 2,
TWAIN_STATE_CANCELED = 3
};
class ImpTwain : public ::cppu::WeakImplHelper< util::XCloseListener >
{
friend LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam );
uno::Reference< uno::XInterface > mxSelfRef;
uno::Reference< scanner::XScannerManager > mxMgr;
ScannerManager& mrMgr;
TW_IDENTITY aAppIdent;
TW_IDENTITY aSrcIdent;
Link<unsigned long,void> aNotifyLink;
DSMENTRYPROC pDSM;
osl::Module* pMod;
ULONG_PTR nCurState;
HWND hTwainWnd;
HHOOK hTwainHook;
bool mbCloseFrameOnExit;
bool ImplHandleMsg( void* pMsg );
void ImplOpenSourceManager();
void ImplOpenSource();
bool ImplEnableSource();
void ImplXfer();
void ImplFallback( ULONG_PTR nEvent );
void ImplDeregisterCloseListener();
void ImplRegisterCloseListener();
DECL_LINK( ImplFallbackHdl, void*, void );
DECL_LINK( ImplDestroyHdl, void*, void );
// from util::XCloseListener
virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) override;
virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) override;
// from lang::XEventListener
virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
public:
ImpTwain( ScannerManager& rMgr, const Link<unsigned long,void>& rNotifyLink );
~ImpTwain() override;
void Destroy();
bool SelectSource();
bool InitXfer();
};
static ImpTwain* pImpTwainInstance = nullptr;
LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
{
return DefWindowProcW( hWnd, nMsg, nPar1, nPar2 );
}
LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
{
MSG* pMsg = reinterpret_cast<MSG*>(lParam);
if( ( nCode < 0 ) || ( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) || !pImpTwainInstance->ImplHandleMsg( reinterpret_cast<void*>(lParam) ) )
{
return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam );
}
else
{
pMsg->message = WM_USER;
pMsg->lParam = 0;
return 0;
}
}
namespace {
uno::Reference< frame::XFrame > ImplGetActiveFrame()
{
try
{
// query desktop instance
uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
uno::Reference< frame::XFrame > xActiveFrame = xDesktop->getActiveFrame();
if( xActiveFrame.is() )
{
return xActiveFrame;
}
}
catch( const uno::Exception& )
{
}
OSL_FAIL("ImpTwain::ImplGetActiveFrame: Could not determine active frame!");
return uno::Reference< frame::XFrame >();
}
uno::Reference< util::XCloseBroadcaster > ImplGetActiveFrameCloseBroadcaster()
{
try
{
return uno::Reference< util::XCloseBroadcaster >( ImplGetActiveFrame(), uno::UNO_QUERY );
}
catch( const uno::Exception& )
{
}
OSL_FAIL("ImpTwain::ImplGetActiveFrameCloseBroadcaster: Could determine close broadcaster on active frame!");
return uno::Reference< util::XCloseBroadcaster >();
}
void ImplSendCloseEvent()
{
try
{
uno::Reference< util::XCloseable > xCloseable( ImplGetActiveFrame(), uno::UNO_QUERY );
if( xCloseable.is() )
xCloseable->close( true );
}
catch( const uno::Exception& )
{
}
OSL_FAIL("ImpTwain::ImplSendCloseEvent: Could not send required close broadcast!");
}
}
// #107835# hold reference to ScannerManager, to prevent premature death
ImpTwain::ImpTwain( ScannerManager& rMgr, const Link<unsigned long,void>& rNotifyLink ) :
mxMgr( uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( &rMgr ), uno::UNO_QUERY) ),
mrMgr( rMgr ),
aNotifyLink( rNotifyLink ),
pDSM( nullptr ),
pMod( nullptr ),
nCurState( 1 ),
hTwainWnd( nullptr ),
hTwainHook( nullptr ),
mbCloseFrameOnExit( false )
{
// setup TWAIN window
pImpTwainInstance = this;
aAppIdent.Id = 0;
aAppIdent.Version.MajorNum = 1;
aAppIdent.Version.MinorNum = 0;
aAppIdent.Version.Language = TWLG_USA;
aAppIdent.Version.Country = TWCY_USA;
aAppIdent.ProtocolMajor = TWON_PROTOCOLMAJOR;
aAppIdent.ProtocolMinor = TWON_PROTOCOLMINOR;
aAppIdent.SupportedGroups = DG_IMAGE | DG_CONTROL;
strncpy( aAppIdent.Version.Info, "8.0", 32 );
aAppIdent.Version.Info[32] = aAppIdent.Version.Info[33] = 0;
strncpy( aAppIdent.Manufacturer, "Sun Microsystems", 32 );
aAppIdent.Manufacturer[32] = aAppIdent.Manufacturer[33] = 0;
strncpy( aAppIdent.ProductFamily,"Office", 32 );
aAppIdent.ProductFamily[32] = aAppIdent.ProductFamily[33] = 0;
strncpy( aAppIdent.ProductName, "Office", 32 );
aAppIdent.ProductName[32] = aAppIdent.ProductName[33] = 0;
WNDCLASSW aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASSW ), GetModuleHandleW( nullptr ), nullptr, nullptr, nullptr, nullptr, L"TwainClass" };
RegisterClassW( &aWc );
hTwainWnd = CreateWindowExW( WS_EX_TOPMOST, aWc.lpszClassName, L"TWAIN", 0, 0, 0, 0, 0, HWND_DESKTOP, nullptr, aWc.hInstance, nullptr );
hTwainHook = SetWindowsHookExW( WH_GETMESSAGE, &TwainMsgProc, nullptr, GetCurrentThreadId() );
// block destruction until ImplDestroyHdl is called
mxSelfRef = static_cast< ::cppu::OWeakObject* >( this );
}
ImpTwain::~ImpTwain()
{
// are we responsible for application shutdown?
if( mbCloseFrameOnExit )
ImplSendCloseEvent();
}
void ImpTwain::Destroy()
{
ImplFallback( TWAIN_EVENT_NONE );
Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ) );
}
bool ImpTwain::SelectSource()
{
TW_UINT16 nRet = TWRC_FAILURE;
ImplOpenSourceManager();
if( 3 == nCurState )
{
TW_IDENTITY aIdent;
aIdent.Id = 0;
aIdent.ProductName[ 0 ] = '\0';
aNotifyLink.Call( TWAIN_EVENT_SCANNING );
nRet = PFUNC( &aAppIdent, nullptr, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent );
}
ImplFallback( TWAIN_EVENT_QUIT );
return( TWRC_SUCCESS == nRet );
}
bool ImpTwain::InitXfer()
{
bool bRet = false;
ImplOpenSourceManager();
if( 3 == nCurState )
{
ImplOpenSource();
if( 4 == nCurState )
bRet = ImplEnableSource();
}
if( !bRet )
ImplFallback( TWAIN_EVENT_QUIT );
return bRet;
}
void ImpTwain::ImplOpenSourceManager()
{
if( 1 == nCurState )
{
pMod = new ::osl::Module( OUString() );
if( pMod->load( TWAIN_LIBNAME ) )
{
nCurState = 2;
pDSM = reinterpret_cast<DSMENTRYPROC>(pMod->getSymbol(TWAIN_FUNCNAME));
if (pDSM &&
( PFUNC( &aAppIdent, nullptr, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) )
{
nCurState = 3;
}
}
else
{
delete pMod;
pMod = nullptr;
}
}
}
void ImpTwain::ImplOpenSource()
{
if( 3 == nCurState )
{
if( ( PFUNC( &aAppIdent, nullptr, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) &&
( PFUNC( &aAppIdent, nullptr, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) )
{
TW_CAPABILITY aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) };
TW_ONEVALUE* pVal = static_cast<TW_ONEVALUE*>(GlobalLock( aCap.hContainer ));
pVal->ItemType = TWTY_INT16;
pVal->Item = 1;
GlobalUnlock( aCap.hContainer );
PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap );
GlobalFree( aCap.hContainer );
nCurState = 4;
}
}
}
bool ImpTwain::ImplEnableSource()
{
bool bRet = false;
if( 4 == nCurState )
{
TW_USERINTERFACE aUI = { true, true, hTwainWnd };
aNotifyLink.Call( TWAIN_EVENT_SCANNING );
nCurState = 5;
// register as vetoable close listener, to prevent application to die under us
ImplRegisterCloseListener();
if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI ) == TWRC_SUCCESS )
{
bRet = true;
}
else
{
nCurState = 4;
// deregister as vetoable close listener, dialog failed
ImplDeregisterCloseListener();
}
}
return bRet;
}
bool ImpTwain::ImplHandleMsg( void* pMsg )
{
TW_UINT16 nRet;
PTWAINMSG pMess = static_cast<PTWAINMSG>(pMsg);
TW_EVENT aEvt = { pMess, MSG_NULL };
if (pDSM)
nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt );
else
nRet = TWRC_NOTDSEVENT;
if( aEvt.TWMessage != MSG_NULL )
{
switch( aEvt.TWMessage )
{
case MSG_XFERREADY:
{
ULONG_PTR nEvent = TWAIN_EVENT_QUIT;
if( 5 == nCurState )
{
nCurState = 6;
ImplXfer();
if( mrMgr.GetData() )
nEvent = TWAIN_EVENT_XFER;
}
else if( 7 == nCurState && mrMgr.GetData() )
{
// Already sent TWAIN_EVENT_XFER; not processed yet;
// duplicate event - avoid deleting mpImpTwain
nEvent = TWAIN_EVENT_NONE;
}
ImplFallback( nEvent );
}
break;
case MSG_CLOSEDSREQ:
ImplFallback( TWAIN_EVENT_QUIT );
break;
default:
break;
}
}
else
nRet = TWRC_NOTDSEVENT;
return( TWRC_DSEVENT == nRet );
}
void ImpTwain::ImplXfer()
{
if( nCurState == 6 )
{
TW_IMAGEINFO aInfo;
HANDLE hDIB = nullptr;
long nWidth, nHeight, nXRes, nYRes;
if( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo ) == TWRC_SUCCESS )
{
nWidth = aInfo.ImageWidth;
nHeight = aInfo.ImageLength;
nXRes = FIXTOLONG( aInfo.XResolution );
nYRes = FIXTOLONG( aInfo.YResolution );
}
else
nWidth = nHeight = nXRes = nYRes = -1;
switch( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB ) )
{
case TWRC_CANCEL:
nCurState = 7;
break;
case TWRC_XFERDONE:
{
if( hDIB )
{
if( ( nXRes != -1 ) && ( nYRes != - 1 ) && ( nWidth != - 1 ) && ( nHeight != - 1 ) )
{
// set resolution of bitmap
BITMAPINFOHEADER* pBIH = static_cast<BITMAPINFOHEADER*>(GlobalLock( static_cast<HGLOBAL>(hDIB) ));
static const double fFactor = 100.0 / 2.54;
pBIH->biXPelsPerMeter = FRound( fFactor * nXRes );
pBIH->biYPelsPerMeter = FRound( fFactor * nYRes );
GlobalUnlock( static_cast<HGLOBAL>(hDIB) );
}
mrMgr.SetData( static_cast<void*>(hDIB) );
}
else
GlobalFree( static_cast<HGLOBAL>(hDIB) );
nCurState = 7;
}
break;
default:
break;
}
}
}
void ImpTwain::ImplFallback( ULONG_PTR nEvent )
{
Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), reinterpret_cast<void*>(nEvent) );
}
IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData, void )
{
const sal_uIntPtr nEvent = reinterpret_cast<sal_uIntPtr>(pData);
bool bFallback = true;
switch( nCurState )
{
case 7:
case 6:
{
TW_PENDINGXFERS aXfers;
if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers ) == TWRC_SUCCESS )
{
if( aXfers.Count != 0 )
PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers );
}
nCurState = 5;
}
break;
case 5:
{
TW_USERINTERFACE aUI = { true, true, hTwainWnd };
PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI );
nCurState = 4;
// deregister as vetoable close listener
ImplDeregisterCloseListener();
}
break;
case 4:
{
PFUNC( &aAppIdent, nullptr, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent );
nCurState = 3;
}
break;
case 3:
{
PFUNC( &aAppIdent, nullptr, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd );
nCurState = 2;
}
break;
case 2:
{
delete pMod;
pMod = nullptr;
nCurState = 1;
}
break;
default:
{
if( nEvent != TWAIN_EVENT_NONE )
aNotifyLink.Call( nEvent );
bFallback = false;
}
break;
}
if( bFallback )
ImplFallback( nEvent );
}
IMPL_LINK_NOARG( ImpTwain, ImplDestroyHdl, void*, void )
{
if( hTwainWnd )
DestroyWindow( hTwainWnd );
if( hTwainHook )
UnhookWindowsHookEx( hTwainHook );
// permit destruction of ourselves (normally, refcount
// should drop to zero exactly here)
mxSelfRef = nullptr;
pImpTwainInstance = nullptr;
}
void ImpTwain::ImplRegisterCloseListener()
{
try
{
uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( ImplGetActiveFrameCloseBroadcaster() );
if( xCloseBroadcaster.is() )
{
xCloseBroadcaster->addCloseListener(this);
return; // successfully registered as a close listener
}
else
{
// interface unknown. don't register, then
OSL_FAIL("ImpTwain::ImplRegisterCloseListener: XFrame has no XCloseBroadcaster!");
return;
}
}
catch( const uno::Exception& )
{
}
OSL_FAIL("ImpTwain::ImplRegisterCloseListener: Could not register as close listener!");
}
void ImpTwain::ImplDeregisterCloseListener()
{
try
{
uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
ImplGetActiveFrameCloseBroadcaster() );
if( xCloseBroadcaster.is() )
{
xCloseBroadcaster->removeCloseListener(this);
return; // successfully deregistered as a close listener
}
else
{
// interface unknown. don't deregister, then
OSL_FAIL("ImpTwain::ImplDeregisterCloseListener: XFrame has no XCloseBroadcaster!");
return;
}
}
catch( const uno::Exception& )
{
}
OSL_FAIL("ImpTwain::ImplDeregisterCloseListener: Could not deregister as close listener!");
}
void SAL_CALL ImpTwain::queryClosing( const lang::EventObject& /*Source*/, sal_Bool GetsOwnership )
{
// shall we re-send the close query later on?
mbCloseFrameOnExit = GetsOwnership;
// the sole purpose of this listener is to forbid closing of the listened-at frame
throw util::CloseVetoException();
}
void SAL_CALL ImpTwain::notifyClosing( const lang::EventObject& /*Source*/ )
{
// should not happen
OSL_FAIL("ImpTwain::notifyClosing called, but we vetoed the closing before!");
}
void SAL_CALL ImpTwain::disposing( const lang::EventObject& /*Source*/ )
{
// we're not holding any references to the frame, thus noop
}
class Twain
{
uno::Reference< lang::XEventListener > mxListener;
uno::Reference< scanner::XScannerManager > mxMgr;
const ScannerManager* mpCurMgr;
ImpTwain* mpImpTwain;
TwainState meState;
DECL_LINK( ImpNotifyHdl, unsigned long, void );
public:
Twain();
~Twain();
bool SelectSource( ScannerManager& rMgr );
bool PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener );
TwainState GetState() const { return meState; }
};
Twain::Twain() :
mpCurMgr( nullptr ),
mpImpTwain( nullptr ),
meState( TWAIN_STATE_NONE )
{
}
Twain::~Twain()
{
if( mpImpTwain )
mpImpTwain->Destroy();
}
bool Twain::SelectSource( ScannerManager& rMgr )
{
bool bRet;
if( !mpImpTwain )
{
// hold reference to ScannerManager, to prevent premature death
mxMgr.set( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
uno::UNO_QUERY );
meState = TWAIN_STATE_NONE;
mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
bRet = mpImpTwain->SelectSource();
}
else
bRet = false;
return bRet;
}
bool Twain::PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener )
{
bool bRet;
if( !mpImpTwain )
{
// hold reference to ScannerManager, to prevent premature death
mxMgr.set( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
uno::UNO_QUERY );
mxListener = rxListener;
meState = TWAIN_STATE_NONE;
mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
bRet = mpImpTwain->InitXfer();
}
else
bRet = false;
return bRet;
}
IMPL_LINK( Twain, ImpNotifyHdl, unsigned long, nEvent, void )
{
switch( nEvent )
{
case TWAIN_EVENT_SCANNING:
meState = TWAIN_STATE_SCANNING;
break;
case TWAIN_EVENT_QUIT:
{
if( meState != TWAIN_STATE_DONE )
meState = TWAIN_STATE_CANCELED;
if( mpImpTwain )
{
mpImpTwain->Destroy();
mpImpTwain = nullptr;
mpCurMgr = nullptr;
}
if( mxListener.is() )
mxListener->disposing( lang::EventObject( mxMgr ) );
mxListener = nullptr;
}
break;
case TWAIN_EVENT_XFER:
{
if( mpImpTwain )
{
meState = ( mpCurMgr->GetData() ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED );
mpImpTwain->Destroy();
mpImpTwain = nullptr;
mpCurMgr = nullptr;
if( mxListener.is() )
mxListener->disposing( lang::EventObject( mxMgr ) );
}
mxListener = nullptr;
}
break;
default:
break;
}
}
static Twain aTwain;
void ScannerManager::AcquireData()
{
}
void ScannerManager::ReleaseData()
{
if( mpData )
{
GlobalFree( static_cast<HGLOBAL>(mpData) );
mpData = nullptr;
}
}
awt::Size ScannerManager::getSize()
{
awt::Size aRet;
HGLOBAL hDIB = static_cast<HGLOBAL>(mpData);
if( hDIB )
{
BITMAPINFOHEADER* pBIH = static_cast<BITMAPINFOHEADER*>(GlobalLock( hDIB ));
if( pBIH )
{
aRet.Width = pBIH->biWidth;
aRet.Height = pBIH->biHeight;
}
else
aRet.Width = aRet.Height = 0;
GlobalUnlock( hDIB );
}
else
aRet.Width = aRet.Height = 0;
return aRet;
}
uno::Sequence< sal_Int8 > ScannerManager::getDIB()
{
uno::Sequence< sal_Int8 > aRet;
if( mpData )
{
HGLOBAL hDIB = static_cast<HGLOBAL>(mpData);
const sal_uInt32 nDIBSize = GlobalSize( hDIB );
BITMAPINFOHEADER* pBIH = static_cast<BITMAPINFOHEADER*>(GlobalLock( hDIB ));
if( pBIH )
{
sal_uInt32 nColEntries;
switch( pBIH->biBitCount )
{
case 1:
case 4:
case 8:
nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : ( 1 << pBIH->biBitCount );
break;
case 24:
nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : 0;
break;
case 16:
case 32:
{
nColEntries = pBIH->biClrUsed;
if( pBIH->biCompression == BI_BITFIELDS )
nColEntries += 3;
}
break;
default:
nColEntries = 0;
break;
}
aRet = uno::Sequence< sal_Int8 >( sizeof( BITMAPFILEHEADER ) + nDIBSize );
sal_Int8* pBuf = aRet.getArray();
SvMemoryStream* pMemStm = new SvMemoryStream( pBuf, sizeof( BITMAPFILEHEADER ), StreamMode::WRITE );
pMemStm->WriteChar( 'B' ).WriteChar( 'M' ).WriteUInt32( 0 ).WriteUInt32( 0 );
pMemStm->WriteUInt32( sizeof( BITMAPFILEHEADER ) + pBIH->biSize + ( nColEntries * sizeof( RGBQUAD ) ) );
delete pMemStm;
memcpy( pBuf + sizeof( BITMAPFILEHEADER ), pBIH, nDIBSize );
}
GlobalUnlock( hDIB );
ReleaseData();
}
return aRet;
}
uno::Sequence< ScannerContext > SAL_CALL ScannerManager::getAvailableScanners()
{
osl::MutexGuard aGuard( maProtector );
uno::Sequence< ScannerContext > aRet( 1 );
aRet.getArray()[0].ScannerName = "TWAIN" ;
aRet.getArray()[0].InternalData = 0;
return aRet;
}
sal_Bool SAL_CALL ScannerManager::configureScannerAndScan( ScannerContext& rContext, const uno::Reference< lang::XEventListener >& )
{
osl::MutexGuard aGuard( maProtector );
uno::Reference< XScannerManager > xThis( this );
if( rContext.InternalData != 0 || rContext.ScannerName != "TWAIN" )
throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext );
ReleaseData();
return aTwain.SelectSource( *this );
}
void SAL_CALL ScannerManager::startScan( const ScannerContext& rContext, const uno::Reference< lang::XEventListener >& rxListener )
{
osl::MutexGuard aGuard( maProtector );
uno::Reference< XScannerManager > xThis( this );
if( rContext.InternalData != 0 || rContext.ScannerName != "TWAIN" )
throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext );
ReleaseData();
aTwain.PerformTransfer( *this, rxListener );
}
ScanError SAL_CALL ScannerManager::getError( const ScannerContext& rContext )
{
osl::MutexGuard aGuard( maProtector );
uno::Reference< XScannerManager > xThis( this );
if( rContext.InternalData != 0 || rContext.ScannerName != "TWAIN" )
throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext );
return( ( aTwain.GetState() == TWAIN_STATE_CANCELED ) ? ScanError_ScanCanceled : ScanError_ScanErrorNone );
}
uno::Reference< awt::XBitmap > SAL_CALL ScannerManager::getBitmap( const ScannerContext& /*rContext*/ )
{
osl::MutexGuard aGuard( maProtector );
return uno::Reference< awt::XBitmap >( this );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: aSrcIdent.