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