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