bump product version to 5.0.4.1
[LibreOffice.git] / extensions / source / scanner / scanwin.cxx
blob5d83fa2c96606f32a60a7f4c67624c732281534d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/uno/Any.hxx>
21 #include <com/sun/star/uno/Reference.hxx>
22 #include <com/sun/star/util/XCloseable.hpp>
23 #include <com/sun/star/util/XCloseBroadcaster.hpp>
24 #include <com/sun/star/util/XCloseListener.hpp>
25 #include <com/sun/star/frame/XFrame.hpp>
26 #include <com/sun/star/frame/Desktop.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <cppuhelper/implbase1.hxx>
29 #include <comphelper/processfactory.hxx>
31 #include <prewin.h>
32 #include <postwin.h>
33 #include <math.h>
34 #include <tools/stream.hxx>
35 #include <tools/helpers.hxx>
36 #include <osl/mutex.hxx>
37 #include <osl/module.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/wrkwin.hxx>
40 #include <vcl/sysdata.hxx>
41 #include "scanner.hxx"
43 #if defined _MSC_VER
44 #pragma warning (push,1)
45 #pragma warning (disable:4668)
46 #endif
47 #include "twain/twain.h"
48 #if defined _MSC_VER
49 #pragma warning (pop)
50 #endif
52 using namespace ::com::sun::star;
54 #define TWAIN_EVENT_NONE 0x00000000UL
55 #define TWAIN_EVENT_QUIT 0x00000001UL
56 #define TWAIN_EVENT_SCANNING 0x00000002UL
57 #define TWAIN_EVENT_XFER 0x00000004UL
59 #define PFUNC (*pDSM)
60 #define PTWAINMSG MSG*
61 #define FIXTODOUBLE( nFix ) ((double)nFix.Whole+(double)nFix.Frac/65536.)
62 #define FIXTOLONG( nFix ) ((long)floor(FIXTODOUBLE(nFix)+0.5))
64 #if defined WNT
65 #define TWAIN_LIBNAME "TWAIN_32.DLL"
66 #define TWAIN_FUNCNAME "DSM_Entry"
67 #endif
69 enum TwainState
71 TWAIN_STATE_NONE = 0,
72 TWAIN_STATE_SCANNING = 1,
73 TWAIN_STATE_DONE = 2,
74 TWAIN_STATE_CANCELED = 3
77 class ImpTwain : public ::cppu::WeakImplHelper1< util::XCloseListener >
79 friend LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam );
81 uno::Reference< uno::XInterface > mxSelfRef;
82 uno::Reference< scanner::XScannerManager > mxMgr;
83 ScannerManager& mrMgr;
84 TW_IDENTITY aAppIdent;
85 TW_IDENTITY aSrcIdent;
86 Link<> aNotifyLink;
87 DSMENTRYPROC pDSM;
88 osl::Module* pMod;
89 ULONG_PTR nCurState;
90 HWND hTwainWnd;
91 HHOOK hTwainHook;
92 bool mbCloseFrameOnExit;
94 bool ImplHandleMsg( void* pMsg );
95 void ImplCreate();
96 void ImplOpenSourceManager();
97 void ImplOpenSource();
98 bool ImplEnableSource();
99 void ImplXfer();
100 void ImplFallback( ULONG_PTR nEvent );
101 void ImplSendCloseEvent();
102 void ImplDeregisterCloseListener();
103 void ImplRegisterCloseListener();
104 uno::Reference< frame::XFrame > ImplGetActiveFrame();
105 uno::Reference< util::XCloseBroadcaster > ImplGetActiveFrameCloseBroadcaster();
107 DECL_LINK( ImplFallbackHdl, void* );
108 DECL_LINK( ImplDestroyHdl, void* );
110 // from util::XCloseListener
111 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException);
112 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException);
114 // from lang::XEventListener
115 virtual void SAL_CALL disposing( const lang::EventObject& Source ) throw (uno::RuntimeException);
117 public:
119 ImpTwain( ScannerManager& rMgr, const Link<>& rNotifyLink );
120 ~ImpTwain();
122 void Destroy();
124 bool SelectSource();
125 bool InitXfer();
128 static ImpTwain* pImpTwainInstance = NULL;
130 LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
132 return DefWindowProc( hWnd, nMsg, nPar1, nPar2 );
135 LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
137 MSG* pMsg = (MSG*) lParam;
139 if( ( nCode < 0 ) || ( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) || !pImpTwainInstance->ImplHandleMsg( (void*) lParam ) )
141 return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam );
143 else
145 pMsg->message = WM_USER;
146 pMsg->lParam = 0;
148 return 0;
152 // #107835# hold reference to ScannerManager, to prevent premature death
153 ImpTwain::ImpTwain( ScannerManager& rMgr, const Link<>& rNotifyLink ) :
154 mxMgr( uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( &rMgr ), uno::UNO_QUERY) ),
155 mrMgr( rMgr ),
156 aNotifyLink( rNotifyLink ),
157 pDSM( NULL ),
158 pMod( NULL ),
159 nCurState( 1 ),
160 hTwainWnd( 0 ),
161 hTwainHook( 0 ),
162 mbCloseFrameOnExit( false )
164 // setup TWAIN window
165 pImpTwainInstance = this;
167 aAppIdent.Id = 0;
168 aAppIdent.Version.MajorNum = 1;
169 aAppIdent.Version.MinorNum = 0;
170 aAppIdent.Version.Language = TWLG_USA;
171 aAppIdent.Version.Country = TWCY_USA;
172 aAppIdent.ProtocolMajor = TWON_PROTOCOLMAJOR;
173 aAppIdent.ProtocolMinor = TWON_PROTOCOLMINOR;
174 aAppIdent.SupportedGroups = DG_IMAGE | DG_CONTROL;
175 strncpy( aAppIdent.Version.Info, "8.0", 32 );
176 aAppIdent.Version.Info[32] = aAppIdent.Version.Info[33] = 0;
177 strncpy( aAppIdent.Manufacturer, "Sun Microsystems", 32 );
178 aAppIdent.Manufacturer[32] = aAppIdent.Manufacturer[33] = 0;
179 strncpy( aAppIdent.ProductFamily,"Office", 32 );
180 aAppIdent.ProductFamily[32] = aAppIdent.ProductFamily[33] = 0;
181 strncpy( aAppIdent.ProductName, "Office", 32 );
182 aAppIdent.ProductName[32] = aAppIdent.ProductName[33] = 0;
184 WNDCLASS aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASS ), GetModuleHandle( NULL ), NULL, NULL, NULL, NULL, "TwainClass" };
185 RegisterClass( &aWc );
187 hTwainWnd = CreateWindowEx( WS_EX_TOPMOST, aWc.lpszClassName, "TWAIN", 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, aWc.hInstance, 0 );
188 hTwainHook = SetWindowsHookEx( WH_GETMESSAGE, &TwainMsgProc, NULL, GetCurrentThreadId() );
190 // block destruction until ImplDestroyHdl is called
191 mxSelfRef = static_cast< ::cppu::OWeakObject* >( this );
194 ImpTwain::~ImpTwain()
196 // are we responsible for application shutdown?
197 if( mbCloseFrameOnExit )
198 ImplSendCloseEvent();
201 void ImpTwain::Destroy()
203 ImplFallback( TWAIN_EVENT_NONE );
204 Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL );
207 bool ImpTwain::SelectSource()
209 TW_UINT16 nRet = TWRC_FAILURE;
211 ImplOpenSourceManager();
213 if( 3 == nCurState )
215 TW_IDENTITY aIdent;
217 aIdent.Id = 0, aIdent.ProductName[ 0 ] = '\0';
218 aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
219 nRet = PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent );
222 ImplFallback( TWAIN_EVENT_QUIT );
224 return( TWRC_SUCCESS == nRet );
227 bool ImpTwain::InitXfer()
229 bool bRet = false;
231 ImplOpenSourceManager();
233 if( 3 == nCurState )
235 ImplOpenSource();
237 if( 4 == nCurState )
238 bRet = ImplEnableSource();
241 if( !bRet )
242 ImplFallback( TWAIN_EVENT_QUIT );
244 return bRet;
247 void ImpTwain::ImplOpenSourceManager()
249 if( 1 == nCurState )
251 pMod = new ::osl::Module( OUString() );
253 if( pMod->load( OUString( TWAIN_LIBNAME ) ) )
255 nCurState = 2;
257 pDSM = (DSMENTRYPROC) pMod->getSymbol(OUString(TWAIN_FUNCNAME));
258 if (pDSM &&
259 ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) )
261 nCurState = 3;
264 else
266 delete pMod;
267 pMod = NULL;
272 void ImpTwain::ImplOpenSource()
274 if( 3 == nCurState )
276 if( ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) &&
277 ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) )
279 TW_CAPABILITY aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) };
280 TW_ONEVALUE* pVal = (TW_ONEVALUE*) GlobalLock( aCap.hContainer );
282 pVal->ItemType = TWTY_INT16, pVal->Item = 1;
283 GlobalUnlock( aCap.hContainer );
284 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap );
285 GlobalFree( aCap.hContainer );
286 nCurState = 4;
291 bool ImpTwain::ImplEnableSource()
293 bool bRet = false;
295 if( 4 == nCurState )
297 TW_USERINTERFACE aUI = { true, true, hTwainWnd };
299 aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
300 nCurState = 5;
302 // register as vetoable close listener, to prevent application to die under us
303 ImplRegisterCloseListener();
305 if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI ) == TWRC_SUCCESS )
307 bRet = true;
309 else
311 nCurState = 4;
313 // deregister as vetoable close listener, dialog failed
314 ImplDeregisterCloseListener();
318 return bRet;
321 bool ImpTwain::ImplHandleMsg( void* pMsg )
323 TW_UINT16 nRet;
324 PTWAINMSG pMess = (PTWAINMSG) pMsg;
325 TW_EVENT aEvt = { pMess, MSG_NULL };
327 nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt );
329 if( aEvt.TWMessage != MSG_NULL )
331 switch( aEvt.TWMessage )
333 case MSG_XFERREADY:
335 ULONG_PTR nEvent = TWAIN_EVENT_QUIT;
337 if( 5 == nCurState )
339 nCurState = 6;
340 ImplXfer();
342 if( mrMgr.GetData() )
343 nEvent = TWAIN_EVENT_XFER;
346 ImplFallback( nEvent );
348 break;
350 case MSG_CLOSEDSREQ:
351 ImplFallback( TWAIN_EVENT_QUIT );
352 break;
354 default:
355 break;
358 else
359 nRet = TWRC_NOTDSEVENT;
361 return( TWRC_DSEVENT == nRet );
364 void ImpTwain::ImplXfer()
366 if( nCurState == 6 )
368 TW_IMAGEINFO aInfo;
369 TW_UINT32 hDIB = 0;
370 long nWidth, nHeight, nXRes, nYRes;
372 if( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo ) == TWRC_SUCCESS )
374 nWidth = aInfo.ImageWidth;
375 nHeight = aInfo.ImageLength;
376 nXRes = FIXTOLONG( aInfo.XResolution );
377 nYRes = FIXTOLONG( aInfo.YResolution );
379 else
380 nWidth = nHeight = nXRes = nYRes = -1L;
382 switch( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB ) )
384 case( TWRC_CANCEL ):
385 nCurState = 7;
386 break;
388 case( TWRC_XFERDONE ):
390 if( hDIB )
392 if( ( nXRes != -1 ) && ( nYRes != - 1 ) && ( nWidth != - 1 ) && ( nHeight != - 1 ) )
394 // set resolution of bitmap
395 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( (HGLOBAL) (sal_IntPtr) hDIB );
396 static const double fFactor = 100.0 / 2.54;
398 pBIH->biXPelsPerMeter = FRound( fFactor * nXRes );
399 pBIH->biYPelsPerMeter = FRound( fFactor * nYRes );
401 GlobalUnlock( (HGLOBAL) (sal_IntPtr) hDIB );
404 mrMgr.SetData( (void*) (sal_IntPtr) hDIB );
406 else
407 GlobalFree( (HGLOBAL) (sal_IntPtr) hDIB );
409 nCurState = 7;
411 break;
413 default:
414 break;
419 void ImpTwain::ImplFallback( ULONG_PTR nEvent )
421 Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent );
424 IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData )
426 const sal_uIntPtr nEvent = (sal_uIntPtr) pData;
427 bool bFallback = true;
429 switch( nCurState )
431 case( 7 ):
432 case( 6 ):
434 TW_PENDINGXFERS aXfers;
436 if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers ) == TWRC_SUCCESS )
438 if( aXfers.Count != 0 )
439 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers );
442 nCurState = 5;
444 break;
446 case( 5 ):
448 TW_USERINTERFACE aUI = { true, true, hTwainWnd };
450 PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI );
451 nCurState = 4;
453 // deregister as vetoable close listener
454 ImplDeregisterCloseListener();
456 break;
458 case( 4 ):
460 PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent );
461 nCurState = 3;
463 break;
465 case( 3 ):
467 PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd );
468 nCurState = 2;
470 break;
472 case( 2 ):
474 delete pMod;
475 pMod = NULL;
476 nCurState = 1;
478 break;
480 default:
482 if( nEvent != TWAIN_EVENT_NONE )
483 aNotifyLink.Call( (void*) nEvent );
485 bFallback = false;
487 break;
490 if( bFallback )
491 ImplFallback( nEvent );
493 return 0L;
496 IMPL_LINK_NOARG( ImpTwain, ImplDestroyHdl )
498 if( hTwainWnd )
499 DestroyWindow( hTwainWnd );
501 if( hTwainHook )
502 UnhookWindowsHookEx( hTwainHook );
504 // permit destruction of ourselves (normally, refcount
505 // should drop to zero exactly here)
506 mxSelfRef = NULL;
507 pImpTwainInstance = NULL;
509 return 0L;
512 uno::Reference< frame::XFrame > ImpTwain::ImplGetActiveFrame()
516 // query desktop instance
517 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
519 uno::Reference< frame::XFrame > xActiveFrame = xDesktop->getActiveFrame();
521 if( xActiveFrame.is() )
523 return xActiveFrame;
526 catch( const uno::Exception& )
530 OSL_FAIL("ImpTwain::ImplGetActiveFrame: Could not determine active frame!");
531 return uno::Reference< frame::XFrame >();
534 uno::Reference< util::XCloseBroadcaster > ImpTwain::ImplGetActiveFrameCloseBroadcaster()
538 return uno::Reference< util::XCloseBroadcaster >( ImplGetActiveFrame(), uno::UNO_QUERY );
540 catch( const uno::Exception& )
544 OSL_FAIL("ImpTwain::ImplGetActiveFrameCloseBroadcaster: Could determine close broadcaster on active frame!");
545 return uno::Reference< util::XCloseBroadcaster >();
548 void ImpTwain::ImplRegisterCloseListener()
552 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( ImplGetActiveFrameCloseBroadcaster() );
554 if( xCloseBroadcaster.is() )
556 xCloseBroadcaster->addCloseListener(this);
557 return; // successfully registered as a close listener
559 else
561 // interface unknown. don't register, then
562 OSL_FAIL("ImpTwain::ImplRegisterCloseListener: XFrame has no XCloseBroadcaster!");
563 return;
566 catch( const uno::Exception& )
570 OSL_FAIL("ImpTwain::ImplRegisterCloseListener: Could not register as close listener!");
573 void ImpTwain::ImplDeregisterCloseListener()
577 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
578 ImplGetActiveFrameCloseBroadcaster() );
580 if( xCloseBroadcaster.is() )
582 xCloseBroadcaster->removeCloseListener(this);
583 return; // successfully deregistered as a close listener
585 else
587 // interface unknown. don't deregister, then
588 OSL_FAIL("ImpTwain::ImplDeregisterCloseListener: XFrame has no XCloseBroadcaster!");
589 return;
592 catch( const uno::Exception& )
596 OSL_FAIL("ImpTwain::ImplDeregisterCloseListener: Could not deregister as close listener!");
599 void SAL_CALL ImpTwain::queryClosing( const lang::EventObject& /*Source*/, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException)
601 // shall we re-send the close query later on?
602 mbCloseFrameOnExit = GetsOwnership;
604 // the sole purpose of this listener is to forbid closing of the listened-at frame
605 throw util::CloseVetoException();
608 void SAL_CALL ImpTwain::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
610 // should not happen
611 OSL_FAIL("ImpTwain::notifyClosing called, but we vetoed the closing before!");
614 void SAL_CALL ImpTwain::disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
616 // we're not holding any references to the frame, thus noop
619 void ImpTwain::ImplSendCloseEvent()
623 uno::Reference< util::XCloseable > xCloseable( ImplGetActiveFrame(), uno::UNO_QUERY );
625 if( xCloseable.is() )
626 xCloseable->close( true );
628 catch( const uno::Exception& )
632 OSL_FAIL("ImpTwain::ImplSendCloseEvent: Could not send required close broadcast!");
636 class Twain
638 uno::Reference< lang::XEventListener > mxListener;
639 uno::Reference< scanner::XScannerManager > mxMgr;
640 const ScannerManager* mpCurMgr;
641 ImpTwain* mpImpTwain;
642 TwainState meState;
644 DECL_LINK( ImpNotifyHdl, ImpTwain* );
646 public:
648 Twain();
649 ~Twain();
651 bool SelectSource( ScannerManager& rMgr );
652 bool PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener );
654 TwainState GetState() const { return meState; }
657 Twain::Twain() :
658 mpCurMgr( NULL ),
659 mpImpTwain( NULL ),
660 meState( TWAIN_STATE_NONE )
664 Twain::~Twain()
666 if( mpImpTwain )
667 mpImpTwain->Destroy();
670 bool Twain::SelectSource( ScannerManager& rMgr )
672 bool bRet;
674 if( !mpImpTwain )
676 // hold reference to ScannerManager, to prevent premature death
677 mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
678 uno::UNO_QUERY ),
680 meState = TWAIN_STATE_NONE;
681 mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
682 bRet = mpImpTwain->SelectSource();
684 else
685 bRet = false;
687 return bRet;
690 bool Twain::PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener )
692 bool bRet;
694 if( !mpImpTwain )
696 // hold reference to ScannerManager, to prevent premature death
697 mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
698 uno::UNO_QUERY ),
700 mxListener = rxListener;
701 meState = TWAIN_STATE_NONE;
702 mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
703 bRet = mpImpTwain->InitXfer();
705 else
706 bRet = false;
708 return bRet;
711 IMPL_LINK( Twain, ImpNotifyHdl, ImpTwain*, nEvent )
713 switch( (sal_uIntPtr)(void*) nEvent )
715 case( TWAIN_EVENT_SCANNING ):
716 meState = TWAIN_STATE_SCANNING;
717 break;
719 case( TWAIN_EVENT_QUIT ):
721 if( meState != TWAIN_STATE_DONE )
722 meState = TWAIN_STATE_CANCELED;
724 if( mpImpTwain )
726 mpImpTwain->Destroy();
727 mpImpTwain = NULL;
728 mpCurMgr = NULL;
731 if( mxListener.is() )
732 mxListener->disposing( lang::EventObject( mxMgr ) );
734 mxListener = NULL;
736 break;
738 case( TWAIN_EVENT_XFER ):
740 if( mpImpTwain )
742 meState = ( mpCurMgr->GetData() ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED );
744 mpImpTwain->Destroy();
745 mpImpTwain = NULL;
746 mpCurMgr = NULL;
748 if( mxListener.is() )
749 mxListener->disposing( lang::EventObject( mxMgr ) );
752 mxListener = NULL;
754 break;
756 default:
757 break;
760 return 0L;
763 static Twain aTwain;
765 void ScannerManager::AcquireData()
769 void ScannerManager::ReleaseData()
771 if( mpData )
773 GlobalFree( (HGLOBAL)(sal_IntPtr) mpData );
774 mpData = NULL;
778 awt::Size ScannerManager::getSize() throw()
780 awt::Size aRet;
781 HGLOBAL hDIB = (HGLOBAL)(sal_IntPtr) mpData;
783 if( hDIB )
785 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB );
787 if( pBIH )
789 aRet.Width = pBIH->biWidth;
790 aRet.Height = pBIH->biHeight;
792 else
793 aRet.Width = aRet.Height = 0;
795 GlobalUnlock( hDIB );
797 else
798 aRet.Width = aRet.Height = 0;
800 return aRet;
803 uno::Sequence< sal_Int8 > ScannerManager::getDIB() throw()
805 uno::Sequence< sal_Int8 > aRet;
807 if( mpData )
809 HGLOBAL hDIB = (HGLOBAL)(sal_IntPtr) mpData;
810 const sal_uInt32 nDIBSize = GlobalSize( hDIB );
811 BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB );
813 if( pBIH )
815 sal_uInt32 nColEntries;
817 switch( pBIH->biBitCount )
819 case( 1 ):
820 case( 4 ):
821 case( 8 ):
822 nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : ( 1 << pBIH->biBitCount );
823 break;
825 case( 24 ):
826 nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : 0;
827 break;
829 case( 16 ):
830 case( 32 ):
832 nColEntries = pBIH->biClrUsed;
834 if( pBIH->biCompression == BI_BITFIELDS )
835 nColEntries += 3;
837 break;
839 default:
840 nColEntries = 0;
841 break;
844 aRet = uno::Sequence< sal_Int8 >( sizeof( BITMAPFILEHEADER ) + nDIBSize );
846 sal_Int8* pBuf = aRet.getArray();
847 SvMemoryStream* pMemStm = new SvMemoryStream( (char*) pBuf, sizeof( BITMAPFILEHEADER ), StreamMode::WRITE );
849 pMemStm->WriteChar( 'B' ).WriteChar( 'M' ).WriteUInt32( 0 ).WriteUInt32( 0 );
850 pMemStm->WriteUInt32( sizeof( BITMAPFILEHEADER ) + pBIH->biSize + ( nColEntries * sizeof( RGBQUAD ) ) );
852 delete pMemStm;
853 memcpy( pBuf + sizeof( BITMAPFILEHEADER ), pBIH, nDIBSize );
856 GlobalUnlock( hDIB );
857 ReleaseData();
860 return aRet;
863 uno::Sequence< ScannerContext > SAL_CALL ScannerManager::getAvailableScanners() throw()
865 osl::MutexGuard aGuard( maProtector );
866 uno::Sequence< ScannerContext > aRet( 1 );
868 aRet.getArray()[0].ScannerName = "TWAIN" ;
869 aRet.getArray()[0].InternalData = 0;
871 return aRet;
874 sal_Bool SAL_CALL ScannerManager::configureScannerAndScan( ScannerContext& rContext, const uno::Reference< lang::XEventListener >& )
875 throw (ScannerException, RuntimeException, std::exception)
877 osl::MutexGuard aGuard( maProtector );
878 uno::Reference< XScannerManager > xThis( this );
880 if( rContext.InternalData != 0 || rContext.ScannerName != "TWAIN" )
881 throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext );
883 ReleaseData();
885 return aTwain.SelectSource( *this );
888 void SAL_CALL ScannerManager::startScan( const ScannerContext& rContext, const uno::Reference< lang::XEventListener >& rxListener )
889 throw( ScannerException )
891 osl::MutexGuard aGuard( maProtector );
892 uno::Reference< XScannerManager > xThis( this );
894 if( rContext.InternalData != 0 || rContext.ScannerName != "TWAIN" )
895 throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext );
897 ReleaseData();
898 aTwain.PerformTransfer( *this, rxListener );
901 ScanError SAL_CALL ScannerManager::getError( const ScannerContext& rContext )
902 throw( ScannerException )
904 osl::MutexGuard aGuard( maProtector );
905 uno::Reference< XScannerManager > xThis( this );
907 if( rContext.InternalData != 0 || rContext.ScannerName != "TWAIN" )
908 throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext );
910 return( ( aTwain.GetState() == TWAIN_STATE_CANCELED ) ? ScanError_ScanCanceled : ScanError_ScanErrorNone );
913 uno::Reference< awt::XBitmap > SAL_CALL ScannerManager::getBitmap( const ScannerContext& /*rContext*/ )
914 throw( ScannerException )
916 osl::MutexGuard aGuard( maProtector );
917 return uno::Reference< awt::XBitmap >( this );
920 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */