LibreOffice Module dtrans (master)  1
APNDataObject.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 #include "APNDataObject.hxx"
21 #include <osl/diagnose.h>
22 
23 #include <systools/win32/comtools.hxx>
24 
25 #define FREE_HGLOB_ON_RELEASE TRUE
26 #define KEEP_HGLOB_ON_RELEASE FALSE
27 
28 // ctor
29 
30 CAPNDataObject::CAPNDataObject( IDataObjectPtr rIDataObject ) :
31  m_rIDataObjectOrg( rIDataObject ),
32  m_hGlobal( nullptr ),
33  m_nRefCnt( 0 )
34 {
35 
36  OSL_ENSURE( m_rIDataObjectOrg.get( ), "constructing CAPNDataObject with empty data object" );
37 
38  // we marshal the IDataObject interface pointer here so
39  // that it can be unmarshalled multiple times when this
40  // class will be used from another apartment
41  IStreamPtr pStm;
42  HRESULT hr = CreateStreamOnHGlobal( nullptr, KEEP_HGLOB_ON_RELEASE, &pStm );
43 
44  OSL_ENSURE( E_INVALIDARG != hr, "invalid args passed to CreateStreamOnHGlobal" );
45 
46  if ( SUCCEEDED( hr ) )
47  {
48  HRESULT hr_marshal = CoMarshalInterface(
49  pStm.get(),
50  __uuidof(IDataObject),
51  static_cast<LPUNKNOWN>(m_rIDataObjectOrg.get()),
52  MSHCTX_LOCAL,
53  nullptr,
54  MSHLFLAGS_TABLEWEAK );
55 
56  OSL_ENSURE( CO_E_NOTINITIALIZED != hr_marshal, "COM is not initialized" );
57 
58  // marshalling may fail if COM is not initialized
59  // for the calling thread which is a program time
60  // error or because of stream errors which are runtime
61  // errors for instance E_OUTOFMEMORY etc.
62 
63  hr = GetHGlobalFromStream(pStm.get(), &m_hGlobal );
64 
65  OSL_ENSURE( E_INVALIDARG != hr, "invalid stream passed to GetHGlobalFromStream" );
66 
67  // if the marshalling failed we free the
68  // global memory again and set m_hGlobal
69  // to a defined value
70  if (FAILED(hr_marshal))
71  {
72  OSL_FAIL("marshalling failed");
73 
74  HGLOBAL hGlobal =
75  GlobalFree(m_hGlobal);
76  OSL_ENSURE(nullptr == hGlobal, "GlobalFree failed");
77  m_hGlobal = nullptr;
78  }
79  }
80 }
81 
83 {
84  if (m_hGlobal)
85  {
86  IStreamPtr pStm;
87  HRESULT hr = CreateStreamOnHGlobal(m_hGlobal, FREE_HGLOB_ON_RELEASE, &pStm);
88 
89  OSL_ENSURE( E_INVALIDARG != hr, "invalid args passed to CreateStreamOnHGlobal" );
90 
91  if (SUCCEEDED(hr))
92  {
93  hr = CoReleaseMarshalData(pStm.get());
94  OSL_ENSURE(SUCCEEDED(hr), "CoReleaseMarshalData failed");
95  }
96  }
97 }
98 
99 // IUnknown->QueryInterface
100 
101 STDMETHODIMP CAPNDataObject::QueryInterface( REFIID iid, void** ppvObject )
102 {
103  OSL_ASSERT( nullptr != ppvObject );
104 
105  if ( nullptr == ppvObject )
106  return E_INVALIDARG;
107 
108  HRESULT hr = E_NOINTERFACE;
109  *ppvObject = nullptr;
110 
111  if ( ( __uuidof( IUnknown ) == iid ) || ( __uuidof( IDataObject ) == iid ) )
112  {
113  *ppvObject = static_cast< IUnknown* >( this );
114  static_cast<LPUNKNOWN>(*ppvObject)->AddRef( );
115  hr = S_OK;
116  }
117 
118  return hr;
119 }
120 
121 // IUnknown->AddRef
122 
123 STDMETHODIMP_(ULONG) CAPNDataObject::AddRef( )
124 {
125  return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) );
126 }
127 
128 // IUnknown->Release
129 
130 STDMETHODIMP_(ULONG) CAPNDataObject::Release( )
131 {
132  // we need a helper variable because it's not allowed to access
133  // a member variable after an object is destroyed
134  ULONG nRefCnt = static_cast< ULONG >( InterlockedDecrement( &m_nRefCnt ) );
135 
136  if ( 0 == nRefCnt )
137  delete this;
138 
139  return nRefCnt;
140 }
141 
142 // IDataObject->GetData
143 
144 STDMETHODIMP CAPNDataObject::GetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium )
145 {
146  HRESULT hr = m_rIDataObjectOrg->GetData( pFormatetc, pmedium );
147 
148  if (RPC_E_WRONG_THREAD == hr)
149  {
150  IDataObjectPtr pIDOTmp;
152 
153  if (SUCCEEDED(hr))
154  hr = pIDOTmp->GetData(pFormatetc, pmedium);
155  }
156  return hr;
157 }
158 
159 // IDataObject->EnumFormatEtc
160 
161 STDMETHODIMP CAPNDataObject::EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc )
162 {
163  HRESULT hr = m_rIDataObjectOrg->EnumFormatEtc(dwDirection, ppenumFormatetc);
164 
165  if (RPC_E_WRONG_THREAD == hr)
166  {
167  IDataObjectPtr pIDOTmp;
169 
170  if (SUCCEEDED(hr))
171  hr = pIDOTmp->EnumFormatEtc(dwDirection, ppenumFormatetc);
172  }
173  return hr;
174 }
175 
176 // IDataObject->QueryGetData
177 
178 STDMETHODIMP CAPNDataObject::QueryGetData( FORMATETC * pFormatetc )
179 {
180  HRESULT hr = m_rIDataObjectOrg->QueryGetData( pFormatetc );
181 
182  if (RPC_E_WRONG_THREAD == hr)
183  {
184  IDataObjectPtr pIDOTmp;
186 
187  if (SUCCEEDED(hr))
188  hr = pIDOTmp->QueryGetData(pFormatetc);
189  }
190  return hr;
191 }
192 
193 // IDataObject->GetDataHere
194 
195 STDMETHODIMP CAPNDataObject::GetDataHere( FORMATETC * pFormatetc, STGMEDIUM * pmedium )
196 {
197  HRESULT hr = m_rIDataObjectOrg->GetDataHere(pFormatetc, pmedium);
198 
199  if (RPC_E_WRONG_THREAD == hr)
200  {
201  IDataObjectPtr pIDOTmp;
203 
204  if (SUCCEEDED(hr))
205  hr = pIDOTmp->GetDataHere(pFormatetc, pmedium);
206  }
207  return hr;
208 }
209 
210 // IDataObject->GetCanonicalFormatEtc
211 
212 STDMETHODIMP CAPNDataObject::GetCanonicalFormatEtc(FORMATETC * pFormatectIn, FORMATETC * pFormatetcOut)
213 {
214  HRESULT hr = m_rIDataObjectOrg->GetCanonicalFormatEtc( pFormatectIn, pFormatetcOut );
215 
216  if (RPC_E_WRONG_THREAD == hr)
217  {
218  IDataObjectPtr pIDOTmp;
220 
221  if (SUCCEEDED(hr))
222  hr = pIDOTmp->GetCanonicalFormatEtc(pFormatectIn, pFormatetcOut);
223  }
224  return hr;
225 }
226 
227 // IDataObject->SetData
228 
229 STDMETHODIMP CAPNDataObject::SetData( FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease )
230 {
231  HRESULT hr = m_rIDataObjectOrg->SetData( pFormatetc, pmedium, fRelease );
232 
233  if (RPC_E_WRONG_THREAD == hr)
234  {
235  IDataObjectPtr pIDOTmp;
237 
238  if (SUCCEEDED(hr))
239  hr = pIDOTmp->SetData(pFormatetc, pmedium, fRelease);
240  }
241  return hr;
242 }
243 
244 // IDataObject->DAdvise
245 
246 STDMETHODIMP CAPNDataObject::DAdvise( FORMATETC * pFormatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD * pdwConnection )
247 {
248  HRESULT hr = m_rIDataObjectOrg->DAdvise(pFormatetc, advf, pAdvSink, pdwConnection);
249 
250  if (RPC_E_WRONG_THREAD == hr)
251  {
252  IDataObjectPtr pIDOTmp;
254 
255  if (SUCCEEDED(hr))
256  hr = pIDOTmp->DAdvise(pFormatetc, advf, pAdvSink, pdwConnection);
257  }
258  return hr;
259 }
260 
261 // IDataObject->DUnadvise
262 
263 STDMETHODIMP CAPNDataObject::DUnadvise( DWORD dwConnection )
264 {
265  HRESULT hr = m_rIDataObjectOrg->DUnadvise( dwConnection );
266 
267  if (RPC_E_WRONG_THREAD == hr)
268  {
269  IDataObjectPtr pIDOTmp;
271 
272  if (SUCCEEDED(hr))
273  hr = pIDOTmp->DUnadvise(dwConnection);
274  }
275  return hr;
276 }
277 
278 // IDataObject->EnumDAdvise
279 
280 STDMETHODIMP CAPNDataObject::EnumDAdvise( IEnumSTATDATA ** ppenumAdvise )
281 {
282  HRESULT hr = m_rIDataObjectOrg->EnumDAdvise(ppenumAdvise);
283 
284  if (RPC_E_WRONG_THREAD == hr)
285  {
286  IDataObjectPtr pIDOTmp;
288 
289  if (SUCCEEDED(hr))
290  hr = pIDOTmp->EnumDAdvise(ppenumAdvise);
291  }
292  return hr;
293 }
294 
295 // for our convenience
296 
297 CAPNDataObject::operator IDataObject*( )
298 {
299  return static_cast< IDataObject* >( this );
300 }
301 
302 // helper function
303 
305 {
306  OSL_ASSERT(nullptr != ppIDataObj);
307 
308  *ppIDataObj = nullptr;
309  HRESULT hr = E_FAIL;
310 
311  if (m_hGlobal)
312  {
313  IStreamPtr pStm;
314  hr = CreateStreamOnHGlobal(m_hGlobal, KEEP_HGLOB_ON_RELEASE, &pStm);
315 
316  OSL_ENSURE(E_INVALIDARG != hr, "CreateStreamOnHGlobal with invalid args called");
317 
318  if (SUCCEEDED(hr))
319  {
320  hr = CoUnmarshalInterface(pStm.get(), __uuidof(IDataObject), reinterpret_cast<void**>(ppIDataObj));
321  OSL_ENSURE(CO_E_NOTINITIALIZED != hr, "COM is not initialized");
322  }
323  }
324  return hr;
325 }
326 
327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
STDMETHODIMP SetData(LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium, BOOL fRelease)
CAPNDataObject(IDataObjectPtr rIDataObject)
#define KEEP_HGLOB_ON_RELEASE
EXTERN_C BOOL BOOL const wchar_t *pProgramPath HRESULT hr
STDMETHODIMP GetData(LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium)
#define FREE_HGLOB_ON_RELEASE
STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObject)
STDMETHODIMP DAdvise(LPFORMATETC pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD *pdwConnection)
const wchar_t *typedef BOOL
IDataObjectPtr m_rIDataObjectOrg
STDMETHODIMP DUnadvise(DWORD dwConnection)
STDMETHODIMP GetCanonicalFormatEtc(LPFORMATETC pFormatectIn, LPFORMATETC pFormatetcOut)
STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatetc)
STDMETHODIMP EnumDAdvise(LPENUMSTATDATA *ppenumAdvise)
STDMETHODIMP QueryGetData(LPFORMATETC pFormatetc)
STDMETHODIMP GetDataHere(LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium)
HRESULT MarshalIDataObjectIntoCurrentApartment(IDataObject **ppIDataObj)
STDMETHODIMP_(ULONG) CAPNDataObject