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 // 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
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