LibreOffice Module dtrans (master)  1
MtaOleClipb.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 /*
21  MtaOleClipb.cxx - documentation
22 
23  This class setup a single threaded apartment (sta) thread to deal with
24  the ole clipboard, which runs only in an sta thread.
25  The consequence is that callback from the ole clipboard are in the
26  context of this sta thread. In the soffice applications this may lead
27  to problems because they all use the one and only mutex called
28  SolarMutex.
29  In order to transfer clipboard requests to our sta thread we use a
30  hidden window and forward these requests via window messages.
31 */
32 
33 #include <osl/diagnose.h>
34 #include <sal/log.hxx>
35 
36 #include "MtaOleClipb.hxx"
37 #include <osl/thread.h>
38 
39 #include <wchar.h>
40 #include <process.h>
41 
42 #include <systools/win32/comtools.hxx>
43 
44 // namespace directives
45 
46 using osl::MutexGuard;
47 using osl::ClearableMutexGuard;
48 
49 namespace /* private */
50 {
51  wchar_t CLIPSRV_DLL_NAME[] = L"sysdtrans.dll";
52  wchar_t g_szWndClsName[] = L"MtaOleReqWnd###";
53 
54  // messages constants
55 
56  const sal_uInt32 MSG_SETCLIPBOARD = WM_USER + 0x0001;
57  const sal_uInt32 MSG_GETCLIPBOARD = WM_USER + 0x0002;
58  const sal_uInt32 MSG_REGCLIPVIEWER = WM_USER + 0x0003;
59  const sal_uInt32 MSG_FLUSHCLIPBOARD = WM_USER + 0x0004;
60  const sal_uInt32 MSG_SHUTDOWN = WM_USER + 0x0005;
61 
62  const sal_uInt32 MAX_WAITTIME = 10000; // msec
63  const sal_uInt32 MAX_WAIT_SHUTDOWN = 10000; // msec
64 
65  const bool MANUAL_RESET = true;
66  const bool INIT_NONSIGNALED = false;
67 
68  /* Cannot use osl conditions because they are blocking
69  without waking up on messages sent by another thread
70  this leads to deadlocks because we are blocking the
71  communication between inter-thread marshalled COM
72  pointers.
73  COM Proxy-Stub communication uses SendMessages for
74  synchronization purposes.
75  */
76  class Win32Condition
77  {
78  public:
79  Win32Condition() = default;
80 
81  ~Win32Condition() { CloseHandle(m_hEvent); }
82 
83  // wait infinite for own event (or abort event) be signaled
84  // leave messages sent through
85  bool wait(HANDLE hEvtAbort)
86  {
87  const HANDLE hWaitArray[2] = { m_hEvent, hEvtAbort };
88  while (true)
89  {
90  DWORD dwResult
91  = MsgWaitForMultipleObjects(2, hWaitArray, FALSE, INFINITE, QS_SENDMESSAGE);
92 
93  switch (dwResult)
94  {
95  case WAIT_OBJECT_0: // wait successful
96  return true;
97 
98  case WAIT_OBJECT_0 + 1: // wait aborted
99  return false;
100 
101  case WAIT_OBJECT_0 + 2:
102  {
103  /* PeekMessage processes all messages in the SendMessage
104  queue that's what we want, messages from the PostMessage
105  queue stay untouched */
106  MSG msg;
107  PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE);
108 
109  break;
110  }
111 
112  default: // WAIT_FAILED?
113  return false;
114  }
115  }
116  }
117 
118  // set the event
119  void set() { SetEvent(m_hEvent); }
120 
121  private:
122  HANDLE m_hEvent = CreateEventW(nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr);
123 
124  // prevent copy/assignment
125  Win32Condition(const Win32Condition&) = delete;
126  Win32Condition& operator=(const Win32Condition&) = delete;
127  };
128 
129  // we use one condition for every request
130 
131  struct MsgCtx
132  {
133  Win32Condition aCondition;
134  HRESULT hr;
135  };
136 
137 } /* namespace private */
138 
139 // static member initialization
140 
142 
143 // marshal an IDataObject
144 
145 //inline
146 static HRESULT MarshalIDataObjectInStream( IDataObject* pIDataObject, LPSTREAM* ppStream )
147 {
148  OSL_ASSERT( nullptr != pIDataObject );
149  OSL_ASSERT( nullptr != ppStream );
150 
151  *ppStream = nullptr;
152  return CoMarshalInterThreadInterfaceInStream(
153  __uuidof(IDataObject), //The IID of interface to be marshalled
154  pIDataObject, //The interface pointer
155  ppStream //IStream pointer
156  );
157 }
158 
159 // unmarshal an IDataObject
160 
161 //inline
162 static HRESULT UnmarshalIDataObjectAndReleaseStream( LPSTREAM lpStream, IDataObject** ppIDataObject )
163 {
164  OSL_ASSERT( nullptr != lpStream );
165  OSL_ASSERT( nullptr != ppIDataObject );
166 
167  *ppIDataObject = nullptr;
168  return CoGetInterfaceAndReleaseStream(
169  lpStream,
170  __uuidof(IDataObject),
171  reinterpret_cast<LPVOID*>(ppIDataObject));
172 }
173 
174 // helper class to ensure that the calling thread has com initialized
175 
176 namespace {
177 
178 class CAutoComInit
179 {
180 public:
181  /*
182  to be safe we call CoInitialize
183  although it is not necessary if
184  the calling thread was created
185  using osl_CreateThread because
186  this function calls CoInitialize
187  for every thread it creates
188  */
189  CAutoComInit( ) : m_hResult( CoInitialize( nullptr ) )
190  {
191  if ( S_OK == m_hResult )
192  OSL_FAIL(
193  "com was not yet initialized, the thread was not created using osl_createThread" );
194  else if ( FAILED( m_hResult ) && !( RPC_E_CHANGED_MODE == m_hResult ) )
195  OSL_FAIL(
196  "com could not be initialized, maybe the thread was not created using osl_createThread" );
197  }
198 
199  ~CAutoComInit( )
200  {
201  /*
202  we only call CoUninitialize when
203  CoInitialize returned S_FALSE, what
204  means that com was already initialize
205  for that thread so we keep the balance
206  if CoInitialize returned S_OK what means
207  com was not yet initialized we better
208  let com initialized or we may run into
209  the realm of undefined behaviour
210  */
211  if ( m_hResult == S_FALSE )
212  CoUninitialize( );
213  }
214 
215 private:
216  HRESULT m_hResult;
217 };
218 
219 }
220 
221 // ctor
222 
224  m_hOleThread( nullptr ),
225  m_uOleThreadId( 0 ),
226  // signals that the thread was successfully setup
227  m_hEvtThrdReady(CreateEventW( nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr )),
228  m_hwndMtaOleReqWnd( nullptr ),
229  // signals that the window is destroyed - to stop waiting any winproc result
230  m_hEvtWndDisposed(CreateEventW(nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr)),
231  m_MtaOleReqWndClassAtom( 0 ),
232  m_pfncClipViewerCallback( nullptr ),
233  m_bRunClipboardNotifierThread( true ),
234  m_hClipboardChangedEvent( m_hClipboardChangedNotifierEvents[0] ),
235  m_hTerminateClipboardChangedNotifierEvent( m_hClipboardChangedNotifierEvents[1] ),
236  m_ClipboardChangedEventCount( 0 )
237 {
238  OSL_ASSERT( nullptr != m_hEvtThrdReady );
239  SAL_WARN_IF(!m_hEvtWndDisposed, "dtrans", "CreateEventW failed: m_hEvtWndDisposed is nullptr");
240 
242 
243  m_hOleThread = reinterpret_cast<HANDLE>(_beginthreadex(
244  nullptr, 0, CMtaOleClipboard::oleThreadProc, this, 0, &m_uOleThreadId ));
245  OSL_ASSERT( nullptr != m_hOleThread );
246 
247  // setup the clipboard changed notifier thread
248 
249  m_hClipboardChangedNotifierEvents[0] = CreateEventW( nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr );
250  OSL_ASSERT( nullptr != m_hClipboardChangedNotifierEvents[0] );
251 
252  m_hClipboardChangedNotifierEvents[1] = CreateEventW( nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr );
253  OSL_ASSERT( nullptr != m_hClipboardChangedNotifierEvents[1] );
254 
255  unsigned uThreadId;
256  m_hClipboardChangedNotifierThread = reinterpret_cast<HANDLE>(_beginthreadex(
257  nullptr, 0, CMtaOleClipboard::clipboardChangedNotifierThreadProc, this, 0, &uThreadId ));
258 
259  OSL_ASSERT( nullptr != m_hClipboardChangedNotifierThread );
260 }
261 
262 // dtor
263 
265 {
266  // block calling threads out
267  if ( nullptr != m_hEvtThrdReady )
268  ResetEvent( m_hEvtThrdReady );
269 
270  // terminate the clipboard changed notifier thread
273 
274  // unblock whoever could still wait for event processing
275  if (m_hEvtWndDisposed)
276  SetEvent(m_hEvtWndDisposed);
277 
278  sal_uInt32 dwResult = WaitForSingleObject(
279  m_hClipboardChangedNotifierThread, MAX_WAIT_SHUTDOWN );
280 
281  OSL_ENSURE( dwResult == WAIT_OBJECT_0, "clipboard notifier thread could not terminate" );
282 
283  if ( nullptr != m_hClipboardChangedNotifierThread )
284  CloseHandle( m_hClipboardChangedNotifierThread );
285 
286  if ( nullptr != m_hClipboardChangedNotifierEvents[0] )
287  CloseHandle( m_hClipboardChangedNotifierEvents[0] );
288 
289  if ( nullptr != m_hClipboardChangedNotifierEvents[1] )
290  CloseHandle( m_hClipboardChangedNotifierEvents[1] );
291 
292  // end the thread
293  // because DestroyWindow can only be called
294  // from within the thread that created the window
295  sendMessage( MSG_SHUTDOWN );
296 
297  // wait for thread shutdown
298  dwResult = WaitForSingleObject( m_hOleThread, MAX_WAIT_SHUTDOWN );
299  OSL_ENSURE( dwResult == WAIT_OBJECT_0, "OleThread could not terminate" );
300 
301  if ( nullptr != m_hOleThread )
302  CloseHandle( m_hOleThread );
303 
304  if ( nullptr != m_hEvtThrdReady )
305  CloseHandle( m_hEvtThrdReady );
306 
307  if (m_hEvtWndDisposed)
308  CloseHandle(m_hEvtWndDisposed);
309 
311  UnregisterClassW( g_szWndClsName, nullptr );
312 
313  OSL_ENSURE( ( nullptr == m_pfncClipViewerCallback ),
314  "Clipboard viewer not properly unregistered" );
315 }
316 
318 {
319  if ( !WaitForThreadReady( ) )
320  {
321  OSL_FAIL( "clipboard sta thread not ready" );
322  return E_FAIL;
323  }
324 
325  OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId,
326  "flushClipboard from within clipboard sta thread called" );
327 
328  MsgCtx aMsgCtx;
329 
330  const bool bWaitSuccess = postMessage(MSG_FLUSHCLIPBOARD, 0, reinterpret_cast<LPARAM>(&aMsgCtx))
331  && aMsgCtx.aCondition.wait(m_hEvtWndDisposed);
332 
333  return bWaitSuccess ? aMsgCtx.hr : E_ABORT;
334 }
335 
336 HRESULT CMtaOleClipboard::getClipboard( IDataObject** ppIDataObject )
337 {
338  OSL_PRECOND( nullptr != ppIDataObject, "invalid parameter" );
339  OSL_PRECOND( GetCurrentThreadId( ) != m_uOleThreadId, "getClipboard from within clipboard sta thread called" );
340 
341  if ( !WaitForThreadReady( ) )
342  {
343  OSL_FAIL( "clipboard sta thread not ready" );
344  return E_FAIL;
345  }
346 
347  CAutoComInit comAutoInit;
348 
349  LPSTREAM lpStream;
350 
351  *ppIDataObject = nullptr;
352 
353  MsgCtx aMsgCtx;
354 
355  const bool bWaitSuccess = postMessage(MSG_GETCLIPBOARD, reinterpret_cast<WPARAM>(&lpStream),
356  reinterpret_cast<LPARAM>(&aMsgCtx))
357  && aMsgCtx.aCondition.wait(m_hEvtWndDisposed);
358 
359  HRESULT hr = bWaitSuccess ? aMsgCtx.hr : E_ABORT;
360 
361  if ( SUCCEEDED( hr ) )
362  {
363  hr = UnmarshalIDataObjectAndReleaseStream( lpStream, ppIDataObject );
364  OSL_ENSURE( SUCCEEDED( hr ), "unmarshalling clipboard data object failed" );
365  }
366 
367  return hr;
368 }
369 
370 // this is an asynchronous method that's why we don't wait until the
371 // request is completed
372 
373 HRESULT CMtaOleClipboard::setClipboard( IDataObject* pIDataObject )
374 {
375  if ( !WaitForThreadReady( ) )
376  {
377  OSL_FAIL( "clipboard sta thread not ready" );
378  return E_FAIL;
379  }
380 
381  CAutoComInit comAutoInit;
382 
383  OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "setClipboard from within the clipboard sta thread called" );
384 
385  // because we marshall this request
386  // into the sta thread we better
387  // acquire the interface here so
388  // that the object will not be
389  // destroyed before the ole clipboard
390  // can acquire it
391  // remember: pIDataObject may be NULL
392  // which is a request to clear the
393  // current clipboard content
394  if ( pIDataObject )
395  pIDataObject->AddRef( );
396 
397  postMessage(
398  MSG_SETCLIPBOARD,
399  reinterpret_cast< WPARAM >( pIDataObject ) );
400 
401  // because this is an asynchronous function
402  // the return value is useless
403  return S_OK;
404 }
405 
406 // register a clipboard viewer
407 
408 bool CMtaOleClipboard::registerClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback )
409 {
410  if ( !WaitForThreadReady( ) )
411  {
412  OSL_FAIL( "clipboard sta thread not ready" );
413  return false;
414  }
415 
416  OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "registerClipViewer from within the OleThread called" );
417 
418  MsgCtx aMsgCtx;
419 
420  if (postMessage(MSG_REGCLIPVIEWER, reinterpret_cast<WPARAM>(pfncClipViewerCallback),
421  reinterpret_cast<LPARAM>(&aMsgCtx)))
422  aMsgCtx.aCondition.wait(m_hEvtWndDisposed);
423 
424  return false;
425 }
426 
427 // register a clipboard viewer
428 
429 bool CMtaOleClipboard::onRegisterClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback )
430 {
431  bool bRet = false;
432 
433  // we need exclusive access because the clipboard changed notifier
434  // thread also accesses this variable
435  MutexGuard aGuard( m_pfncClipViewerCallbackMutex );
436 
437  // register if not yet done
438  if ( ( nullptr != pfncClipViewerCallback ) && ( nullptr == m_pfncClipViewerCallback ) )
439  {
440  // SetClipboardViewer sends a WM_DRAWCLIPBOARD message we ignore
441  // this message if we register ourself as clip viewer
443  bRet = AddClipboardFormatListener(m_hwndMtaOleReqWnd);
444  m_bInRegisterClipViewer = false;
445 
446  // save the new callback function
447  m_pfncClipViewerCallback = pfncClipViewerCallback;
448  }
449  else if ( ( nullptr == pfncClipViewerCallback ) && ( nullptr != m_pfncClipViewerCallback ) )
450  {
451  m_pfncClipViewerCallback = nullptr;
452 
453  // unregister if input parameter is NULL and we previously registered
454  // as clipboard viewer
455  bRet = RemoveClipboardFormatListener(m_hwndMtaOleReqWnd);
456  }
457 
458  return bRet;
459 }
460 
461 HRESULT CMtaOleClipboard::onSetClipboard( IDataObject* pIDataObject )
462 {
463  return OleSetClipboard( pIDataObject );
464 }
465 
466 HRESULT CMtaOleClipboard::onGetClipboard( LPSTREAM* ppStream )
467 {
468  OSL_ASSERT(nullptr != ppStream);
469 
470  IDataObjectPtr pIDataObject;
471 
472  // forward the request to the OleClipboard
473  HRESULT hr = OleGetClipboard( &pIDataObject );
474  if ( SUCCEEDED( hr ) )
475  {
476  hr = MarshalIDataObjectInStream(pIDataObject.get(), ppStream);
477  OSL_ENSURE(SUCCEEDED(hr), "marshalling cliboard data object failed");
478  }
479  return hr;
480 }
481 
482 // flush the ole-clipboard
483 
485 {
486  return OleFlushClipboard();
487 }
488 
489 // handle clipboard update event
490 
492 {
493  // we don't send a notification if we are
494  // registering ourself as clipboard
496  {
497  MutexGuard aGuard( m_ClipboardChangedEventCountMutex );
498 
500  SetEvent( m_hClipboardChangedEvent );
501  }
502 
503  return 0;
504 }
505 
506 // SendMessage so we don't need to supply the HWND if we send
507 // something to our wrapped window
508 
509 LRESULT CMtaOleClipboard::sendMessage( UINT msg, WPARAM wParam, LPARAM lParam )
510 {
511  return ::SendMessageW( m_hwndMtaOleReqWnd, msg, wParam, lParam );
512 }
513 
514 // PostMessage so we don't need to supply the HWND if we send
515 // something to our wrapped window
516 
517 bool CMtaOleClipboard::postMessage( UINT msg, WPARAM wParam, LPARAM lParam )
518 {
519  bool const ret = PostMessageW(m_hwndMtaOleReqWnd, msg, wParam, lParam);
520  SAL_WARN_IF(!ret, "dtrans", "ERROR: PostMessage() failed!");
521  return ret;
522 }
523 
524 // the window proc
525 
526 LRESULT CALLBACK CMtaOleClipboard::mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
527 {
528  LRESULT lResult = 0;
529 
530  // get a connection to the class-instance via the static member
532  OSL_ASSERT( nullptr != pImpl );
533 
534  switch( uMsg )
535  {
536  case MSG_SETCLIPBOARD:
537  {
538  IDataObject* pIDataObject = reinterpret_cast< IDataObject* >( wParam );
539  CMtaOleClipboard::onSetClipboard( pIDataObject );
540 
541  // in setClipboard we did acquire the
542  // interface pointer in order to prevent
543  // destruction of the object before the
544  // ole clipboard can acquire the interface
545  // now we release the interface so that
546  // our lostOwnership mechanism works
547  // remember: pIDataObject may be NULL
548  if ( pIDataObject )
549  pIDataObject->Release( );
550  }
551  break;
552 
553  case MSG_GETCLIPBOARD:
554  {
555  MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam );
556  OSL_ASSERT( aMsgCtx );
557 
558  aMsgCtx->hr = CMtaOleClipboard::onGetClipboard( reinterpret_cast< LPSTREAM* >(wParam) );
559  aMsgCtx->aCondition.set( );
560  }
561  break;
562 
563  case MSG_FLUSHCLIPBOARD:
564  {
565  MsgCtx* aMsgCtx = reinterpret_cast< MsgCtx* >( lParam );
566  OSL_ASSERT( aMsgCtx );
567 
568  aMsgCtx->hr = CMtaOleClipboard::onFlushClipboard( );
569  aMsgCtx->aCondition.set( );
570  }
571  break;
572 
573  case MSG_REGCLIPVIEWER:
574  {
575  MsgCtx* pMsgCtx = reinterpret_cast<MsgCtx*>(lParam);
576  SAL_WARN_IF(!pMsgCtx, "dtrans", "pMsgCtx is nullptr");
577 
578  pImpl->onRegisterClipViewer(
579  reinterpret_cast<CMtaOleClipboard::LPFNC_CLIPVIEWER_CALLBACK_t>(wParam));
580  pMsgCtx->aCondition.set();
581  }
582  break;
583 
584  case WM_CLIPBOARDUPDATE:
585  lResult = pImpl->onClipboardUpdate();
586  break;
587 
588  case MSG_SHUTDOWN:
589  DestroyWindow( pImpl->m_hwndMtaOleReqWnd );
590  break;
591 
592  // force the sta thread to end
593  case WM_DESTROY:
594  SetEvent(pImpl->m_hEvtWndDisposed); // stop waiting for conditions set by this wndproc
595  PostQuitMessage( 0 );
596  break;
597 
598  default:
599  lResult = DefWindowProcW( hWnd, uMsg, wParam, lParam );
600  break;
601  }
602 
603  return lResult;
604 }
605 
607 {
608  WNDCLASSEXW wcex;
609 
610  HINSTANCE hInst = GetModuleHandleW( CLIPSRV_DLL_NAME );
611  OSL_ENSURE( nullptr != hInst, "The name of the clipboard service dll must have changed" );
612 
613  ZeroMemory( &wcex, sizeof(wcex) );
614 
615  wcex.cbSize = sizeof(wcex);
616  wcex.style = 0;
617  wcex.lpfnWndProc = CMtaOleClipboard::mtaOleReqWndProc;
618  wcex.cbClsExtra = 0;
619  wcex.cbWndExtra = 0;
620  wcex.hInstance = hInst;
621  wcex.hIcon = nullptr;
622  wcex.hCursor = nullptr;
623  wcex.hbrBackground = nullptr;
624  wcex.lpszMenuName = nullptr;
625  wcex.lpszClassName = g_szWndClsName;
626  wcex.hIconSm = nullptr;
627 
628  m_MtaOleReqWndClassAtom = RegisterClassExW( &wcex );
629 
630  if ( 0 != m_MtaOleReqWndClassAtom )
631  m_hwndMtaOleReqWnd = CreateWindowW(
632  g_szWndClsName, nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, hInst, nullptr );
633 }
634 
635 unsigned int CMtaOleClipboard::run( )
636 {
637  HRESULT hr = OleInitialize( nullptr );
638  OSL_ASSERT( SUCCEEDED( hr ) );
639 
641 
642  unsigned int nRet;
643 
644  if ( IsWindow( m_hwndMtaOleReqWnd ) )
645  {
646  if ( nullptr != m_hEvtThrdReady )
647  SetEvent( m_hEvtThrdReady );
648 
649  // pumping messages
650  MSG msg;
651  while( GetMessageW( &msg, nullptr, 0, 0 ) )
652  DispatchMessageW( &msg );
653 
654  nRet = 0;
655  }
656  else
657  nRet = ~0U;
658 
659  OleUninitialize( );
660 
661  return nRet;
662 }
663 
664 unsigned int WINAPI CMtaOleClipboard::oleThreadProc( LPVOID pParam )
665 {
666  osl_setThreadName("CMtaOleClipboard::run()");
667 
668  CMtaOleClipboard* pInst =
669  static_cast<CMtaOleClipboard*>( pParam );
670  OSL_ASSERT( nullptr != pInst );
671 
672  return pInst->run( );
673 }
674 
675 unsigned int WINAPI CMtaOleClipboard::clipboardChangedNotifierThreadProc( LPVOID pParam )
676 {
677  osl_setThreadName("CMtaOleClipboard::clipboardChangedNotifierThreadProc()");
678  CMtaOleClipboard* pInst = static_cast< CMtaOleClipboard* >( pParam );
679  OSL_ASSERT( nullptr != pInst );
680 
681  CoInitialize( nullptr );
682 
683  // assuming we don't need a lock for
684  // a boolean variable like m_bRun...
685  while ( pInst->m_bRunClipboardNotifierThread )
686  {
687  // wait for clipboard changed or terminate event
688  WaitForMultipleObjects( 2, pInst->m_hClipboardChangedNotifierEvents, false, INFINITE );
689 
690  ClearableMutexGuard aGuard( pInst->m_ClipboardChangedEventCountMutex );
691 
692  if ( pInst->m_ClipboardChangedEventCount > 0 )
693  {
695  if ( 0 == pInst->m_ClipboardChangedEventCount )
696  ResetEvent( pInst->m_hClipboardChangedEvent );
697 
698  aGuard.clear( );
699 
700  // nobody should touch m_pfncClipViewerCallback while we do
701  MutexGuard aClipViewerGuard( pInst->m_pfncClipViewerCallbackMutex );
702 
703  // notify all clipboard listener
704  if ( pInst->m_pfncClipViewerCallback )
705  pInst->m_pfncClipViewerCallback( );
706  }
707  else
708  aGuard.clear( );
709  }
710 
711  CoUninitialize( );
712 
713  return 0;
714 }
715 
717 {
718  bool bRet = false;
719 
720  if ( nullptr != m_hEvtThrdReady )
721  {
722  DWORD dwResult = WaitForSingleObject(
723  m_hEvtThrdReady, MAX_WAITTIME );
724  bRet = ( dwResult == WAIT_OBJECT_0 );
725  }
726 
727  return bRet;
728 }
729 
730 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static LRESULT CALLBACK mtaOleReqWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
HANDLE & m_hTerminateClipboardChangedNotifierEvent
Definition: MtaOleClipb.hxx:99
HANDLE & m_hClipboardChangedEvent
Definition: MtaOleClipb.hxx:98
LRESULT sendMessage(UINT msg, WPARAM wParam=0, LPARAM lParam=0)
EXTERN_C BOOL BOOL const wchar_t *pProgramPath HRESULT hr
void createMtaOleReqWnd()
bool m_bRunClipboardNotifierThread
Definition: MtaOleClipb.hxx:95
static CMtaOleClipboard * s_theMtaOleClipboardInst
static HRESULT MarshalIDataObjectInStream(IDataObject *pIDataObject, LPSTREAM *ppStream)
static HRESULT onSetClipboard(IDataObject *pIDataObject)
HANDLE m_hEvtWndDisposed
Definition: MtaOleClipb.hxx:90
static unsigned int WINAPI clipboardChangedNotifierThreadProc(LPVOID pParam)
sal_Int32 m_ClipboardChangedEventCount
bool registerClipViewer(LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback)
bool onRegisterClipViewer(LPFNC_CLIPVIEWER_CALLBACK_t pfncClipViewerCallback)
bool WaitForThreadReady() const
HANDLE m_hClipboardChangedNotifierThread
Definition: MtaOleClipb.hxx:96
LRESULT onClipboardUpdate()
HRESULT flushClipboard()
LPFNC_CLIPVIEWER_CALLBACK_t m_pfncClipViewerCallback
Definition: MtaOleClipb.hxx:92
static HRESULT onFlushClipboard()
unsigned int run()
HANDLE m_hClipboardChangedNotifierEvents[2]
Definition: MtaOleClipb.hxx:97
static HRESULT onGetClipboard(LPSTREAM *ppStream)
#define SAL_WARN_IF(condition, area, stream)
bool m_bInRegisterClipViewer
Definition: MtaOleClipb.hxx:93
osl::Mutex m_ClipboardChangedEventCountMutex
unsigned m_uOleThreadId
Definition: MtaOleClipb.hxx:87
ATOM m_MtaOleReqWndClassAtom
Definition: MtaOleClipb.hxx:91
static unsigned int WINAPI oleThreadProc(LPVOID pParam)
osl::Mutex m_pfncClipViewerCallbackMutex
HRESULT setClipboard(IDataObject *pIDataObject)
HRESULT getClipboard(IDataObject **ppIDataObject)
#define CALLBACK
HANDLE m_hEvtThrdReady
Definition: MtaOleClipb.hxx:88
static HRESULT UnmarshalIDataObjectAndReleaseStream(LPSTREAM lpStream, IDataObject **ppIDataObject)
bool postMessage(UINT msg, WPARAM wParam=0, LPARAM lParam=0)
void set(css::uno::UnoInterfaceReference const &value)