diff options
Diffstat (limited to 'embeddedobj/source/msole/olecomponent.cxx')
-rw-r--r-- | embeddedobj/source/msole/olecomponent.cxx | 861 |
1 files changed, 426 insertions, 435 deletions
diff --git a/embeddedobj/source/msole/olecomponent.cxx b/embeddedobj/source/msole/olecomponent.cxx index da5b02874b07..b9c1c27827bb 100644 --- a/embeddedobj/source/msole/olecomponent.cxx +++ b/embeddedobj/source/msole/olecomponent.cxx @@ -24,6 +24,7 @@ #include <com/sun/star/lang/DisposedException.hpp> #include <com/sun/star/embed/WrongStateException.hpp> #include <com/sun/star/embed/UnreachableStateException.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> #include <com/sun/star/ucb/XSimpleFileAccess.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/io/TempFile.hpp> @@ -32,12 +33,17 @@ #include <com/sun/star/awt/XRequestCallback.hpp> #include "platform.h" -#include <cppuhelper/interfacecontainer.h> +#include <comphelper/multicontainer2.hxx> #include <comphelper/mimeconfighelper.hxx> #include <comphelper/processfactory.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/windowserrorstring.hxx> #include <osl/file.hxx> #include <rtl/ref.hxx> #include <o3tl/char16_t2wchar_t.hxx> +#include <o3tl/unit_conversion.hxx> +#include <systools/win32/comtools.hxx> +#include <vcl/svapp.hxx> #include <vcl/threadex.hxx> #include "graphconvert.hxx" @@ -55,168 +61,118 @@ using namespace ::comphelper; #define MAX_ENUM_ELE 20 #define FORMATS_NUM 3 -// ============ class ComSmart ===================== -namespace { - -template< class T > class ComSmart -{ - T* m_pInterface; - - void OwnRelease() - { - if ( m_pInterface ) - { - T* pInterface = m_pInterface; - m_pInterface = nullptr; - pInterface->Release(); - } - } - -public: - ComSmart() - : m_pInterface( nullptr ) - {} - - ComSmart( const ComSmart<T>& rObj ) - : m_pInterface( rObj.m_pInterface ) - { - if ( m_pInterface != NULL ) - m_pInterface->AddRef(); - } - - ComSmart( T* pInterface ) - : m_pInterface( pInterface ) - { - if ( m_pInterface != NULL ) - m_pInterface->AddRef(); - } - - ~ComSmart() - { - OwnRelease(); - } - - ComSmart& operator=( const ComSmart<T>& rObj ) - { - if(this == &rObj) - return *this; - - OwnRelease(); - - m_pInterface = rObj.m_pInterface; - - if ( m_pInterface != NULL ) - m_pInterface->AddRef(); - - return *this; - } - - ComSmart<T>& operator=( T* pInterface ) - { - OwnRelease(); - - m_pInterface = pInterface; - - if ( m_pInterface != NULL ) - m_pInterface->AddRef(); - - return *this; - } - - operator T*() const - { - return m_pInterface; - } - - T& operator*() const - { - return *m_pInterface; - } - - T** operator&() - { - OwnRelease(); - - m_pInterface = nullptr; - - return &m_pInterface; - } - - T* operator->() const - { - return m_pInterface; - } - - bool operator==( const ComSmart<T>& rObj ) const - { - return ( m_pInterface == rObj.m_pInterface ); - } - - bool operator!=( const ComSmart<T>& rObj ) const - { - return ( m_pInterface != rObj.m_pInterface ); - } - - bool operator==( const T* pInterface ) const - { - return ( m_pInterface == pInterface ); - } - - bool operator!=( const T* pInterface ) const - { - return ( m_pInterface != pInterface ); - } -}; - -} - -// ============ class ComSmart ===================== - -typedef std::vector< FORMATETC* > FormatEtcList; - FORMATETC const pFormatTemplates[FORMATS_NUM] = { { CF_ENHMETAFILE, nullptr, 0, -1, TYMED_ENHMF }, { CF_METAFILEPICT, nullptr, 0, -1, TYMED_MFPICT }, { CF_BITMAP, nullptr, 0, -1, TYMED_GDI } }; -struct OleComponentNative_Impl { - ComSmart< IUnknown > m_pObj; - ComSmart< IOleObject > m_pOleObject; - ComSmart< IViewObject2 > m_pViewObject2; - ComSmart< IStorage > m_pIStorage; - FormatEtcList m_aFormatsList; +// We have at least one single-threaded apartment (STA) in the process (the VCL Main thread, which +// is the GUI thread), and a multithreaded apartment (MTA) for most of other threads. OLE objects +// may be created in either: in interactive mode, this typically happens in the STA; when serving +// external requests, this may be either in STA (when explicit "OnMainThread" argument is passed to +// loadComponentFromURL, and the instantiation of the object happens during the load), or in MTA +// (the thread actually serving the incoming calls). +// +// The objects typically can only be used in the apartment where they were instantiated. This means +// that e.g. a call to IOleObject::Close will fail, if it is performed in a different thread, when +// it was started in the main thread. And vice versa, opening a document in a handler thread, then +// trying to interact with the OLE object in GUI would fail. +// +// To handle this, several workarounds were implemented in the past; the mentioned "OnMainThread" +// argument is one of these, allowing open document requests be processed not in the handler threads +// that received the request, but in the main thread which will then be used for interaction. Also +// OleComponent::GetExtent was changed to check if the first call to IDataObject::GetData failed +// with RPC_E_WRONG_THREAD, and then retry in the main thread. +// +// But ultimately every call to the OLE object needs such checks. E.g., failing to close the object +// keeps the server running, effectively leaking resources, until it crashes/freezes after multiple +// iterations. +// +// Currently, OleComponentNative_Impl is implemented using IGlobalInterfaceTable, which allows to +// register an object in process-global instance of the table from the thread that instantiated the +// object, and obtain a "cookie" (a number); and then use that cookie from any thread to access that +// object. The global table will do its magic to provide either the original object (when it is +// requested from the same apartment as used for its registration), or a "proxy", which will marshal +// all calls to the proper thread, transparently for the caller. This implementation should obsolete +// the previous workarounds (in theory). +// +// m_pGlobalTable is the reference to the global table. +// The storage object gets registered in the global table immediately when it's created. +// But the OLE object itself can't be registered immediately, before it is run: an attempt to call +// RegisterInterfaceInGlobal with such a newly created OLE object fails with CO_E_OBJNOTCONNECTED. +// Thus, the initial reference to the OLE object (which at this stage seems to be apartment-neutral) +// is stored to m_pObj. Only when it is run, it is registered in the global table. +// +// Indeed, the implicit change of the thread is a blocking operation, which opens a wonderful new +// opportunities for shiny deadlocks. Thus, precautions are needed to avoid them. +// +// When the OLE object is accessed by m_pObj (should be only in initialization code!), no measures +// are taken to change locking. But when it is accessed by getObj() - which may return the proxy - +// the calls are guarded by a SolarMutexReleaser, to allow the other thread do its job. +// +// There are at least two other mutexes in play here. One is in OleEmbeddedObject, that holds the +// OleComponent. The calls to OleComponent's methods are also wrapped there into unlock/lock pairs +// (see OleEmbeddedObject::changeState). The other is in OleComponent itself. For now, I see no +// deadlocks caused by that mutex, so no unlock/lock is introduced for that. It may turn out to be +// required eventually. +class OleComponentNative_Impl +{ +public: + sal::systools::COMReference< IUnknown > m_pObj; uno::Sequence< datatransfer::DataFlavor > m_aSupportedGraphFormats; + // The getters may return a proxy, that redirects the calls to another thread. + // Thus, calls to methods of returned objects must be inside solar mutex releaser. + auto getStorage() const { return getInterface<IStorage>(m_nStorage); } + auto getObj() const { return m_nOleObject ? getInterface<IUnknown>(m_nOleObject) : m_pObj; } + template <typename T> + auto get() const { return getObj().QueryInterface<T>(sal::systools::COM_QUERY); } + + void registerStorage(IStorage* pStorage) { registerInterface(pStorage, m_nStorage); } + void registerObj() { registerInterface(m_pObj.get(), m_nOleObject); } + + bool IsStorageRegistered() const { return m_nStorage != 0; } + OleComponentNative_Impl() + : m_pGlobalTable(CLSID_StdGlobalInterfaceTable, nullptr, CLSCTX_INPROC_SERVER) { // TODO: Extend format list - m_aSupportedGraphFormats.realloc( 5 ); + m_aSupportedGraphFormats = { - m_aSupportedGraphFormats[0] = datatransfer::DataFlavor( + datatransfer::DataFlavor( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"", "Windows Enhanced Metafile", - cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); + cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ), - m_aSupportedGraphFormats[1] = datatransfer::DataFlavor( + datatransfer::DataFlavor( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"", "Windows Metafile", - cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); + cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ), - m_aSupportedGraphFormats[2] = datatransfer::DataFlavor( + datatransfer::DataFlavor( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"", "Bitmap", - cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); + cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ), - m_aSupportedGraphFormats[3] = datatransfer::DataFlavor( + datatransfer::DataFlavor( "image/png", "PNG", - cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); + cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ), - m_aSupportedGraphFormats[0] = datatransfer::DataFlavor( + datatransfer::DataFlavor( "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"", "GDIMetafile", - cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); + cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) + }; + } + + ~OleComponentNative_Impl() + { + if (m_nOleObject) + m_pGlobalTable->RevokeInterfaceFromGlobal(m_nOleObject); + if (m_nStorage) + m_pGlobalTable->RevokeInterfaceFromGlobal(m_nStorage); } bool ConvertDataForFlavor( const STGMEDIUM& aMedium, @@ -226,8 +182,31 @@ struct OleComponentNative_Impl { bool GraphicalFlavor( const datatransfer::DataFlavor& aFlavor ); uno::Sequence< datatransfer::DataFlavor > GetFlavorsForAspects( sal_uInt32 nSupportedAspects ); -}; + sal::systools::COMReference<IStorage> CreateNewStorage(const OUString& url); + +private: + sal::systools::COMReference<IGlobalInterfaceTable> m_pGlobalTable; + DWORD m_nStorage = 0; + DWORD m_nOleObject = 0; + + template <typename T> sal::systools::COMReference<T> getInterface(DWORD cookie) const + { + sal::systools::COMReference<T> result; + HRESULT hr = m_pGlobalTable->GetInterfaceFromGlobal(cookie, IID_PPV_ARGS(&result)); + SAL_WARN_IF(FAILED(hr), "embeddedobj.ole", + "GetInterfaceFromGlobal failed: is cookie " << cookie << " not registered?"); + return result; + } + + template <typename T> void registerInterface(T* pInterface, DWORD& cookie) + { + if (cookie != 0) // E.g., on subsequent RunObject calls + return; + HRESULT hr = m_pGlobalTable->RegisterInterfaceInGlobal(pInterface, __uuidof(T), &cookie); + SAL_WARN_IF(FAILED(hr), "embeddedobj.ole", "RegisterInterfaceInGlobal failed"); + } +}; static DWORD GetAspectFromFlavor( const datatransfer::DataFlavor& aFlavor ) { @@ -259,23 +238,6 @@ static OUString GetFlavorSuffixFromAspect( DWORD nAsp ) } -static HRESULT OpenIStorageFromURL_Impl( const OUString& aURL, IStorage** ppIStorage ) -{ - OSL_ENSURE( ppIStorage, "The pointer must not be empty!" ); - - OUString aFilePath; - if ( !ppIStorage || ::osl::FileBase::getSystemPathFromFileURL( aURL, aFilePath ) != ::osl::FileBase::E_None ) - throw uno::RuntimeException(); // TODO: something dangerous happened - - return StgOpenStorage( o3tl::toW(aFilePath.getStr()), - nullptr, - STGM_READWRITE | STGM_TRANSACTED, // | STGM_DELETEONRELEASE, - nullptr, - 0, - ppIStorage ); -} - - bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM& aMedium, const datatransfer::DataFlavor& aFlavor, uno::Any& aResult ) @@ -312,7 +274,7 @@ bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM& aMedium, if ( nBufSize && nBufSize == GetMetaFileBitsEx( pMF->hMF, nBufSize - 22, pBuf.get() + 22 ) ) { - if ( aFlavor.MimeType.matchAsciiL( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"", 57 ) ) + if ( aFlavor.MimeType.match( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ) ) { aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize ); bAnyIsReady = true; @@ -329,7 +291,7 @@ bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM& aMedium, pBuf.reset(new sal_Int8[nBufSize]); if ( nBufSize && nBufSize == GetEnhMetaFileBits( aMedium.hEnhMetaFile, nBufSize, reinterpret_cast<LPBYTE>(pBuf.get()) ) ) { - if ( aFlavor.MimeType.matchAsciiL( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"", 57 ) ) + if ( aFlavor.MimeType.match( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ) ) { aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize ); bAnyIsReady = true; @@ -349,7 +311,7 @@ bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM& aMedium, pBuf.reset(new sal_Int8[nBufSize]); if ( nBufSize && nBufSize == sal::static_int_cast< ULONG >( GetBitmapBits( aMedium.hBitmap, nBufSize, pBuf.get() ) ) ) { - if ( aFlavor.MimeType.matchAsciiL( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"", 54 ) ) + if ( aFlavor.MimeType.match( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ) ) { aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize ); bAnyIsReady = true; @@ -359,14 +321,14 @@ bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM& aMedium, if ( pBuf && !bAnyIsReady ) { - for ( auto const & supportedFormat : std::as_const(m_aSupportedGraphFormats) ) - if ( aFlavor.MimeType.match( supportedFormat.MimeType ) + for (auto const& supportedFormat : m_aSupportedGraphFormats) + if ( aFlavor.MimeType.match( supportedFormat.MimeType ) && aFlavor.DataType == supportedFormat.DataType && aFlavor.DataType == cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) - { - bAnyIsReady = ConvertBufferToFormat( pBuf.get(), nBufSize, aFormat, aResult ); - break; - } + { + bAnyIsReady = ConvertBufferToFormat( pBuf.get(), nBufSize, aFormat, aResult ); + break; + } } } @@ -377,7 +339,7 @@ bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM& aMedium, bool OleComponentNative_Impl::GraphicalFlavor( const datatransfer::DataFlavor& aFlavor ) { // Actually all the required graphical formats must be supported - for ( auto const & supportedFormat : std::as_const(m_aSupportedGraphFormats) ) + for (auto const& supportedFormat : m_aSupportedGraphFormats) if ( aFlavor.MimeType.match( supportedFormat.MimeType ) && aFlavor.DataType == supportedFormat.DataType ) return true; @@ -432,12 +394,10 @@ OleComponent::OleComponent( const uno::Reference< uno::XComponentContext >& xCon : m_pInterfaceContainer( nullptr ) , m_bDisposed( false ) , m_bModified( false ) -, m_pNativeImpl( new OleComponentNative_Impl() ) +, m_pNativeImpl( std::make_unique<OleComponentNative_Impl>() ) , m_pUnoOleObject( pUnoOleObject ) , m_pOleWrapClientSite( nullptr ) , m_pImplAdviseSink( nullptr ) -, m_nOLEMiscFlags( 0 ) -, m_nAdvConn( 0 ) , m_xContext( xContext ) , m_bOleInitialized( false ) , m_bWorkaroundActive( false ) @@ -445,9 +405,14 @@ OleComponent::OleComponent( const uno::Reference< uno::XComponentContext >& xCon OSL_ENSURE( m_pUnoOleObject, "No owner object is provided!" ); HRESULT hr = OleInitialize( nullptr ); - OSL_ENSURE( hr == S_OK || hr == S_FALSE, "The ole can not be successfully initialized" ); if ( hr == S_OK || hr == S_FALSE ) m_bOleInitialized = true; + else + { + SAL_WARN("embeddedobj.ole", "OleComponent ctor: OleInitialize() failed with 0x" + << OUString::number(static_cast<sal_uInt32>(hr), 16) << ": " + << WindowsErrorStringFromHRESULT(hr)); + } m_pOleWrapClientSite = new OleWrapperClientSite( this ); m_pOleWrapClientSite->AddRef(); @@ -470,14 +435,6 @@ OleComponent::~OleComponent() Dispose(); } catch( const uno::Exception& ) {} } - - for (auto const& format : m_pNativeImpl->m_aFormatsList) - { - delete format; - } - m_pNativeImpl->m_aFormatsList.clear(); - - delete m_pNativeImpl; } void OleComponent::Dispose() @@ -535,30 +492,37 @@ void OleComponent::disconnectEmbeddedObject() } -void OleComponent::CreateNewIStorage_Impl() +OUString OleComponent::getTempURL() const { - // TODO: in future a global memory could be used instead of file. - - // write the stream to the temporary file - OUString aTempURL; - OSL_ENSURE( m_pUnoOleObject, "Unexpected object absence!" ); if ( m_pUnoOleObject ) - aTempURL = m_pUnoOleObject->CreateTempURLEmpty_Impl(); + return m_pUnoOleObject->CreateTempURLEmpty_Impl(); else - aTempURL = GetNewTempFileURL_Impl( m_xContext ); + return GetNewTempFileURL_Impl(m_xContext); +} - if ( !aTempURL.getLength() ) + +sal::systools::COMReference<IStorage> OleComponentNative_Impl::CreateNewStorage(const OUString& url) +{ + if (IsStorageRegistered()) + throw io::IOException(); // TODO:the object is already initialized + // TODO: in future a global memory could be used instead of file. + + // write the stream to the temporary file + if (url.isEmpty()) throw uno::RuntimeException(); // TODO // open an IStorage based on the temporary file OUString aTempFilePath; - if ( ::osl::FileBase::getSystemPathFromFileURL( aTempURL, aTempFilePath ) != ::osl::FileBase::E_None ) + if (osl::FileBase::getSystemPathFromFileURL(url, aTempFilePath) != osl::FileBase::E_None) throw uno::RuntimeException(); // TODO: something dangerous happened - HRESULT hr = StgCreateDocfile( o3tl::toW(aTempFilePath.getStr()), STGM_CREATE | STGM_READWRITE | STGM_TRANSACTED | STGM_DELETEONRELEASE, 0, &m_pNativeImpl->m_pIStorage ); - if ( FAILED( hr ) || !m_pNativeImpl->m_pIStorage ) + sal::systools::COMReference<IStorage> pStorage; + HRESULT hr = StgCreateDocfile( o3tl::toW(aTempFilePath.getStr()), STGM_CREATE | STGM_READWRITE | STGM_TRANSACTED | STGM_DELETEONRELEASE, 0, &pStorage ); + if (FAILED(hr) || !pStorage) throw io::IOException(); // TODO: transport error code? + registerStorage(pStorage); + return pStorage; } @@ -572,12 +536,13 @@ uno::Sequence< datatransfer::DataFlavor > OleComponentNative_Impl::GetFlavorsFor sal_Int32 nLength = aResult.getLength(); aResult.realloc( nLength + m_aSupportedGraphFormats.getLength() ); + auto pResult = aResult.getArray(); for ( sal_Int32 nInd = 0; nInd < m_aSupportedGraphFormats.getLength(); nInd++ ) { - aResult[nLength + nInd].MimeType = m_aSupportedGraphFormats[nInd].MimeType + aAspectSuffix; - aResult[nLength + nInd].HumanPresentableName = m_aSupportedGraphFormats[nInd].HumanPresentableName; - aResult[nLength + nInd].DataType = m_aSupportedGraphFormats[nInd].DataType; + pResult[nLength + nInd].MimeType = m_aSupportedGraphFormats[nInd].MimeType + aAspectSuffix; + pResult[nLength + nInd].HumanPresentableName = m_aSupportedGraphFormats[nInd].HumanPresentableName; + pResult[nLength + nInd].DataType = m_aSupportedGraphFormats[nInd].DataType; } } @@ -587,17 +552,19 @@ uno::Sequence< datatransfer::DataFlavor > OleComponentNative_Impl::GetFlavorsFor void OleComponent::RetrieveObjectDataFlavors_Impl() { - if ( !m_pNativeImpl->m_pOleObject ) + if (!m_pNativeImpl->m_pObj) throw embed::WrongStateException(); // TODO: the object is in wrong state if ( !m_aDataFlavors.getLength() ) { - ComSmart< IDataObject > pDataObject; - HRESULT hr = m_pNativeImpl->m_pObj->QueryInterface( IID_IDataObject, reinterpret_cast<void**>(&pDataObject) ); - if ( SUCCEEDED( hr ) && pDataObject ) + if (auto pDataObject = m_pNativeImpl->get<IDataObject>()) { - ComSmart< IEnumFORMATETC > pFormatEnum; - hr = pDataObject->EnumFormatEtc( DATADIR_GET, &pFormatEnum ); + HRESULT hr; + sal::systools::COMReference< IEnumFORMATETC > pFormatEnum; + { + SolarMutexReleaser releaser; + hr = pDataObject->EnumFormatEtc(DATADIR_GET, &pFormatEnum); + } if ( SUCCEEDED( hr ) && pFormatEnum ) { FORMATETC pElem[ MAX_ENUM_ELE ]; @@ -612,7 +579,7 @@ void OleComponent::RetrieveObjectDataFlavors_Impl() if( hr2 == S_OK || hr2 == S_FALSE ) { for( sal_uInt32 nInd = 0; nInd < FORMATS_NUM; nInd++ ) - { + { if ( pElem[nInd].cfFormat == pFormatTemplates[nInd].cfFormat && pElem[nInd].tymed == pFormatTemplates[nInd].tymed ) nSupportedAspects |= pElem[nInd].dwAspect; @@ -637,27 +604,23 @@ void OleComponent::RetrieveObjectDataFlavors_Impl() } -bool OleComponent::InitializeObject_Impl() +void OleComponent::InitializeObject_Impl() // There will be no static objects! { if ( !m_pNativeImpl->m_pObj ) - return false; + throw embed::WrongStateException(); // the linked object will be detected here - ComSmart< IOleLink > pOleLink; - HRESULT hr = m_pNativeImpl->m_pObj->QueryInterface( IID_IOleLink, reinterpret_cast<void**>(&pOleLink) ); OSL_ENSURE( m_pUnoOleObject, "Unexpected object absence!" ); if ( m_pUnoOleObject ) - m_pUnoOleObject->SetObjectIsLink_Impl( pOleLink != nullptr ); - + m_pUnoOleObject->SetObjectIsLink_Impl( m_pNativeImpl->m_pObj.QueryInterface<IOleLink>(sal::systools::COM_QUERY).is() ); - hr = m_pNativeImpl->m_pObj->QueryInterface( IID_IViewObject2, reinterpret_cast<void**>(&m_pNativeImpl->m_pViewObject2) ); - if ( FAILED( hr ) || !m_pNativeImpl->m_pViewObject2 ) - return false; + auto pViewObject2(m_pNativeImpl->m_pObj.QueryInterface<IViewObject2>(sal::systools::COM_QUERY)); + if (!pViewObject2) + throw uno::RuntimeException(); // TODO // remove all the caches - IOleCache* pIOleCache = nullptr; - if ( SUCCEEDED( m_pNativeImpl->m_pObj->QueryInterface( IID_IOleCache, reinterpret_cast<void**>(&pIOleCache) ) ) && pIOleCache ) + if ( sal::systools::COMReference< IOleCache > pIOleCache{ m_pNativeImpl->m_pObj, sal::systools::COM_QUERY } ) { IEnumSTATDATA* pEnumSD = nullptr; HRESULT hr2 = pIOleCache->EnumCache( &pEnumSD ); @@ -675,41 +638,51 @@ bool OleComponent::InitializeObject_Impl() DWORD nConn; FORMATETC aFormat = { 0, nullptr, DVASPECT_CONTENT, -1, TYMED_MFPICT }; hr2 = pIOleCache->Cache( &aFormat, ADVFCACHE_ONSAVE, &nConn ); - - pIOleCache->Release(); - pIOleCache = nullptr; } - hr = m_pNativeImpl->m_pObj->QueryInterface( IID_IOleObject, reinterpret_cast<void**>(&m_pNativeImpl->m_pOleObject) ); - if ( FAILED( hr ) || !m_pNativeImpl->m_pOleObject ) - return false; // Static objects are not supported, they should be inserted as graphics + auto pOleObject(m_pNativeImpl->m_pObj.QueryInterface<IOleObject>(sal::systools::COM_QUERY)); + if (!pOleObject) + throw uno::RuntimeException(); // Static objects are not supported, they should be inserted as graphics - m_pNativeImpl->m_pOleObject->GetMiscStatus( DVASPECT_CONTENT, reinterpret_cast<DWORD*>(&m_nOLEMiscFlags) ); + DWORD nOLEMiscFlags(0); + pOleObject->GetMiscStatus(DVASPECT_CONTENT, reinterpret_cast<DWORD*>(&nOLEMiscFlags)); // TODO: use other misc flags also // the object should have drawable aspect even in case it supports only iconic representation - // if ( m_nOLEMiscFlags & OLEMISC_ONLYICONIC ) + // if ( nOLEMiscFlags & OLEMISC_ONLYICONIC ) - m_pNativeImpl->m_pOleObject->SetClientSite( m_pOleWrapClientSite ); + pOleObject->SetClientSite(m_pOleWrapClientSite); // the only need in this registration is workaround for close notification - m_pNativeImpl->m_pOleObject->Advise( m_pImplAdviseSink, reinterpret_cast<DWORD*>(&m_nAdvConn) ); - m_pNativeImpl->m_pViewObject2->SetAdvise( DVASPECT_CONTENT, 0, m_pImplAdviseSink ); - - OleSetContainedObject( m_pNativeImpl->m_pOleObject, TRUE ); + DWORD nAdvConn(0); + pOleObject->Advise(m_pImplAdviseSink, reinterpret_cast<DWORD*>(&nAdvConn)); + pViewObject2->SetAdvise(DVASPECT_CONTENT, 0, m_pImplAdviseSink); - return true; + OleSetContainedObject(pOleObject, TRUE); } namespace { - HRESULT OleLoadSeh(LPSTORAGE pIStorage, LPVOID* ppObj) + HRESULT OleLoadSeh(LPSTORAGE pIStorage, IUnknown** ppObj) { HRESULT hr = E_FAIL; + // tdf#119039: there is a nasty bug in OleLoad, that may call an unpaired + // IUnknown::Release on pIStorage on STG_E_FILENOTFOUND: see + // https://developercommunity.visualstudio.com/t/10144795 + // Workaround it here to avoid crash in smart COM pointer destructor that + // would try to release already released object. Since we don't know if + // the bug appears each time STG_E_FILENOTFOUND is returned, this might + // potentially leak the storage object. + if (pIStorage) + pIStorage->AddRef(); + __try { - hr = OleLoad(pIStorage, IID_IUnknown, nullptr, ppObj); + hr = OleLoad(pIStorage, IID_IUnknown, nullptr, IID_PPV_ARGS_Helper(ppObj)); } __except( EXCEPTION_EXECUTE_HANDLER ) { - return E_FAIL; + hr = E_FAIL; } + if (pIStorage && hr != STG_E_FILENOTFOUND) + pIStorage->Release(); + return hr; } } @@ -719,62 +692,62 @@ void OleComponent::LoadEmbeddedObject( const OUString& aTempURL ) if ( !aTempURL.getLength() ) throw lang::IllegalArgumentException(); // TODO - if ( m_pNativeImpl->m_pIStorage ) + if (m_pNativeImpl->IsStorageRegistered()) throw io::IOException(); // TODO the object is already initialized or wrong initialization is done // open an IStorage based on the temporary file - HRESULT hr = OpenIStorageFromURL_Impl( aTempURL, &m_pNativeImpl->m_pIStorage ); + OUString aFilePath; + if (osl::FileBase::getSystemPathFromFileURL(aTempURL, aFilePath) != ::osl::FileBase::E_None) + throw uno::RuntimeException(); // TODO: something dangerous happened - if ( FAILED( hr ) || !m_pNativeImpl->m_pIStorage ) + sal::systools::COMReference<IStorage> pStorage; + HRESULT hr = StgOpenStorage(o3tl::toW(aFilePath.getStr()), nullptr, + STGM_READWRITE | STGM_TRANSACTED, // | STGM_DELETEONRELEASE, + nullptr, 0, &pStorage); + if (FAILED(hr) || !pStorage) throw io::IOException(); // TODO: transport error code? - hr = OleLoadSeh(m_pNativeImpl->m_pIStorage, reinterpret_cast<void**>(&m_pNativeImpl->m_pObj)); - if ( FAILED( hr ) || !m_pNativeImpl->m_pObj ) - { + m_pNativeImpl->registerStorage(pStorage); + + hr = OleLoadSeh(pStorage, &m_pNativeImpl->m_pObj); + if (FAILED(hr)) throw uno::RuntimeException(); - } - if ( !InitializeObject_Impl() ) - throw uno::RuntimeException(); // TODO + InitializeObject_Impl(); } void OleComponent::CreateObjectFromClipboard() { - if ( m_pNativeImpl->m_pIStorage ) - throw io::IOException(); // TODO:the object is already initialized - - CreateNewIStorage_Impl(); - if ( !m_pNativeImpl->m_pIStorage ) + auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL())); + if (!pStorage) throw uno::RuntimeException(); // TODO IDataObject * pDO = nullptr; HRESULT hr = OleGetClipboard( &pDO ); - if( SUCCEEDED( hr ) && pDO ) + if (FAILED(hr)) + throw uno::RuntimeException(); + + hr = OleQueryCreateFromData(pDO); + if (S_OK == hr) { - hr = OleQueryCreateFromData( pDO ); - if( S_OK == GetScode( hr ) ) - { - hr = OleCreateFromData( pDO, - IID_IUnknown, - OLERENDER_DRAW, // OLERENDER_FORMAT - nullptr, // &aFormat, - nullptr, - m_pNativeImpl->m_pIStorage, - reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) ); - } - else - { - // Static objects are not supported - pDO->Release(); - } + hr = OleCreateFromData( pDO, + IID_IUnknown, + OLERENDER_DRAW, // OLERENDER_FORMAT + nullptr, // &aFormat, + nullptr, + pStorage, + IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) ); + if (FAILED(hr)) + throw uno::RuntimeException(); + } + else + { + // Static objects are not supported + pDO->Release(); } - if ( FAILED( hr ) || !m_pNativeImpl->m_pObj ) - throw uno::RuntimeException(); - - if ( !InitializeObject_Impl() ) - throw uno::RuntimeException(); // TODO + InitializeObject_Impl(); } @@ -785,11 +758,8 @@ void OleComponent::CreateNewEmbeddedObject( const uno::Sequence< sal_Int8 >& aSe if ( !GetClassIDFromSequence_Impl( aSeqCLSID, aClsID ) ) throw lang::IllegalArgumentException(); // TODO - if ( m_pNativeImpl->m_pIStorage ) - throw io::IOException(); // TODO:the object is already initialized - - CreateNewIStorage_Impl(); - if ( !m_pNativeImpl->m_pIStorage ) + auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL())); + if (!pStorage) throw uno::RuntimeException(); // TODO // FORMATETC aFormat = { CF_METAFILEPICT, NULL, nAspect, -1, TYMED_MFPICT }; // for OLE..._DRAW should be NULL @@ -799,14 +769,12 @@ void OleComponent::CreateNewEmbeddedObject( const uno::Sequence< sal_Int8 >& aSe OLERENDER_DRAW, // OLERENDER_FORMAT nullptr, // &aFormat, nullptr, - m_pNativeImpl->m_pIStorage, - reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) ); - - if ( FAILED( hr ) || !m_pNativeImpl->m_pObj ) + pStorage, + IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) ); + if (FAILED(hr)) throw uno::RuntimeException(); // TODO - if ( !InitializeObject_Impl() ) - throw uno::RuntimeException(); // TODO + InitializeObject_Impl(); // TODO: getExtent??? } @@ -825,11 +793,8 @@ void OleComponent::CreateObjectFromData( const uno::Reference< datatransfer::XTr void OleComponent::CreateObjectFromFile( const OUString& aFileURL ) { - if ( m_pNativeImpl->m_pIStorage ) - throw io::IOException(); // TODO:the object is already initialized - - CreateNewIStorage_Impl(); - if ( !m_pNativeImpl->m_pIStorage ) + auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL())); + if (!pStorage) throw uno::RuntimeException(); // TODO: OUString aFilePath; @@ -842,24 +807,19 @@ void OleComponent::CreateObjectFromFile( const OUString& aFileURL ) OLERENDER_DRAW, // OLERENDER_FORMAT nullptr, nullptr, - m_pNativeImpl->m_pIStorage, - reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) ); - - if ( FAILED( hr ) || !m_pNativeImpl->m_pObj ) + pStorage, + IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) ); + if (FAILED(hr)) throw uno::RuntimeException(); // TODO - if ( !InitializeObject_Impl() ) - throw uno::RuntimeException(); // TODO + InitializeObject_Impl(); } void OleComponent::CreateLinkFromFile( const OUString& aFileURL ) { - if ( m_pNativeImpl->m_pIStorage ) - throw io::IOException(); // TODO:the object is already initialized - - CreateNewIStorage_Impl(); - if ( !m_pNativeImpl->m_pIStorage ) + auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL())); + if (!pStorage) throw uno::RuntimeException(); // TODO: OUString aFilePath; @@ -871,52 +831,52 @@ void OleComponent::CreateLinkFromFile( const OUString& aFileURL ) OLERENDER_DRAW, // OLERENDER_FORMAT nullptr, nullptr, - m_pNativeImpl->m_pIStorage, - reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) ); - - if ( FAILED( hr ) || !m_pNativeImpl->m_pObj ) + pStorage, + IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) ); + if (FAILED(hr)) throw uno::RuntimeException(); // TODO - if ( !InitializeObject_Impl() ) - throw uno::RuntimeException(); // TODO + InitializeObject_Impl(); } void OleComponent::InitEmbeddedCopyOfLink( rtl::Reference<OleComponent> const & pOleLinkComponent ) { - if ( !pOleLinkComponent || !pOleLinkComponent->m_pNativeImpl->m_pObj ) + if (!pOleLinkComponent) throw lang::IllegalArgumentException(); // TODO - if ( m_pNativeImpl->m_pIStorage ) - throw io::IOException(); // TODO:the object is already initialized + auto pOleLinkComponentObj(pOleLinkComponent->m_pNativeImpl->getObj()); + if (!pOleLinkComponentObj) + throw lang::IllegalArgumentException(); + + // the object must be already disconnected from the temporary URL + auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL())); + + SolarMutexReleaser releaser; - ComSmart< IDataObject > pDataObject; - HRESULT hr = pOleLinkComponent->m_pNativeImpl->m_pObj->QueryInterface( IID_IDataObject, reinterpret_cast<void**>(&pDataObject) ); - if ( SUCCEEDED( hr ) && pDataObject && SUCCEEDED( OleQueryCreateFromData( pDataObject ) ) ) + auto pDataObject(pOleLinkComponentObj.QueryInterface<IDataObject>(sal::systools::COM_QUERY)); + if ( pDataObject && SUCCEEDED( OleQueryCreateFromData( pDataObject ) ) ) { - // the object must be already disconnected from the temporary URL - CreateNewIStorage_Impl(); - if ( !m_pNativeImpl->m_pIStorage ) + if (!pStorage) throw uno::RuntimeException(); // TODO: - hr = OleCreateFromData( pDataObject, + OleCreateFromData( pDataObject, IID_IUnknown, OLERENDER_DRAW, nullptr, nullptr, - m_pNativeImpl->m_pIStorage, - reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) ); + pStorage, + IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) ); } if ( !m_pNativeImpl->m_pObj ) { - ComSmart< IOleLink > pOleLink; - hr = pOleLinkComponent->m_pNativeImpl->m_pObj->QueryInterface( IID_IOleLink, reinterpret_cast<void**>(&pOleLink) ); - if ( FAILED( hr ) || !pOleLink ) + auto pOleLink(pOleLinkComponentObj.QueryInterface<IOleLink>(sal::systools::COM_QUERY)); + if ( !pOleLink ) throw io::IOException(); // TODO: the object doesn't support IOleLink - ComSmart< IMoniker > pMoniker; - hr = pOleLink->GetSourceMoniker( &pMoniker ); + sal::systools::COMReference< IMoniker > pMoniker; + HRESULT hr = pOleLink->GetSourceMoniker( &pMoniker ); if ( FAILED( hr ) || !pMoniker ) throw io::IOException(); // TODO: can not retrieve moniker @@ -925,7 +885,7 @@ void OleComponent::InitEmbeddedCopyOfLink( rtl::Reference<OleComponent> const & hr = pMoniker->IsSystemMoniker( &aMonType ); if ( SUCCEEDED( hr ) && aMonType == MKSYS_FILEMONIKER ) { - ComSmart< IMalloc > pMalloc; + sal::systools::COMReference< IMalloc > pMalloc; hr = CoGetMalloc( 1, &pMalloc ); // if fails there will be a memory leak OSL_ENSURE(SUCCEEDED(hr) && pMalloc, "CoGetMalloc() failed!"); @@ -943,56 +903,74 @@ void OleComponent::InitEmbeddedCopyOfLink( rtl::Reference<OleComponent> const & OLERENDER_DRAW, // OLERENDER_FORMAT nullptr, nullptr, - m_pNativeImpl->m_pIStorage, - reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) ); + pStorage, + IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) ); } } // in case of other moniker types the only way is to get storage if ( !m_pNativeImpl->m_pObj ) { - ComSmart< IBindCtx > pBindCtx; + sal::systools::COMReference< IBindCtx > pBindCtx; hr = CreateBindCtx( 0, &pBindCtx ); if ( SUCCEEDED( hr ) && pBindCtx ) { - ComSmart< IStorage > pObjectStorage; - hr = pMoniker->BindToStorage( pBindCtx, nullptr, IID_IStorage, reinterpret_cast<void**>(&pObjectStorage) ); + sal::systools::COMReference< IStorage > pObjectStorage; + hr = pMoniker->BindToStorage(pBindCtx, nullptr, IID_PPV_ARGS(&pObjectStorage)); if ( SUCCEEDED( hr ) && pObjectStorage ) { - hr = pObjectStorage->CopyTo( 0, nullptr, nullptr, m_pNativeImpl->m_pIStorage ); + hr = pObjectStorage->CopyTo(0, nullptr, nullptr, pStorage); if ( SUCCEEDED( hr ) ) - hr = OleLoadSeh(m_pNativeImpl->m_pIStorage, reinterpret_cast<void**>(&m_pNativeImpl->m_pObj)); + hr = OleLoadSeh(pStorage, &m_pNativeImpl->m_pObj); } } } } - // If object could not be created the only way is to use graphical representation - if ( FAILED( hr ) || !m_pNativeImpl->m_pObj ) - throw uno::RuntimeException(); // TODO - - if ( !InitializeObject_Impl() ) - throw uno::RuntimeException(); // TODO + InitializeObject_Impl(); } void OleComponent::RunObject() { - OSL_ENSURE( m_pNativeImpl->m_pOleObject, "The pointer can not be set to NULL here!" ); - if ( !m_pNativeImpl->m_pOleObject ) + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + OSL_ENSURE(pOleObject, "The pointer can not be set to NULL here!"); + if (!pOleObject) throw embed::WrongStateException(); // TODO: the object is in wrong state - if ( !OleIsRunning( m_pNativeImpl->m_pOleObject ) ) + if (!OleIsRunning(pOleObject)) { HRESULT hr = OleRun( m_pNativeImpl->m_pObj ); if ( FAILED( hr ) ) { + OUString error = WindowsErrorStringFromHRESULT(hr); if ( hr == REGDB_E_CLASSNOTREG ) - throw embed::UnreachableStateException(); // the object server is not installed + { + if (auto pOleObj + = m_pNativeImpl->m_pObj.QueryInterface<IOleObject>(sal::systools::COM_QUERY)) + { + LPOLESTR lpUserType = nullptr; + if (SUCCEEDED(pOleObj->GetUserType(USERCLASSTYPE_FULL, &lpUserType))) + { + error += OUString::Concat("\n") + o3tl::toU(lpUserType); + sal::systools::COMReference<IMalloc> pMalloc; + hr = CoGetMalloc(1, &pMalloc); // if fails there will be a memory leak + SAL_WARN_IF(FAILED(hr) || !pMalloc, "embeddedobj.ole", "CoGetMalloc() failed"); + if (pMalloc) + pMalloc->Free(lpUserType); + } + } + throw embed::UnreachableStateException( + error, getXWeak(), -1, + css::embed::EmbedStates::RUNNING); // the object server is not installed + } else - throw io::IOException(); + throw io::IOException(error, getXWeak()); } + // Only now, when the object is activated, it can be registered in the global table; + // before this point, RegisterInterfaceInGlobal would return CO_E_OBJNOTCONNECTED + m_pNativeImpl->registerObj(); } } @@ -1018,20 +996,31 @@ awt::Size OleComponent::CalculateWithFactor( const awt::Size& aSize, void OleComponent::CloseObject() { - if ( m_pNativeImpl->m_pOleObject && OleIsRunning( m_pNativeImpl->m_pOleObject ) ) - m_pNativeImpl->m_pOleObject->Close( OLECLOSE_NOSAVE ); // must be saved before + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (pOleObject && OleIsRunning(pOleObject)) + { + SolarMutexReleaser releaser; + HRESULT hr = pOleObject->Close(OLECLOSE_NOSAVE); // must be saved before + SAL_WARN_IF(FAILED(hr), "embeddedobj.ole", "IOleObject::Close failed"); + } } uno::Sequence< embed::VerbDescriptor > OleComponent::GetVerbList() { - if ( !m_pNativeImpl->m_pOleObject ) + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (!pOleObject) throw embed::WrongStateException(); // TODO: the object is in wrong state if( !m_aVerbList.getLength() ) { - ComSmart< IEnumOLEVERB > pEnum; - if( SUCCEEDED( m_pNativeImpl->m_pOleObject->EnumVerbs( &pEnum ) ) ) + sal::systools::COMReference< IEnumOLEVERB > pEnum; + HRESULT hr; + { + SolarMutexReleaser releaser; + hr = pOleObject->EnumVerbs(&pEnum); + } + if (SUCCEEDED(hr)) { OLEVERB szEle[ MAX_ENUM_ELE ]; ULONG nNum = 0; @@ -1039,16 +1028,17 @@ uno::Sequence< embed::VerbDescriptor > OleComponent::GetVerbList() do { - HRESULT hr = pEnum->Next( MAX_ENUM_ELE, szEle, &nNum ); + hr = pEnum->Next(MAX_ENUM_ELE, szEle, &nNum); if( hr == S_OK || hr == S_FALSE ) { m_aVerbList.realloc( nSeqSize += nNum ); + auto pVerbList = m_aVerbList.getArray(); for( sal_uInt32 nInd = 0; nInd < nNum; nInd++ ) { - m_aVerbList[nSeqSize-nNum+nInd].VerbID = szEle[ nInd ].lVerb; - m_aVerbList[nSeqSize-nNum+nInd].VerbName = WinAccToVcl_Impl( o3tl::toU(szEle[ nInd ].lpszVerbName) ); - m_aVerbList[nSeqSize-nNum+nInd].VerbFlags = szEle[ nInd ].fuFlags; - m_aVerbList[nSeqSize-nNum+nInd].VerbAttributes = szEle[ nInd ].grfAttribs; + pVerbList[nSeqSize-nNum+nInd].VerbID = szEle[ nInd ].lVerb; + pVerbList[nSeqSize-nNum+nInd].VerbName = WinAccToVcl_Impl( o3tl::toU(szEle[ nInd ].lpszVerbName) ); + pVerbList[nSeqSize-nNum+nInd].VerbFlags = szEle[ nInd ].fuFlags; + pVerbList[nSeqSize-nNum+nInd].VerbAttributes = szEle[ nInd ].grfAttribs; } } else @@ -1064,16 +1054,17 @@ uno::Sequence< embed::VerbDescriptor > OleComponent::GetVerbList() void OleComponent::ExecuteVerb( sal_Int32 nVerbID ) { - if ( !m_pNativeImpl->m_pOleObject ) + RunObject(); + + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (!pOleObject) throw embed::WrongStateException(); // TODO - HRESULT hr = OleRun( m_pNativeImpl->m_pOleObject ); - if ( FAILED( hr ) ) - throw io::IOException(); // TODO: a specific exception that transport error code can be thrown here + SolarMutexReleaser releaser; // TODO: probably extents should be set here and stored in aRect // TODO: probably the parent window also should be set - hr = m_pNativeImpl->m_pOleObject->DoVerb( nVerbID, nullptr, m_pOleWrapClientSite, 0, nullptr, nullptr ); + HRESULT hr = pOleObject->DoVerb(nVerbID, nullptr, m_pOleWrapClientSite, 0, nullptr, nullptr); if ( FAILED( hr ) ) throw io::IOException(); // TODO @@ -1082,22 +1073,29 @@ void OleComponent::ExecuteVerb( sal_Int32 nVerbID ) void OleComponent::SetHostName( const OUString& aEmbDocName ) { - if ( !m_pNativeImpl->m_pOleObject ) + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (!pOleObject) throw embed::WrongStateException(); // TODO: the object is in wrong state - m_pNativeImpl->m_pOleObject->SetHostNames( L"app name", o3tl::toW( aEmbDocName.getStr() ) ); + SolarMutexReleaser releaser; + pOleObject->SetHostNames(L"app name", o3tl::toW(aEmbDocName.getStr())); } void OleComponent::SetExtent( const awt::Size& aVisAreaSize, sal_Int64 nAspect ) { - if ( !m_pNativeImpl->m_pOleObject ) + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (!pOleObject) throw embed::WrongStateException(); // TODO: the object is in wrong state DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects SIZEL aSize = { aVisAreaSize.Width, aVisAreaSize.Height }; - HRESULT hr = m_pNativeImpl->m_pOleObject->SetExtent( nMSAspect, &aSize ); + HRESULT hr; + { + SolarMutexReleaser releaser; + hr = pOleObject->SetExtent(nMSAspect, &aSize); + } if ( FAILED( hr ) ) { @@ -1113,7 +1111,7 @@ void OleComponent::SetExtent( const awt::Size& aVisAreaSize, sal_Int64 nAspect ) awt::Size OleComponent::GetExtent( sal_Int64 nAspect ) { - if ( !m_pNativeImpl->m_pOleObject ) + if (!m_pNativeImpl->m_pObj) throw embed::WrongStateException(); // TODO: the object is in wrong state DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects @@ -1123,15 +1121,17 @@ awt::Size OleComponent::GetExtent( sal_Int64 nAspect ) if ( nMSAspect == DVASPECT_CONTENT ) { // Try to get the size from the replacement image first - ComSmart< IDataObject > pDataObject; - HRESULT hr = m_pNativeImpl->m_pObj->QueryInterface( IID_IDataObject, reinterpret_cast<void**>(&pDataObject) ); - if ( SUCCEEDED( hr ) || pDataObject ) + if (auto pDataObject = m_pNativeImpl->get<IDataObject>()) { STGMEDIUM aMedium; FORMATETC aFormat = pFormatTemplates[1]; // use windows metafile format aFormat.dwAspect = nMSAspect; - hr = pDataObject->GetData( &aFormat, &aMedium ); + HRESULT hr; + { + SolarMutexReleaser releaser; + hr = pDataObject->GetData(&aFormat, &aMedium); + } if (hr == RPC_E_WRONG_THREAD) { @@ -1150,27 +1150,23 @@ awt::Size OleComponent::GetExtent( sal_Int64 nAspect ) if ( pMF ) { // the object uses 0.01 mm as unit, so the metafile size should be converted to object unit - sal_Int64 nMult = 1; - sal_Int64 nDiv = 1; + o3tl::Length eFrom = o3tl::Length::mm100; switch( pMF->mm ) { case MM_HIENGLISH: - nMult = 254; - nDiv = 100; + eFrom = o3tl::Length::in1000; break; case MM_LOENGLISH: - nMult = 254; - nDiv = 10; + eFrom = o3tl::Length::in100; break; case MM_LOMETRIC: - nMult = 10; + eFrom = o3tl::Length::mm10; break; case MM_TWIPS: - nMult = 254; - nDiv = 144; + eFrom = o3tl::Length::twip; break; case MM_ISOTROPIC: @@ -1180,8 +1176,8 @@ awt::Size OleComponent::GetExtent( sal_Int64 nAspect ) break; } - sal_Int64 nX = static_cast<sal_Int64>(abs( pMF->xExt )) * nMult / nDiv; - sal_Int64 nY = static_cast<sal_Int64>(abs( pMF->yExt )) * nMult / nDiv; + sal_Int64 nX = o3tl::convert(abs( pMF->xExt ), eFrom, o3tl::Length::mm100); + sal_Int64 nY = o3tl::convert(abs( pMF->yExt ), eFrom, o3tl::Length::mm100); if ( nX < SAL_MAX_INT32 && nY < SAL_MAX_INT32 ) { aSize.Width = static_cast<sal_Int32>(nX); @@ -1211,13 +1207,18 @@ awt::Size OleComponent::GetExtent( sal_Int64 nAspect ) awt::Size OleComponent::GetCachedExtent( sal_Int64 nAspect ) { - if ( !m_pNativeImpl->m_pOleObject ) + auto pViewObject2(m_pNativeImpl->get<IViewObject2>()); + if (!pViewObject2) throw embed::WrongStateException(); // TODO: the object is in wrong state DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects SIZEL aSize; - HRESULT hr = m_pNativeImpl->m_pViewObject2->GetExtent( nMSAspect, -1, nullptr, &aSize ); + HRESULT hr; + { + SolarMutexReleaser releaser; + hr = pViewObject2->GetExtent(nMSAspect, -1, nullptr, &aSize); + } if ( FAILED( hr ) ) { @@ -1238,12 +1239,17 @@ awt::Size OleComponent::GetCachedExtent( sal_Int64 nAspect ) awt::Size OleComponent::GetRecommendedExtent( sal_Int64 nAspect ) { - if ( !m_pNativeImpl->m_pOleObject ) + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (!pOleObject) throw embed::WrongStateException(); // TODO: the object is in wrong state DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects SIZEL aSize; - HRESULT hr = m_pNativeImpl->m_pOleObject->GetExtent( nMSAspect, &aSize ); + HRESULT hr; + { + SolarMutexReleaser releaser; + hr = pOleObject->GetExtent(nMSAspect, &aSize); + } if ( FAILED( hr ) ) { SAL_WARN("embeddedobj.ole", " OleComponent::GetRecommendedExtent: GetExtent() failed"); @@ -1256,22 +1262,31 @@ awt::Size OleComponent::GetRecommendedExtent( sal_Int64 nAspect ) sal_Int64 OleComponent::GetMiscStatus( sal_Int64 nAspect ) { - if ( !m_pNativeImpl->m_pOleObject ) + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (!pOleObject) throw embed::WrongStateException(); // TODO: the object is in wrong state - DWORD nResult; - m_pNativeImpl->m_pOleObject->GetMiscStatus( static_cast<DWORD>(nAspect), &nResult ); + DWORD nResult = 0; + { + SolarMutexReleaser releaser; + pOleObject->GetMiscStatus(static_cast<DWORD>(nAspect), &nResult); + } return static_cast<sal_Int64>(nResult); // first 32 bits are for MS flags } uno::Sequence< sal_Int8 > OleComponent::GetCLSID() { - if ( !m_pNativeImpl->m_pOleObject ) + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (!pOleObject) throw embed::WrongStateException(); // TODO: the object is in wrong state GUID aCLSID; - HRESULT hr = m_pNativeImpl->m_pOleObject->GetUserClassID( &aCLSID ); + HRESULT hr; + { + SolarMutexReleaser releaser; + hr = pOleObject->GetUserClassID(&aCLSID); + } if ( FAILED( hr ) ) throw io::IOException(); // TODO: @@ -1285,60 +1300,60 @@ uno::Sequence< sal_Int8 > OleComponent::GetCLSID() bool OleComponent::IsDirty() { - if ( !m_pNativeImpl->m_pOleObject ) - throw embed::WrongStateException(); // TODO: the object is in wrong state - if ( IsWorkaroundActive() ) return true; - ComSmart< IPersistStorage > pPersistStorage; - HRESULT hr = m_pNativeImpl->m_pObj->QueryInterface( IID_IPersistStorage, reinterpret_cast<void**>(&pPersistStorage) ); - if ( FAILED( hr ) || !pPersistStorage ) + auto pPersistStorage(m_pNativeImpl->get<IPersistStorage>()); + if ( !pPersistStorage ) throw io::IOException(); // TODO - hr = pPersistStorage->IsDirty(); + SolarMutexReleaser releaser; + HRESULT hr = pPersistStorage->IsDirty(); return ( hr != S_FALSE ); } void OleComponent::StoreOwnTmpIfNecessary() { - if ( !m_pNativeImpl->m_pOleObject ) + auto pOleObject(m_pNativeImpl->get<IOleObject>()); + if (!pOleObject) throw embed::WrongStateException(); // TODO: the object is in wrong state - ComSmart< IPersistStorage > pPersistStorage; - HRESULT hr = m_pNativeImpl->m_pObj->QueryInterface( IID_IPersistStorage, reinterpret_cast<void**>(&pPersistStorage) ); - if ( FAILED( hr ) || !pPersistStorage ) + auto pPersistStorage(m_pNativeImpl->get<IPersistStorage>()); + if ( !pPersistStorage ) throw io::IOException(); // TODO + SolarMutexReleaser releaser; + if ( m_bWorkaroundActive || pPersistStorage->IsDirty() != S_FALSE ) { - hr = OleSave( pPersistStorage, m_pNativeImpl->m_pIStorage, TRUE ); + auto pStorage(m_pNativeImpl->getStorage()); + HRESULT hr = OleSave(pPersistStorage, pStorage, TRUE); if ( FAILED( hr ) ) { // Till now was required only for AcrobatReader7.0.8 GUID aCLSID; - hr = m_pNativeImpl->m_pOleObject->GetUserClassID( &aCLSID ); + hr = pOleObject->GetUserClassID(&aCLSID); if ( FAILED( hr ) ) { SAL_WARN("embeddedobj.ole", "OleComponent::StoreOwnTmpIfNecessary: GetUserClassID() failed"); throw io::IOException(); // TODO } - hr = WriteClassStg( m_pNativeImpl->m_pIStorage, aCLSID ); + hr = WriteClassStg(pStorage, aCLSID); if ( FAILED( hr ) ) throw io::IOException(); // TODO // the result of the following call is not checked because some objects, for example AcrobatReader7.0.8 // return error even in case the saving was done correctly - hr = pPersistStorage->Save( m_pNativeImpl->m_pIStorage, TRUE ); + hr = pPersistStorage->Save(pStorage, TRUE); // another workaround for AcrobatReader7.0.8 object, this object might think that it is not changed // when it has been created from file, although it must be saved m_bWorkaroundActive = true; } - hr = m_pNativeImpl->m_pIStorage->Commit( STGC_DEFAULT ); + hr = pStorage->Commit(STGC_DEFAULT); if ( FAILED( hr ) ) throw io::IOException(); // TODO @@ -1454,11 +1469,11 @@ void SAL_CALL OleComponent::close( sal_Bool bDeliverOwnership ) if (m_pInterfaceContainer) { - ::cppu::OInterfaceContainerHelper* pContainer + comphelper::OInterfaceContainerHelper2* pContainer = m_pInterfaceContainer->getContainer(cppu::UnoType<util::XCloseListener>::get()); if (pContainer != nullptr) { - ::cppu::OInterfaceIteratorHelper pIterator(*pContainer); + comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer); while (pIterator.hasMoreElements()) { try @@ -1477,7 +1492,7 @@ void SAL_CALL OleComponent::close( sal_Bool bDeliverOwnership ) = m_pInterfaceContainer->getContainer(cppu::UnoType<util::XCloseListener>::get()); if (pContainer != nullptr) { - ::cppu::OInterfaceIteratorHelper pCloseIterator(*pContainer); + comphelper::OInterfaceIteratorHelper2 pCloseIterator(*pContainer); while (pCloseIterator.hasMoreElements()) { try @@ -1505,7 +1520,7 @@ void SAL_CALL OleComponent::addCloseListener( const uno::Reference< util::XClose throw lang::DisposedException(); // TODO if ( !m_pInterfaceContainer ) - m_pInterfaceContainer = new ::cppu::OMultiTypeInterfaceContainerHelper( m_aMutex ); + m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex ); m_pInterfaceContainer->addInterface( cppu::UnoType<util::XCloseListener>::get(), xListener ); } @@ -1530,7 +1545,7 @@ uno::Any SAL_CALL OleComponent::getTransferData( const datatransfer::DataFlavor& if ( m_bDisposed ) throw lang::DisposedException(); // TODO - if ( !m_pNativeImpl->m_pOleObject ) + if (!m_pNativeImpl->m_pObj) throw embed::WrongStateException(); // TODO: the object is in wrong state uno::Any aResult; @@ -1541,9 +1556,8 @@ uno::Any SAL_CALL OleComponent::getTransferData( const datatransfer::DataFlavor& DWORD nRequestedAspect = GetAspectFromFlavor( aFlavor ); // if own icon is set and icon aspect is requested the own icon can be returned directly - ComSmart< IDataObject > pDataObject; - HRESULT hr = m_pNativeImpl->m_pObj->QueryInterface( IID_IDataObject, reinterpret_cast<void**>(&pDataObject) ); - if ( FAILED( hr ) || !pDataObject ) + auto pDataObject(m_pNativeImpl->get<IDataObject>()); + if ( !pDataObject ) throw io::IOException(); // TODO: transport error code // The following optimization does not make much sense currently just because @@ -1569,7 +1583,11 @@ uno::Any SAL_CALL OleComponent::getTransferData( const datatransfer::DataFlavor& FORMATETC aFormat = pFormatTemplates[nInd]; aFormat.dwAspect = nRequestedAspect; - hr = pDataObject->GetData( &aFormat, &aMedium ); + HRESULT hr; + { + SolarMutexReleaser releaser; + hr = pDataObject->GetData(&aFormat, &aMedium); + } if ( SUCCEEDED( hr ) ) { bSupportedFlavor = m_pNativeImpl->ConvertDataForFlavor( aMedium, aFlavor, aResult ); @@ -1628,9 +1646,6 @@ uno::Sequence< datatransfer::DataFlavor > SAL_CALL OleComponent::getTransferData if ( m_bDisposed ) throw lang::DisposedException(); // TODO - if ( !m_pNativeImpl->m_pOleObject ) - throw embed::WrongStateException(); // TODO: the object is in wrong state - RetrieveObjectDataFlavors_Impl(); return m_aDataFlavors; @@ -1643,15 +1658,9 @@ sal_Bool SAL_CALL OleComponent::isDataFlavorSupported( const datatransfer::DataF if ( m_bDisposed ) throw lang::DisposedException(); // TODO - if ( !m_pNativeImpl->m_pOleObject ) - throw embed::WrongStateException(); // TODO: the object is in wrong state - - if ( !m_aDataFlavors.getLength() ) - { - RetrieveObjectDataFlavors_Impl(); - } + RetrieveObjectDataFlavors_Impl(); - for ( auto const & supportedFormat : std::as_const(m_aDataFlavors) ) + for (auto const& supportedFormat : m_aDataFlavors) if ( supportedFormat.MimeType.equals( aFlavor.MimeType ) && supportedFormat.DataType == aFlavor.DataType ) return true; @@ -1676,7 +1685,7 @@ void SAL_CALL OleComponent::addEventListener( const uno::Reference< lang::XEvent throw lang::DisposedException(); // TODO if ( !m_pInterfaceContainer ) - m_pInterfaceContainer = new ::cppu::OMultiTypeInterfaceContainerHelper( m_aMutex ); + m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex ); m_pInterfaceContainer->addInterface( cppu::UnoType<lang::XEventListener>::get(), xListener ); } @@ -1699,25 +1708,7 @@ sal_Int64 SAL_CALL OleComponent::getSomething( const css::uno::Sequence< sal_Int { uno::Sequence < sal_Int8 > aCLSID = GetCLSID(); if ( MimeConfigurationHelper::ClassIDsEqual( aIdentifier, aCLSID ) ) - return reinterpret_cast<sal_Int64>(static_cast<IUnknown*>(m_pNativeImpl->m_pObj)); - - // compatibility hack for old versions: CLSID was used in wrong order (SvGlobalName order) - sal_Int32 nLength = aIdentifier.getLength(); - if ( nLength == 16 ) - { - for ( sal_Int32 n=8; n<16; n++ ) - if ( aIdentifier[n] != aCLSID[n] ) - return 0; - if ( aIdentifier[7] == aCLSID[6] && - aIdentifier[6] == aCLSID[7] && - aIdentifier[5] == aCLSID[4] && - aIdentifier[4] == aCLSID[5] && - aIdentifier[3] == aCLSID[0] && - aIdentifier[2] == aCLSID[1] && - aIdentifier[1] == aCLSID[2] && - aIdentifier[0] == aCLSID[3] ) - return reinterpret_cast<sal_Int64>(static_cast<IUnknown*>(m_pNativeImpl->m_pObj)); - } + return comphelper::getSomething_cast(m_pNativeImpl->m_pObj.get()); } catch ( const uno::Exception& ) { @@ -1737,11 +1728,11 @@ void SAL_CALL OleComponent::setModified( sal_Bool bModified ) if ( bModified && m_pInterfaceContainer ) { - ::cppu::OInterfaceContainerHelper* pContainer = + comphelper::OInterfaceContainerHelper2* pContainer = m_pInterfaceContainer->getContainer( cppu::UnoType<util::XModifyListener>::get()); if ( pContainer != nullptr ) { - ::cppu::OInterfaceIteratorHelper pIterator( *pContainer ); + comphelper::OInterfaceIteratorHelper2 pIterator( *pContainer ); while ( pIterator.hasMoreElements() ) { try @@ -1765,7 +1756,7 @@ void SAL_CALL OleComponent::addModifyListener( const css::uno::Reference < css:: throw lang::DisposedException(); // TODO if ( !m_pInterfaceContainer ) - m_pInterfaceContainer = new ::cppu::OMultiTypeInterfaceContainerHelper( m_aMutex ); + m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex ); m_pInterfaceContainer->addInterface( cppu::UnoType<util::XModifyListener>::get(), xListener ); } |