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