1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_extensions.hxx"
26 #include <com/sun/star/uno/Any.hxx>
27 #include <com/sun/star/uno/Reference.hxx>
28 #include <com/sun/star/util/XCloseable.hpp>
29 #include <com/sun/star/util/XCloseBroadcaster.hpp>
30 #include <com/sun/star/util/XCloseListener.hpp>
31 #include <com/sun/star/frame/XFrame.hpp>
32 #include <com/sun/star/frame/XDesktop.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <cppuhelper/implbase1.hxx>
35 #include <comphelper/processfactory.hxx>
36 
37 #include <math.h>
38 #include <tools/svwin.h>
39 #include <tools/stream.hxx>
40 #include <vos/mutex.hxx>
41 #include <vos/module.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/wrkwin.hxx>
44 #include <vcl/sysdata.hxx>
45 #include <vcl/salbtype.hxx>
46 #include "scanner.hxx"
47 
48 #pragma warning (push,1)
49 #pragma warning (disable:4668)
50 #include "twain/twain.h"
51 #pragma warning (pop)
52 
53 using namespace ::com::sun::star;
54 
55 // -----------
56 // - Defines -
57 // -----------
58 
59 #define TWAIN_SELECT			0x00000001UL
60 #define TWAIN_ACQUIRE			0x00000002UL
61 #define TWAIN_TERMINATE			0xFFFFFFFFUL
62 
63 #define TWAIN_EVENT_NONE		0x00000000UL
64 #define TWAIN_EVENT_QUIT		0x00000001UL
65 #define TWAIN_EVENT_SCANNING	0x00000002UL
66 #define TWAIN_EVENT_XFER		0x00000004UL
67 
68 #define PFUNC					(*pDSM)
69 #define PTWAINMSG				MSG*
70 #define FIXTODOUBLE( nFix ) 	((double)nFix.Whole+(double)nFix.Frac/65536.)
71 #define FIXTOLONG( nFix )		((long)floor(FIXTODOUBLE(nFix)+0.5))
72 
73 #if defined WNT
74 #define TWAIN_LIBNAME			"TWAIN_32.DLL"
75 #define TWAIN_FUNCNAME			"DSM_Entry"
76 #endif
77 
78 // --------------
79 // - TwainState -
80 // --------------
81 
82 enum TwainState
83 {
84 	TWAIN_STATE_NONE = 0,
85 	TWAIN_STATE_SCANNING = 1,
86 	TWAIN_STATE_DONE = 2,
87 	TWAIN_STATE_CANCELED = 3
88 };
89 
90 // ------------
91 // - ImpTwain -
92 // ------------
93 
94 class ImpTwain : public ::cppu::WeakImplHelper1< util::XCloseListener >
95 {
96     friend LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam );
97 
98     uno::Reference< uno::XInterface >			mxSelfRef;
99 	uno::Reference< scanner::XScannerManager >	mxMgr;
100 	ScannerManager&								mrMgr;
101 	TW_IDENTITY									aAppIdent;
102 	TW_IDENTITY									aSrcIdent;
103 	Link										aNotifyLink;
104 	DSMENTRYPROC								pDSM;
105 	vos:: OModule *					pMod;
106 	ULONG										nCurState;
107 	HWND						                hTwainWnd;
108 	HHOOK						                hTwainHook;
109     bool										mbCloseFrameOnExit;
110 
111 	bool						                ImplHandleMsg( void* pMsg );
112 	void										ImplCreate();
113 	void										ImplOpenSourceManager();
114 	void										ImplOpenSource();
115 	bool										ImplEnableSource();
116 	void										ImplXfer();
117 	void										ImplFallback( ULONG nEvent );
118     void 										ImplSendCloseEvent();
119     void 										ImplDeregisterCloseListener();
120     void 										ImplRegisterCloseListener();
121     uno::Reference< frame::XFrame > 			ImplGetActiveFrame();
122     uno::Reference< util::XCloseBroadcaster > 	ImplGetActiveFrameCloseBroadcaster();
123 
124 												DECL_LINK( ImplFallbackHdl, void* );
125 												DECL_LINK( ImplDestroyHdl, void* );
126 
127     // from util::XCloseListener
128     virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException);
129     virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException);
130 
131     // from lang::XEventListener
132     virtual void SAL_CALL disposing( const lang::EventObject& Source ) throw (uno::RuntimeException);
133 
134 public:
135 
136 								                ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink );
137 								                ~ImpTwain();
138 
139 	void						                Destroy();
140 
141 	bool						                SelectSource();
142 	bool						                InitXfer();
143 };
144 
145 // ---------
146 // - Procs -
147 // ---------
148 
149 static ImpTwain* pImpTwainInstance = NULL;
150 
151 // -------------------------------------------------------------------------
152 
TwainWndProc(HWND hWnd,UINT nMsg,WPARAM nPar1,LPARAM nPar2)153 LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
154 {
155 	return DefWindowProc( hWnd, nMsg, nPar1, nPar2 );
156 }
157 
158 // -------------------------------------------------------------------------
159 
TwainMsgProc(int nCode,WPARAM wParam,LPARAM lParam)160 LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
161 {
162 	MSG* pMsg = (MSG*) lParam;
163 
164 	if( ( nCode < 0 ) || ( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) || !pImpTwainInstance->ImplHandleMsg( (void*) lParam ) )
165 	{
166 		return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam );
167 	}
168 	else
169 	{
170 		pMsg->message = WM_USER;
171 		pMsg->lParam = 0;
172 
173 		return 0;
174 	}
175 }
176 
177 // -----------------------------------------------------------------------------
178 
179 // #107835# hold reference to ScannerManager, to prevent premature death
ImpTwain(ScannerManager & rMgr,const Link & rNotifyLink)180 ImpTwain::ImpTwain( ScannerManager& rMgr, const Link& rNotifyLink ) :
181 			mrMgr( rMgr ),
182 		    mxMgr( uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( &rMgr ), uno::UNO_QUERY) ),
183 			aNotifyLink( rNotifyLink ),
184 			pDSM( NULL ),
185 			pMod( NULL ),
186 			hTwainWnd( 0 ),
187 			hTwainHook( 0 ),
188 			nCurState( 1 ),
189             mbCloseFrameOnExit( false )
190 {
191     // setup TWAIN window
192 	pImpTwainInstance = this;
193 
194 	aAppIdent.Id = 0;
195 	aAppIdent.Version.MajorNum = 1;
196 	aAppIdent.Version.MinorNum = 0;
197 	aAppIdent.Version.Language = TWLG_USA;
198 	aAppIdent.Version.Country = TWCY_USA;
199 	aAppIdent.ProtocolMajor = TWON_PROTOCOLMAJOR;
200 	aAppIdent.ProtocolMinor = TWON_PROTOCOLMINOR;
201 	aAppIdent.SupportedGroups =	DG_IMAGE | DG_CONTROL;
202 	strncpy( aAppIdent.Version.Info, "8.0", 32 );
203     aAppIdent.Version.Info[32] = aAppIdent.Version.Info[33] = 0;
204 	strncpy( aAppIdent.Manufacturer, "Sun Microsystems", 32 );
205     aAppIdent.Manufacturer[32] = aAppIdent.Manufacturer[33] = 0;
206 	strncpy( aAppIdent.ProductFamily,"Office", 32 );
207     aAppIdent.ProductFamily[32] = aAppIdent.ProductFamily[33] = 0;
208 	strncpy( aAppIdent.ProductName, "Office", 32 );
209     aAppIdent.ProductName[32] = aAppIdent.ProductName[33] = 0;
210 
211 	WNDCLASS aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASS ), GetModuleHandle( NULL ), NULL, NULL, NULL, NULL, "TwainClass" };
212 	RegisterClass( &aWc );
213 
214 	hTwainWnd = CreateWindowEx( WS_EX_TOPMOST, aWc.lpszClassName, "TWAIN", 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, aWc.hInstance, 0 );
215 	hTwainHook = SetWindowsHookEx( WH_GETMESSAGE, &TwainMsgProc, NULL, GetCurrentThreadId() );
216 
217     // #107835# block destruction until ImplDestroyHdl is called
218     mxSelfRef = static_cast< ::cppu::OWeakObject* >( this );
219 }
220 
221 // -----------------------------------------------------------------------------
222 
~ImpTwain()223 ImpTwain::~ImpTwain()
224 {
225     // are we responsible for application shutdown?
226     if( mbCloseFrameOnExit )
227         ImplSendCloseEvent();
228 }
229 
230 // -----------------------------------------------------------------------------
231 
Destroy()232 void ImpTwain::Destroy()
233 {
234 	ImplFallback( TWAIN_EVENT_NONE );
235 	Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL );
236 }
237 
238 // -----------------------------------------------------------------------------
239 
SelectSource()240 bool ImpTwain::SelectSource()
241 {
242 	TW_UINT16 nRet = TWRC_FAILURE;
243 
244 	ImplOpenSourceManager();
245 
246 	if( 3 == nCurState )
247 	{
248 		TW_IDENTITY aIdent;
249 
250 		aIdent.Id = 0, aIdent.ProductName[ 0 ] = '\0';
251 		aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
252 		nRet = PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent );
253 	}
254 
255 	ImplFallback( TWAIN_EVENT_QUIT );
256 
257 	return( TWRC_SUCCESS == nRet );
258 }
259 
260 // -----------------------------------------------------------------------------
261 
InitXfer()262 bool ImpTwain::InitXfer()
263 {
264 	bool bRet = false;
265 
266 	ImplOpenSourceManager();
267 
268 	if( 3 == nCurState )
269 	{
270 		ImplOpenSource();
271 
272 		if( 4 == nCurState )
273 			bRet = ImplEnableSource();
274 	}
275 
276 	if( !bRet )
277 		ImplFallback( TWAIN_EVENT_QUIT );
278 
279 	return bRet;
280 }
281 
282 // -----------------------------------------------------------------------------
283 
ImplOpenSourceManager()284 void ImpTwain::ImplOpenSourceManager()
285 {
286 	if( 1 == nCurState )
287 	{
288 		pMod = new ::vos::OModule( ::rtl::OUString() );
289 
290 		if( pMod->load( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( TWAIN_LIBNAME ) ) ) )
291 		{
292 			nCurState = 2;
293 
294 			if( ( ( pDSM = (DSMENTRYPROC) pMod->getSymbol( String( RTL_CONSTASCII_USTRINGPARAM( TWAIN_FUNCNAME ) ) ) ) != NULL ) &&
295 				( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) )
296 			{
297 				nCurState = 3;
298 			}
299 		}
300 		else
301 		{
302 			delete pMod;
303 			pMod = NULL;
304 		}
305 	}
306 }
307 
308 // -----------------------------------------------------------------------------
309 
ImplOpenSource()310 void ImpTwain::ImplOpenSource()
311 {
312 	if( 3 == nCurState )
313 	{
314 		if( ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) &&
315 			( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) )
316 		{
317 			TW_CAPABILITY	aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) };
318 			TW_ONEVALUE*	pVal = (TW_ONEVALUE*) GlobalLock( aCap.hContainer );
319 
320 			pVal->ItemType = TWTY_INT16, pVal->Item = 1;
321 			GlobalUnlock( aCap.hContainer );
322 			PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap );
323 			GlobalFree( aCap.hContainer );
324 			nCurState = 4;
325 		}
326 	}
327 }
328 
329 // -----------------------------------------------------------------------------
330 
ImplEnableSource()331 bool ImpTwain::ImplEnableSource()
332 {
333 	bool bRet = false;
334 
335 	if( 4 == nCurState )
336 	{
337 		TW_USERINTERFACE aUI = { true, true, hTwainWnd };
338 
339 		aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
340 		nCurState = 5;
341 
342         // #107835# register as vetoable close listener, to prevent application to die under us
343         ImplRegisterCloseListener();
344 
345 		if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI ) == TWRC_SUCCESS )
346         {
347 			bRet = true;
348         }
349 		else
350         {
351 			nCurState = 4;
352 
353             // #107835# deregister as vetoable close listener, dialog failed
354             ImplDeregisterCloseListener();
355         }
356 	}
357 
358 	return bRet;
359 }
360 
361 // -----------------------------------------------------------------------------
362 
ImplHandleMsg(void * pMsg)363 bool ImpTwain::ImplHandleMsg( void* pMsg )
364 {
365 	TW_UINT16	nRet;
366 	PTWAINMSG	pMess = (PTWAINMSG) pMsg;
367 	TW_EVENT	aEvt = { pMess, MSG_NULL };
368 
369 	nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt );
370 
371 	if( aEvt.TWMessage != MSG_NULL )
372 	{
373 		switch( aEvt.TWMessage )
374 		{
375 			case MSG_XFERREADY:
376 			{
377 				ULONG nEvent = TWAIN_EVENT_QUIT;
378 
379 				if( 5 == nCurState )
380 				{
381 					nCurState = 6;
382 					ImplXfer();
383 
384 					if( mrMgr.GetData() )
385 						nEvent = TWAIN_EVENT_XFER;
386 				}
387 
388 				ImplFallback( nEvent );
389 			}
390 			break;
391 
392 			case MSG_CLOSEDSREQ:
393 				ImplFallback( TWAIN_EVENT_QUIT );
394 			break;
395 
396 			default:
397 			break;
398 		}
399 	}
400 	else
401 		nRet = TWRC_NOTDSEVENT;
402 
403 	return( TWRC_DSEVENT == nRet );
404 }
405 
406 // -----------------------------------------------------------------------------
407 
ImplXfer()408 void ImpTwain::ImplXfer()
409 {
410 	if( nCurState == 6 )
411 	{
412 		TW_IMAGEINFO	aInfo;
413 		TW_UINT32		hDIB = 0;
414 		long			nWidth, nHeight, nXRes, nYRes;
415 
416 		if( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo ) == TWRC_SUCCESS )
417 		{
418 			nWidth = aInfo.ImageWidth;
419 			nHeight = aInfo.ImageLength;
420 			nXRes = FIXTOLONG( aInfo.XResolution );
421 			nYRes = FIXTOLONG( aInfo.YResolution );
422 		}
423 		else
424 			nWidth = nHeight = nXRes = nYRes = -1L;
425 
426 		switch( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB ) )
427 		{
428 			case( TWRC_CANCEL ):
429 				nCurState = 7;
430 			break;
431 
432 			case( TWRC_XFERDONE ):
433 			{
434 				if( hDIB )
435 				{
436 					if( ( nXRes != -1 ) && ( nYRes != - 1 ) && ( nWidth != - 1 ) && ( nHeight != - 1 ) )
437 					{
438 						// set resolution of bitmap
439 						BITMAPINFOHEADER*	pBIH = (BITMAPINFOHEADER*) GlobalLock( (HGLOBAL) hDIB );
440 						static const double	fFactor = 100.0 / 2.54;
441 
442 						pBIH->biXPelsPerMeter = FRound( fFactor * nXRes );
443 						pBIH->biYPelsPerMeter = FRound( fFactor * nYRes );
444 
445 						GlobalUnlock( (HGLOBAL) hDIB );
446 					}
447 
448 					mrMgr.SetData( (void*)(long) hDIB );
449 				}
450 				else
451 					GlobalFree( (HGLOBAL) hDIB );
452 
453 				nCurState = 7;
454 			}
455 			break;
456 
457 			default:
458 			break;
459 		}
460 	}
461 }
462 
463 // -----------------------------------------------------------------------------
464 
ImplFallback(ULONG nEvent)465 void ImpTwain::ImplFallback( ULONG nEvent )
466 {
467 	Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent );
468 }
469 
470 // -----------------------------------------------------------------------------
471 
IMPL_LINK(ImpTwain,ImplFallbackHdl,void *,pData)472 IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData )
473 {
474 	const ULONG	nEvent = (ULONG) pData;
475 	bool		bFallback = true;
476 
477 	switch( nCurState )
478 	{
479 		case( 7 ):
480 		case( 6 ):
481 		{
482 			TW_PENDINGXFERS aXfers;
483 
484 			if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers ) == TWRC_SUCCESS )
485 			{
486 				if( aXfers.Count != 0 )
487 					PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers );
488 			}
489 
490 			nCurState = 5;
491 		}
492 		break;
493 
494 		case( 5 ):
495 		{
496 			TW_USERINTERFACE aUI = { true, true, hTwainWnd };
497 
498 			PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI );
499 			nCurState = 4;
500 
501             // #107835# deregister as vetoable close listener
502             ImplDeregisterCloseListener();
503 		}
504 		break;
505 
506 		case( 4 ):
507 		{
508 			PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent );
509 			nCurState = 3;
510 		}
511 		break;
512 
513 		case( 3 ):
514 		{
515 			PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd );
516 			nCurState = 2;
517 		}
518 		break;
519 
520 		case( 2 ):
521 		{
522 			delete pMod;
523 			pMod = NULL;
524 			nCurState = 1;
525 		}
526 		break;
527 
528 		default:
529 		{
530 			if( nEvent != TWAIN_EVENT_NONE )
531 				aNotifyLink.Call( (void*) nEvent );
532 
533 			bFallback = false;
534 		}
535 		break;
536 	}
537 
538 	if( bFallback )
539 		ImplFallback( nEvent );
540 
541 	return 0L;
542 }
543 
544 // -----------------------------------------------------------------------------
545 
546 IMPL_LINK( ImpTwain, ImplDestroyHdl, void*, /*p*/ )
547 {
548 	if( hTwainWnd )
549 		DestroyWindow( hTwainWnd );
550 
551 	if( hTwainHook )
552 		UnhookWindowsHookEx( hTwainHook );
553 
554     // #107835# permit destruction of ourselves (normally, refcount
555     // should drop to zero exactly here)
556 	mxSelfRef = NULL;
557 	pImpTwainInstance = NULL;
558 
559 	return 0L;
560 }
561 
562 // -----------------------------------------------------------------------------
563 
ImplGetActiveFrame()564 uno::Reference< frame::XFrame > ImpTwain::ImplGetActiveFrame()
565 {
566     try
567     {
568         uno::Reference< lang::XMultiServiceFactory >  xMgr( ::comphelper::getProcessServiceFactory() );
569 
570         if( xMgr.is() )
571         {
572             // query desktop instance
573             uno::Reference< frame::XDesktop > xDesktop( xMgr->createInstance(
574                                                             OUString::createFromAscii( "com.sun.star.frame.Desktop" ) ), uno::UNO_QUERY );
575 
576             if( xDesktop.is() )
577             {
578                 // query property set from desktop, which contains the currently active frame
579                 uno::Reference< beans::XPropertySet > xDesktopProps( xDesktop, uno::UNO_QUERY );
580 
581                 if( xDesktopProps.is() )
582                 {
583                     uno::Any aActiveFrame;
584 
585                     try
586                     {
587                         aActiveFrame = xDesktopProps->getPropertyValue(
588                             OUString::createFromAscii( "ActiveFrame" ) );
589                     }
590                     catch( const beans::UnknownPropertyException& )
591                     {
592                         // property unknown.
593                         DBG_ERROR("ImpTwain::ImplGetActiveFrame: ActiveFrame property unknown, cannot determine active frame!");
594                         return uno::Reference< frame::XFrame >();
595                     }
596 
597                     uno::Reference< frame::XFrame > xActiveFrame;
598 
599                     if( (aActiveFrame >>= xActiveFrame) &&
600                         xActiveFrame.is() )
601                     {
602                         return xActiveFrame;
603                     }
604                 }
605             }
606         }
607     }
608     catch( const uno::Exception& )
609     {
610     }
611 
612     DBG_ERROR("ImpTwain::ImplGetActiveFrame: Could not determine active frame!");
613     return uno::Reference< frame::XFrame >();
614 }
615 
616 // -----------------------------------------------------------------------------
617 
ImplGetActiveFrameCloseBroadcaster()618 uno::Reference< util::XCloseBroadcaster > ImpTwain::ImplGetActiveFrameCloseBroadcaster()
619 {
620     try
621     {
622         return uno::Reference< util::XCloseBroadcaster >( ImplGetActiveFrame(), uno::UNO_QUERY );
623     }
624     catch( const uno::Exception& )
625     {
626     }
627 
628     DBG_ERROR("ImpTwain::ImplGetActiveFrameCloseBroadcaster: Could determine close broadcaster on active frame!");
629     return uno::Reference< util::XCloseBroadcaster >();
630 }
631 
632 // -----------------------------------------------------------------------------
633 
ImplRegisterCloseListener()634 void ImpTwain::ImplRegisterCloseListener()
635 {
636     try
637     {
638         uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( ImplGetActiveFrameCloseBroadcaster() );
639 
640         if( xCloseBroadcaster.is() )
641         {
642             xCloseBroadcaster->addCloseListener(this);
643             return; // successfully registered as a close listener
644         }
645         else
646         {
647             // interface unknown. don't register, then
648             DBG_ERROR("ImpTwain::ImplRegisterCloseListener: XFrame has no XCloseBroadcaster!");
649             return;
650         }
651     }
652     catch( const uno::Exception& )
653     {
654     }
655 
656     DBG_ERROR("ImpTwain::ImplRegisterCloseListener: Could not register as close listener!");
657 }
658 
659 // -----------------------------------------------------------------------------
660 
ImplDeregisterCloseListener()661 void ImpTwain::ImplDeregisterCloseListener()
662 {
663     try
664     {
665         uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
666             ImplGetActiveFrameCloseBroadcaster() );
667 
668         if( xCloseBroadcaster.is() )
669         {
670             xCloseBroadcaster->removeCloseListener(this);
671             return; // successfully deregistered as a close listener
672         }
673         else
674         {
675             // interface unknown. don't deregister, then
676             DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: XFrame has no XCloseBroadcaster!");
677             return;
678         }
679     }
680     catch( const uno::Exception& )
681     {
682     }
683 
684     DBG_ERROR("ImpTwain::ImplDeregisterCloseListener: Could not deregister as close listener!");
685 }
686 
687 // -----------------------------------------------------------------------------
688 
queryClosing(const lang::EventObject &,sal_Bool GetsOwnership)689 void SAL_CALL ImpTwain::queryClosing( const lang::EventObject& /*Source*/, sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException)
690 {
691     // shall we re-send the close query later on?
692     mbCloseFrameOnExit = GetsOwnership;
693 
694     // the sole purpose of this listener is to forbid closing of the listened-at frame
695     throw util::CloseVetoException();
696 }
697 
698 // -----------------------------------------------------------------------------
699 
notifyClosing(const lang::EventObject &)700 void SAL_CALL ImpTwain::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
701 {
702     // should not happen
703     DBG_ERROR("ImpTwain::notifyClosing called, but we vetoed the closing before!");
704 }
705 
706 // -----------------------------------------------------------------------------
707 
disposing(const lang::EventObject &)708 void SAL_CALL ImpTwain::disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
709 {
710     // we're not holding any references to the frame, thus noop
711 }
712 
713 // -----------------------------------------------------------------------------
714 
ImplSendCloseEvent()715 void ImpTwain::ImplSendCloseEvent()
716 {
717     try
718     {
719         uno::Reference< util::XCloseable > xCloseable( ImplGetActiveFrame(), uno::UNO_QUERY );
720 
721         if( xCloseable.is() )
722             xCloseable->close( true );
723     }
724     catch( const uno::Exception& )
725     {
726     }
727 
728     DBG_ERROR("ImpTwain::ImplSendCloseEvent: Could not send required close broadcast!");
729 }
730 
731 
732 // ---------
733 // - Twain -
734 // ---------
735 
736 class Twain
737 {
738 	uno::Reference< lang::XEventListener >	    mxListener;
739 	uno::Reference< scanner::XScannerManager >	mxMgr;
740 	const ScannerManager*			            mpCurMgr;
741 	ImpTwain* 						            mpImpTwain;
742 	TwainState						            meState;
743 
744 									            DECL_LINK( ImpNotifyHdl, ImpTwain* );
745 
746 public:
747 
748 									Twain();
749 									~Twain();
750 
751 	bool							SelectSource( ScannerManager& rMgr );
752 	bool							PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener );
753 
GetState() const754 	TwainState						GetState() const { return meState; }
755 };
756 
757 // ------------------------------------------------------------------------
758 
Twain()759 Twain::Twain() :
760 		mpCurMgr( NULL ),
761 		mpImpTwain( NULL ),
762 		meState( TWAIN_STATE_NONE )
763 {
764 }
765 
766 // ------------------------------------------------------------------------
767 
~Twain()768 Twain::~Twain()
769 {
770 	if( mpImpTwain )
771 		mpImpTwain->Destroy();
772 }
773 
774 // ------------------------------------------------------------------------
775 
SelectSource(ScannerManager & rMgr)776 bool Twain::SelectSource( ScannerManager& rMgr )
777 {
778 	bool bRet;
779 
780 	if( !mpImpTwain )
781 	{
782         // #107835# hold reference to ScannerManager, to prevent premature death
783         mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
784                                                             uno::UNO_QUERY ),
785 
786 		meState = TWAIN_STATE_NONE;
787 		mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
788 		bRet = mpImpTwain->SelectSource();
789 	}
790 	else
791 		bRet = false;
792 
793 	return bRet;
794 }
795 
796 // ------------------------------------------------------------------------
797 
PerformTransfer(ScannerManager & rMgr,const uno::Reference<lang::XEventListener> & rxListener)798 bool Twain::PerformTransfer( ScannerManager& rMgr, const uno::Reference< lang::XEventListener >& rxListener )
799 {
800 	bool bRet;
801 
802 	if( !mpImpTwain )
803 	{
804         // #107835# hold reference to ScannerManager, to prevent premature death
805         mxMgr = uno::Reference< scanner::XScannerManager >( static_cast< OWeakObject* >( const_cast< ScannerManager* >( mpCurMgr = &rMgr ) ),
806                                                             uno::UNO_QUERY ),
807 
808 		mxListener = rxListener;
809 		meState = TWAIN_STATE_NONE;
810 		mpImpTwain = new ImpTwain( rMgr, LINK( this, Twain, ImpNotifyHdl ) );
811 		bRet = mpImpTwain->InitXfer();
812 	}
813 	else
814 		bRet = false;
815 
816 	return bRet;
817 }
818 
819 // ------------------------------------------------------------------------
820 
IMPL_LINK(Twain,ImpNotifyHdl,ImpTwain *,nEvent)821 IMPL_LINK( Twain, ImpNotifyHdl, ImpTwain*, nEvent )
822 {
823 	switch( (ULONG)(void*) nEvent )
824 	{
825 		case( TWAIN_EVENT_SCANNING ):
826 			meState = TWAIN_STATE_SCANNING;
827 		break;
828 
829 		case( TWAIN_EVENT_QUIT ):
830 		{
831 			if( meState != TWAIN_STATE_DONE )
832 				meState = TWAIN_STATE_CANCELED;
833 
834 			if( mpImpTwain )
835 			{
836 			    mpImpTwain->Destroy();
837 			    mpImpTwain = NULL;
838                 mpCurMgr = NULL;
839 			}
840 
841 			if( mxListener.is() )
842 				mxListener->disposing( lang::EventObject( mxMgr ) );
843 
844 			mxListener = NULL;
845 		}
846 		break;
847 
848 		case( TWAIN_EVENT_XFER ):
849 		{
850 			if( mpImpTwain )
851 			{
852 				meState = ( mpCurMgr->GetData() ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED );
853 
854 				mpImpTwain->Destroy();
855 				mpImpTwain = NULL;
856                 mpCurMgr = NULL;
857 
858 				if( mxListener.is() )
859 					mxListener->disposing( lang::EventObject( mxMgr ) );
860 			}
861 
862 			mxListener = NULL;
863 		}
864 		break;
865 
866 		default:
867 		break;
868 	}
869 
870 	return 0L;
871 }
872 
873 // -----------
874 // - statics -
875 // -----------
876 
877 static Twain aTwain;
878 
879 // ------------------
880 // - ScannerManager -
881 // ------------------
882 
AcquireData()883 void ScannerManager::AcquireData()
884 {
885 }
886 
ReleaseData()887 void ScannerManager::ReleaseData()
888 {
889 	if( mpData )
890 	{
891 		GlobalFree( (HGLOBAL)(long) mpData );
892 		mpData = NULL;
893 	}
894 }
895 
896 // -----------------------------------------------------------------------------
897 
getSize()898 AWT::Size ScannerManager::getSize() throw()
899 {
900 	AWT::Size	aRet;
901 	HGLOBAL		hDIB = (HGLOBAL)(long) mpData;
902 
903 	if( hDIB )
904 	{
905 		BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB );
906 
907 		if( pBIH )
908 		{
909 			aRet.Width = pBIH->biWidth;
910 			aRet.Height = pBIH->biHeight;
911 		}
912 		else
913 			aRet.Width = aRet.Height = 0;
914 
915 		GlobalUnlock( hDIB );
916 	}
917 	else
918 		aRet.Width = aRet.Height = 0;
919 
920 	return aRet;
921 }
922 
923 // -----------------------------------------------------------------------------
924 
SEQ(sal_Int8)925 SEQ( sal_Int8 ) ScannerManager::getDIB() throw()
926 {
927 	SEQ( sal_Int8 ) aRet;
928 
929 	if( mpData )
930 	{
931 		HGLOBAL				hDIB = (HGLOBAL)(long) mpData;
932 		const sal_uInt32	nDIBSize = GlobalSize( hDIB );
933 		BITMAPINFOHEADER*	pBIH = (BITMAPINFOHEADER*) GlobalLock( hDIB );
934 
935 		if( pBIH )
936 		{
937 			sal_uInt32	nColEntries;
938 
939 			switch( pBIH->biBitCount )
940 			{
941 				case( 1 ):
942 				case( 4 ):
943 				case( 8 ):
944 					nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : ( 1 << pBIH->biBitCount );
945 				break;
946 
947 				case( 24 ):
948 					nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : 0;
949 				break;
950 
951 				case( 16 ):
952 				case( 32 ):
953 				{
954 					nColEntries = pBIH->biClrUsed;
955 
956 					if( pBIH->biCompression == BI_BITFIELDS )
957 						nColEntries += 3;
958 				}
959 				break;
960 
961 				default:
962 					nColEntries = 0;
963 				break;
964 			}
965 
966 			aRet = SEQ( sal_Int8 )( sizeof( BITMAPFILEHEADER ) + nDIBSize );
967 
968 			sal_Int8*		pBuf = aRet.getArray();
969 			SvMemoryStream* pMemStm = new SvMemoryStream( (char*) pBuf, sizeof( BITMAPFILEHEADER ), STREAM_WRITE );
970 
971 			*pMemStm << 'B' << 'M' << (sal_uInt32) 0 << (sal_uInt32) 0;
972 			*pMemStm << (sal_uInt32) ( sizeof( BITMAPFILEHEADER ) + pBIH->biSize + ( nColEntries * sizeof( RGBQUAD ) ) );
973 
974 			delete pMemStm;
975 			memcpy( pBuf + sizeof( BITMAPFILEHEADER ), pBIH, nDIBSize );
976 		}
977 
978 		GlobalUnlock( hDIB );
979 		ReleaseData();
980 	}
981 
982 	return aRet;
983 }
984 
985 // -----------------------------------------------------------------------------
986 
SEQ(ScannerContext)987 SEQ( ScannerContext ) SAL_CALL ScannerManager::getAvailableScanners() throw()
988 {
989 	vos::OGuard				aGuard( maProtector );
990 	SEQ( ScannerContext )	aRet( 1 );
991 
992 	aRet.getArray()[0].ScannerName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) );
993 	aRet.getArray()[0].InternalData = 0;
994 
995 	return aRet;
996 }
997 
998 // -----------------------------------------------------------------------------
999 
configureScanner(ScannerContext & rContext)1000 sal_Bool SAL_CALL ScannerManager::configureScanner( ScannerContext& rContext )
1001     throw( ScannerException )
1002 {
1003 	vos::OGuard				            aGuard( maProtector );
1004 	uno::Reference< XScannerManager >	xThis( this );
1005 
1006 	if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1007 		throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1008 
1009 	ReleaseData();
1010 
1011 	return aTwain.SelectSource( *this );
1012 }
1013 
1014 // -----------------------------------------------------------------------------
1015 
startScan(const ScannerContext & rContext,const uno::Reference<lang::XEventListener> & rxListener)1016 void SAL_CALL ScannerManager::startScan( const ScannerContext& rContext, const uno::Reference< lang::XEventListener >& rxListener )
1017     throw( ScannerException )
1018 {
1019 	vos::OGuard				            aGuard( maProtector );
1020 	uno::Reference< XScannerManager >	xThis( this );
1021 
1022 	if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1023 		throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1024 
1025 	ReleaseData();
1026 	aTwain.PerformTransfer( *this, rxListener );
1027 }
1028 
1029 // -----------------------------------------------------------------------------
1030 
getError(const ScannerContext & rContext)1031 ScanError SAL_CALL ScannerManager::getError( const ScannerContext& rContext )
1032     throw( ScannerException )
1033 {
1034 	vos::OGuard				            aGuard( maProtector );
1035 	uno::Reference< XScannerManager >	xThis( this );
1036 
1037 	if( rContext.InternalData != 0 || rContext.ScannerName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TWAIN" ) ) )
1038 		throw ScannerException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Scanner does not exist" ) ), xThis, ScanError_InvalidContext );
1039 
1040 	return( ( aTwain.GetState() == TWAIN_STATE_CANCELED ) ? ScanError_ScanCanceled : ScanError_ScanErrorNone );
1041 }
1042 
1043 // -----------------------------------------------------------------------------
1044 
getBitmap(const ScannerContext &)1045 uno::Reference< awt::XBitmap > SAL_CALL ScannerManager::getBitmap( const ScannerContext& /*rContext*/ )
1046     throw( ScannerException )
1047 {
1048 	vos::OGuard	aGuard( maProtector );
1049 	return uno::Reference< awt::XBitmap >( this );
1050 }
1051