Update ooo320-m1
[ooovba.git] / dtrans / source / win32 / mtaole / MtaOleClipb.cxx
blob90d5d4e00efe8f5ebd53de3a6a051d17e3d422e2
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: MtaOleClipb.cxx,v $
10 * $Revision: 1.29 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dtrans.hxx"
35 MtaOleClipb.cxx - documentation
37 This class setup a single threaded apartment (sta) thread to deal with
38 the ole clipboard, which runs only in an sta thread.
39 The consequence is that callback from the ole clipboard are in the
40 context of this sta thread. In the soffice applications this may lead
41 to problems because they all use the one and only mutex called
42 SolarMutex.
43 In order to transfer clipboard requests to our sta thread we use a
44 hidden window an forward these requests via window messages.
47 #ifdef _MSC_VER
48 #pragma warning( disable : 4786 ) // identifier was truncated to 'number'
49 // characters in the debug information
50 #endif
52 //#define UNICODE
53 #include <osl/diagnose.h>
55 #include "..\..\inc\MtaOleClipb.hxx"
56 #include <osl/conditn.hxx>
58 #include <wchar.h>
59 #include <process.h>
61 #include <systools/win32/comtools.hxx>
62 #ifdef __MINGW32__
63 #define __uuidof(I) IID_##I
64 #endif
66 //----------------------------------------------------------------
67 // namespace directives
68 //----------------------------------------------------------------
70 using osl::Condition;
71 using osl::Mutex;
72 using osl::MutexGuard;
73 using osl::ClearableMutexGuard;
75 //----------------------------------------------------------------
76 // defines
77 //----------------------------------------------------------------
79 namespace /* private */
81 char CLIPSRV_DLL_NAME[] = "sysdtrans.dll";
82 char g_szWndClsName[] = "MtaOleReqWnd###";
84 //--------------------------------------------------------
85 // messages constants
86 //--------------------------------------------------------
88 const sal_uInt32 MSG_SETCLIPBOARD = WM_USER + 0x0001;
89 const sal_uInt32 MSG_GETCLIPBOARD = WM_USER + 0x0002;
90 const sal_uInt32 MSG_REGCLIPVIEWER = WM_USER + 0x0003;
91 const sal_uInt32 MSG_FLUSHCLIPBOARD = WM_USER + 0x0004;
92 const sal_uInt32 MSG_SHUTDOWN = WM_USER + 0x0005;
94 const sal_uInt32 MAX_WAITTIME = 10000; // msec
95 const sal_uInt32 MAX_WAIT_SHUTDOWN = 10000; // msec
96 const sal_uInt32 MAX_CLIPEVENT_PROCESSING_TIME = 5000; // msec
98 const sal_Bool MANUAL_RESET = sal_True;
99 const sal_Bool AUTO_RESET = sal_False;
100 const sal_Bool INIT_NONSIGNALED = sal_False;
102 //------------------------------------------------------
103 /* Cannot use osl conditions because they are blocking
104 without waking up on messages sent by another thread
105 this leads to deadlocks because we are blocking the
106 communication between inter-thread marshalled COM
107 pointers.
108 COM Proxy-Stub communication uses SendMessages for
109 synchronization purposes.
111 class Win32Condition
113 public:
114 // ctor
115 Win32Condition()
117 m_hEvent = CreateEvent(
118 0, /* no security */
119 true, /* manual reset */
120 false, /* initial state not signaled */
121 0); /* automatic name */
124 // dtor
125 ~Win32Condition()
127 CloseHandle(m_hEvent);
130 // wait infinite for event be signaled
131 // leave messages sent through
132 void wait()
134 while(1)
136 DWORD dwResult =
137 MsgWaitForMultipleObjects(1, &m_hEvent, FALSE, INFINITE, QS_SENDMESSAGE);
139 switch (dwResult)
141 case WAIT_OBJECT_0:
142 return;
144 case WAIT_OBJECT_0 + 1:
146 /* PeekMessage processes all messages in the SendMessage
147 queue that's what we want, messages from the PostMessage
148 queue stay untouched */
149 MSG msg;
150 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
152 break;
158 // reset the event
159 void set()
161 SetEvent(m_hEvent);
164 private:
165 HANDLE m_hEvent;
167 // prevent copy/assignment
168 private:
169 Win32Condition(const Win32Condition&);
170 Win32Condition& operator=(const Win32Condition&);
173 //------------------------------------------
174 // we use one condition for every request
175 //------------------------------------------
177 struct MsgCtx
179 Win32Condition aCondition;
180 HRESULT hr;
183 } /* namespace private */
185 //----------------------------------------------------------------
186 // static member initialization
187 //----------------------------------------------------------------
189 CMtaOleClipboard* CMtaOleClipboard::s_theMtaOleClipboardInst = NULL;
191 //--------------------------------------------------------------------
192 // marshal an IDataObject
193 //--------------------------------------------------------------------
195 //inline
196 HRESULT MarshalIDataObjectInStream( IDataObject* pIDataObject, LPSTREAM* ppStream )
198 OSL_ASSERT( NULL != pIDataObject );
199 OSL_ASSERT( NULL != ppStream );
201 *ppStream = NULL;
202 return CoMarshalInterThreadInterfaceInStream(
203 __uuidof(IDataObject), //The IID of inteface to be marshaled
204 pIDataObject, //The interface pointer
205 ppStream //IStream pointer
209 //--------------------------------------------------------------------
210 // unmarshal an IDataObject
211 //--------------------------------------------------------------------
213 //inline
214 HRESULT UnmarshalIDataObjectAndReleaseStream( LPSTREAM lpStream, IDataObject** ppIDataObject )
216 OSL_ASSERT( NULL != lpStream );
217 OSL_ASSERT( NULL != ppIDataObject );
219 *ppIDataObject = NULL;
220 return CoGetInterfaceAndReleaseStream(
221 lpStream,
222 __uuidof(IDataObject),
223 reinterpret_cast<LPVOID*>(ppIDataObject));
226 //--------------------------------------------------------------------
227 // helper class to ensure that the calling thread has com initialized
228 //--------------------------------------------------------------------
230 class CAutoComInit
232 public:
233 CAutoComInit( )
236 to be safe we call CoInitialize
237 although it is not necessary if
238 the calling thread was created
239 using osl_CreateThread because
240 this function calls CoInitialize
241 for every thread it creates
243 m_hResult = CoInitialize( NULL );
245 if ( S_OK == m_hResult )
246 OSL_ENSURE( sal_False, \
247 "com was not yet initialzed, the thread was not created using osl_createThread" );
248 else if ( FAILED( m_hResult ) && !( RPC_E_CHANGED_MODE == m_hResult ) )
249 OSL_ENSURE( sal_False, \
250 "com could not be initialized, maybe the thread was not created using osl_createThread" );
253 ~CAutoComInit( )
256 we only call CoUninitialize when
257 CoInitailize returned S_FALSE, what
258 means that com was already initialize
259 for that thread so we keep the balance
260 if CoInitialize returned S_OK what means
261 com was not yet initialized we better
262 let com initialized or we may run into
263 the realm of undefined behaviour
265 if ( m_hResult == S_FALSE )
266 CoUninitialize( );
269 private:
270 HRESULT m_hResult;
273 //--------------------------------------------------------------------
274 // ctor
275 //--------------------------------------------------------------------
277 CMtaOleClipboard::CMtaOleClipboard( ) :
278 m_hOleThread( NULL ),
279 m_uOleThreadId( 0 ),
280 m_hEvtThrdReady( NULL ),
281 m_hwndMtaOleReqWnd( NULL ),
282 m_MtaOleReqWndClassAtom( 0 ),
283 m_hwndNextClipViewer( NULL ),
284 m_pfncClipViewerCallback( NULL ),
285 m_bRunClipboardNotifierThread( sal_True ),
286 m_hClipboardChangedEvent( m_hClipboardChangedNotifierEvents[0] ),
287 m_hTerminateClipboardChangedNotifierEvent( m_hClipboardChangedNotifierEvents[1] ),
288 m_ClipboardChangedEventCount( 0 )
290 // signals that the thread was successfully setup
291 m_hEvtThrdReady = CreateEventA( 0, MANUAL_RESET, INIT_NONSIGNALED, NULL );
293 OSL_ASSERT( NULL != m_hEvtThrdReady );
295 s_theMtaOleClipboardInst = this;
297 m_hOleThread = (HANDLE)_beginthreadex(
298 NULL, 0, CMtaOleClipboard::oleThreadProc, this, 0, &m_uOleThreadId );
299 OSL_ASSERT( NULL != m_hOleThread );
301 //----------------------------------------------
302 // setup the clipboard changed notifier thread
303 //----------------------------------------------
305 m_hClipboardChangedNotifierEvents[0] = CreateEventA( 0, MANUAL_RESET, INIT_NONSIGNALED, NULL );
306 OSL_ASSERT( NULL != m_hClipboardChangedNotifierEvents[0] );
308 m_hClipboardChangedNotifierEvents[1] = CreateEventA( 0, MANUAL_RESET, INIT_NONSIGNALED, NULL );
309 OSL_ASSERT( NULL != m_hClipboardChangedNotifierEvents[1] );
311 unsigned uThreadId;
312 m_hClipboardChangedNotifierThread = (HANDLE)_beginthreadex(
313 NULL, 0, CMtaOleClipboard::clipboardChangedNotifierThreadProc, this, 0, &uThreadId );
315 OSL_ASSERT( NULL != m_hClipboardChangedNotifierThread );
318 //--------------------------------------------------------------------
319 // dtor
320 //--------------------------------------------------------------------
322 CMtaOleClipboard::~CMtaOleClipboard( )
324 // block calling threads out
325 if ( NULL != m_hEvtThrdReady )
326 ResetEvent( m_hEvtThrdReady );
328 // terminate the clipboard changed notifier thread
329 m_bRunClipboardNotifierThread = sal_False;
330 SetEvent( m_hTerminateClipboardChangedNotifierEvent );
332 sal_uInt32 dwResult = WaitForSingleObject(
333 m_hClipboardChangedNotifierThread, MAX_WAIT_SHUTDOWN );
335 OSL_ENSURE( dwResult == WAIT_OBJECT_0, "clipboard notifier thread could not terminate" );
337 if ( NULL != m_hClipboardChangedNotifierThread )
338 CloseHandle( m_hClipboardChangedNotifierThread );
340 if ( NULL != m_hClipboardChangedNotifierEvents[0] )
341 CloseHandle( m_hClipboardChangedNotifierEvents[0] );
343 if ( NULL != m_hClipboardChangedNotifierEvents[1] )
344 CloseHandle( m_hClipboardChangedNotifierEvents[1] );
346 // end the thread
347 // because DestroyWindow can only be called
348 // from within the thread that created the window
349 sendMessage( MSG_SHUTDOWN,
350 static_cast< WPARAM >( 0 ),
351 static_cast< LPARAM >( 0 ) );
353 // wait for thread shutdown
354 dwResult = WaitForSingleObject( m_hOleThread, MAX_WAIT_SHUTDOWN );
355 OSL_ENSURE( dwResult == WAIT_OBJECT_0, "OleThread could not terminate" );
357 if ( NULL != m_hOleThread )
358 CloseHandle( m_hOleThread );
360 if ( NULL != m_hEvtThrdReady )
361 CloseHandle( m_hEvtThrdReady );
363 if ( m_MtaOleReqWndClassAtom )
364 UnregisterClassA( g_szWndClsName, NULL );
366 OSL_ENSURE( ( NULL == m_pfncClipViewerCallback ) &&
367 !IsWindow( m_hwndNextClipViewer ), \
368 "Clipboard viewer not properly unregistered" );
372 //--------------------------------------------------------------------
374 //--------------------------------------------------------------------
376 HRESULT CMtaOleClipboard::flushClipboard( )
378 if ( !WaitForThreadReady( ) )
380 OSL_ENSURE( sal_False, "clipboard sta thread not ready" );
381 return E_FAIL;
384 OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, \
385 "flushClipboard from within clipboard sta thread called" );
387 MsgCtx aMsgCtx;
389 postMessage( MSG_FLUSHCLIPBOARD,
390 static_cast< WPARAM >( 0 ),
391 reinterpret_cast< LPARAM >( &aMsgCtx ) );
393 aMsgCtx.aCondition.wait( /* infinite */ );
395 return aMsgCtx.hr;
398 //--------------------------------------------------------------------
400 //--------------------------------------------------------------------
402 HRESULT CMtaOleClipboard::getClipboard( IDataObject** ppIDataObject )
404 OSL_PRECOND( NULL != ppIDataObject, "invalid parameter" );
405 OSL_PRECOND( GetCurrentThreadId( ) != m_uOleThreadId, "getClipboard from within clipboard sta thread called" );
407 if ( !WaitForThreadReady( ) )
409 OSL_ENSURE( sal_False, "clipboard sta thread not ready" );
410 return E_FAIL;
413 CAutoComInit comAutoInit;
415 LPSTREAM lpStream;
416 HRESULT hr = E_FAIL;
418 *ppIDataObject = NULL;
420 MsgCtx aMsgCtx;
422 postMessage( MSG_GETCLIPBOARD,
423 reinterpret_cast< WPARAM >( &lpStream ),
424 reinterpret_cast< LPARAM >( &aMsgCtx ) );
426 aMsgCtx.aCondition.wait( /* infinite */ );
428 hr = aMsgCtx.hr;
430 if ( SUCCEEDED( hr ) )
432 hr = UnmarshalIDataObjectAndReleaseStream( lpStream, ppIDataObject );
433 OSL_ENSURE( SUCCEEDED( hr ), "unmarshalling clipboard data object failed" );
436 return hr;
439 //--------------------------------------------------------------------
440 // this is an asynchronous method that's why we don't wait until the
441 // request is completed
442 //--------------------------------------------------------------------
444 HRESULT CMtaOleClipboard::setClipboard( IDataObject* pIDataObject )
446 if ( !WaitForThreadReady( ) )
448 OSL_ENSURE( sal_False, "clipboard sta thread not ready" );
449 return E_FAIL;
452 CAutoComInit comAutoInit;
454 OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "setClipboard from within the clipboard sta thread called" );
456 // because we marshall this request
457 // into the sta thread we better
458 // acquire the interface here so
459 // that the object will not be
460 // destroyed before the ole clipboard
461 // can acquire it
462 // remember: pIDataObject may be NULL
463 // which is an request to clear the
464 // current clipboard content
465 if ( pIDataObject )
466 pIDataObject->AddRef( );
468 postMessage(
469 MSG_SETCLIPBOARD,
470 reinterpret_cast< WPARAM >( pIDataObject ),
471 0 );
473 // because this is an asynchronous function
474 // the return value is useless
475 return S_OK;
478 //--------------------------------------------------------------------
479 // register a clipboard viewer
480 //--------------------------------------------------------------------
482 sal_Bool CMtaOleClipboard::registerClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback )
484 if ( !WaitForThreadReady( ) )
486 OSL_ENSURE( sal_False, "clipboard sta thread not ready" );
487 return sal_False;
490 sal_Bool bRet = sal_False;
492 OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "registerClipViewer from within the OleThread called" );
494 MsgCtx aMsgCtx;
496 postMessage( MSG_REGCLIPVIEWER,
497 reinterpret_cast<WPARAM>( pfncClipViewerCallback ),
498 reinterpret_cast<LPARAM>( &aMsgCtx ) );
500 aMsgCtx.aCondition.wait( /* infinite */ );
502 return bRet;
505 //--------------------------------------------------------------------
506 // register a clipboard viewer
507 //--------------------------------------------------------------------
509 sal_Bool CMtaOleClipboard::onRegisterClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback )
511 sal_Bool bRet = sal_True;
513 // we need exclusive access because the clipboard changed notifier
514 // thread also accesses this variable
515 MutexGuard aGuard( m_pfncClipViewerCallbackMutex );
517 // register if not yet done
518 if ( ( NULL != pfncClipViewerCallback ) && ( NULL == m_pfncClipViewerCallback ) )
520 // SetClipboardViewer sends a WM_DRAWCLIPBOARD message we ignore
521 // this message if we register ourself as clip viewer
522 m_bInRegisterClipViewer = sal_True;
523 m_hwndNextClipViewer = SetClipboardViewer( m_hwndMtaOleReqWnd );
524 m_bInRegisterClipViewer = sal_False;
526 // if there is no other cb-viewer the
527 // return value is NULL!!!
528 bRet = IsWindow( m_hwndNextClipViewer ) ? sal_True : sal_False;
530 // save the new callback function
531 m_pfncClipViewerCallback = pfncClipViewerCallback;
533 else if ( ( NULL == pfncClipViewerCallback ) && ( NULL != m_pfncClipViewerCallback ) )
535 m_pfncClipViewerCallback = NULL;
537 // unregister if input parameter is NULL and we previously registered
538 // as clipboard viewer
539 ChangeClipboardChain( m_hwndMtaOleReqWnd, m_hwndNextClipViewer );
540 m_hwndNextClipViewer = NULL;
543 return bRet;
546 //--------------------------------------------------------------------
548 //--------------------------------------------------------------------
550 LRESULT CMtaOleClipboard::onSetClipboard( IDataObject* pIDataObject )
552 return static_cast<LRESULT>( OleSetClipboard( pIDataObject ) );
555 //--------------------------------------------------------------------
557 //--------------------------------------------------------------------
559 LRESULT CMtaOleClipboard::onGetClipboard( LPSTREAM* ppStream )
561 OSL_ASSERT(NULL != ppStream);
563 IDataObjectPtr pIDataObject;
565 // forward the request to the OleClipboard
566 HRESULT hr = OleGetClipboard( &pIDataObject );
567 if ( SUCCEEDED( hr ) )
569 hr = MarshalIDataObjectInStream(pIDataObject.get(), ppStream);
570 OSL_ENSURE(SUCCEEDED(hr), "marshalling cliboard data object failed");
572 return static_cast<LRESULT>(hr);
575 //--------------------------------------------------------------------
576 // flush the ole-clipboard
577 //--------------------------------------------------------------------
579 LRESULT CMtaOleClipboard::onFlushClipboard( )
581 return static_cast<LRESULT>( OleFlushClipboard( ) );
584 //--------------------------------------------------------------------
585 // handle clipboard chain change event
586 //--------------------------------------------------------------------
588 LRESULT CMtaOleClipboard::onChangeCBChain( HWND hWndRemove, HWND hWndNext )
590 if ( hWndRemove == m_hwndNextClipViewer )
591 m_hwndNextClipViewer = hWndNext;
592 else if ( IsWindow( m_hwndNextClipViewer ) )
594 // forward the message to the next one
595 DWORD dwResult;
596 SendMessageTimeoutA(
597 m_hwndNextClipViewer,
598 WM_CHANGECBCHAIN,
599 reinterpret_cast<WPARAM>(hWndRemove),
600 reinterpret_cast<LPARAM>(hWndNext),
601 SMTO_BLOCK,
602 MAX_CLIPEVENT_PROCESSING_TIME,
603 &dwResult );
606 return 0;
609 //--------------------------------------------------------------------
610 // handle draw clipboard event
611 //--------------------------------------------------------------------
613 LRESULT CMtaOleClipboard::onDrawClipboard( )
615 // we don't send a notification if we are
616 // registering ourself as clipboard
617 if ( !m_bInRegisterClipViewer )
619 ClearableMutexGuard aGuard( m_ClipboardChangedEventCountMutex );
621 m_ClipboardChangedEventCount++;
622 SetEvent( m_hClipboardChangedEvent );
624 aGuard.clear( );
627 // foward the message to the next viewer in the chain
628 if ( IsWindow( m_hwndNextClipViewer ) )
630 DWORD dwResult;
631 SendMessageTimeoutA(
632 m_hwndNextClipViewer,
633 WM_DRAWCLIPBOARD,
634 static_cast< WPARAM >( 0 ),
635 static_cast< LPARAM >( 0 ),
636 SMTO_BLOCK,
637 MAX_CLIPEVENT_PROCESSING_TIME,
638 &dwResult );
641 return 0;
644 //--------------------------------------------------------------------
645 // SendMessage so we don't need to supply the HWND if we send
646 // something to our wrapped window
647 //--------------------------------------------------------------------
649 LRESULT CMtaOleClipboard::sendMessage( UINT msg, WPARAM wParam, LPARAM lParam )
651 return ::SendMessageA( m_hwndMtaOleReqWnd, msg, wParam, lParam );
654 //--------------------------------------------------------------------
655 // PostMessage so we don't need to supply the HWND if we send
656 // something to our wrapped window
657 //--------------------------------------------------------------------
659 sal_Bool CMtaOleClipboard::postMessage( UINT msg, WPARAM wParam, LPARAM lParam )
661 return PostMessageA( m_hwndMtaOleReqWnd, msg, wParam, lParam ) ? sal_True : sal_False;
665 //--------------------------------------------------------------------
666 // the window proc
667 //--------------------------------------------------------------------
669 LRESULT CALLBACK CMtaOleClipboard::mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
671 LRESULT lResult = 0;
673 // get a connection to the class-instance via the static member
674 CMtaOleClipboard* pImpl = CMtaOleClipboard::s_theMtaOleClipboardInst;
675 OSL_ASSERT( NULL != pImpl );
677 switch( uMsg )
679 case MSG_SETCLIPBOARD:
681 IDataObject* pIDataObject = reinterpret_cast< IDataObject* >( wParam );
682 pImpl->onSetClipboard( pIDataObject );
684 // in setClipboard we did acquire the
685 // interface pointer in order to prevent
686 // destruction of the object before the
687 // ole clipboard can acquire the interface
688 // now we release the interface so that
689 // our lostOwnership mechanism works
690 // remember: pIDataObject may be NULL
691 if ( pIDataObject )
692 pIDataObject->Release( );
694 break;
696 case MSG_GETCLIPBOARD:
698 MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam );
699 OSL_ASSERT( aMsgCtx );
701 aMsgCtx->hr = pImpl->onGetClipboard( reinterpret_cast< LPSTREAM* >(wParam) );
702 aMsgCtx->aCondition.set( );
704 break;
706 case MSG_FLUSHCLIPBOARD:
708 MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam );
709 OSL_ASSERT( aMsgCtx );
711 aMsgCtx->hr = pImpl->onFlushClipboard( );
712 aMsgCtx->aCondition.set( );
714 break;
716 case MSG_REGCLIPVIEWER:
718 MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam );
719 OSL_ASSERT( aMsgCtx );
721 pImpl->onRegisterClipViewer( reinterpret_cast<CMtaOleClipboard::LPFNC_CLIPVIEWER_CALLBACK_t>(wParam) );
722 aMsgCtx->aCondition.set( );
724 break;
726 case WM_CHANGECBCHAIN:
727 lResult = pImpl->onChangeCBChain(
728 reinterpret_cast< HWND >( wParam ), reinterpret_cast< HWND >( lParam ) );
729 break;
731 case WM_DRAWCLIPBOARD:
732 lResult = pImpl->onDrawClipboard( );
733 break;
735 case MSG_SHUTDOWN:
736 DestroyWindow( pImpl->m_hwndMtaOleReqWnd );
737 break;
739 // force the sta thread to end
740 case WM_DESTROY:
741 PostQuitMessage( 0 );
742 break;
744 default:
745 lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam );
746 break;
749 return lResult;
752 //--------------------------------------------------------------------
754 //--------------------------------------------------------------------
756 void CMtaOleClipboard::createMtaOleReqWnd( )
758 WNDCLASSEXA wcex;
760 HINSTANCE hInst = GetModuleHandleA( CLIPSRV_DLL_NAME );
761 OSL_ENSURE( NULL != hInst, "The name of the clipboard service dll must have changed" );
763 ZeroMemory( &wcex, sizeof( WNDCLASSEXA ) );
765 wcex.cbSize = sizeof(WNDCLASSEXA);
766 wcex.style = 0;
767 wcex.lpfnWndProc = static_cast< WNDPROC >( CMtaOleClipboard::mtaOleReqWndProc );
768 wcex.cbClsExtra = 0;
769 wcex.cbWndExtra = 0;
770 wcex.hInstance = hInst;
771 wcex.hIcon = NULL;
772 wcex.hCursor = NULL;
773 wcex.hbrBackground = NULL;
774 wcex.lpszMenuName = NULL;
775 wcex.lpszClassName = g_szWndClsName;
776 wcex.hIconSm = NULL;
778 m_MtaOleReqWndClassAtom = RegisterClassExA( &wcex );
780 if ( 0 != m_MtaOleReqWndClassAtom )
781 m_hwndMtaOleReqWnd = CreateWindowA(
782 g_szWndClsName, NULL, 0, 0, 0, 0, 0, NULL, NULL, hInst, NULL );
785 //--------------------------------------------------------------------
787 //--------------------------------------------------------------------
789 unsigned int CMtaOleClipboard::run( )
791 #if OSL_DEBUG_LEVEL > 0
792 HRESULT hr =
793 #endif
794 OleInitialize( NULL );
795 OSL_ASSERT( SUCCEEDED( hr ) );
797 createMtaOleReqWnd( );
799 unsigned int nRet;
801 if ( IsWindow( m_hwndMtaOleReqWnd ) )
803 if ( NULL != m_hEvtThrdReady )
804 SetEvent( m_hEvtThrdReady );
806 // pumping messages
807 MSG msg;
808 while( GetMessageA( &msg, NULL, 0, 0 ) )
809 DispatchMessageA( &msg );
811 nRet = 0;
813 else
814 nRet = ~0U;
816 OleUninitialize( );
818 return nRet;
821 //--------------------------------------------------------------------
823 //--------------------------------------------------------------------
825 unsigned int WINAPI CMtaOleClipboard::oleThreadProc( LPVOID pParam )
827 CMtaOleClipboard* pInst =
828 reinterpret_cast<CMtaOleClipboard*>( pParam );
829 OSL_ASSERT( NULL != pInst );
831 return pInst->run( );
834 //--------------------------------------------------------------------
836 //--------------------------------------------------------------------
838 unsigned int WINAPI CMtaOleClipboard::clipboardChangedNotifierThreadProc( LPVOID pParam )
840 CMtaOleClipboard* pInst = reinterpret_cast< CMtaOleClipboard* >( pParam );
841 OSL_ASSERT( NULL != pInst );
843 CoInitialize( NULL );
845 // assuming we don't need a lock for
846 // a boolean variable like m_bRun...
847 while ( pInst->m_bRunClipboardNotifierThread )
849 // wait for clipboard changed or terminate event
850 WaitForMultipleObjects( 2, pInst->m_hClipboardChangedNotifierEvents, false, INFINITE );
852 ClearableMutexGuard aGuard( pInst->m_ClipboardChangedEventCountMutex );
854 if ( pInst->m_ClipboardChangedEventCount > 0 )
856 pInst->m_ClipboardChangedEventCount--;
857 if ( 0 == pInst->m_ClipboardChangedEventCount )
858 ResetEvent( pInst->m_hClipboardChangedEvent );
860 aGuard.clear( );
862 // nobody should touch m_pfncClipViewerCallback while we do
863 MutexGuard aClipViewerGuard( pInst->m_pfncClipViewerCallbackMutex );
865 // notify all clipboard listener
866 if ( pInst->m_pfncClipViewerCallback )
867 pInst->m_pfncClipViewerCallback( );
869 else
870 aGuard.clear( );
873 CoUninitialize( );
875 return ( 0 );
878 //--------------------------------------------------------------------
880 //--------------------------------------------------------------------
882 inline
883 sal_Bool CMtaOleClipboard::WaitForThreadReady( ) const
885 sal_Bool bRet = sal_False;
887 if ( NULL != m_hEvtThrdReady )
889 DWORD dwResult = WaitForSingleObject(
890 m_hEvtThrdReady, MAX_WAITTIME );
891 bRet = ( dwResult == WAIT_OBJECT_0 );
894 return bRet;