xref: /AOO41X/main/dtrans/source/win32/mtaole/MtaOleClipb.cxx (revision 48123e16153c92857455f9e7a0d17cc19307983f)
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
Win32Condition()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
~Win32Condition()118             ~Win32Condition()
119             {
120                 CloseHandle(m_hEvent);
121             }
122 
123             // wait infinite for event be signaled
124             // leave messages sent through
wait()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
set()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
MarshalIDataObjectInStream(IDataObject * pIDataObject,LPSTREAM * ppStream)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
UnmarshalIDataObjectAndReleaseStream(LPSTREAM lpStream,IDataObject ** ppIDataObject)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:
CAutoComInit()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 
~CAutoComInit()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 
CMtaOleClipboard()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 
~CMtaOleClipboard()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 
flushClipboard()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 
getClipboard(IDataObject ** ppIDataObject)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 
setClipboard(IDataObject * pIDataObject)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 
registerClipViewer(LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback)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 
onRegisterClipViewer(LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback)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 
onSetClipboard(IDataObject * pIDataObject)543 LRESULT CMtaOleClipboard::onSetClipboard( IDataObject* pIDataObject )
544 {
545     return static_cast<LRESULT>( OleSetClipboard( pIDataObject ) );
546 }
547 
548 //--------------------------------------------------------------------
549 //
550 //--------------------------------------------------------------------
551 
onGetClipboard(LPSTREAM * ppStream)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 
onFlushClipboard()572 LRESULT CMtaOleClipboard::onFlushClipboard( )
573 {
574     return static_cast<LRESULT>( OleFlushClipboard( ) );
575 }
576 
577 //--------------------------------------------------------------------
578 // handle clipboard chain change event
579 //--------------------------------------------------------------------
580 
onChangeCBChain(HWND hWndRemove,HWND hWndNext)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 
onDrawClipboard()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     // foward 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 
sendMessage(UINT msg,WPARAM wParam,LPARAM lParam)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 
postMessage(UINT msg,WPARAM wParam,LPARAM lParam)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 
mtaOleReqWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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 
createMtaOleReqWnd()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 
run()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 
oleThreadProc(LPVOID pParam)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 
clipboardChangedNotifierThreadProc(LPVOID pParam)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
WaitForThreadReady() const876 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