Files
libreoffice/extensions/source/scanner/scanwin.cxx
Mike Kaganski 362a21d3a1 Use explicit function names for fooA/fooW WinAPI; prefer fooW
We should only use generic foo function name when it takes params
that are also dependent on UNICODE define, like
LoadCursor( nullptr, IDC_ARROW )
where IDC_ARROW is defined in MSVC headers synchronised with
LoadCursor definition.

We should always use Unicode API for any file paths operations,
because otherwise we will get "?" for any character in path that
is not in current non-unicode codepage, which will result in failed
file operations.

Change-Id: I3a7f453ca0f893002d8a9764318919709fd8b633
Reviewed-on: https://gerrit.libreoffice.org/42935
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
2017-09-30 11:23:41 +02:00

917 lines
26 KiB
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 <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"
#if defined _MSC_VER
#pragma warning (push,1)
#pragma warning (disable:4668)
#endif
#include "twain/twain.h"
#if defined _MSC_VER
#pragma warning (pop)
#endif
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 ) ((double)nFix.Whole+(double)nFix.Frac/65536.)
#define FIXTOLONG( nFix ) ((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;
}
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;
TW_UINT32 hDIB = 0;
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( reinterpret_cast<HGLOBAL>((sal_IntPtr) hDIB) ));
static const double fFactor = 100.0 / 2.54;
pBIH->biXPelsPerMeter = FRound( fFactor * nXRes );
pBIH->biYPelsPerMeter = FRound( fFactor * nYRes );
GlobalUnlock( reinterpret_cast<HGLOBAL>((sal_IntPtr) hDIB) );
}
mrMgr.SetData( reinterpret_cast<void*>((sal_IntPtr) hDIB) );
}
else
GlobalFree( reinterpret_cast<HGLOBAL>((sal_IntPtr) 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: */