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 153 LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 ) 154 { 155 return DefWindowProc( hWnd, nMsg, nPar1, nPar2 ); 156 } 157 158 // ------------------------------------------------------------------------- 159 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 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 223 ImpTwain::~ImpTwain() 224 { 225 // are we responsible for application shutdown? 226 if( mbCloseFrameOnExit ) 227 ImplSendCloseEvent(); 228 } 229 230 // ----------------------------------------------------------------------------- 231 232 void ImpTwain::Destroy() 233 { 234 ImplFallback( TWAIN_EVENT_NONE ); 235 Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL ); 236 } 237 238 // ----------------------------------------------------------------------------- 239 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 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 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 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 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 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 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 465 void ImpTwain::ImplFallback( ULONG nEvent ) 466 { 467 Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent ); 468 } 469 470 // ----------------------------------------------------------------------------- 471 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 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 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 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 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 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 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 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 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 754 TwainState GetState() const { return meState; } 755 }; 756 757 // ------------------------------------------------------------------------ 758 759 Twain::Twain() : 760 mpCurMgr( NULL ), 761 mpImpTwain( NULL ), 762 meState( TWAIN_STATE_NONE ) 763 { 764 } 765 766 // ------------------------------------------------------------------------ 767 768 Twain::~Twain() 769 { 770 if( mpImpTwain ) 771 mpImpTwain->Destroy(); 772 } 773 774 // ------------------------------------------------------------------------ 775 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 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 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 883 void ScannerManager::AcquireData() 884 { 885 } 886 887 void ScannerManager::ReleaseData() 888 { 889 if( mpData ) 890 { 891 GlobalFree( (HGLOBAL)(long) mpData ); 892 mpData = NULL; 893 } 894 } 895 896 // ----------------------------------------------------------------------------- 897 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 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 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 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 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 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 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