blob: 6d1150e6a7e53172ef7bf75f6b0325ee9443e60b [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dtrans.hxx"
//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------
#include "APNDataObject.hxx"
#include <osl/diagnose.h>
#include <systools/win32/comtools.hxx>
#ifdef __MINGW32__
#define __uuidof(I) IID_##I
#endif
//------------------------------------------------------------------------
// defines
//------------------------------------------------------------------------
#define FREE_HGLOB_ON_RELEASE TRUE
#define KEEP_HGLOB_ON_RELEASE FALSE
//------------------------------------------------------------------------
// ctor
//------------------------------------------------------------------------
CAPNDataObject::CAPNDataObject( IDataObjectPtr rIDataObject ) :
m_rIDataObjectOrg( rIDataObject ),
m_hGlobal( NULL ),
m_nRefCnt( 0 )
{
OSL_ENSURE( m_rIDataObjectOrg.get( ), "constructing CAPNDataObject with empty data object" );
// we marshal the IDataObject interface pointer here so
// that it can be unmarshaled multiple times when this
// class will be used from another apartment
IStreamPtr pStm;
HRESULT hr = CreateStreamOnHGlobal( 0, KEEP_HGLOB_ON_RELEASE, &pStm );
OSL_ENSURE( E_INVALIDARG != hr, "invalid args passed to CreateStreamOnHGlobal" );
if ( SUCCEEDED( hr ) )
{
HRESULT hr_marshal = CoMarshalInterface(
pStm.get(),
__uuidof(IDataObject),
static_cast<LPUNKNOWN>(m_rIDataObjectOrg.get()),
MSHCTX_LOCAL,
NULL,
MSHLFLAGS_TABLEWEAK );
OSL_ENSURE( CO_E_NOTINITIALIZED != hr_marshal, "COM is not initialized" );
// marshalling may fail if COM is not initialized
// for the calling thread which is a program time
// error or because of stream errors which are runtime
// errors for instance E_OUTOFMEMORY etc.
hr = GetHGlobalFromStream(pStm.get(), &m_hGlobal );
OSL_ENSURE( E_INVALIDARG != hr, "invalid stream passed to GetHGlobalFromStream" );
// if the marshalling failed we free the
// global memory again and set m_hGlobal
// to a defined value
if (FAILED(hr_marshal))
{
OSL_ENSURE(sal_False, "marshalling failed");
#if OSL_DEBUG_LEVEL > 0
HGLOBAL hGlobal =
#endif
GlobalFree(m_hGlobal);
OSL_ENSURE(NULL == hGlobal, "GlobalFree failed");
m_hGlobal = NULL;
}
}
}
CAPNDataObject::~CAPNDataObject( )
{
if (m_hGlobal)
{
IStreamPtr pStm;
HRESULT hr = CreateStreamOnHGlobal(m_hGlobal, FREE_HGLOB_ON_RELEASE, &pStm);
OSL_ENSURE( E_INVALIDARG != hr, "invalid args passed to CreateStreamOnHGlobal" );
if (SUCCEEDED(hr))
{
hr = CoReleaseMarshalData(pStm.get());
OSL_ENSURE(SUCCEEDED(hr), "CoReleaseMarshalData failed");
}
}
}
//------------------------------------------------------------------------
// IUnknown->QueryInterface
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::QueryInterface( REFIID iid, LPVOID* ppvObject )
{
OSL_ASSERT( NULL != ppvObject );
if ( NULL == ppvObject )
return E_INVALIDARG;
HRESULT hr = E_NOINTERFACE;
*ppvObject = NULL;
if ( ( __uuidof( IUnknown ) == iid ) || ( __uuidof( IDataObject ) == iid ) )
{
*ppvObject = static_cast< IUnknown* >( this );
( (LPUNKNOWN)*ppvObject )->AddRef( );
hr = S_OK;
}
return hr;
}
//------------------------------------------------------------------------
// IUnknown->AddRef
//------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAPNDataObject::AddRef( )
{
return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) );
}
//------------------------------------------------------------------------
// IUnknown->Release
//------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAPNDataObject::Release( )
{
// we need a helper variable because it's not allowed to access
// a member variable after an object is destroyed
ULONG nRefCnt = static_cast< ULONG >( InterlockedDecrement( &m_nRefCnt ) );
if ( 0 == nRefCnt )
delete this;
return nRefCnt;
}
//------------------------------------------------------------------------
// IDataObject->GetData
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::GetData( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium )
{
HRESULT hr = m_rIDataObjectOrg->GetData( pFormatetc, pmedium );
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
if (SUCCEEDED(hr))
hr = pIDOTmp->GetData(pFormatetc, pmedium);
}
return hr;
}
//------------------------------------------------------------------------
// IDataObject->EnumFormatEtc
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc )
{
HRESULT hr = m_rIDataObjectOrg->EnumFormatEtc(dwDirection, ppenumFormatetc);
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
if (SUCCEEDED(hr))
hr = pIDOTmp->EnumFormatEtc(dwDirection, ppenumFormatetc);
}
return hr;
}
//------------------------------------------------------------------------
// IDataObject->QueryGetData
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::QueryGetData( LPFORMATETC pFormatetc )
{
HRESULT hr = m_rIDataObjectOrg->QueryGetData( pFormatetc );
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment( &pIDOTmp );
if (SUCCEEDED(hr))
hr = pIDOTmp->QueryGetData(pFormatetc);
}
return hr;
}
//------------------------------------------------------------------------
// IDataObject->GetDataHere
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::GetDataHere( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium )
{
HRESULT hr = m_rIDataObjectOrg->GetDataHere(pFormatetc, pmedium);
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
if (SUCCEEDED(hr))
hr = pIDOTmp->GetDataHere(pFormatetc, pmedium);
}
return hr;
}
//------------------------------------------------------------------------
// IDataObject->GetCanonicalFormatEtc
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::GetCanonicalFormatEtc(LPFORMATETC pFormatectIn, LPFORMATETC pFormatetcOut)
{
HRESULT hr = m_rIDataObjectOrg->GetCanonicalFormatEtc( pFormatectIn, pFormatetcOut );
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
if (SUCCEEDED(hr))
hr = pIDOTmp->GetCanonicalFormatEtc(pFormatectIn, pFormatetcOut);
}
return hr;
}
//------------------------------------------------------------------------
// IDataObject->SetData
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::SetData( LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium, BOOL fRelease )
{
HRESULT hr = m_rIDataObjectOrg->SetData( pFormatetc, pmedium, fRelease );
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
if (SUCCEEDED(hr))
hr = pIDOTmp->SetData(pFormatetc, pmedium, fRelease);
}
return hr;
}
//------------------------------------------------------------------------
// IDataObject->DAdvise
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::DAdvise( LPFORMATETC pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection )
{
HRESULT hr = m_rIDataObjectOrg->DAdvise(pFormatetc, advf, pAdvSink, pdwConnection);
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
if (SUCCEEDED(hr))
hr = pIDOTmp->DAdvise(pFormatetc, advf, pAdvSink, pdwConnection);
}
return hr;
}
//------------------------------------------------------------------------
// IDataObject->DUnadvise
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::DUnadvise( DWORD dwConnection )
{
HRESULT hr = m_rIDataObjectOrg->DUnadvise( dwConnection );
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
if (SUCCEEDED(hr))
hr = pIDOTmp->DUnadvise(dwConnection);
}
return hr;
}
//------------------------------------------------------------------------
// IDataObject->EnumDAdvise
//------------------------------------------------------------------------
STDMETHODIMP CAPNDataObject::EnumDAdvise( LPENUMSTATDATA * ppenumAdvise )
{
HRESULT hr = m_rIDataObjectOrg->EnumDAdvise(ppenumAdvise);
if (RPC_E_WRONG_THREAD == hr)
{
IDataObjectPtr pIDOTmp;
hr = MarshalIDataObjectIntoCurrentApartment(&pIDOTmp);
if (SUCCEEDED(hr))
hr = pIDOTmp->EnumDAdvise(ppenumAdvise);
}
return hr;
}
//------------------------------------------------------------------------
// for our convenience
//------------------------------------------------------------------------
CAPNDataObject::operator IDataObject*( )
{
return static_cast< IDataObject* >( this );
}
//------------------------------------------------------------------------
// helper function
//------------------------------------------------------------------------
HRESULT CAPNDataObject::MarshalIDataObjectIntoCurrentApartment( IDataObject** ppIDataObj )
{
OSL_ASSERT(NULL != ppIDataObj);
*ppIDataObj = NULL;
HRESULT hr = E_FAIL;
if (m_hGlobal)
{
IStreamPtr pStm;
hr = CreateStreamOnHGlobal(m_hGlobal, KEEP_HGLOB_ON_RELEASE, &pStm);
OSL_ENSURE(E_INVALIDARG != hr, "CreateStreamOnHGlobal with invalid args called");
if (SUCCEEDED(hr))
{
hr = CoUnmarshalInterface(pStm.get(), __uuidof(IDataObject), (void**)ppIDataObj);
OSL_ENSURE(CO_E_NOTINITIALIZED != hr, "COM is not initialized");
}
}
return hr;
}