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_dtrans.hxx" 30 31 /* 32 MtaOleClipb.cxx - documentation 33 34 This class setup a single threaded apartment (sta) thread to deal with 35 the ole clipboard, which runs only in an sta thread. 36 The consequence is that callback from the ole clipboard are in the 37 context of this sta thread. In the soffice applications this may lead 38 to problems because they all use the one and only mutex called 39 SolarMutex. 40 In order to transfer clipboard requests to our sta thread we use a 41 hidden window an forward these requests via window messages. 42 */ 43 44 #ifdef _MSC_VER 45 #pragma warning( disable : 4786 ) // identifier was truncated to 'number' 46 // characters in the debug information 47 #endif 48 49 //#define UNICODE 50 #include <osl/diagnose.h> 51 52 #include "..\..\inc\MtaOleClipb.hxx" 53 #include <osl/conditn.hxx> 54 55 #include <wchar.h> 56 #include <process.h> 57 58 #include <systools/win32/comtools.hxx> 59 #ifdef __MINGW32__ 60 #define __uuidof(I) IID_##I 61 #endif 62 63 //---------------------------------------------------------------- 64 // namespace directives 65 //---------------------------------------------------------------- 66 67 using osl::Condition; 68 using osl::Mutex; 69 using osl::MutexGuard; 70 using osl::ClearableMutexGuard; 71 72 //---------------------------------------------------------------- 73 // defines 74 //---------------------------------------------------------------- 75 76 namespace /* private */ 77 { 78 char CLIPSRV_DLL_NAME[] = "sysdtrans.dll"; 79 char g_szWndClsName[] = "MtaOleReqWnd###"; 80 81 //-------------------------------------------------------- 82 // messages constants 83 //-------------------------------------------------------- 84 85 const sal_uInt32 MSG_SETCLIPBOARD = WM_USER + 0x0001; 86 const sal_uInt32 MSG_GETCLIPBOARD = WM_USER + 0x0002; 87 const sal_uInt32 MSG_REGCLIPVIEWER = WM_USER + 0x0003; 88 const sal_uInt32 MSG_FLUSHCLIPBOARD = WM_USER + 0x0004; 89 const sal_uInt32 MSG_SHUTDOWN = WM_USER + 0x0005; 90 91 const sal_uInt32 MAX_WAITTIME = 10000; // msec 92 const sal_uInt32 MAX_WAIT_SHUTDOWN = 10000; // msec 93 const sal_uInt32 MAX_CLIPEVENT_PROCESSING_TIME = 5000; // msec 94 95 const sal_Bool MANUAL_RESET = sal_True; 96 const sal_Bool AUTO_RESET = sal_False; 97 const sal_Bool INIT_NONSIGNALED = sal_False; 98 99 //------------------------------------------------------ 100 /* Cannot use osl conditions because they are blocking 101 without waking up on messages sent by another thread 102 this leads to deadlocks because we are blocking the 103 communication between inter-thread marshalled COM 104 pointers. 105 COM Proxy-Stub communication uses SendMessages for 106 synchronization purposes. 107 */ 108 class Win32Condition 109 { 110 public: 111 // ctor 112 Win32Condition() 113 { 114 m_hEvent = CreateEvent( 115 0, /* no security */ 116 true, /* manual reset */ 117 false, /* initial state not signaled */ 118 0); /* automatic name */ 119 } 120 121 // dtor 122 ~Win32Condition() 123 { 124 CloseHandle(m_hEvent); 125 } 126 127 // wait infinite for event be signaled 128 // leave messages sent through 129 void wait() 130 { 131 while(1) 132 { 133 DWORD dwResult = 134 MsgWaitForMultipleObjects(1, &m_hEvent, FALSE, INFINITE, QS_SENDMESSAGE); 135 136 switch (dwResult) 137 { 138 case WAIT_OBJECT_0: 139 return; 140 141 case WAIT_OBJECT_0 + 1: 142 { 143 /* PeekMessage processes all messages in the SendMessage 144 queue that's what we want, messages from the PostMessage 145 queue stay untouched */ 146 MSG msg; 147 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); 148 149 break; 150 } 151 } 152 } 153 } 154 155 // reset the event 156 void set() 157 { 158 SetEvent(m_hEvent); 159 } 160 161 private: 162 HANDLE m_hEvent; 163 164 // prevent copy/assignment 165 private: 166 Win32Condition(const Win32Condition&); 167 Win32Condition& operator=(const Win32Condition&); 168 }; 169 170 //------------------------------------------ 171 // we use one condition for every request 172 //------------------------------------------ 173 174 struct MsgCtx 175 { 176 Win32Condition aCondition; 177 HRESULT hr; 178 }; 179 180 } /* namespace private */ 181 182 //---------------------------------------------------------------- 183 // static member initialization 184 //---------------------------------------------------------------- 185 186 CMtaOleClipboard* CMtaOleClipboard::s_theMtaOleClipboardInst = NULL; 187 188 //-------------------------------------------------------------------- 189 // marshal an IDataObject 190 //-------------------------------------------------------------------- 191 192 //inline 193 HRESULT MarshalIDataObjectInStream( IDataObject* pIDataObject, LPSTREAM* ppStream ) 194 { 195 OSL_ASSERT( NULL != pIDataObject ); 196 OSL_ASSERT( NULL != ppStream ); 197 198 *ppStream = NULL; 199 return CoMarshalInterThreadInterfaceInStream( 200 __uuidof(IDataObject), //The IID of inteface to be marshaled 201 pIDataObject, //The interface pointer 202 ppStream //IStream pointer 203 ); 204 } 205 206 //-------------------------------------------------------------------- 207 // unmarshal an IDataObject 208 //-------------------------------------------------------------------- 209 210 //inline 211 HRESULT UnmarshalIDataObjectAndReleaseStream( LPSTREAM lpStream, IDataObject** ppIDataObject ) 212 { 213 OSL_ASSERT( NULL != lpStream ); 214 OSL_ASSERT( NULL != ppIDataObject ); 215 216 *ppIDataObject = NULL; 217 return CoGetInterfaceAndReleaseStream( 218 lpStream, 219 __uuidof(IDataObject), 220 reinterpret_cast<LPVOID*>(ppIDataObject)); 221 } 222 223 //-------------------------------------------------------------------- 224 // helper class to ensure that the calling thread has com initialized 225 //-------------------------------------------------------------------- 226 227 class CAutoComInit 228 { 229 public: 230 CAutoComInit( ) 231 { 232 /* 233 to be safe we call CoInitialize 234 although it is not necessary if 235 the calling thread was created 236 using osl_CreateThread because 237 this function calls CoInitialize 238 for every thread it creates 239 */ 240 m_hResult = CoInitialize( NULL ); 241 242 if ( S_OK == m_hResult ) 243 OSL_ENSURE( sal_False, \ 244 "com was not yet initialzed, the thread was not created using osl_createThread" ); 245 else if ( FAILED( m_hResult ) && !( RPC_E_CHANGED_MODE == m_hResult ) ) 246 OSL_ENSURE( sal_False, \ 247 "com could not be initialized, maybe the thread was not created using osl_createThread" ); 248 } 249 250 ~CAutoComInit( ) 251 { 252 /* 253 we only call CoUninitialize when 254 CoInitailize returned S_FALSE, what 255 means that com was already initialize 256 for that thread so we keep the balance 257 if CoInitialize returned S_OK what means 258 com was not yet initialized we better 259 let com initialized or we may run into 260 the realm of undefined behaviour 261 */ 262 if ( m_hResult == S_FALSE ) 263 CoUninitialize( ); 264 } 265 266 private: 267 HRESULT m_hResult; 268 }; 269 270 //-------------------------------------------------------------------- 271 // ctor 272 //-------------------------------------------------------------------- 273 274 CMtaOleClipboard::CMtaOleClipboard( ) : 275 m_hOleThread( NULL ), 276 m_uOleThreadId( 0 ), 277 m_hEvtThrdReady( NULL ), 278 m_hwndMtaOleReqWnd( NULL ), 279 m_MtaOleReqWndClassAtom( 0 ), 280 m_hwndNextClipViewer( NULL ), 281 m_pfncClipViewerCallback( NULL ), 282 m_bRunClipboardNotifierThread( sal_True ), 283 m_hClipboardChangedEvent( m_hClipboardChangedNotifierEvents[0] ), 284 m_hTerminateClipboardChangedNotifierEvent( m_hClipboardChangedNotifierEvents[1] ), 285 m_ClipboardChangedEventCount( 0 ) 286 { 287 // signals that the thread was successfully setup 288 m_hEvtThrdReady = CreateEventA( 0, MANUAL_RESET, INIT_NONSIGNALED, NULL ); 289 290 OSL_ASSERT( NULL != m_hEvtThrdReady ); 291 292 s_theMtaOleClipboardInst = this; 293 294 m_hOleThread = (HANDLE)_beginthreadex( 295 NULL, 0, CMtaOleClipboard::oleThreadProc, this, 0, &m_uOleThreadId ); 296 OSL_ASSERT( NULL != m_hOleThread ); 297 298 //---------------------------------------------- 299 // setup the clipboard changed notifier thread 300 //---------------------------------------------- 301 302 m_hClipboardChangedNotifierEvents[0] = CreateEventA( 0, MANUAL_RESET, INIT_NONSIGNALED, NULL ); 303 OSL_ASSERT( NULL != m_hClipboardChangedNotifierEvents[0] ); 304 305 m_hClipboardChangedNotifierEvents[1] = CreateEventA( 0, MANUAL_RESET, INIT_NONSIGNALED, NULL ); 306 OSL_ASSERT( NULL != m_hClipboardChangedNotifierEvents[1] ); 307 308 unsigned uThreadId; 309 m_hClipboardChangedNotifierThread = (HANDLE)_beginthreadex( 310 NULL, 0, CMtaOleClipboard::clipboardChangedNotifierThreadProc, this, 0, &uThreadId ); 311 312 OSL_ASSERT( NULL != m_hClipboardChangedNotifierThread ); 313 } 314 315 //-------------------------------------------------------------------- 316 // dtor 317 //-------------------------------------------------------------------- 318 319 CMtaOleClipboard::~CMtaOleClipboard( ) 320 { 321 // block calling threads out 322 if ( NULL != m_hEvtThrdReady ) 323 ResetEvent( m_hEvtThrdReady ); 324 325 // terminate the clipboard changed notifier thread 326 m_bRunClipboardNotifierThread = sal_False; 327 SetEvent( m_hTerminateClipboardChangedNotifierEvent ); 328 329 sal_uInt32 dwResult = WaitForSingleObject( 330 m_hClipboardChangedNotifierThread, MAX_WAIT_SHUTDOWN ); 331 332 OSL_ENSURE( dwResult == WAIT_OBJECT_0, "clipboard notifier thread could not terminate" ); 333 334 if ( NULL != m_hClipboardChangedNotifierThread ) 335 CloseHandle( m_hClipboardChangedNotifierThread ); 336 337 if ( NULL != m_hClipboardChangedNotifierEvents[0] ) 338 CloseHandle( m_hClipboardChangedNotifierEvents[0] ); 339 340 if ( NULL != m_hClipboardChangedNotifierEvents[1] ) 341 CloseHandle( m_hClipboardChangedNotifierEvents[1] ); 342 343 // end the thread 344 // because DestroyWindow can only be called 345 // from within the thread that created the window 346 sendMessage( MSG_SHUTDOWN, 347 static_cast< WPARAM >( 0 ), 348 static_cast< LPARAM >( 0 ) ); 349 350 // wait for thread shutdown 351 dwResult = WaitForSingleObject( m_hOleThread, MAX_WAIT_SHUTDOWN ); 352 OSL_ENSURE( dwResult == WAIT_OBJECT_0, "OleThread could not terminate" ); 353 354 if ( NULL != m_hOleThread ) 355 CloseHandle( m_hOleThread ); 356 357 if ( NULL != m_hEvtThrdReady ) 358 CloseHandle( m_hEvtThrdReady ); 359 360 if ( m_MtaOleReqWndClassAtom ) 361 UnregisterClassA( g_szWndClsName, NULL ); 362 363 OSL_ENSURE( ( NULL == m_pfncClipViewerCallback ) && 364 !IsWindow( m_hwndNextClipViewer ), \ 365 "Clipboard viewer not properly unregistered" ); 366 } 367 368 369 //-------------------------------------------------------------------- 370 // 371 //-------------------------------------------------------------------- 372 373 HRESULT CMtaOleClipboard::flushClipboard( ) 374 { 375 if ( !WaitForThreadReady( ) ) 376 { 377 OSL_ENSURE( sal_False, "clipboard sta thread not ready" ); 378 return E_FAIL; 379 } 380 381 OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, \ 382 "flushClipboard from within clipboard sta thread called" ); 383 384 MsgCtx aMsgCtx; 385 386 postMessage( MSG_FLUSHCLIPBOARD, 387 static_cast< WPARAM >( 0 ), 388 reinterpret_cast< LPARAM >( &aMsgCtx ) ); 389 390 aMsgCtx.aCondition.wait( /* infinite */ ); 391 392 return aMsgCtx.hr; 393 } 394 395 //-------------------------------------------------------------------- 396 // 397 //-------------------------------------------------------------------- 398 399 HRESULT CMtaOleClipboard::getClipboard( IDataObject** ppIDataObject ) 400 { 401 OSL_PRECOND( NULL != ppIDataObject, "invalid parameter" ); 402 OSL_PRECOND( GetCurrentThreadId( ) != m_uOleThreadId, "getClipboard from within clipboard sta thread called" ); 403 404 if ( !WaitForThreadReady( ) ) 405 { 406 OSL_ENSURE( sal_False, "clipboard sta thread not ready" ); 407 return E_FAIL; 408 } 409 410 CAutoComInit comAutoInit; 411 412 LPSTREAM lpStream; 413 HRESULT hr = E_FAIL; 414 415 *ppIDataObject = NULL; 416 417 MsgCtx aMsgCtx; 418 419 postMessage( MSG_GETCLIPBOARD, 420 reinterpret_cast< WPARAM >( &lpStream ), 421 reinterpret_cast< LPARAM >( &aMsgCtx ) ); 422 423 aMsgCtx.aCondition.wait( /* infinite */ ); 424 425 hr = aMsgCtx.hr; 426 427 if ( SUCCEEDED( hr ) ) 428 { 429 hr = UnmarshalIDataObjectAndReleaseStream( lpStream, ppIDataObject ); 430 OSL_ENSURE( SUCCEEDED( hr ), "unmarshalling clipboard data object failed" ); 431 } 432 433 return hr; 434 } 435 436 //-------------------------------------------------------------------- 437 // this is an asynchronous method that's why we don't wait until the 438 // request is completed 439 //-------------------------------------------------------------------- 440 441 HRESULT CMtaOleClipboard::setClipboard( IDataObject* pIDataObject ) 442 { 443 if ( !WaitForThreadReady( ) ) 444 { 445 OSL_ENSURE( sal_False, "clipboard sta thread not ready" ); 446 return E_FAIL; 447 } 448 449 CAutoComInit comAutoInit; 450 451 OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "setClipboard from within the clipboard sta thread called" ); 452 453 // because we marshall this request 454 // into the sta thread we better 455 // acquire the interface here so 456 // that the object will not be 457 // destroyed before the ole clipboard 458 // can acquire it 459 // remember: pIDataObject may be NULL 460 // which is an request to clear the 461 // current clipboard content 462 if ( pIDataObject ) 463 pIDataObject->AddRef( ); 464 465 postMessage( 466 MSG_SETCLIPBOARD, 467 reinterpret_cast< WPARAM >( pIDataObject ), 468 0 ); 469 470 // because this is an asynchronous function 471 // the return value is useless 472 return S_OK; 473 } 474 475 //-------------------------------------------------------------------- 476 // register a clipboard viewer 477 //-------------------------------------------------------------------- 478 479 sal_Bool CMtaOleClipboard::registerClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback ) 480 { 481 if ( !WaitForThreadReady( ) ) 482 { 483 OSL_ENSURE( sal_False, "clipboard sta thread not ready" ); 484 return sal_False; 485 } 486 487 sal_Bool bRet = sal_False; 488 489 OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "registerClipViewer from within the OleThread called" ); 490 491 MsgCtx aMsgCtx; 492 493 postMessage( MSG_REGCLIPVIEWER, 494 reinterpret_cast<WPARAM>( pfncClipViewerCallback ), 495 reinterpret_cast<LPARAM>( &aMsgCtx ) ); 496 497 aMsgCtx.aCondition.wait( /* infinite */ ); 498 499 return bRet; 500 } 501 502 //-------------------------------------------------------------------- 503 // register a clipboard viewer 504 //-------------------------------------------------------------------- 505 506 sal_Bool CMtaOleClipboard::onRegisterClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback ) 507 { 508 sal_Bool bRet = sal_True; 509 510 // we need exclusive access because the clipboard changed notifier 511 // thread also accesses this variable 512 MutexGuard aGuard( m_pfncClipViewerCallbackMutex ); 513 514 // register if not yet done 515 if ( ( NULL != pfncClipViewerCallback ) && ( NULL == m_pfncClipViewerCallback ) ) 516 { 517 // SetClipboardViewer sends a WM_DRAWCLIPBOARD message we ignore 518 // this message if we register ourself as clip viewer 519 m_bInRegisterClipViewer = sal_True; 520 m_hwndNextClipViewer = SetClipboardViewer( m_hwndMtaOleReqWnd ); 521 m_bInRegisterClipViewer = sal_False; 522 523 // if there is no other cb-viewer the 524 // return value is NULL!!! 525 bRet = IsWindow( m_hwndNextClipViewer ) ? sal_True : sal_False; 526 527 // save the new callback function 528 m_pfncClipViewerCallback = pfncClipViewerCallback; 529 } 530 else if ( ( NULL == pfncClipViewerCallback ) && ( NULL != m_pfncClipViewerCallback ) ) 531 { 532 m_pfncClipViewerCallback = NULL; 533 534 // unregister if input parameter is NULL and we previously registered 535 // as clipboard viewer 536 ChangeClipboardChain( m_hwndMtaOleReqWnd, m_hwndNextClipViewer ); 537 m_hwndNextClipViewer = NULL; 538 } 539 540 return bRet; 541 } 542 543 //-------------------------------------------------------------------- 544 // 545 //-------------------------------------------------------------------- 546 547 LRESULT CMtaOleClipboard::onSetClipboard( IDataObject* pIDataObject ) 548 { 549 return static_cast<LRESULT>( OleSetClipboard( pIDataObject ) ); 550 } 551 552 //-------------------------------------------------------------------- 553 // 554 //-------------------------------------------------------------------- 555 556 LRESULT CMtaOleClipboard::onGetClipboard( LPSTREAM* ppStream ) 557 { 558 OSL_ASSERT(NULL != ppStream); 559 560 IDataObjectPtr pIDataObject; 561 562 // forward the request to the OleClipboard 563 HRESULT hr = OleGetClipboard( &pIDataObject ); 564 if ( SUCCEEDED( hr ) ) 565 { 566 hr = MarshalIDataObjectInStream(pIDataObject.get(), ppStream); 567 OSL_ENSURE(SUCCEEDED(hr), "marshalling cliboard data object failed"); 568 } 569 return static_cast<LRESULT>(hr); 570 } 571 572 //-------------------------------------------------------------------- 573 // flush the ole-clipboard 574 //-------------------------------------------------------------------- 575 576 LRESULT CMtaOleClipboard::onFlushClipboard( ) 577 { 578 return static_cast<LRESULT>( OleFlushClipboard( ) ); 579 } 580 581 //-------------------------------------------------------------------- 582 // handle clipboard chain change event 583 //-------------------------------------------------------------------- 584 585 LRESULT CMtaOleClipboard::onChangeCBChain( HWND hWndRemove, HWND hWndNext ) 586 { 587 if ( hWndRemove == m_hwndNextClipViewer ) 588 m_hwndNextClipViewer = hWndNext; 589 else if ( IsWindow( m_hwndNextClipViewer ) ) 590 { 591 // forward the message to the next one 592 DWORD dwResult; 593 SendMessageTimeoutA( 594 m_hwndNextClipViewer, 595 WM_CHANGECBCHAIN, 596 reinterpret_cast<WPARAM>(hWndRemove), 597 reinterpret_cast<LPARAM>(hWndNext), 598 SMTO_BLOCK, 599 MAX_CLIPEVENT_PROCESSING_TIME, 600 &dwResult ); 601 } 602 603 return 0; 604 } 605 606 //-------------------------------------------------------------------- 607 // handle draw clipboard event 608 //-------------------------------------------------------------------- 609 610 LRESULT CMtaOleClipboard::onDrawClipboard( ) 611 { 612 // we don't send a notification if we are 613 // registering ourself as clipboard 614 if ( !m_bInRegisterClipViewer ) 615 { 616 ClearableMutexGuard aGuard( m_ClipboardChangedEventCountMutex ); 617 618 m_ClipboardChangedEventCount++; 619 SetEvent( m_hClipboardChangedEvent ); 620 621 aGuard.clear( ); 622 } 623 624 // foward the message to the next viewer in the chain 625 if ( IsWindow( m_hwndNextClipViewer ) ) 626 { 627 DWORD dwResult; 628 SendMessageTimeoutA( 629 m_hwndNextClipViewer, 630 WM_DRAWCLIPBOARD, 631 static_cast< WPARAM >( 0 ), 632 static_cast< LPARAM >( 0 ), 633 SMTO_BLOCK, 634 MAX_CLIPEVENT_PROCESSING_TIME, 635 &dwResult ); 636 } 637 638 return 0; 639 } 640 641 //-------------------------------------------------------------------- 642 // SendMessage so we don't need to supply the HWND if we send 643 // something to our wrapped window 644 //-------------------------------------------------------------------- 645 646 LRESULT CMtaOleClipboard::sendMessage( UINT msg, WPARAM wParam, LPARAM lParam ) 647 { 648 return ::SendMessageA( m_hwndMtaOleReqWnd, msg, wParam, lParam ); 649 } 650 651 //-------------------------------------------------------------------- 652 // PostMessage so we don't need to supply the HWND if we send 653 // something to our wrapped window 654 //-------------------------------------------------------------------- 655 656 sal_Bool CMtaOleClipboard::postMessage( UINT msg, WPARAM wParam, LPARAM lParam ) 657 { 658 return PostMessageA( m_hwndMtaOleReqWnd, msg, wParam, lParam ) ? sal_True : sal_False; 659 } 660 661 662 //-------------------------------------------------------------------- 663 // the window proc 664 //-------------------------------------------------------------------- 665 666 LRESULT CALLBACK CMtaOleClipboard::mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 667 { 668 LRESULT lResult = 0; 669 670 // get a connection to the class-instance via the static member 671 CMtaOleClipboard* pImpl = CMtaOleClipboard::s_theMtaOleClipboardInst; 672 OSL_ASSERT( NULL != pImpl ); 673 674 switch( uMsg ) 675 { 676 case MSG_SETCLIPBOARD: 677 { 678 IDataObject* pIDataObject = reinterpret_cast< IDataObject* >( wParam ); 679 pImpl->onSetClipboard( pIDataObject ); 680 681 // in setClipboard we did acquire the 682 // interface pointer in order to prevent 683 // destruction of the object before the 684 // ole clipboard can acquire the interface 685 // now we release the interface so that 686 // our lostOwnership mechanism works 687 // remember: pIDataObject may be NULL 688 if ( pIDataObject ) 689 pIDataObject->Release( ); 690 } 691 break; 692 693 case MSG_GETCLIPBOARD: 694 { 695 MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam ); 696 OSL_ASSERT( aMsgCtx ); 697 698 aMsgCtx->hr = pImpl->onGetClipboard( reinterpret_cast< LPSTREAM* >(wParam) ); 699 aMsgCtx->aCondition.set( ); 700 } 701 break; 702 703 case MSG_FLUSHCLIPBOARD: 704 { 705 MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam ); 706 OSL_ASSERT( aMsgCtx ); 707 708 aMsgCtx->hr = pImpl->onFlushClipboard( ); 709 aMsgCtx->aCondition.set( ); 710 } 711 break; 712 713 case MSG_REGCLIPVIEWER: 714 { 715 MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam ); 716 OSL_ASSERT( aMsgCtx ); 717 718 pImpl->onRegisterClipViewer( reinterpret_cast<CMtaOleClipboard::LPFNC_CLIPVIEWER_CALLBACK_t>(wParam) ); 719 aMsgCtx->aCondition.set( ); 720 } 721 break; 722 723 case WM_CHANGECBCHAIN: 724 lResult = pImpl->onChangeCBChain( 725 reinterpret_cast< HWND >( wParam ), reinterpret_cast< HWND >( lParam ) ); 726 break; 727 728 case WM_DRAWCLIPBOARD: 729 lResult = pImpl->onDrawClipboard( ); 730 break; 731 732 case MSG_SHUTDOWN: 733 DestroyWindow( pImpl->m_hwndMtaOleReqWnd ); 734 break; 735 736 // force the sta thread to end 737 case WM_DESTROY: 738 PostQuitMessage( 0 ); 739 break; 740 741 default: 742 lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam ); 743 break; 744 } 745 746 return lResult; 747 } 748 749 //-------------------------------------------------------------------- 750 // 751 //-------------------------------------------------------------------- 752 753 void CMtaOleClipboard::createMtaOleReqWnd( ) 754 { 755 WNDCLASSEXA wcex; 756 757 HINSTANCE hInst = GetModuleHandleA( CLIPSRV_DLL_NAME ); 758 OSL_ENSURE( NULL != hInst, "The name of the clipboard service dll must have changed" ); 759 760 ZeroMemory( &wcex, sizeof( WNDCLASSEXA ) ); 761 762 wcex.cbSize = sizeof(WNDCLASSEXA); 763 wcex.style = 0; 764 wcex.lpfnWndProc = static_cast< WNDPROC >( CMtaOleClipboard::mtaOleReqWndProc ); 765 wcex.cbClsExtra = 0; 766 wcex.cbWndExtra = 0; 767 wcex.hInstance = hInst; 768 wcex.hIcon = NULL; 769 wcex.hCursor = NULL; 770 wcex.hbrBackground = NULL; 771 wcex.lpszMenuName = NULL; 772 wcex.lpszClassName = g_szWndClsName; 773 wcex.hIconSm = NULL; 774 775 m_MtaOleReqWndClassAtom = RegisterClassExA( &wcex ); 776 777 if ( 0 != m_MtaOleReqWndClassAtom ) 778 m_hwndMtaOleReqWnd = CreateWindowA( 779 g_szWndClsName, NULL, 0, 0, 0, 0, 0, NULL, NULL, hInst, NULL ); 780 } 781 782 //-------------------------------------------------------------------- 783 // 784 //-------------------------------------------------------------------- 785 786 unsigned int CMtaOleClipboard::run( ) 787 { 788 #if OSL_DEBUG_LEVEL > 0 789 HRESULT hr = 790 #endif 791 OleInitialize( NULL ); 792 OSL_ASSERT( SUCCEEDED( hr ) ); 793 794 createMtaOleReqWnd( ); 795 796 unsigned int nRet; 797 798 if ( IsWindow( m_hwndMtaOleReqWnd ) ) 799 { 800 if ( NULL != m_hEvtThrdReady ) 801 SetEvent( m_hEvtThrdReady ); 802 803 // pumping messages 804 MSG msg; 805 while( GetMessageA( &msg, NULL, 0, 0 ) ) 806 DispatchMessageA( &msg ); 807 808 nRet = 0; 809 } 810 else 811 nRet = ~0U; 812 813 OleUninitialize( ); 814 815 return nRet; 816 } 817 818 //-------------------------------------------------------------------- 819 // 820 //-------------------------------------------------------------------- 821 822 unsigned int WINAPI CMtaOleClipboard::oleThreadProc( LPVOID pParam ) 823 { 824 CMtaOleClipboard* pInst = 825 reinterpret_cast<CMtaOleClipboard*>( pParam ); 826 OSL_ASSERT( NULL != pInst ); 827 828 return pInst->run( ); 829 } 830 831 //-------------------------------------------------------------------- 832 // 833 //-------------------------------------------------------------------- 834 835 unsigned int WINAPI CMtaOleClipboard::clipboardChangedNotifierThreadProc( LPVOID pParam ) 836 { 837 CMtaOleClipboard* pInst = reinterpret_cast< CMtaOleClipboard* >( pParam ); 838 OSL_ASSERT( NULL != pInst ); 839 840 CoInitialize( NULL ); 841 842 // assuming we don't need a lock for 843 // a boolean variable like m_bRun... 844 while ( pInst->m_bRunClipboardNotifierThread ) 845 { 846 // wait for clipboard changed or terminate event 847 WaitForMultipleObjects( 2, pInst->m_hClipboardChangedNotifierEvents, false, INFINITE ); 848 849 ClearableMutexGuard aGuard( pInst->m_ClipboardChangedEventCountMutex ); 850 851 if ( pInst->m_ClipboardChangedEventCount > 0 ) 852 { 853 pInst->m_ClipboardChangedEventCount--; 854 if ( 0 == pInst->m_ClipboardChangedEventCount ) 855 ResetEvent( pInst->m_hClipboardChangedEvent ); 856 857 aGuard.clear( ); 858 859 // nobody should touch m_pfncClipViewerCallback while we do 860 MutexGuard aClipViewerGuard( pInst->m_pfncClipViewerCallbackMutex ); 861 862 // notify all clipboard listener 863 if ( pInst->m_pfncClipViewerCallback ) 864 pInst->m_pfncClipViewerCallback( ); 865 } 866 else 867 aGuard.clear( ); 868 } 869 870 CoUninitialize( ); 871 872 return ( 0 ); 873 } 874 875 //-------------------------------------------------------------------- 876 // 877 //-------------------------------------------------------------------- 878 879 inline 880 sal_Bool CMtaOleClipboard::WaitForThreadReady( ) const 881 { 882 sal_Bool bRet = sal_False; 883 884 if ( NULL != m_hEvtThrdReady ) 885 { 886 DWORD dwResult = WaitForSingleObject( 887 m_hEvtThrdReady, MAX_WAITTIME ); 888 bRet = ( dwResult == WAIT_OBJECT_0 ); 889 } 890 891 return bRet; 892 } 893 894