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