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