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