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