| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 <math.h> |
| #include <tools/svwin.h> |
| #include <tools/stream.hxx> |
| #include <vos/mutex.hxx> |
| #include <vos/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; |
| vos:: OModule * 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() ); |
| |
| // #107835# 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 ::vos::OModule( ::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; |
| |
| // #107835# 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; |
| |
| // #107835# 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; |
| |
| // #107835# 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 ); |
| |
| // #107835# 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::createFromAscii( "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::createFromAscii( "ActiveFrame" ) ); |
| } |
| catch( const beans::UnknownPropertyException& ) |
| { |
| // property unknown. |
| DBG_ERROR("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& ) |
| { |
| } |
| |
| DBG_ERROR("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& ) |
| { |
| } |
| |
| DBG_ERROR("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 |
| DBG_ERROR("ImpTwain::ImplRegisterCloseListener: XFrame has no XCloseBroadcaster!"); |
| return; |
| } |
| } |
| catch( const uno::Exception& ) |
| { |
| } |
| |
| DBG_ERROR("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 |
| DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: XFrame has no XCloseBroadcaster!"); |
| return; |
| } |
| } |
| catch( const uno::Exception& ) |
| { |
| } |
| |
| DBG_ERROR("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 |
| DBG_ERROR("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& ) |
| { |
| } |
| |
| DBG_ERROR("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 ) |
| { |
| // #107835# 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 ) |
| { |
| // #107835# 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() |
| { |
| vos::OGuard 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 ) |
| { |
| vos::OGuard 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 ) |
| { |
| vos::OGuard 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 ) |
| { |
| vos::OGuard 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 ) |
| { |
| vos::OGuard aGuard( maProtector ); |
| return uno::Reference< awt::XBitmap >( this ); |
| } |