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