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
Win32Condition()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
~Win32Condition()116 ~Win32Condition()
117 {
118 CloseHandle(m_hEvent);
119 }
120
121 // wait infinite for event be signaled
122 // leave messages sent through
wait()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
set()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
MarshalIDataObjectInStream(IDataObject * pIDataObject,LPSTREAM * ppStream)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
UnmarshalIDataObjectAndReleaseStream(LPSTREAM lpStream,IDataObject ** ppIDataObject)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:
CAutoComInit()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
~CAutoComInit()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
CMtaOleClipboard()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
~CMtaOleClipboard()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
flushClipboard()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
getClipboard(IDataObject ** ppIDataObject)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
setClipboard(IDataObject * pIDataObject)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
registerClipViewer(LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback)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
onRegisterClipViewer(LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback)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
onSetClipboard(IDataObject * pIDataObject)541 HRESULT CMtaOleClipboard::onSetClipboard( IDataObject* pIDataObject )
542 {
543 return OleSetClipboard( pIDataObject );
544 }
545
546 //--------------------------------------------------------------------
547 //
548 //--------------------------------------------------------------------
549
onGetClipboard(LPSTREAM * ppStream)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
onFlushClipboard()570 HRESULT CMtaOleClipboard::onFlushClipboard( )
571 {
572 return OleFlushClipboard( );
573 }
574
575 //--------------------------------------------------------------------
576 // handle clipboard chain change event
577 //--------------------------------------------------------------------
578
onChangeCBChain(HWND hWndRemove,HWND hWndNext)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
onDrawClipboard()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
sendMessage(UINT msg,WPARAM wParam,LPARAM lParam)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
postMessage(UINT msg,WPARAM wParam,LPARAM lParam)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
mtaOleReqWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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
createMtaOleReqWnd()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
run()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
oleThreadProc(LPVOID pParam)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
clipboardChangedNotifierThreadProc(LPVOID pParam)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
WaitForThreadReady() const874 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