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