summaryrefslogtreecommitdiff
path: root/extensions/source/scanner/scanwin.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/source/scanner/scanwin.cxx')
-rw-r--r--extensions/source/scanner/scanwin.cxx1059
1 files changed, 1059 insertions, 0 deletions
diff --git a/extensions/source/scanner/scanwin.cxx b/extensions/source/scanner/scanwin.cxx
new file mode 100644
index 000000000000..5f6d47e44e48
--- /dev/null
+++ b/extensions/source/scanner/scanwin.cxx
@@ -0,0 +1,1059 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#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/XDesktop.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <prewin.h>
+#include <windows.h>
+#include <postwin.h>
+#include <math.h>
+#include <tools/stream.hxx>
+#include <osl/mutex.hxx>
+#include <osl/module.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/salbtype.hxx>
+#include "scanner.hxx"
+
+#pragma warning (push,1)
+#pragma warning (disable:4668)
+#include "twain/twain.h"
+#pragma warning (pop)
+
+using namespace ::com::sun::star;
+
+// -----------
+// - Defines -
+// -----------
+
+#define TWAIN_SELECT 0x00000001UL
+#define TWAIN_ACQUIRE 0x00000002UL
+#define TWAIN_TERMINATE 0xFFFFFFFFUL
+
+#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))
+
+#if defined WNT
+#define TWAIN_LIBNAME "TWAIN_32.DLL"
+#define TWAIN_FUNCNAME "DSM_Entry"
+#endif
+
+// --------------
+// - TwainState -
+// --------------
+
+enum TwainState
+{
+ TWAIN_STATE_NONE = 0,
+ TWAIN_STATE_SCANNING = 1,
+ TWAIN_STATE_DONE = 2,
+ TWAIN_STATE_CANCELED = 3
+};
+
+// ------------
+// - ImpTwain -
+// ------------
+
+class ImpTwain : public ::cppu::WeakImplHelper1< 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 aNotifyLink;
+ DSMENTRYPROC pDSM;
+ osl::Module* pMod;
+ ULONG nCurState;
+ HWND hTwainWnd;
+ HHOOK hTwainHook;
+ bool mbCloseFrameOnExit;
+
+ bool ImplHandleMsg( void* pMsg );
+ void ImplCreate();
+ void ImplOpenSourceManager();
+ void ImplOpenSource();
+ bool ImplEnableSource();
+ void ImplXfer();
+ void ImplFallback( ULONG nEvent );
+ void ImplSendCloseEvent();
+ void ImplDeregisterCloseListener();
+ void ImplRegisterCloseListener();
+ uno::Reference< frame::XFrame > ImplGetActiveFrame();
+ uno::Reference< util::XCloseBroadcaster > ImplGetActiveFrameCloseBroadcaster();
+
+ DECL_LINK( ImplFallbackHdl, void* );
+ DECL_LINK( ImplDestroyHdl, void* );
+
+ // from util::XCloseListener
+ virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException);
+ virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException);
+
+ // from lang::XEventListener
+ virtual void SAL_CALL disposing( const lang::EventObject& Source ) throw (uno::RuntimeException);
+
+public:
+
+ ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink );
+ ~ImpTwain();
+
+ void Destroy();
+
+ bool SelectSource();
+ bool InitXfer();
+};
+
+// ---------
+// - Procs -
+// ---------
+
+static ImpTwain* pImpTwainInstance = NULL;
+
+// -------------------------------------------------------------------------
+
+LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
+{
+ return DefWindowProc( hWnd, nMsg, nPar1, nPar2 );
+}
+
+// -------------------------------------------------------------------------
+
+LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
+{
+ MSG* pMsg = (MSG*) lParam;
+
+ if( ( nCode < 0 ) || ( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) || !pImpTwainInstance->ImplHandleMsg( (void*) lParam ) )
+ {
+ return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam );
+ }
+ else
+ {
+ pMsg->message = WM_USER;
+ pMsg->lParam = 0;
+
+ return 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+// #107835# hold reference to ScannerManager, to prevent premature death
+ImpTwain::ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink ) :
+ mrMgr( rMgr ),
+ mxMgr( uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( &rMgr ), uno::UNO_QUERY) ),
+ aNotifyLink( rNotifyLink ),
+ pDSM( NULL ),
+ pMod( NULL ),
+ hTwainWnd( 0 ),
+ hTwainHook( 0 ),
+ nCurState( 1 ),
+ 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;
+
+ WNDCLASS aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASS ), GetModuleHandle( NULL ), NULL, NULL, NULL, NULL, "TwainClass" };
+ RegisterClass( &aWc );
+
+ hTwainWnd = CreateWindowEx( WS_EX_TOPMOST, aWc.lpszClassName, "TWAIN", 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, aWc.hInstance, 0 );
+ hTwainHook = SetWindowsHookEx( WH_GETMESSAGE, &TwainMsgProc, NULL, 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 ), NULL );
+}
+
+// -----------------------------------------------------------------------------
+
+bool ImpTwain::SelectSource()
+{
+ TW_UINT16 nRet = TWRC_FAILURE;
+
+ ImplOpenSourceManager();
+
+ if( 3 == nCurState )
+ {
+ TW_IDENTITY aIdent;
+
+ aIdent.Id = 0, aIdent.ProductName[ 0 ] = '\0';
+ aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
+ nRet = PFUNC( &aAppIdent, NULL, 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( ::rtl::OUString() );
+
+ if( pMod->load( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( TWAIN_LIBNAME ) ) ) )
+ {
+ nCurState = 2;
+
+ if( ( ( pDSM = (DSMENTRYPROC) pMod->getSymbol( String( RTL_CONSTASCII_USTRINGPARAM( TWAIN_FUNCNAME ) ) ) ) != NULL ) &&
+ ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) )
+ {
+ nCurState = 3;
+ }
+ }
+ else
+ {
+ delete pMod;
+ pMod = NULL;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void ImpTwain::ImplOpenSource()
+{
+ if( 3 == nCurState )
+ {
+ if( ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) &&
+ ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) )
+ {
+ TW_CAPABILITY aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) };
+ TW_ONEVALUE* pVal = (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( (void*) 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 = (PTWAINMSG) pMsg;
+ TW_EVENT aEvt = { pMess, MSG_NULL };
+
+ nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt );
+
+ if( aEvt.TWMessage != MSG_NULL )
+ {
+ switch( aEvt.TWMessage )
+ {
+ case MSG_XFERREADY:
+ {
+ ULONG 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 = -1L;
+
+ 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 = (BITMAPINFOHEADER*) GlobalLock( (HGLOBAL) hDIB );
+ static const double fFactor = 100.0 / 2.54;
+
+ pBIH->biXPelsPerMeter = FRound( fFactor * nXRes );
+ pBIH->biYPelsPerMeter = FRound( fFactor * nYRes );
+
+ GlobalUnlock( (HGLOBAL) hDIB );
+ }
+
+ mrMgr.SetData( (void*)(long) hDIB );
+ }
+ else
+ GlobalFree( (HGLOBAL) hDIB );
+
+ nCurState = 7;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void ImpTwain::ImplFallback( ULONG nEvent )
+{
+ Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent );
+}
+
+// -----------------------------------------------------------------------------
+
+IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData )
+{
+ const ULONG nEvent = (ULONG) 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, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent );
+ nCurState = 3;
+ }
+ break;
+
+ case( 3 ):
+ {
+ PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd );
+ nCurState = 2;
+ }
+ break;
+
+ case( 2 ):
+ {
+ delete pMod;
+ pMod = NULL;
+ nCurState = 1;
+ }
+ break;
+
+ default:
+ {
+ if( nEvent != TWAIN_EVENT_NONE )
+ aNotifyLink.Call( (void*) nEvent );
+
+ bFallback = false;
+ }
+ break;
+ }
+
+ if( bFallback )
+ ImplFallback( nEvent );
+
+ return 0L;
+}
+
+// -----------------------------------------------------------------------------
+
+IMPL_LINK( ImpTwain, ImplDestroyHdl, void*, /*p*/ )
+{
+ if( hTwainWnd )
+ DestroyWindow( hTwainWnd );
+
+ if( hTwainHook )
+ UnhookWindowsHookEx( hTwainHook );
+
+ // permit destruction of ourselves (normally, refcount
+ // should drop to zero exactly here)
+ mxSelfRef = NULL;
+ pImpTwainInstance = NULL;
+
+ return 0L;
+}
+
+// -----------------------------------------------------------------------------
+
+uno::Reference< frame::XFrame > ImpTwain::ImplGetActiveFrame()
+{
+ try
+ {
+ uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
+
+ if( xMgr.is() )
+ {
+ // query desktop instance
+ uno::Reference< frame::XDesktop > xDesktop( xMgr->createInstance(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")) ), uno::UNO_QUERY );
+
+ if( xDesktop.is() )
+ {
+ // query property set from desktop, which contains the currently active frame
+ uno::Reference< beans::XPropertySet > xDesktopProps( xDesktop, uno::UNO_QUERY );
+
+ if( xDesktopProps.is() )
+ {
+ uno::Any aActiveFrame;
+
+ try
+ {
+ aActiveFrame = xDesktopProps->getPropertyValue(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("ActiveFrame")) );
+ }
+ catch( const beans::UnknownPropertyException& )
+ {
+ // property unknown.
+ OSL_FAIL("ImpTwain::ImplGetActiveFrame: ActiveFrame property unknown, cannot determine active frame!");
+ return uno::Reference< frame::XFrame >();
+ }
+
+ uno::Reference< frame::XFrame > xActiveFrame;
+
+ if( (aActiveFrame >>= xActiveFrame) &&
+ 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 > ImpTwain::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 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 ) throw (util::CloseVetoException, uno::RuntimeException)
+{
+ // 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*/ ) throw (uno::RuntimeException)
+{
+ // should not happen
+ OSL_FAIL("ImpTwain::notifyClosing called, but we vetoed the closing before!");
+}
+
+// -----------------------------------------------------------------------------
+
+void SAL_CALL ImpTwain::disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
+{
+ // we're not holding any references to the frame, thus noop
+}
+
+// -----------------------------------------------------------------------------
+
+void ImpTwain::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!");
+}
+
+
+// ---------
+// - Twain -
+// ---------
+
+class Twain
+{
+ uno::Reference< lang::XEventListener > mxListener;
+ uno::Reference< scanner::XScannerManager > mxMgr;
+ const ScannerManager* mpCurMgr;
+ ImpTwain* mpImpTwain;
+ TwainState meState;
+
+ DECL_LINK( ImpNotifyHdl, ImpTwain* );
+
+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( NULL ),
+ mpImpTwain( NULL ),
+ 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 = uno::Reference< scanner::XScannerManager >( 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 = uno::Reference< scanner::XScannerManager >( 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, ImpTwain*, nEvent )
+{
+ switch( (ULONG)(void*) 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 = NULL;
+ mpCurMgr = NULL;
+ }
+
+ if( mxListener.is() )
+ mxListener->disposing( lang::EventObject( mxMgr ) );
+
+ mxListener = NULL;
+ }
+ break;
+
+ case( TWAIN_EVENT_XFER ):
+ {
+ if( mpImpTwain )
+ {
+ meState = ( mpCurMgr->GetData() ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED );
+
+ mpImpTwain->Destroy();
+ mpImpTwain = NULL;
+ mpCurMgr = NULL;
+
+ if( mxListener.is() )
+ mxListener->disposing( lang::EventObject( mxMgr ) );
+ }
+
+ mxListener = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0L;
+}
+
+// -----------
+// - statics -
+// -----------
+
+static Twain aTwain;
+
+// ------------------
+// - ScannerManager -
+// ------------------
+
+void ScannerManager::AcquireData()
+{
+}
+
+void ScannerManager::ReleaseData()
+{
+ if( mpData )
+ {
+ GlobalFree( (HGLOBAL)(long) mpData );
+ mpData = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+AWT::Size ScannerManager::getSize() throw()
+{
+ AWT::Size aRet;
+ HGLOBAL hDIB = (HGLOBAL)(long) mpData;
+
+ if( hDIB )
+ {
+ BITMAPINFOHEADER* pBIH = (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;
+}
+
+// -----------------------------------------------------------------------------
+
+SEQ( sal_Int8 ) ScannerManager::getDIB() throw()
+{
+ SEQ( sal_Int8 ) aRet;
+
+ if( mpData )
+ {
+ HGLOBAL hDIB = (HGLOBAL)(long) mpData;
+ const sal_uInt32 nDIBSize = GlobalSize( hDIB );
+ BITMAPINFOHEADER* pBIH = (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 = SEQ( sal_Int8 )( sizeof( BITMAPFILEHEADER ) + nDIBSize );
+
+ sal_Int8* pBuf = aRet.getArray();
+ SvMemoryStream* pMemStm = new SvMemoryStream( (char*) pBuf, sizeof( BITMAPFILEHEADER ), STREAM_WRITE );
+
+ *pMemStm << 'B' << 'M' << (sal_uInt32) 0 << (sal_uInt32) 0;
+ *pMemStm << (sal_uInt32) ( sizeof( BITMAPFILEHEADER ) + pBIH->biSize + ( nColEntries * sizeof( RGBQUAD ) ) );
+
+ delete pMemStm;
+ memcpy( pBuf + sizeof( BITMAPFILEHEADER ), pBIH, nDIBSize );
+ }
+
+ GlobalUnlock( hDIB );
+ ReleaseData();
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------------
+
+SEQ( ScannerContext ) SAL_CALL ScannerManager::getAvailableScanners() throw()
+{
+ osl::MutexGuard aGuard( maProtector );
+ SEQ( ScannerContext ) aRet( 1 );
+
+ aRet.getArray()[0].ScannerName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) );
+ aRet.getArray()[0].InternalData = 0;
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Bool SAL_CALL ScannerManager::configureScanner( ScannerContext& rContext )
+ throw( ScannerException )
+{
+ osl::MutexGuard aGuard( maProtector );
+ uno::Reference< XScannerManager > xThis( this );
+
+ if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
+ throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "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 )
+ throw( ScannerException )
+{
+ osl::MutexGuard aGuard( maProtector );
+ uno::Reference< XScannerManager > xThis( this );
+
+ if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
+ throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
+
+ ReleaseData();
+ aTwain.PerformTransfer( *this, rxListener );
+}
+
+// -----------------------------------------------------------------------------
+
+ScanError SAL_CALL ScannerManager::getError( const ScannerContext& rContext )
+ throw( ScannerException )
+{
+ osl::MutexGuard aGuard( maProtector );
+ uno::Reference< XScannerManager > xThis( this );
+
+ if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
+ throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "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*/ )
+ throw( ScannerException )
+{
+ osl::MutexGuard aGuard( maProtector );
+ return uno::Reference< awt::XBitmap >( this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */