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 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 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 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 148 STDMETHODIMP_(ULONG) CAPNDataObject::AddRef( ) 149 { 150 return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) ); 151 } 152 153 //------------------------------------------------------------------------ 154 // IUnknown->Release 155 //------------------------------------------------------------------------ 156 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 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 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 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 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 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 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 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 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 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 344 CAPNDataObject::operator IDataObject*( ) 345 { 346 return static_cast< IDataObject* >( this ); 347 } 348 349 //------------------------------------------------------------------------ 350 // helper function 351 //------------------------------------------------------------------------ 352 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