xref: /AOO41X/main/extensions/source/scanner/scanwin.cxx (revision 2a97ec55f1442d65917e8c8b82a55ab76c9ff676)
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