merged tag ooo/OOO330_m14
[LibreOffice.git] / extensions / source / scanner / scanwin.cxx
blobe14fffa87d0c7129cf15126dab7931f1bc0c1b84
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 #include <com/sun/star/uno/Any.hxx>
31 #include <com/sun/star/uno/Reference.hxx>
32 #include <com/sun/star/util/XCloseable.hpp>
33 #include <com/sun/star/util/XCloseBroadcaster.hpp>
34 #include <com/sun/star/util/XCloseListener.hpp>
35 #include <com/sun/star/frame/XFrame.hpp>
36 #include <com/sun/star/frame/XDesktop.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <cppuhelper/implbase1.hxx>
39 #include <comphelper/processfactory.hxx>
41 #include <math.h>
42 #include <tools/svwin.h>
43 #include <tools/stream.hxx>
44 #include <vos/mutex.hxx>
45 #include <vos/module.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/wrkwin.hxx>
48 #include <vcl/sysdata.hxx>
49 #include <vcl/salbtype.hxx>
50 #include "scanner.hxx"
52 #pragma warning (push,1)
53 #pragma warning (disable:4668)
54 #include "twain/twain.h"
55 #pragma warning (pop)
57 using namespace ::com::sun::star;
59 // -----------
60 // - Defines -
61 // -----------
63 #define TWAIN_SELECT 0x00000001UL
64 #define TWAIN_ACQUIRE 0x00000002UL
65 #define TWAIN_TERMINATE 0xFFFFFFFFUL
67 #define TWAIN_EVENT_NONE 0x00000000UL
68 #define TWAIN_EVENT_QUIT 0x00000001UL
69 #define TWAIN_EVENT_SCANNING 0x00000002UL
70 #define TWAIN_EVENT_XFER 0x00000004UL
72 #define PFUNC (*pDSM)
73 #define PTWAINMSG MSG*
74 #define FIXTODOUBLE( nFix ) ((double)nFix.Whole+(double)nFix.Frac/65536.)
75 #define FIXTOLONG( nFix ) ((long)floor(FIXTODOUBLE(nFix)+0.5))
77 #if defined WIN
78 #define TWAIN_LIBNAME "TWAIN.DLL"
79 #define TWAIN_FUNCNAME "DSM_Entry"
80 #elif defined WNT
81 #define TWAIN_LIBNAME "TWAIN_32.DLL"
82 #define TWAIN_FUNCNAME "DSM_Entry"
83 #endif
85 // --------------
86 // - TwainState -
87 // --------------
89 enum TwainState
91 TWAIN_STATE_NONE = 0,
92 TWAIN_STATE_SCANNING = 1,
93 TWAIN_STATE_DONE = 2,
94 TWAIN_STATE_CANCELED = 3
97 // ------------
98 // - ImpTwain -
99 // ------------
101 class ImpTwain : public ::cppu::WeakImplHelper1< util::XCloseListener >
103 friend LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam );
105 uno::Reference< uno::XInterface > mxSelfRef;
106 uno::Reference< scanner::XScannerManager > mxMgr;
107 ScannerManager& mrMgr;
108 TW_IDENTITY aAppIdent;
109 TW_IDENTITY aSrcIdent;
110 Link aNotifyLink;
111 DSMENTRYPROC pDSM;
112 NAMESPACE_VOS( OModule )* pMod;
113 ULONG nCurState;
114 HWND hTwainWnd;
115 HHOOK hTwainHook;
116 bool mbCloseFrameOnExit;
118 bool ImplHandleMsg( void* pMsg );
119 void ImplCreate();
120 void ImplOpenSourceManager();
121 void ImplOpenSource();
122 bool ImplEnableSource();
123 void ImplXfer();
124 void ImplFallback( ULONG nEvent );
125 void ImplSendCloseEvent();
126 void ImplDeregisterCloseListener();
127 void ImplRegisterCloseListener();
128 uno::Reference< frame::XFrame > ImplGetActiveFrame();
129 uno::Reference< util::XCloseBroadcaster > ImplGetActiveFrameCloseBroadcaster();
131 DECL_LINK( ImplFallbackHdl, void* );
132 DECL_LINK( ImplDestroyHdl, void* );
134 // from util::XCloseListener
135 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException);
136 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException);
138 // from lang::XEventListener
139 virtual void SAL_CALL disposing( const lang::EventObject& Source ) throw (uno::RuntimeException);
141 public:
143 ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink );
144 ~ImpTwain();
146 void Destroy();
148 bool SelectSource();
149 bool InitXfer();
152 // ---------
153 // - Procs -
154 // ---------
156 static ImpTwain* pImpTwainInstance = NULL;
158 // -------------------------------------------------------------------------
160 LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
162 return DefWindowProc( hWnd, nMsg, nPar1, nPar2 );
165 // -------------------------------------------------------------------------
167 LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
169 MSG* pMsg = (MSG*) lParam;
171 if( ( nCode < 0 ) || ( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) || !pImpTwainInstance->ImplHandleMsg( (void*) lParam ) )
173 return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam );
175 else
177 pMsg->message = WM_USER;
178 pMsg->lParam = 0;
180 return 0;
184 // -----------------------------------------------------------------------------
186 // #107835# hold reference to ScannerManager, to prevent premature death
187 ImpTwain::ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink ) :
188 mrMgr( rMgr ),
189 mxMgr( uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( &rMgr ), uno::UNO_QUERY) ),
190 aNotifyLink( rNotifyLink ),
191 pDSM( NULL ),
192 pMod( NULL ),
193 hTwainWnd( 0 ),
194 hTwainHook( 0 ),
195 nCurState( 1 ),
196 mbCloseFrameOnExit( false )
198 // setup TWAIN window
199 pImpTwainInstance = this;
201 aAppIdent.Id = 0;
202 aAppIdent.Version.MajorNum = 1;
203 aAppIdent.Version.MinorNum = 0;
204 aAppIdent.Version.Language = TWLG_USA;
205 aAppIdent.Version.Country = TWCY_USA;
206 aAppIdent.ProtocolMajor = TWON_PROTOCOLMAJOR;
207 aAppIdent.ProtocolMinor = TWON_PROTOCOLMINOR;
208 aAppIdent.SupportedGroups = DG_IMAGE | DG_CONTROL;
209 strncpy( aAppIdent.Version.Info, "8.0", 32 );
210 aAppIdent.Version.Info[32] = aAppIdent.Version.Info[33] = 0;
211 strncpy( aAppIdent.Manufacturer, "Sun Microsystems", 32 );
212 aAppIdent.Manufacturer[32] = aAppIdent.Manufacturer[33] = 0;
213 strncpy( aAppIdent.ProductFamily,"Office", 32 );
214 aAppIdent.ProductFamily[32] = aAppIdent.ProductFamily[33] = 0;
215 strncpy( aAppIdent.ProductName, "Office", 32 );
216 aAppIdent.ProductName[32] = aAppIdent.ProductName[33] = 0;
218 WNDCLASS aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASS ), GetModuleHandle( NULL ), NULL, NULL, NULL, NULL, "TwainClass" };
219 RegisterClass( &aWc );
221 hTwainWnd = CreateWindowEx( WS_EX_TOPMOST, aWc.lpszClassName, "TWAIN", 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, aWc.hInstance, 0 );
222 hTwainHook = SetWindowsHookEx( WH_GETMESSAGE, &TwainMsgProc, NULL, GetCurrentThreadId() );
224 // #107835# block destruction until ImplDestroyHdl is called
225 mxSelfRef = static_cast< ::cppu::OWeakObject* >( this );
228 // -----------------------------------------------------------------------------
230 ImpTwain::~ImpTwain()
232 // are we responsible for application shutdown?
233 if( mbCloseFrameOnExit )
234 ImplSendCloseEvent();
237 // -----------------------------------------------------------------------------
239 void ImpTwain::Destroy()
241 ImplFallback( TWAIN_EVENT_NONE );
242 Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL );
245 // -----------------------------------------------------------------------------
247 bool ImpTwain::SelectSource()
249 TW_UINT16 nRet = TWRC_FAILURE;
251 ImplOpenSourceManager();
253 if( 3 == nCurState )
255 TW_IDENTITY aIdent;
257 aIdent.Id = 0, aIdent.ProductName[ 0 ] = '\0';
258 aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
259 nRet = PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent );
262 ImplFallback( TWAIN_EVENT_QUIT );
264 return( TWRC_SUCCESS == nRet );
267 // -----------------------------------------------------------------------------
269 bool ImpTwain::InitXfer()
271 bool bRet = false;
273 ImplOpenSourceManager();
275 if( 3 == nCurState )
277 ImplOpenSource();
279 if( 4 == nCurState )
280 bRet = ImplEnableSource();
283 if( !bRet )
284 ImplFallback( TWAIN_EVENT_QUIT );
286 return bRet;
289 // -----------------------------------------------------------------------------
291 void ImpTwain::ImplOpenSourceManager()
293 if( 1 == nCurState )
295 pMod = new ::vos::OModule( ::rtl::OUString() );
297 if( pMod->load( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( TWAIN_LIBNAME ) ) ) )
299 nCurState = 2;
301 if( ( ( pDSM = (DSMENTRYPROC) pMod->getSymbol( String( RTL_CONSTASCII_USTRINGPARAM( TWAIN_FUNCNAME ) ) ) ) != NULL ) &&
302 ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) )
304 nCurState = 3;
307 else
309 delete pMod;
310 pMod = NULL;
315 // -----------------------------------------------------------------------------
317 void ImpTwain::ImplOpenSource()
319 if( 3 == nCurState )
321 if( ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) &&
322 ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) )
324 TW_CAPABILITY aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) };
325 TW_ONEVALUE* pVal = (TW_ONEVALUE*) GlobalLock( aCap.hContainer );
327 pVal->ItemType = TWTY_INT16, pVal->Item = 1;
328 GlobalUnlock( aCap.hContainer );
329 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap );
330 GlobalFree( aCap.hContainer );
331 nCurState = 4;
336 // -----------------------------------------------------------------------------
338 bool ImpTwain::ImplEnableSource()
340 bool bRet = false;
342 if( 4 == nCurState )
344 TW_USERINTERFACE aUI = { true, true, hTwainWnd };
346 aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
347 nCurState = 5;
349 // #107835# register as vetoable close listener, to prevent application to die under us
350 ImplRegisterCloseListener();
352 if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI ) == TWRC_SUCCESS )
354 bRet = true;
356 else
358 nCurState = 4;
360 // #107835# deregister as vetoable close listener, dialog failed
361 ImplDeregisterCloseListener();
365 return bRet;
368 // -----------------------------------------------------------------------------
370 bool ImpTwain::ImplHandleMsg( void* pMsg )
372 TW_UINT16 nRet;
373 PTWAINMSG pMess = (PTWAINMSG) pMsg;
374 TW_EVENT aEvt = { pMess, MSG_NULL };
376 nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt );
378 if( aEvt.TWMessage != MSG_NULL )
380 switch( aEvt.TWMessage )
382 case MSG_XFERREADY:
384 ULONG nEvent = TWAIN_EVENT_QUIT;
386 if( 5 == nCurState )
388 nCurState = 6;
389 ImplXfer();
391 if( mrMgr.GetData() )
392 nEvent = TWAIN_EVENT_XFER;
395 ImplFallback( nEvent );
397 break;
399 case MSG_CLOSEDSREQ:
400 ImplFallback( TWAIN_EVENT_QUIT );
401 break;
403 default:
404 break;
407 else
408 nRet = TWRC_NOTDSEVENT;
410 return( TWRC_DSEVENT == nRet );
413 // -----------------------------------------------------------------------------
415 void ImpTwain::ImplXfer()
417 if( nCurState == 6 )
419 TW_IMAGEINFO aInfo;
420 TW_UINT32 hDIB = 0;
421 long nWidth, nHeight, nXRes, nYRes;
423 if( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo ) == TWRC_SUCCESS )
425 nWidth = aInfo.ImageWidth;
426 nHeight = aInfo.ImageLength;
427 nXRes = FIXTOLONG( aInfo.XResolution );
428 nYRes = FIXTOLONG( aInfo.YResolution );
430 else
431 nWidth = nHeight = nXRes = nYRes = -1L;
433 switch( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB ) )
435 case( TWRC_CANCEL ):
436 nCurState = 7;
437 break;
439 case( TWRC_XFERDONE ):
441 if( hDIB )
443 if( ( nXRes != -1 ) && ( nYRes != - 1 ) && ( nWidth != - 1 ) && ( nHeight != - 1 ) )
445 // set resolution of bitmap
446 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( (HGLOBAL) hDIB );
447 static const double fFactor = 100.0 / 2.54;
449 pBIH->biXPelsPerMeter = FRound( fFactor * nXRes );
450 pBIH->biYPelsPerMeter = FRound( fFactor * nYRes );
452 GlobalUnlock( (HGLOBAL) hDIB );
455 mrMgr.SetData( (void*)(long) hDIB );
457 else
458 GlobalFree( (HGLOBAL) hDIB );
460 nCurState = 7;
462 break;
464 default:
465 break;
470 // -----------------------------------------------------------------------------
472 void ImpTwain::ImplFallback( ULONG nEvent )
474 Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent );
477 // -----------------------------------------------------------------------------
479 IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData )
481 const ULONG nEvent = (ULONG) pData;
482 bool bFallback = true;
484 switch( nCurState )
486 case( 7 ):
487 case( 6 ):
489 TW_PENDINGXFERS aXfers;
491 if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers ) == TWRC_SUCCESS )
493 if( aXfers.Count != 0 )
494 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers );
497 nCurState = 5;
499 break;
501 case( 5 ):
503 TW_USERINTERFACE aUI = { true, true, hTwainWnd };
505 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI );
506 nCurState = 4;
508 // #107835# deregister as vetoable close listener
509 ImplDeregisterCloseListener();
511 break;
513 case( 4 ):
515 PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent );
516 nCurState = 3;
518 break;
520 case( 3 ):
522 PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd );
523 nCurState = 2;
525 break;
527 case( 2 ):
529 delete pMod;
530 pMod = NULL;
531 nCurState = 1;
533 break;
535 default:
537 if( nEvent != TWAIN_EVENT_NONE )
538 aNotifyLink.Call( (void*) nEvent );
540 bFallback = false;
542 break;
545 if( bFallback )
546 ImplFallback( nEvent );
548 return 0L;
551 // -----------------------------------------------------------------------------
553 IMPL_LINK( ImpTwain, ImplDestroyHdl, void*, /*p*/ )
555 if( hTwainWnd )
556 DestroyWindow( hTwainWnd );
558 if( hTwainHook )
559 UnhookWindowsHookEx( hTwainHook );
561 // #107835# permit destruction of ourselves (normally, refcount
562 // should drop to zero exactly here)
563 mxSelfRef = NULL;
564 pImpTwainInstance = NULL;
566 return 0L;
569 // -----------------------------------------------------------------------------
571 uno::Reference< frame::XFrame > ImpTwain::ImplGetActiveFrame()
575 uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
577 if( xMgr.is() )
579 // query desktop instance
580 uno::Reference< frame::XDesktop > xDesktop( xMgr->createInstance(
581 OUString::createFromAscii( "com.sun.star.frame.Desktop" ) ), uno::UNO_QUERY );
583 if( xDesktop.is() )
585 // query property set from desktop, which contains the currently active frame
586 uno::Reference< beans::XPropertySet > xDesktopProps( xDesktop, uno::UNO_QUERY );
588 if( xDesktopProps.is() )
590 uno::Any aActiveFrame;
594 aActiveFrame = xDesktopProps->getPropertyValue(
595 OUString::createFromAscii( "ActiveFrame" ) );
597 catch( const beans::UnknownPropertyException& )
599 // property unknown.
600 DBG_ERROR("ImpTwain::ImplGetActiveFrame: ActiveFrame property unknown, cannot determine active frame!");
601 return uno::Reference< frame::XFrame >();
604 uno::Reference< frame::XFrame > xActiveFrame;
606 if( (aActiveFrame >>= xActiveFrame) &&
607 xActiveFrame.is() )
609 return xActiveFrame;
615 catch( const uno::Exception& )
619 DBG_ERROR("ImpTwain::ImplGetActiveFrame: Could not determine active frame!");
620 return uno::Reference< frame::XFrame >();
623 // -----------------------------------------------------------------------------
625 uno::Reference< util::XCloseBroadcaster > ImpTwain::ImplGetActiveFrameCloseBroadcaster()
629 return uno::Reference< util::XCloseBroadcaster >( ImplGetActiveFrame(), uno::UNO_QUERY );
631 catch( const uno::Exception& )
635 DBG_ERROR("ImpTwain::ImplGetActiveFrameCloseBroadcaster: Could determine close broadcaster on active frame!");
636 return uno::Reference< util::XCloseBroadcaster >();
639 // -----------------------------------------------------------------------------
641 void ImpTwain::ImplRegisterCloseListener()
645 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( ImplGetActiveFrameCloseBroadcaster() );
647 if( xCloseBroadcaster.is() )
649 xCloseBroadcaster->addCloseListener(this);
650 return; // successfully registered as a close listener
652 else
654 // interface unknown. don't register, then
655 DBG_ERROR("ImpTwain::ImplRegisterCloseListener: XFrame has no XCloseBroadcaster!");
656 return;
659 catch( const uno::Exception& )
663 DBG_ERROR("ImpTwain::ImplRegisterCloseListener: Could not register as close listener!");
666 // -----------------------------------------------------------------------------
668 void ImpTwain::ImplDeregisterCloseListener()
672 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
673 ImplGetActiveFrameCloseBroadcaster() );
675 if( xCloseBroadcaster.is() )
677 xCloseBroadcaster->removeCloseListener(this);
678 return; // successfully deregistered as a close listener
680 else
682 // interface unknown. don't deregister, then
683 DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: XFrame has no XCloseBroadcaster!");
684 return;
687 catch( const uno::Exception& )
691 DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: Could not deregister as close listener!");
694 // -----------------------------------------------------------------------------
696 void SAL_CALL ImpTwain::queryClosing( const lang::EventObject& /*Source*/, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException)
698 // shall we re-send the close query later on?
699 mbCloseFrameOnExit = GetsOwnership;
701 // the sole purpose of this listener is to forbid closing of the listened-at frame
702 throw util::CloseVetoException();
705 // -----------------------------------------------------------------------------
707 void SAL_CALL ImpTwain::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
709 // should not happen
710 DBG_ERROR("ImpTwain::notifyClosing called, but we vetoed the closing before!");
713 // -----------------------------------------------------------------------------
715 void SAL_CALL ImpTwain::disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
717 // we're not holding any references to the frame, thus noop
720 // -----------------------------------------------------------------------------
722 void ImpTwain::ImplSendCloseEvent()
726 uno::Reference< util::XCloseable > xCloseable( ImplGetActiveFrame(), uno::UNO_QUERY );
728 if( xCloseable.is() )
729 xCloseable->close( true );
731 catch( const uno::Exception& )
735 DBG_ERROR("ImpTwain::ImplSendCloseEvent: Could not send required close broadcast!");
739 // ---------
740 // - Twain -
741 // ---------
743 class Twain
745 uno::Reference< lang::XEventListener > mxListener;
746 uno::Reference< scanner::XScannerManager > mxMgr;
747 const ScannerManager* mpCurMgr;
748 ImpTwain* mpImpTwain;
749 TwainState meState;
751 DECL_LINK( ImpNotifyHdl, ImpTwain* );
753 public:
755 Twain();
756 ~Twain();
758 bool SelectSource( ScannerManager& rMgr );
759 bool PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener );
761 TwainState GetState() const { return meState; }
764 // ------------------------------------------------------------------------
766 Twain::Twain() :
767 mpCurMgr( NULL ),
768 mpImpTwain( NULL ),
769 meState( TWAIN_STATE_NONE )
773 // ------------------------------------------------------------------------
775 Twain::~Twain()
777 if( mpImpTwain )
778 mpImpTwain->Destroy();
781 // ------------------------------------------------------------------------
783 bool Twain::SelectSource( ScannerManager& rMgr )
785 bool bRet;
787 if( !mpImpTwain )
789 // #107835# hold reference to ScannerManager, to prevent premature death
790 mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
791 uno::UNO_QUERY ),
793 meState = TWAIN_STATE_NONE;
794 mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
795 bRet = mpImpTwain->SelectSource();
797 else
798 bRet = false;
800 return bRet;
803 // ------------------------------------------------------------------------
805 bool Twain::PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener )
807 bool bRet;
809 if( !mpImpTwain )
811 // #107835# hold reference to ScannerManager, to prevent premature death
812 mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
813 uno::UNO_QUERY ),
815 mxListener = rxListener;
816 meState = TWAIN_STATE_NONE;
817 mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
818 bRet = mpImpTwain->InitXfer();
820 else
821 bRet = false;
823 return bRet;
826 // ------------------------------------------------------------------------
828 IMPL_LINK( Twain, ImpNotifyHdl, ImpTwain*, nEvent )
830 switch( (ULONG)(void*) nEvent )
832 case( TWAIN_EVENT_SCANNING ):
833 meState = TWAIN_STATE_SCANNING;
834 break;
836 case( TWAIN_EVENT_QUIT ):
838 if( meState != TWAIN_STATE_DONE )
839 meState = TWAIN_STATE_CANCELED;
841 if( mpImpTwain )
843 mpImpTwain->Destroy();
844 mpImpTwain = NULL;
845 mpCurMgr = NULL;
848 if( mxListener.is() )
849 mxListener->disposing( lang::EventObject( mxMgr ) );
851 mxListener = NULL;
853 break;
855 case( TWAIN_EVENT_XFER ):
857 if( mpImpTwain )
859 meState = ( mpCurMgr->GetData() ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED );
861 mpImpTwain->Destroy();
862 mpImpTwain = NULL;
863 mpCurMgr = NULL;
865 if( mxListener.is() )
866 mxListener->disposing( lang::EventObject( mxMgr ) );
869 mxListener = NULL;
871 break;
873 default:
874 break;
877 return 0L;
880 // -----------
881 // - statics -
882 // -----------
884 static Twain aTwain;
886 // ------------------
887 // - ScannerManager -
888 // ------------------
890 void ScannerManager::DestroyData()
892 if( mpData )
894 GlobalFree( (HGLOBAL)(long) mpData );
895 mpData = NULL;
899 // -----------------------------------------------------------------------------
901 AWT::Size ScannerManager::getSize() throw()
903 AWT::Size aRet;
904 HGLOBAL hDIB = (HGLOBAL)(long) mpData;
906 if( hDIB )
908 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB );
910 if( pBIH )
912 aRet.Width = pBIH->biWidth;
913 aRet.Height = pBIH->biHeight;
915 else
916 aRet.Width = aRet.Height = 0;
918 GlobalUnlock( hDIB );
920 else
921 aRet.Width = aRet.Height = 0;
923 return aRet;
926 // -----------------------------------------------------------------------------
928 SEQ( sal_Int8 ) ScannerManager::getDIB() throw()
930 SEQ( sal_Int8 ) aRet;
932 if( mpData )
934 HGLOBAL hDIB = (HGLOBAL)(long) mpData;
935 const sal_uInt32 nDIBSize = GlobalSize( hDIB );
936 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB );
938 if( pBIH )
940 sal_uInt32 nColEntries;
942 switch( pBIH->biBitCount )
944 case( 1 ):
945 case( 4 ):
946 case( 8 ):
947 nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : ( 1 << pBIH->biBitCount );
948 break;
950 case( 24 ):
951 nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : 0;
952 break;
954 case( 16 ):
955 case( 32 ):
957 nColEntries = pBIH->biClrUsed;
959 if( pBIH->biCompression == BI_BITFIELDS )
960 nColEntries += 3;
962 break;
964 default:
965 nColEntries = 0;
966 break;
969 aRet = SEQ( sal_Int8 )( sizeof( BITMAPFILEHEADER ) + nDIBSize );
971 sal_Int8* pBuf = aRet.getArray();
972 SvMemoryStream* pMemStm = new SvMemoryStream( (char*) pBuf, sizeof( BITMAPFILEHEADER ), STREAM_WRITE );
974 *pMemStm << 'B' << 'M' << (sal_uInt32) 0 << (sal_uInt32) 0;
975 *pMemStm << (sal_uInt32) ( sizeof( BITMAPFILEHEADER ) + pBIH->biSize + ( nColEntries * sizeof( RGBQUAD ) ) );
977 delete pMemStm;
978 memcpy( pBuf + sizeof( BITMAPFILEHEADER ), pBIH, nDIBSize );
981 GlobalUnlock( hDIB );
982 DestroyData();
985 return aRet;
988 // -----------------------------------------------------------------------------
990 SEQ( ScannerContext ) SAL_CALL ScannerManager::getAvailableScanners() throw()
992 vos::OGuard aGuard( maProtector );
993 SEQ( ScannerContext ) aRet( 1 );
995 aRet.getArray()[0].ScannerName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) );
996 aRet.getArray()[0].InternalData = 0;
998 return aRet;
1001 // -----------------------------------------------------------------------------
1003 BOOL SAL_CALL ScannerManager::configureScanner( ScannerContext& rContext )
1004 throw( ScannerException )
1006 vos::OGuard aGuard( maProtector );
1007 uno::Reference< XScannerManager > xThis( this );
1009 if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1010 throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1012 DestroyData();
1014 return aTwain.SelectSource( *this );
1017 // -----------------------------------------------------------------------------
1019 void SAL_CALL ScannerManager::startScan( const ScannerContext& rContext, const uno::Reference< lang::XEventListener >& rxListener )
1020 throw( ScannerException )
1022 vos::OGuard aGuard( maProtector );
1023 uno::Reference< XScannerManager > xThis( this );
1025 if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1026 throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1028 DestroyData();
1029 aTwain.PerformTransfer( *this, rxListener );
1032 // -----------------------------------------------------------------------------
1034 ScanError SAL_CALL ScannerManager::getError( const ScannerContext& rContext )
1035 throw( ScannerException )
1037 vos::OGuard aGuard( maProtector );
1038 uno::Reference< XScannerManager > xThis( this );
1040 if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1041 throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1043 return( ( aTwain.GetState() == TWAIN_STATE_CANCELED ) ? ScanError_ScanCanceled : ScanError_ScanErrorNone );
1046 // -----------------------------------------------------------------------------
1048 uno::Reference< awt::XBitmap > SAL_CALL ScannerManager::getBitmap( const ScannerContext& /*rContext*/ )
1049 throw( ScannerException )
1051 vos::OGuard aGuard( maProtector );
1052 return uno::Reference< awt::XBitmap >( this );