Update ooo320-m1
[ooovba.git] / extensions / source / scanner / scanwin.cxx
blobb7d7e3c0b051e73ff89bc71fbacd5ae8c506ff22
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: scanwin.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_extensions.hxx"
33 #include <com/sun/star/uno/Any.hxx>
34 #include <com/sun/star/uno/Reference.hxx>
35 #include <com/sun/star/util/XCloseable.hpp>
36 #include <com/sun/star/util/XCloseBroadcaster.hpp>
37 #include <com/sun/star/util/XCloseListener.hpp>
38 #include <com/sun/star/frame/XFrame.hpp>
39 #include <com/sun/star/frame/XDesktop.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <cppuhelper/implbase1.hxx>
42 #include <comphelper/processfactory.hxx>
44 #include <math.h>
45 #include <tools/svwin.h>
46 #include <tools/stream.hxx>
47 #include <vos/mutex.hxx>
48 #include <vos/module.hxx>
49 #include <vcl/svapp.hxx>
50 #include <vcl/wrkwin.hxx>
51 #include <vcl/sysdata.hxx>
52 #include <vcl/salbtype.hxx>
53 #include "scanner.hxx"
55 #pragma warning (push,1)
56 #pragma warning (disable:4668)
57 #include "twain/twain.h"
58 #pragma warning (pop)
60 using namespace ::com::sun::star;
62 // -----------
63 // - Defines -
64 // -----------
66 #define TWAIN_SELECT 0x00000001UL
67 #define TWAIN_ACQUIRE 0x00000002UL
68 #define TWAIN_TERMINATE 0xFFFFFFFFUL
70 #define TWAIN_EVENT_NONE 0x00000000UL
71 #define TWAIN_EVENT_QUIT 0x00000001UL
72 #define TWAIN_EVENT_SCANNING 0x00000002UL
73 #define TWAIN_EVENT_XFER 0x00000004UL
75 #define PFUNC (*pDSM)
76 #define PTWAINMSG MSG*
77 #define FIXTODOUBLE( nFix ) ((double)nFix.Whole+(double)nFix.Frac/65536.)
78 #define FIXTOLONG( nFix ) ((long)floor(FIXTODOUBLE(nFix)+0.5))
80 #if defined WIN
81 #define TWAIN_LIBNAME "TWAIN.DLL"
82 #define TWAIN_FUNCNAME "DSM_Entry"
83 #elif defined WNT
84 #define TWAIN_LIBNAME "TWAIN_32.DLL"
85 #define TWAIN_FUNCNAME "DSM_Entry"
86 #endif
88 // --------------
89 // - TwainState -
90 // --------------
92 enum TwainState
94 TWAIN_STATE_NONE = 0,
95 TWAIN_STATE_SCANNING = 1,
96 TWAIN_STATE_DONE = 2,
97 TWAIN_STATE_CANCELED = 3
100 // ------------
101 // - ImpTwain -
102 // ------------
104 class ImpTwain : public ::cppu::WeakImplHelper1< util::XCloseListener >
106 friend LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam );
108 uno::Reference< uno::XInterface > mxSelfRef;
109 uno::Reference< scanner::XScannerManager > mxMgr;
110 ScannerManager& mrMgr;
111 TW_IDENTITY aAppIdent;
112 TW_IDENTITY aSrcIdent;
113 Link aNotifyLink;
114 DSMENTRYPROC pDSM;
115 NAMESPACE_VOS( OModule )* pMod;
116 ULONG nCurState;
117 HWND hTwainWnd;
118 HHOOK hTwainHook;
119 bool mbCloseFrameOnExit;
121 bool ImplHandleMsg( void* pMsg );
122 void ImplCreate();
123 void ImplOpenSourceManager();
124 void ImplOpenSource();
125 bool ImplEnableSource();
126 void ImplXfer();
127 void ImplFallback( ULONG nEvent );
128 void ImplSendCloseEvent();
129 void ImplDeregisterCloseListener();
130 void ImplRegisterCloseListener();
131 uno::Reference< frame::XFrame > ImplGetActiveFrame();
132 uno::Reference< util::XCloseBroadcaster > ImplGetActiveFrameCloseBroadcaster();
134 DECL_LINK( ImplFallbackHdl, void* );
135 DECL_LINK( ImplDestroyHdl, void* );
137 // from util::XCloseListener
138 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException);
139 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException);
141 // from lang::XEventListener
142 virtual void SAL_CALL disposing( const lang::EventObject& Source ) throw (uno::RuntimeException);
144 public:
146 ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink );
147 ~ImpTwain();
149 void Destroy();
151 bool SelectSource();
152 bool InitXfer();
155 // ---------
156 // - Procs -
157 // ---------
159 static ImpTwain* pImpTwainInstance = NULL;
161 // -------------------------------------------------------------------------
163 LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
165 return DefWindowProc( hWnd, nMsg, nPar1, nPar2 );
168 // -------------------------------------------------------------------------
170 LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
172 MSG* pMsg = (MSG*) lParam;
174 if( ( nCode < 0 ) || ( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) || !pImpTwainInstance->ImplHandleMsg( (void*) lParam ) )
176 return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam );
178 else
180 pMsg->message = WM_USER;
181 pMsg->lParam = 0;
183 return 0;
187 // -----------------------------------------------------------------------------
189 // #107835# hold reference to ScannerManager, to prevent premature death
190 ImpTwain::ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink ) :
191 mrMgr( rMgr ),
192 mxMgr( uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( &rMgr ), uno::UNO_QUERY) ),
193 aNotifyLink( rNotifyLink ),
194 pDSM( NULL ),
195 pMod( NULL ),
196 hTwainWnd( 0 ),
197 hTwainHook( 0 ),
198 nCurState( 1 ),
199 mbCloseFrameOnExit( false )
201 // setup TWAIN window
202 pImpTwainInstance = this;
204 aAppIdent.Id = 0;
205 aAppIdent.Version.MajorNum = 1;
206 aAppIdent.Version.MinorNum = 0;
207 aAppIdent.Version.Language = TWLG_USA;
208 aAppIdent.Version.Country = TWCY_USA;
209 aAppIdent.ProtocolMajor = TWON_PROTOCOLMAJOR;
210 aAppIdent.ProtocolMinor = TWON_PROTOCOLMINOR;
211 aAppIdent.SupportedGroups = DG_IMAGE | DG_CONTROL;
212 strncpy( aAppIdent.Version.Info, "8.0", 32 );
213 aAppIdent.Version.Info[32] = aAppIdent.Version.Info[33] = 0;
214 strncpy( aAppIdent.Manufacturer, "Sun Microsystems", 32 );
215 aAppIdent.Manufacturer[32] = aAppIdent.Manufacturer[33] = 0;
216 strncpy( aAppIdent.ProductFamily,"Office", 32 );
217 aAppIdent.ProductFamily[32] = aAppIdent.ProductFamily[33] = 0;
218 strncpy( aAppIdent.ProductName, "Office", 32 );
219 aAppIdent.ProductName[32] = aAppIdent.ProductName[33] = 0;
221 WNDCLASS aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASS ), GetModuleHandle( NULL ), NULL, NULL, NULL, NULL, "TwainClass" };
222 RegisterClass( &aWc );
224 hTwainWnd = CreateWindowEx( WS_EX_TOPMOST, aWc.lpszClassName, "TWAIN", 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, aWc.hInstance, 0 );
225 hTwainHook = SetWindowsHookEx( WH_GETMESSAGE, &TwainMsgProc, NULL, GetCurrentThreadId() );
227 // #107835# block destruction until ImplDestroyHdl is called
228 mxSelfRef = static_cast< ::cppu::OWeakObject* >( this );
231 // -----------------------------------------------------------------------------
233 ImpTwain::~ImpTwain()
235 // are we responsible for application shutdown?
236 if( mbCloseFrameOnExit )
237 ImplSendCloseEvent();
240 // -----------------------------------------------------------------------------
242 void ImpTwain::Destroy()
244 ImplFallback( TWAIN_EVENT_NONE );
245 Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL );
248 // -----------------------------------------------------------------------------
250 bool ImpTwain::SelectSource()
252 TW_UINT16 nRet = TWRC_FAILURE;
254 ImplOpenSourceManager();
256 if( 3 == nCurState )
258 TW_IDENTITY aIdent;
260 aIdent.Id = 0, aIdent.ProductName[ 0 ] = '\0';
261 aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
262 nRet = PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent );
265 ImplFallback( TWAIN_EVENT_QUIT );
267 return( TWRC_SUCCESS == nRet );
270 // -----------------------------------------------------------------------------
272 bool ImpTwain::InitXfer()
274 bool bRet = false;
276 ImplOpenSourceManager();
278 if( 3 == nCurState )
280 ImplOpenSource();
282 if( 4 == nCurState )
283 bRet = ImplEnableSource();
286 if( !bRet )
287 ImplFallback( TWAIN_EVENT_QUIT );
289 return bRet;
292 // -----------------------------------------------------------------------------
294 void ImpTwain::ImplOpenSourceManager()
296 if( 1 == nCurState )
298 pMod = new ::vos::OModule( ::rtl::OUString() );
300 if( pMod->load( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( TWAIN_LIBNAME ) ) ) )
302 nCurState = 2;
304 if( ( ( pDSM = (DSMENTRYPROC) pMod->getSymbol( String( RTL_CONSTASCII_USTRINGPARAM( TWAIN_FUNCNAME ) ) ) ) != NULL ) &&
305 ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) )
307 nCurState = 3;
310 else
312 delete pMod;
313 pMod = NULL;
318 // -----------------------------------------------------------------------------
320 void ImpTwain::ImplOpenSource()
322 if( 3 == nCurState )
324 if( ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) &&
325 ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) )
327 TW_CAPABILITY aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) };
328 TW_ONEVALUE* pVal = (TW_ONEVALUE*) GlobalLock( aCap.hContainer );
330 pVal->ItemType = TWTY_INT16, pVal->Item = 1;
331 GlobalUnlock( aCap.hContainer );
332 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap );
333 GlobalFree( aCap.hContainer );
334 nCurState = 4;
339 // -----------------------------------------------------------------------------
341 bool ImpTwain::ImplEnableSource()
343 bool bRet = false;
345 if( 4 == nCurState )
347 TW_USERINTERFACE aUI = { true, true, hTwainWnd };
349 aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
350 nCurState = 5;
352 // #107835# register as vetoable close listener, to prevent application to die under us
353 ImplRegisterCloseListener();
355 if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI ) == TWRC_SUCCESS )
357 bRet = true;
359 else
361 nCurState = 4;
363 // #107835# deregister as vetoable close listener, dialog failed
364 ImplDeregisterCloseListener();
368 return bRet;
371 // -----------------------------------------------------------------------------
373 bool ImpTwain::ImplHandleMsg( void* pMsg )
375 TW_UINT16 nRet;
376 PTWAINMSG pMess = (PTWAINMSG) pMsg;
377 TW_EVENT aEvt = { pMess, MSG_NULL };
379 nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt );
381 if( aEvt.TWMessage != MSG_NULL )
383 switch( aEvt.TWMessage )
385 case MSG_XFERREADY:
387 ULONG nEvent = TWAIN_EVENT_QUIT;
389 if( 5 == nCurState )
391 nCurState = 6;
392 ImplXfer();
394 if( mrMgr.GetData() )
395 nEvent = TWAIN_EVENT_XFER;
398 ImplFallback( nEvent );
400 break;
402 case MSG_CLOSEDSREQ:
403 ImplFallback( TWAIN_EVENT_QUIT );
404 break;
406 default:
407 break;
410 else
411 nRet = TWRC_NOTDSEVENT;
413 return( TWRC_DSEVENT == nRet );
416 // -----------------------------------------------------------------------------
418 void ImpTwain::ImplXfer()
420 if( nCurState == 6 )
422 TW_IMAGEINFO aInfo;
423 TW_UINT32 hDIB = 0;
424 long nWidth, nHeight, nXRes, nYRes;
426 if( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo ) == TWRC_SUCCESS )
428 nWidth = aInfo.ImageWidth;
429 nHeight = aInfo.ImageLength;
430 nXRes = FIXTOLONG( aInfo.XResolution );
431 nYRes = FIXTOLONG( aInfo.YResolution );
433 else
434 nWidth = nHeight = nXRes = nYRes = -1L;
436 switch( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB ) )
438 case( TWRC_CANCEL ):
439 nCurState = 7;
440 break;
442 case( TWRC_XFERDONE ):
444 if( hDIB )
446 if( ( nXRes != -1 ) && ( nYRes != - 1 ) && ( nWidth != - 1 ) && ( nHeight != - 1 ) )
448 // set resolution of bitmap
449 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( (HGLOBAL) hDIB );
450 static const double fFactor = 100.0 / 2.54;
452 pBIH->biXPelsPerMeter = FRound( fFactor * nXRes );
453 pBIH->biYPelsPerMeter = FRound( fFactor * nYRes );
455 GlobalUnlock( (HGLOBAL) hDIB );
458 mrMgr.SetData( (void*)(long) hDIB );
460 else
461 GlobalFree( (HGLOBAL) hDIB );
463 nCurState = 7;
465 break;
467 default:
468 break;
473 // -----------------------------------------------------------------------------
475 void ImpTwain::ImplFallback( ULONG nEvent )
477 Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent );
480 // -----------------------------------------------------------------------------
482 IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData )
484 const ULONG nEvent = (ULONG) pData;
485 bool bFallback = true;
487 switch( nCurState )
489 case( 7 ):
490 case( 6 ):
492 TW_PENDINGXFERS aXfers;
494 if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers ) == TWRC_SUCCESS )
496 if( aXfers.Count != 0 )
497 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers );
500 nCurState = 5;
502 break;
504 case( 5 ):
506 TW_USERINTERFACE aUI = { true, true, hTwainWnd };
508 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI );
509 nCurState = 4;
511 // #107835# deregister as vetoable close listener
512 ImplDeregisterCloseListener();
514 break;
516 case( 4 ):
518 PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent );
519 nCurState = 3;
521 break;
523 case( 3 ):
525 PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd );
526 nCurState = 2;
528 break;
530 case( 2 ):
532 delete pMod;
533 pMod = NULL;
534 nCurState = 1;
536 break;
538 default:
540 if( nEvent != TWAIN_EVENT_NONE )
541 aNotifyLink.Call( (void*) nEvent );
543 bFallback = false;
545 break;
548 if( bFallback )
549 ImplFallback( nEvent );
551 return 0L;
554 // -----------------------------------------------------------------------------
556 IMPL_LINK( ImpTwain, ImplDestroyHdl, void*, /*p*/ )
558 if( hTwainWnd )
559 DestroyWindow( hTwainWnd );
561 if( hTwainHook )
562 UnhookWindowsHookEx( hTwainHook );
564 // #107835# permit destruction of ourselves (normally, refcount
565 // should drop to zero exactly here)
566 mxSelfRef = NULL;
567 pImpTwainInstance = NULL;
569 return 0L;
572 // -----------------------------------------------------------------------------
574 uno::Reference< frame::XFrame > ImpTwain::ImplGetActiveFrame()
578 uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
580 if( xMgr.is() )
582 // query desktop instance
583 uno::Reference< frame::XDesktop > xDesktop( xMgr->createInstance(
584 OUString::createFromAscii( "com.sun.star.frame.Desktop" ) ), uno::UNO_QUERY );
586 if( xDesktop.is() )
588 // query property set from desktop, which contains the currently active frame
589 uno::Reference< beans::XPropertySet > xDesktopProps( xDesktop, uno::UNO_QUERY );
591 if( xDesktopProps.is() )
593 uno::Any aActiveFrame;
597 aActiveFrame = xDesktopProps->getPropertyValue(
598 OUString::createFromAscii( "ActiveFrame" ) );
600 catch( const beans::UnknownPropertyException& )
602 // property unknown.
603 DBG_ERROR("ImpTwain::ImplGetActiveFrame: ActiveFrame property unknown, cannot determine active frame!");
604 return uno::Reference< frame::XFrame >();
607 uno::Reference< frame::XFrame > xActiveFrame;
609 if( (aActiveFrame >>= xActiveFrame) &&
610 xActiveFrame.is() )
612 return xActiveFrame;
618 catch( const uno::Exception& )
622 DBG_ERROR("ImpTwain::ImplGetActiveFrame: Could not determine active frame!");
623 return uno::Reference< frame::XFrame >();
626 // -----------------------------------------------------------------------------
628 uno::Reference< util::XCloseBroadcaster > ImpTwain::ImplGetActiveFrameCloseBroadcaster()
632 return uno::Reference< util::XCloseBroadcaster >( ImplGetActiveFrame(), uno::UNO_QUERY );
634 catch( const uno::Exception& )
638 DBG_ERROR("ImpTwain::ImplGetActiveFrameCloseBroadcaster: Could determine close broadcaster on active frame!");
639 return uno::Reference< util::XCloseBroadcaster >();
642 // -----------------------------------------------------------------------------
644 void ImpTwain::ImplRegisterCloseListener()
648 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( ImplGetActiveFrameCloseBroadcaster() );
650 if( xCloseBroadcaster.is() )
652 xCloseBroadcaster->addCloseListener(this);
653 return; // successfully registered as a close listener
655 else
657 // interface unknown. don't register, then
658 DBG_ERROR("ImpTwain::ImplRegisterCloseListener: XFrame has no XCloseBroadcaster!");
659 return;
662 catch( const uno::Exception& )
666 DBG_ERROR("ImpTwain::ImplRegisterCloseListener: Could not register as close listener!");
669 // -----------------------------------------------------------------------------
671 void ImpTwain::ImplDeregisterCloseListener()
675 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
676 ImplGetActiveFrameCloseBroadcaster() );
678 if( xCloseBroadcaster.is() )
680 xCloseBroadcaster->removeCloseListener(this);
681 return; // successfully deregistered as a close listener
683 else
685 // interface unknown. don't deregister, then
686 DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: XFrame has no XCloseBroadcaster!");
687 return;
690 catch( const uno::Exception& )
694 DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: Could not deregister as close listener!");
697 // -----------------------------------------------------------------------------
699 void SAL_CALL ImpTwain::queryClosing( const lang::EventObject& /*Source*/, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException)
701 // shall we re-send the close query later on?
702 mbCloseFrameOnExit = GetsOwnership;
704 // the sole purpose of this listener is to forbid closing of the listened-at frame
705 throw util::CloseVetoException();
708 // -----------------------------------------------------------------------------
710 void SAL_CALL ImpTwain::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
712 // should not happen
713 DBG_ERROR("ImpTwain::notifyClosing called, but we vetoed the closing before!");
716 // -----------------------------------------------------------------------------
718 void SAL_CALL ImpTwain::disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
720 // we're not holding any references to the frame, thus noop
723 // -----------------------------------------------------------------------------
725 void ImpTwain::ImplSendCloseEvent()
729 uno::Reference< util::XCloseable > xCloseable( ImplGetActiveFrame(), uno::UNO_QUERY );
731 if( xCloseable.is() )
732 xCloseable->close( true );
734 catch( const uno::Exception& )
738 DBG_ERROR("ImpTwain::ImplSendCloseEvent: Could not send required close broadcast!");
742 // ---------
743 // - Twain -
744 // ---------
746 class Twain
748 uno::Reference< lang::XEventListener > mxListener;
749 uno::Reference< scanner::XScannerManager > mxMgr;
750 const ScannerManager* mpCurMgr;
751 ImpTwain* mpImpTwain;
752 TwainState meState;
754 DECL_LINK( ImpNotifyHdl, ImpTwain* );
756 public:
758 Twain();
759 ~Twain();
761 bool SelectSource( ScannerManager& rMgr );
762 bool PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener );
764 TwainState GetState() const { return meState; }
767 // ------------------------------------------------------------------------
769 Twain::Twain() :
770 mpCurMgr( NULL ),
771 mpImpTwain( NULL ),
772 meState( TWAIN_STATE_NONE )
776 // ------------------------------------------------------------------------
778 Twain::~Twain()
780 if( mpImpTwain )
781 mpImpTwain->Destroy();
784 // ------------------------------------------------------------------------
786 bool Twain::SelectSource( ScannerManager& rMgr )
788 bool bRet;
790 if( !mpImpTwain )
792 // #107835# hold reference to ScannerManager, to prevent premature death
793 mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
794 uno::UNO_QUERY ),
796 meState = TWAIN_STATE_NONE;
797 mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
798 bRet = mpImpTwain->SelectSource();
800 else
801 bRet = false;
803 return bRet;
806 // ------------------------------------------------------------------------
808 bool Twain::PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener )
810 bool bRet;
812 if( !mpImpTwain )
814 // #107835# hold reference to ScannerManager, to prevent premature death
815 mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
816 uno::UNO_QUERY ),
818 mxListener = rxListener;
819 meState = TWAIN_STATE_NONE;
820 mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
821 bRet = mpImpTwain->InitXfer();
823 else
824 bRet = false;
826 return bRet;
829 // ------------------------------------------------------------------------
831 IMPL_LINK( Twain, ImpNotifyHdl, ImpTwain*, nEvent )
833 switch( (ULONG)(void*) nEvent )
835 case( TWAIN_EVENT_SCANNING ):
836 meState = TWAIN_STATE_SCANNING;
837 break;
839 case( TWAIN_EVENT_QUIT ):
841 if( meState != TWAIN_STATE_DONE )
842 meState = TWAIN_STATE_CANCELED;
844 if( mpImpTwain )
846 mpImpTwain->Destroy();
847 mpImpTwain = NULL;
848 mpCurMgr = NULL;
851 if( mxListener.is() )
852 mxListener->disposing( lang::EventObject( mxMgr ) );
854 mxListener = NULL;
856 break;
858 case( TWAIN_EVENT_XFER ):
860 if( mpImpTwain )
862 meState = ( mpCurMgr->GetData() ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED );
864 mpImpTwain->Destroy();
865 mpImpTwain = NULL;
866 mpCurMgr = NULL;
868 if( mxListener.is() )
869 mxListener->disposing( lang::EventObject( mxMgr ) );
872 mxListener = NULL;
874 break;
876 default:
877 break;
880 return 0L;
883 // -----------
884 // - statics -
885 // -----------
887 static Twain aTwain;
889 // ------------------
890 // - ScannerManager -
891 // ------------------
893 void ScannerManager::DestroyData()
895 if( mpData )
897 GlobalFree( (HGLOBAL)(long) mpData );
898 mpData = NULL;
902 // -----------------------------------------------------------------------------
904 AWT::Size ScannerManager::getSize() throw()
906 AWT::Size aRet;
907 HGLOBAL hDIB = (HGLOBAL)(long) mpData;
909 if( hDIB )
911 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB );
913 if( pBIH )
915 aRet.Width = pBIH->biWidth;
916 aRet.Height = pBIH->biHeight;
918 else
919 aRet.Width = aRet.Height = 0;
921 GlobalUnlock( hDIB );
923 else
924 aRet.Width = aRet.Height = 0;
926 return aRet;
929 // -----------------------------------------------------------------------------
931 SEQ( sal_Int8 ) ScannerManager::getDIB() throw()
933 SEQ( sal_Int8 ) aRet;
935 if( mpData )
937 HGLOBAL hDIB = (HGLOBAL)(long) mpData;
938 const sal_uInt32 nDIBSize = GlobalSize( hDIB );
939 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB );
941 if( pBIH )
943 sal_uInt32 nColEntries;
945 switch( pBIH->biBitCount )
947 case( 1 ):
948 case( 4 ):
949 case( 8 ):
950 nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : ( 1 << pBIH->biBitCount );
951 break;
953 case( 24 ):
954 nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : 0;
955 break;
957 case( 16 ):
958 case( 32 ):
960 nColEntries = pBIH->biClrUsed;
962 if( pBIH->biCompression == BI_BITFIELDS )
963 nColEntries += 3;
965 break;
967 default:
968 nColEntries = 0;
969 break;
972 aRet = SEQ( sal_Int8 )( sizeof( BITMAPFILEHEADER ) + nDIBSize );
974 sal_Int8* pBuf = aRet.getArray();
975 SvMemoryStream* pMemStm = new SvMemoryStream( (char*) pBuf, sizeof( BITMAPFILEHEADER ), STREAM_WRITE );
977 *pMemStm << 'B' << 'M' << (sal_uInt32) 0 << (sal_uInt32) 0;
978 *pMemStm << (sal_uInt32) ( sizeof( BITMAPFILEHEADER ) + pBIH->biSize + ( nColEntries * sizeof( RGBQUAD ) ) );
980 delete pMemStm;
981 memcpy( pBuf + sizeof( BITMAPFILEHEADER ), pBIH, nDIBSize );
984 GlobalUnlock( hDIB );
985 DestroyData();
988 return aRet;
991 // -----------------------------------------------------------------------------
993 SEQ( ScannerContext ) SAL_CALL ScannerManager::getAvailableScanners() throw()
995 vos::OGuard aGuard( maProtector );
996 SEQ( ScannerContext ) aRet( 1 );
998 aRet.getArray()[0].ScannerName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) );
999 aRet.getArray()[0].InternalData = 0;
1001 return aRet;
1004 // -----------------------------------------------------------------------------
1006 BOOL SAL_CALL ScannerManager::configureScanner( ScannerContext& rContext )
1007 throw( ScannerException )
1009 vos::OGuard aGuard( maProtector );
1010 uno::Reference< XScannerManager > xThis( this );
1012 if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1013 throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1015 DestroyData();
1017 return aTwain.SelectSource( *this );
1020 // -----------------------------------------------------------------------------
1022 void SAL_CALL ScannerManager::startScan( const ScannerContext& rContext, const uno::Reference< lang::XEventListener >& rxListener )
1023 throw( ScannerException )
1025 vos::OGuard aGuard( maProtector );
1026 uno::Reference< XScannerManager > xThis( this );
1028 if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1029 throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1031 DestroyData();
1032 aTwain.PerformTransfer( *this, rxListener );
1035 // -----------------------------------------------------------------------------
1037 ScanError SAL_CALL ScannerManager::getError( const ScannerContext& rContext )
1038 throw( ScannerException )
1040 vos::OGuard aGuard( maProtector );
1041 uno::Reference< XScannerManager > xThis( this );
1043 if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1044 throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1046 return( ( aTwain.GetState() == TWAIN_STATE_CANCELED ) ? ScanError_ScanCanceled : ScanError_ScanErrorNone );
1049 // -----------------------------------------------------------------------------
1051 uno::Reference< awt::XBitmap > SAL_CALL ScannerManager::getBitmap( const ScannerContext& /*rContext*/ )
1052 throw( ScannerException )
1054 vos::OGuard aGuard( maProtector );
1055 return uno::Reference< awt::XBitmap >( this );