/************************************************************************* * * $RCSfile: scanwin.cxx,v $ * * $Revision: 1.5 $ * * last change: $Author: rt $ $Date: 2003-04-08 15:40:31 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses * * - GNU Lesser General Public License Version 2.1 * - Sun Industry Standards Source License Version 1.1 * * Sun Microsystems Inc., October, 2000 * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2000 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library 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 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * * Sun Industry Standards Source License Version 1.1 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.1 (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.openoffice.org/license.html. * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2000 by Sun Microsystems, Inc. * * All Rights Reserved. * * Contributor(s): _______________________________________ * * ************************************************************************/ #ifndef _COM_SUN_STAR_UNO_ANY_HXX_ #include #endif #ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_ #include #endif #ifndef _COM_SUN_STAR_UTIL_XCLOSEABLE_HPP_ #include #endif #ifndef _COM_SUN_STAR_UTIL_XCLOSEBROADCASTER_HPP_ #include #endif #ifndef _COM_SUN_STAR_UTIL_XCLOSELISTENER_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XFRAME_HPP_ #include #endif #ifndef _COM_SUN_STAR_FRAME_XDESKTOP_HPP_ #include #endif #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_ #include #endif #ifndef _CPPUHELPER_IMPLBASE1_HXX_ #include #endif #ifndef _COMPHELPER_PROCESSFACTORY_HXX_ #include #endif #include #include #include #include #include #include #include #include #include #include "scanner.hxx" #include "twain/twain.h" 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 WIN #define TWAIN_LIBNAME "TWAIN.DLL" #define TWAIN_FUNCNAME "DSM_Entry" #elif 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 - // ------------ typedef ::cppu::WeakImplHelper1< ::com::sun::star::util::XCloseListener > CloseListenerBase; class ImpTwain : public CloseListenerBase { REF( com::sun::star::scanner::XScannerManager ) mxMgr; ScannerManager* mpMgr; TW_IDENTITY aAppIdent; TW_IDENTITY aSrcIdent; Link aNotifyLink; DSMENTRYPROC pDSM; NAMESPACE_VOS( OModule )* pMod; ULONG nCurState; bool mbCloseFrameOnExit; uno::Reference< uno::XInterface > mxSelfRef; 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* ); public: HWND hTwainWnd; HHOOK hTwainHook; BOOL ImplHandleMsg( void* pMsg ); public: ImpTwain( ScannerManager* pMgr, const Link& rNotifyLink ); ~ImpTwain(); void Destroy(); BOOL SelectSource(); BOOL InitXfer(); // from util::XCloseListener virtual void SAL_CALL queryClosing( const ::com::sun::star::lang::EventObject& Source, sal_Bool GetsOwnership ) throw (::com::sun::star::util::CloseVetoException, ::com::sun::star::uno::RuntimeException); virtual void SAL_CALL notifyClosing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); // from lang::XEventListener virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); }; // --------- // - 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; } } // ----------------------------------------------------------------------------- ImpTwain::ImpTwain( ScannerManager* pMgr, const Link& rNotifyLink ) : // #107835# hold reference to ScannerManager, to prevent premature death mxMgr ( REF(com::sun::star::scanner::XScannerManager)( static_cast< OWeakObject* >(pMgr), ::com::sun::star::uno::UNO_QUERY) ), mpMgr ( pMgr ), 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, "6.1", 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; HWND hParentWnd = HWND_DESKTOP; 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, hParentWnd, 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( mxMgr.is() && mpMgr && mpMgr->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( mxMgr.is() && mpMgr && 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 ); } mpMgr->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 { REF( com::sun::star::scanner::XScannerManager ) mxMgr; ScannerManager* mpMgr; REF( com::sun::star::lang::XEventListener ) mxListener; ImpTwain* mpImpTwain; TwainState meState; DECL_LINK( ImpNotifyHdl, ImpTwain* ); public: Twain(); ~Twain(); BOOL SelectSource(); BOOL PerformTransfer( ScannerManager* pMgr, const REF( com::sun::star::lang::XEventListener )& rxListener ); TwainState GetState() const { return meState; } }; // ------------------------------------------------------------------------ Twain::Twain() : mxMgr (), mpMgr ( NULL ), mpImpTwain ( NULL ), meState ( TWAIN_STATE_NONE ) { } // ------------------------------------------------------------------------ Twain::~Twain() { if( mpImpTwain ) mpImpTwain->Destroy(); } // ------------------------------------------------------------------------ BOOL Twain::SelectSource() { BOOL bRet; if( !mpImpTwain && mxMgr.is() ) { meState = TWAIN_STATE_NONE; mpImpTwain = new ImpTwain( mpMgr, LINK( this, Twain, ImpNotifyHdl ) ); bRet = mpImpTwain->SelectSource(); } else bRet = FALSE; return bRet; } // ------------------------------------------------------------------------ BOOL Twain::PerformTransfer( ScannerManager* pMgr, const REF( com::sun::star::lang::XEventListener )& rxListener ) { BOOL bRet; if( pMgr && !mpImpTwain ) { // #107835# hold reference to ScannerManager, to prevent premature death mxMgr = REF(com::sun::star::scanner::XScannerManager)(static_cast< OWeakObject* >(pMgr), ::com::sun::star::uno::UNO_QUERY), mpMgr = pMgr; mxListener = rxListener; meState = TWAIN_STATE_NONE; mpImpTwain = new ImpTwain( mpMgr, 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; } if( mxMgr.is() && mpMgr && mxListener.is() ) mxListener->disposing( com::sun::star::lang::EventObject( REF( XInterface )( static_cast< OWeakObject* >( mpMgr ) ) ) ); mxListener = REF( com::sun::star::lang::XEventListener )(); } break; case( TWAIN_EVENT_XFER ): { if( mxMgr.is() && mpMgr && mpImpTwain ) { meState = ( ( mpMgr && mpMgr->GetData() ) ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED ); mpImpTwain->Destroy(); mpImpTwain = NULL; if( mpMgr && mxListener.is() ) mxListener->disposing( com::sun::star::lang::EventObject( REF( XInterface )( static_cast< OWeakObject* >( mpMgr ) ) ) ); } mxListener = REF( com::sun::star::lang::XEventListener )(); } break; default: break; } return 0L; } // ----------- // - statics - // ----------- static Twain aTwain; // ------------------ // - ScannerManager - // ------------------ void ScannerManager::DestroyData() { if( mpData ) { GlobalFree( (HGLOBAL)(long) mpData ); mpData = NULL; } } // ----------------------------------------------------------------------------- AWT::Size ScannerManager::getSize() { 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() { SEQ( sal_Int8 ) aRet; if( mpData ) { HGLOBAL hDIB = (HGLOBAL)(long) mpData; const sal_uInt32 nDIBSize = GlobalSize( hDIB ); sal_uInt32 nSize = sizeof( BITMAPFILEHEADER) + nDIBSize; 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; HMEMCPY( pBuf + sizeof( BITMAPFILEHEADER ), pBIH, nDIBSize ); } GlobalUnlock( hDIB ); DestroyData(); } return aRet; } // ----------------------------------------------------------------------------- SEQ( ScannerContext ) SAL_CALL ScannerManager::getAvailableScanners() { 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; } // ----------------------------------------------------------------------------- BOOL SAL_CALL ScannerManager::configureScanner( ScannerContext& rContext ) throw( ScannerException ) { vos::OGuard aGuard( maProtector ); REF( 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 ); DestroyData(); return aTwain.SelectSource(); } // ----------------------------------------------------------------------------- void SAL_CALL ScannerManager::startScan( const ScannerContext& rContext, const REF( com::sun::star::lang::XEventListener )& rxListener ) throw( ScannerException ) { vos::OGuard aGuard( maProtector ); REF( 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 ); DestroyData(); aTwain.PerformTransfer( this, rxListener ); } // ----------------------------------------------------------------------------- ScanError SAL_CALL ScannerManager::getError( const ScannerContext& rContext ) throw( ScannerException ) { vos::OGuard aGuard( maProtector ); ScanError eError; REF( 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 ); if( aTwain.GetState() == TWAIN_STATE_CANCELED ) eError = ScanError_ScanCanceled; else eError = ScanError_ScanErrorNone; return eError; } // ----------------------------------------------------------------------------- REF( AWT::XBitmap ) SAL_CALL ScannerManager::getBitmap( const ScannerContext& rContext ) throw( ScannerException ) { vos::OGuard aGuard( maProtector ); return REF( AWT::XBitmap )( this ); }