1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
23 #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 #include <com/sun/star/lang/DisposedException.hpp>
25 #include <com/sun/star/embed/WrongStateException.hpp>
26 #include <com/sun/star/embed/UnreachableStateException.hpp>
27 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/io/TempFile.hpp>
30 #include <com/sun/star/io/XTruncate.hpp>
31 #include <com/sun/star/io/IOException.hpp>
32 #include <com/sun/star/awt/XRequestCallback.hpp>
35 #include <comphelper/multicontainer2.hxx>
36 #include <comphelper/mimeconfighelper.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <comphelper/servicehelper.hxx>
39 #include <comphelper/windowserrorstring.hxx>
40 #include <osl/file.hxx>
41 #include <rtl/ref.hxx>
42 #include <o3tl/char16_t2wchar_t.hxx>
43 #include <o3tl/unit_conversion.hxx>
44 #include <systools/win32/comtools.hxx>
45 #include <vcl/threadex.hxx>
47 #include "graphconvert.hxx"
48 #include "olecomponent.hxx"
49 #include "olepersist.hxx"
50 #include "olewrapclient.hxx"
51 #include "advisesink.hxx"
52 #include <oleembobj.hxx>
53 #include "mtnotification.hxx"
57 using namespace ::com::sun::star
;
58 using namespace ::comphelper
;
59 #define MAX_ENUM_ELE 20
62 typedef std::vector
< FORMATETC
* > FormatEtcList
;
64 FORMATETC
const pFormatTemplates
[FORMATS_NUM
] = {
65 { CF_ENHMETAFILE
, nullptr, 0, -1, TYMED_ENHMF
},
66 { CF_METAFILEPICT
, nullptr, 0, -1, TYMED_MFPICT
},
67 { CF_BITMAP
, nullptr, 0, -1, TYMED_GDI
} };
70 struct OleComponentNative_Impl
{
71 sal::systools::COMReference
< IUnknown
> m_pObj
;
72 sal::systools::COMReference
< IOleObject
> m_pOleObject
;
73 sal::systools::COMReference
< IViewObject2
> m_pViewObject2
;
74 sal::systools::COMReference
< IStorage
> m_pIStorage
;
75 FormatEtcList m_aFormatsList
;
76 uno::Sequence
< datatransfer::DataFlavor
> m_aSupportedGraphFormats
;
78 OleComponentNative_Impl()
80 // TODO: Extend format list
81 m_aSupportedGraphFormats
= {
83 datatransfer::DataFlavor(
84 "application/x-openoffice-emf;windows_formatname=\"Image EMF\"",
85 "Windows Enhanced Metafile",
86 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() ),
88 datatransfer::DataFlavor(
89 "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"",
91 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() ),
93 datatransfer::DataFlavor(
94 "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"",
96 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() ),
98 datatransfer::DataFlavor(
101 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() ),
103 datatransfer::DataFlavor(
104 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"",
106 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() )
110 bool ConvertDataForFlavor( const STGMEDIUM
& aMedium
,
111 const datatransfer::DataFlavor
& aFlavor
,
114 bool GraphicalFlavor( const datatransfer::DataFlavor
& aFlavor
);
116 uno::Sequence
< datatransfer::DataFlavor
> GetFlavorsForAspects( sal_uInt32 nSupportedAspects
);
120 static DWORD
GetAspectFromFlavor( const datatransfer::DataFlavor
& aFlavor
)
122 if ( aFlavor
.MimeType
.indexOf( ";Aspect=THUMBNAIL" ) != -1 )
123 return DVASPECT_THUMBNAIL
;
124 else if ( aFlavor
.MimeType
.indexOf( ";Aspect=ICON" ) != -1 )
125 return DVASPECT_ICON
;
126 else if ( aFlavor
.MimeType
.indexOf( ";Aspect=DOCPRINT" ) != -1 )
127 return DVASPECT_DOCPRINT
;
129 return DVASPECT_CONTENT
;
133 static OUString
GetFlavorSuffixFromAspect( DWORD nAsp
)
137 if ( nAsp
== DVASPECT_THUMBNAIL
)
138 aResult
= ";Aspect=THUMBNAIL";
139 else if ( nAsp
== DVASPECT_ICON
)
140 aResult
= ";Aspect=ICON";
141 else if ( nAsp
== DVASPECT_DOCPRINT
)
142 aResult
= ";Aspect=DOCPRINT";
144 // no suffix for DVASPECT_CONTENT
150 static HRESULT
OpenIStorageFromURL_Impl( const OUString
& aURL
, IStorage
** ppIStorage
)
152 OSL_ENSURE( ppIStorage
, "The pointer must not be empty!" );
155 if ( !ppIStorage
|| ::osl::FileBase::getSystemPathFromFileURL( aURL
, aFilePath
) != ::osl::FileBase::E_None
)
156 throw uno::RuntimeException(); // TODO: something dangerous happened
158 return StgOpenStorage( o3tl::toW(aFilePath
.getStr()),
160 STGM_READWRITE
| STGM_TRANSACTED
, // | STGM_DELETEONRELEASE,
167 bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM
& aMedium
,
168 const datatransfer::DataFlavor
& aFlavor
,
171 bool bAnyIsReady
= false;
173 // try to convert data from Medium format to specified Flavor format
174 if ( aFlavor
.DataType
== cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() )
176 // first the GDI-metafile must be generated
178 std::unique_ptr
<sal_Int8
[]> pBuf
;
179 sal_uInt32 nBufSize
= 0;
182 if ( aMedium
.tymed
== TYMED_MFPICT
) // Win Metafile
184 aFormat
= "image/x-wmf";
185 METAFILEPICT
* pMF
= static_cast<METAFILEPICT
*>(GlobalLock( aMedium
.hMetaFilePict
));
188 nBufSize
= GetMetaFileBitsEx( pMF
->hMF
, 0, nullptr ) + 22;
189 pBuf
.reset(new sal_Int8
[nBufSize
]);
192 // TODO/LATER: the unit size must be calculated correctly
193 *reinterpret_cast<long*>( pBuf
.get() ) = 0x9ac6cdd7L
;
194 *reinterpret_cast<short*>( pBuf
.get()+6 ) = SHORT(0);
195 *reinterpret_cast<short*>( pBuf
.get()+8 ) = SHORT(0);
196 *reinterpret_cast<short*>( pBuf
.get()+10 ) = static_cast<SHORT
>(pMF
->xExt
);
197 *reinterpret_cast<short*>( pBuf
.get()+12 ) = static_cast<SHORT
>(pMF
->yExt
);
198 *reinterpret_cast<short*>( pBuf
.get()+14 ) = USHORT(2540);
201 if ( nBufSize
&& nBufSize
== GetMetaFileBitsEx( pMF
->hMF
, nBufSize
- 22, pBuf
.get() + 22 ) )
203 if ( aFlavor
.MimeType
.matchAsciiL( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"", 57 ) )
205 aResult
<<= uno::Sequence
< sal_Int8
>( pBuf
.get(), nBufSize
);
210 GlobalUnlock( aMedium
.hMetaFilePict
);
213 else if ( aMedium
.tymed
== TYMED_ENHMF
) // Enh Metafile
215 aFormat
= "image/x-emf";
216 nBufSize
= GetEnhMetaFileBits( aMedium
.hEnhMetaFile
, 0, nullptr );
217 pBuf
.reset(new sal_Int8
[nBufSize
]);
218 if ( nBufSize
&& nBufSize
== GetEnhMetaFileBits( aMedium
.hEnhMetaFile
, nBufSize
, reinterpret_cast<LPBYTE
>(pBuf
.get()) ) )
220 if ( aFlavor
.MimeType
.matchAsciiL( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"", 57 ) )
222 aResult
<<= uno::Sequence
< sal_Int8
>( pBuf
.get(), nBufSize
);
227 else if ( aMedium
.tymed
== TYMED_GDI
) // Bitmap
229 aFormat
= "image/x-MS-bmp";
231 // Find out size of buffer: deprecated GetBitmapBits does not have a mode to return
232 // required buffer size
234 GetObjectW(aMedium
.hBitmap
, sizeof(aBmp
), &aBmp
);
235 nBufSize
= aBmp
.bmWidthBytes
* aBmp
.bmHeight
;
237 pBuf
.reset(new sal_Int8
[nBufSize
]);
238 if ( nBufSize
&& nBufSize
== sal::static_int_cast
< ULONG
>( GetBitmapBits( aMedium
.hBitmap
, nBufSize
, pBuf
.get() ) ) )
240 if ( aFlavor
.MimeType
.matchAsciiL( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"", 54 ) )
242 aResult
<<= uno::Sequence
< sal_Int8
>( pBuf
.get(), nBufSize
);
248 if ( pBuf
&& !bAnyIsReady
)
250 for ( auto const & supportedFormat
: std::as_const(m_aSupportedGraphFormats
) )
251 if ( aFlavor
.MimeType
.match( supportedFormat
.MimeType
)
252 && aFlavor
.DataType
== supportedFormat
.DataType
253 && aFlavor
.DataType
== cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() )
255 bAnyIsReady
= ConvertBufferToFormat( pBuf
.get(), nBufSize
, aFormat
, aResult
);
265 bool OleComponentNative_Impl::GraphicalFlavor( const datatransfer::DataFlavor
& aFlavor
)
267 // Actually all the required graphical formats must be supported
268 for ( auto const & supportedFormat
: std::as_const(m_aSupportedGraphFormats
) )
269 if ( aFlavor
.MimeType
.match( supportedFormat
.MimeType
)
270 && aFlavor
.DataType
== supportedFormat
.DataType
)
277 static bool GetClassIDFromSequence_Impl( uno::Sequence
< sal_Int8
> const & aSeq
, CLSID
& aResult
)
279 if ( aSeq
.getLength() == 16 )
281 aResult
.Data1
= ( ( ( ( ( static_cast<sal_uInt8
>(aSeq
[0]) << 8 ) + static_cast<sal_uInt8
>(aSeq
[1]) ) << 8 ) + static_cast<sal_uInt8
>(aSeq
[2]) ) << 8 ) + static_cast<sal_uInt8
>(aSeq
[3]);
282 aResult
.Data2
= ( static_cast<sal_uInt8
>(aSeq
[4]) << 8 ) + static_cast<sal_uInt8
>(aSeq
[5]);
283 aResult
.Data3
= ( static_cast<sal_uInt8
>(aSeq
[6]) << 8 ) + static_cast<sal_uInt8
>(aSeq
[7]);
284 for( int nInd
= 0; nInd
< 8; nInd
++ )
285 aResult
.Data4
[nInd
] = static_cast<sal_uInt8
>(aSeq
[nInd
+8]);
294 static OUString
WinAccToVcl_Impl( const sal_Unicode
* pStr
)
305 while( *( ++pStr
) == '&' );
309 aResult
+= OUStringChar( *pStr
);
319 OleComponent::OleComponent( const uno::Reference
< uno::XComponentContext
>& xContext
, OleEmbeddedObject
* pUnoOleObject
)
320 : m_pInterfaceContainer( nullptr )
321 , m_bDisposed( false )
322 , m_bModified( false )
323 , m_pNativeImpl( new OleComponentNative_Impl() )
324 , m_pUnoOleObject( pUnoOleObject
)
325 , m_pOleWrapClientSite( nullptr )
326 , m_pImplAdviseSink( nullptr )
327 , m_nOLEMiscFlags( 0 )
329 , m_xContext( xContext
)
330 , m_bOleInitialized( false )
331 , m_bWorkaroundActive( false )
333 OSL_ENSURE( m_pUnoOleObject
, "No owner object is provided!" );
335 HRESULT hr
= OleInitialize( nullptr );
336 if ( hr
== S_OK
|| hr
== S_FALSE
)
337 m_bOleInitialized
= true;
340 SAL_WARN("embeddedobj.ole", "OleComponent ctor: OleInitialize() failed with 0x"
341 << OUString::number(static_cast<sal_uInt32
>(hr
), 16) << ": "
342 << WindowsErrorStringFromHRESULT(hr
));
345 m_pOleWrapClientSite
= new OleWrapperClientSite( this );
346 m_pOleWrapClientSite
->AddRef();
348 m_pImplAdviseSink
= new OleWrapperAdviseSink( this );
349 m_pImplAdviseSink
->AddRef();
354 OleComponent::~OleComponent()
356 OSL_ENSURE( !m_pOleWrapClientSite
&& !m_pImplAdviseSink
&& !m_pInterfaceContainer
&& !m_bOleInitialized
,
357 "The object was not closed successfully! DISASTER is possible!" );
359 if ( m_pOleWrapClientSite
|| m_pImplAdviseSink
|| m_pInterfaceContainer
|| m_bOleInitialized
)
361 osl_atomic_increment(&m_refCount
);
364 } catch( const uno::Exception
& ) {}
367 for (auto const& format
: m_pNativeImpl
->m_aFormatsList
)
371 m_pNativeImpl
->m_aFormatsList
.clear();
373 delete m_pNativeImpl
;
376 void OleComponent::Dispose()
381 // Call CloseObject() without m_aMutex locked, since it will call
382 // IOleObject::Close(), which can call event listeners, which can run on a
386 osl::MutexGuard
aGuard(m_aMutex
);
387 if ( m_pOleWrapClientSite
)
389 m_pOleWrapClientSite
->disconnectOleComponent();
390 m_pOleWrapClientSite
->Release();
391 m_pOleWrapClientSite
= nullptr;
394 if ( m_pImplAdviseSink
)
396 m_pImplAdviseSink
->disconnectOleComponent();
397 m_pImplAdviseSink
->Release();
398 m_pImplAdviseSink
= nullptr;
401 if ( m_pInterfaceContainer
)
403 lang::EventObject
aEvent( static_cast< ::cppu::OWeakObject
* >( this ) );
404 m_pInterfaceContainer
->disposeAndClear( aEvent
);
406 delete m_pInterfaceContainer
;
407 m_pInterfaceContainer
= nullptr;
410 if ( m_bOleInitialized
)
412 // since the disposing can happen not only from main thread but also from a clipboard
413 // the deinitialization might lead to a disaster, SO7 does not deinitialize OLE at all
414 // so currently the same approach is selected as workaround
415 // OleUninitialize();
416 m_bOleInitialized
= false;
423 void OleComponent::disconnectEmbeddedObject()
425 // must not be called from destructor of UNO OLE object!!!
426 osl::MutexGuard
aGuard( m_aMutex
);
427 m_pUnoOleObject
= nullptr;
431 void OleComponent::CreateNewIStorage_Impl()
433 // TODO: in future a global memory could be used instead of file.
435 // write the stream to the temporary file
438 OSL_ENSURE( m_pUnoOleObject
, "Unexpected object absence!" );
439 if ( m_pUnoOleObject
)
440 aTempURL
= m_pUnoOleObject
->CreateTempURLEmpty_Impl();
442 aTempURL
= GetNewTempFileURL_Impl( m_xContext
);
444 if ( !aTempURL
.getLength() )
445 throw uno::RuntimeException(); // TODO
447 // open an IStorage based on the temporary file
448 OUString aTempFilePath
;
449 if ( ::osl::FileBase::getSystemPathFromFileURL( aTempURL
, aTempFilePath
) != ::osl::FileBase::E_None
)
450 throw uno::RuntimeException(); // TODO: something dangerous happened
452 HRESULT hr
= StgCreateDocfile( o3tl::toW(aTempFilePath
.getStr()), STGM_CREATE
| STGM_READWRITE
| STGM_TRANSACTED
| STGM_DELETEONRELEASE
, 0, &m_pNativeImpl
->m_pIStorage
);
453 if ( FAILED( hr
) || !m_pNativeImpl
->m_pIStorage
)
454 throw io::IOException(); // TODO: transport error code?
458 uno::Sequence
< datatransfer::DataFlavor
> OleComponentNative_Impl::GetFlavorsForAspects( sal_uInt32 nSupportedAspects
)
460 uno::Sequence
< datatransfer::DataFlavor
> aResult
;
461 for ( sal_uInt32 nAsp
= 1; nAsp
<= 8; nAsp
*= 2 )
462 if ( ( nSupportedAspects
& nAsp
) == nAsp
)
464 OUString aAspectSuffix
= GetFlavorSuffixFromAspect( nAsp
);
466 sal_Int32 nLength
= aResult
.getLength();
467 aResult
.realloc( nLength
+ m_aSupportedGraphFormats
.getLength() );
468 auto pResult
= aResult
.getArray();
470 for ( sal_Int32 nInd
= 0; nInd
< m_aSupportedGraphFormats
.getLength(); nInd
++ )
472 pResult
[nLength
+ nInd
].MimeType
= m_aSupportedGraphFormats
[nInd
].MimeType
+ aAspectSuffix
;
473 pResult
[nLength
+ nInd
].HumanPresentableName
= m_aSupportedGraphFormats
[nInd
].HumanPresentableName
;
474 pResult
[nLength
+ nInd
].DataType
= m_aSupportedGraphFormats
[nInd
].DataType
;
482 void OleComponent::RetrieveObjectDataFlavors_Impl()
484 if ( !m_pNativeImpl
->m_pOleObject
)
485 throw embed::WrongStateException(); // TODO: the object is in wrong state
487 if ( !m_aDataFlavors
.getLength() )
489 sal::systools::COMReference
< IDataObject
> pDataObject(m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
);
492 sal::systools::COMReference
< IEnumFORMATETC
> pFormatEnum
;
493 HRESULT hr
= pDataObject
->EnumFormatEtc( DATADIR_GET
, &pFormatEnum
);
494 if ( SUCCEEDED( hr
) && pFormatEnum
)
496 FORMATETC pElem
[ MAX_ENUM_ELE
];
499 // if it is possible to retrieve at least one supported graphical format for an aspect
500 // this format can be converted to other supported formats
501 sal_uInt32 nSupportedAspects
= 0;
504 HRESULT hr2
= pFormatEnum
->Next( MAX_ENUM_ELE
, pElem
, &nNum
);
505 if( hr2
== S_OK
|| hr2
== S_FALSE
)
507 for( sal_uInt32 nInd
= 0; nInd
< FORMATS_NUM
; nInd
++ )
509 if ( pElem
[nInd
].cfFormat
== pFormatTemplates
[nInd
].cfFormat
510 && pElem
[nInd
].tymed
== pFormatTemplates
[nInd
].tymed
)
511 nSupportedAspects
|= pElem
[nInd
].dwAspect
;
517 while( nNum
== MAX_ENUM_ELE
);
519 m_aDataFlavors
= m_pNativeImpl
->GetFlavorsForAspects( nSupportedAspects
);
523 if ( !m_aDataFlavors
.getLength() )
526 // for any reason the object could not provide this information
527 // try to get access to the cached representation
533 bool OleComponent::InitializeObject_Impl()
534 // There will be no static objects!
536 if ( !m_pNativeImpl
->m_pObj
)
539 // the linked object will be detected here
540 OSL_ENSURE( m_pUnoOleObject
, "Unexpected object absence!" );
541 if ( m_pUnoOleObject
)
542 m_pUnoOleObject
->SetObjectIsLink_Impl( m_pNativeImpl
->m_pObj
.QueryInterface
<IOleLink
>(sal::systools::COM_QUERY
).is() );
544 if ( !m_pNativeImpl
->m_pViewObject2
.set(m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
) )
547 // remove all the caches
548 if ( sal::systools::COMReference
< IOleCache
> pIOleCache
{ m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
} )
550 IEnumSTATDATA
* pEnumSD
= nullptr;
551 HRESULT hr2
= pIOleCache
->EnumCache( &pEnumSD
);
553 if ( SUCCEEDED( hr2
) && pEnumSD
)
558 while( SUCCEEDED( pEnumSD
->Next( 1, &aSD
, &nNum
) ) && nNum
== 1 )
559 hr2
= pIOleCache
->Uncache( aSD
.dwConnection
);
562 // No IDataObject implementation, caching must be used instead
564 FORMATETC aFormat
= { 0, nullptr, DVASPECT_CONTENT
, -1, TYMED_MFPICT
};
565 hr2
= pIOleCache
->Cache( &aFormat
, ADVFCACHE_ONSAVE
, &nConn
);
568 if ( !m_pNativeImpl
->m_pOleObject
.set(m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
) )
569 return false; // Static objects are not supported, they should be inserted as graphics
571 m_pNativeImpl
->m_pOleObject
->GetMiscStatus( DVASPECT_CONTENT
, reinterpret_cast<DWORD
*>(&m_nOLEMiscFlags
) );
572 // TODO: use other misc flags also
573 // the object should have drawable aspect even in case it supports only iconic representation
574 // if ( m_nOLEMiscFlags & OLEMISC_ONLYICONIC )
576 m_pNativeImpl
->m_pOleObject
->SetClientSite( m_pOleWrapClientSite
);
578 // the only need in this registration is workaround for close notification
579 m_pNativeImpl
->m_pOleObject
->Advise( m_pImplAdviseSink
, reinterpret_cast<DWORD
*>(&m_nAdvConn
) );
580 m_pNativeImpl
->m_pViewObject2
->SetAdvise( DVASPECT_CONTENT
, 0, m_pImplAdviseSink
);
582 OleSetContainedObject( m_pNativeImpl
->m_pOleObject
, TRUE
);
589 HRESULT
OleLoadSeh(LPSTORAGE pIStorage
, LPVOID
* ppObj
)
592 // tdf#119039: there is a nasty bug in OleLoad, that may call an unpaired
593 // IUnknown::Release on pIStorage on STG_E_FILENOTFOUND: see
594 // https://developercommunity.visualstudio.com/t/10144795
595 // Workaround it here to avoid crash in smart COM pointer destructor that
596 // would try to release already released object. Since we don't know if
597 // the bug appears each time STG_E_FILENOTFOUND is returned, this might
598 // potentially leak the storage object.
603 hr
= OleLoad(pIStorage
, IID_IUnknown
, nullptr, ppObj
);
604 } __except( EXCEPTION_EXECUTE_HANDLER
) {
607 if (pIStorage
&& hr
!= STG_E_FILENOTFOUND
)
608 pIStorage
->Release();
614 void OleComponent::LoadEmbeddedObject( const OUString
& aTempURL
)
616 if ( !aTempURL
.getLength() )
617 throw lang::IllegalArgumentException(); // TODO
619 if ( m_pNativeImpl
->m_pIStorage
)
620 throw io::IOException(); // TODO the object is already initialized or wrong initialization is done
622 // open an IStorage based on the temporary file
623 HRESULT hr
= OpenIStorageFromURL_Impl( aTempURL
, &m_pNativeImpl
->m_pIStorage
);
625 if ( FAILED( hr
) || !m_pNativeImpl
->m_pIStorage
)
626 throw io::IOException(); // TODO: transport error code?
628 hr
= OleLoadSeh(m_pNativeImpl
->m_pIStorage
, reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
));
629 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
631 throw uno::RuntimeException();
634 if ( !InitializeObject_Impl() )
635 throw uno::RuntimeException(); // TODO
639 void OleComponent::CreateObjectFromClipboard()
641 if ( m_pNativeImpl
->m_pIStorage
)
642 throw io::IOException(); // TODO:the object is already initialized
644 CreateNewIStorage_Impl();
645 if ( !m_pNativeImpl
->m_pIStorage
)
646 throw uno::RuntimeException(); // TODO
648 IDataObject
* pDO
= nullptr;
649 HRESULT hr
= OleGetClipboard( &pDO
);
650 if( SUCCEEDED( hr
) && pDO
)
652 hr
= OleQueryCreateFromData( pDO
);
653 if( S_OK
== GetScode( hr
) )
655 hr
= OleCreateFromData( pDO
,
657 OLERENDER_DRAW
, // OLERENDER_FORMAT
658 nullptr, // &aFormat,
660 m_pNativeImpl
->m_pIStorage
,
661 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
665 // Static objects are not supported
670 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
671 throw uno::RuntimeException();
673 if ( !InitializeObject_Impl() )
674 throw uno::RuntimeException(); // TODO
678 void OleComponent::CreateNewEmbeddedObject( const uno::Sequence
< sal_Int8
>& aSeqCLSID
)
682 if ( !GetClassIDFromSequence_Impl( aSeqCLSID
, aClsID
) )
683 throw lang::IllegalArgumentException(); // TODO
685 if ( m_pNativeImpl
->m_pIStorage
)
686 throw io::IOException(); // TODO:the object is already initialized
688 CreateNewIStorage_Impl();
689 if ( !m_pNativeImpl
->m_pIStorage
)
690 throw uno::RuntimeException(); // TODO
692 // FORMATETC aFormat = { CF_METAFILEPICT, NULL, nAspect, -1, TYMED_MFPICT }; // for OLE..._DRAW should be NULL
694 HRESULT hr
= OleCreate( aClsID
,
696 OLERENDER_DRAW
, // OLERENDER_FORMAT
697 nullptr, // &aFormat,
699 m_pNativeImpl
->m_pIStorage
,
700 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
702 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
703 throw uno::RuntimeException(); // TODO
705 if ( !InitializeObject_Impl() )
706 throw uno::RuntimeException(); // TODO
708 // TODO: getExtent???
712 void OleComponent::CreateObjectFromData( const uno::Reference
< datatransfer::XTransferable
>& )
713 // Static objects are not supported, they should be inserted as graphics
715 // TODO: May be this call is useless since there are no static objects
716 // and nonstatic objects will be created based on OLEstorage ( stream ).
719 // OleQueryCreateFromData...
723 void OleComponent::CreateObjectFromFile( const OUString
& aFileURL
)
725 if ( m_pNativeImpl
->m_pIStorage
)
726 throw io::IOException(); // TODO:the object is already initialized
728 CreateNewIStorage_Impl();
729 if ( !m_pNativeImpl
->m_pIStorage
)
730 throw uno::RuntimeException(); // TODO:
733 if ( ::osl::FileBase::getSystemPathFromFileURL( aFileURL
, aFilePath
) != ::osl::FileBase::E_None
)
734 throw uno::RuntimeException(); // TODO: something dangerous happened
736 HRESULT hr
= OleCreateFromFile( CLSID_NULL
,
737 o3tl::toW(aFilePath
.getStr()),
739 OLERENDER_DRAW
, // OLERENDER_FORMAT
742 m_pNativeImpl
->m_pIStorage
,
743 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
745 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
746 throw uno::RuntimeException(); // TODO
748 if ( !InitializeObject_Impl() )
749 throw uno::RuntimeException(); // TODO
753 void OleComponent::CreateLinkFromFile( const OUString
& aFileURL
)
755 if ( m_pNativeImpl
->m_pIStorage
)
756 throw io::IOException(); // TODO:the object is already initialized
758 CreateNewIStorage_Impl();
759 if ( !m_pNativeImpl
->m_pIStorage
)
760 throw uno::RuntimeException(); // TODO:
763 if ( ::osl::FileBase::getSystemPathFromFileURL( aFileURL
, aFilePath
) != ::osl::FileBase::E_None
)
764 throw uno::RuntimeException(); // TODO: something dangerous happened
766 HRESULT hr
= OleCreateLinkToFile( o3tl::toW(aFilePath
.getStr()),
768 OLERENDER_DRAW
, // OLERENDER_FORMAT
771 m_pNativeImpl
->m_pIStorage
,
772 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
774 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
775 throw uno::RuntimeException(); // TODO
777 if ( !InitializeObject_Impl() )
778 throw uno::RuntimeException(); // TODO
782 void OleComponent::InitEmbeddedCopyOfLink( rtl::Reference
<OleComponent
> const & pOleLinkComponent
)
784 if ( !pOleLinkComponent
|| !pOleLinkComponent
->m_pNativeImpl
->m_pObj
)
785 throw lang::IllegalArgumentException(); // TODO
787 if ( m_pNativeImpl
->m_pIStorage
)
788 throw io::IOException(); // TODO:the object is already initialized
790 sal::systools::COMReference
< IDataObject
> pDataObject(pOleLinkComponent
->m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
);
791 if ( pDataObject
&& SUCCEEDED( OleQueryCreateFromData( pDataObject
) ) )
793 // the object must be already disconnected from the temporary URL
794 CreateNewIStorage_Impl();
795 if ( !m_pNativeImpl
->m_pIStorage
)
796 throw uno::RuntimeException(); // TODO:
798 OleCreateFromData( pDataObject
,
803 m_pNativeImpl
->m_pIStorage
,
804 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
807 if ( !m_pNativeImpl
->m_pObj
)
809 sal::systools::COMReference
< IOleLink
> pOleLink(m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
);
811 throw io::IOException(); // TODO: the object doesn't support IOleLink
813 sal::systools::COMReference
< IMoniker
> pMoniker
;
814 HRESULT hr
= pOleLink
->GetSourceMoniker( &pMoniker
);
815 if ( FAILED( hr
) || !pMoniker
)
816 throw io::IOException(); // TODO: can not retrieve moniker
818 // In case of file moniker life is easy : )
820 hr
= pMoniker
->IsSystemMoniker( &aMonType
);
821 if ( SUCCEEDED( hr
) && aMonType
== MKSYS_FILEMONIKER
)
823 sal::systools::COMReference
< IMalloc
> pMalloc
;
824 hr
= CoGetMalloc( 1, &pMalloc
); // if fails there will be a memory leak
825 OSL_ENSURE(SUCCEEDED(hr
) && pMalloc
, "CoGetMalloc() failed!");
827 LPOLESTR pOleStr
= nullptr;
828 hr
= pOleLink
->GetSourceDisplayName( &pOleStr
);
829 if ( SUCCEEDED( hr
) && pOleStr
)
831 std::wstring
aFilePath( pOleStr
);
833 pMalloc
->Free( pOleStr
);
835 hr
= OleCreateFromFile( CLSID_NULL
,
838 OLERENDER_DRAW
, // OLERENDER_FORMAT
841 m_pNativeImpl
->m_pIStorage
,
842 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
846 // in case of other moniker types the only way is to get storage
847 if ( !m_pNativeImpl
->m_pObj
)
849 sal::systools::COMReference
< IBindCtx
> pBindCtx
;
850 hr
= CreateBindCtx( 0, &pBindCtx
);
851 if ( SUCCEEDED( hr
) && pBindCtx
)
853 sal::systools::COMReference
< IStorage
> pObjectStorage
;
854 hr
= pMoniker
->BindToStorage( pBindCtx
, nullptr, IID_IStorage
, reinterpret_cast<void**>(&pObjectStorage
) );
855 if ( SUCCEEDED( hr
) && pObjectStorage
)
857 hr
= pObjectStorage
->CopyTo( 0, nullptr, nullptr, m_pNativeImpl
->m_pIStorage
);
858 if ( SUCCEEDED( hr
) )
859 hr
= OleLoadSeh(m_pNativeImpl
->m_pIStorage
, reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
));
865 // If object could not be created the only way is to use graphical representation
866 if ( !m_pNativeImpl
->m_pObj
)
867 throw uno::RuntimeException(); // TODO
869 if ( !InitializeObject_Impl() )
870 throw uno::RuntimeException(); // TODO
874 void OleComponent::RunObject()
876 OSL_ENSURE( m_pNativeImpl
->m_pOleObject
, "The pointer can not be set to NULL here!" );
877 if ( !m_pNativeImpl
->m_pOleObject
)
878 throw embed::WrongStateException(); // TODO: the object is in wrong state
880 if ( !OleIsRunning( m_pNativeImpl
->m_pOleObject
) )
882 HRESULT hr
= OleRun( m_pNativeImpl
->m_pObj
);
886 if ( hr
== REGDB_E_CLASSNOTREG
)
887 throw embed::UnreachableStateException(); // the object server is not installed
889 throw io::IOException();
895 awt::Size
OleComponent::CalculateWithFactor( const awt::Size
& aSize
,
896 const awt::Size
& aMultiplier
,
897 const awt::Size
& aDivisor
)
901 sal_Int64 nWidth
= static_cast<sal_Int64
>(aSize
.Width
) * static_cast<sal_Int64
>(aMultiplier
.Width
) / static_cast<sal_Int64
>(aDivisor
.Width
);
902 sal_Int64 nHeight
= static_cast<sal_Int64
>(aSize
.Height
) * static_cast<sal_Int64
>(aMultiplier
.Height
) / static_cast<sal_Int64
>(aDivisor
.Height
);
903 OSL_ENSURE( nWidth
< SAL_MAX_INT32
&& nWidth
> SAL_MIN_INT32
904 && nHeight
< SAL_MAX_INT32
&& nHeight
> SAL_MIN_INT32
,
905 "Unacceptable result size!" );
907 aResult
.Width
= static_cast<sal_Int32
>(nWidth
);
908 aResult
.Height
= static_cast<sal_Int32
>(nHeight
);
914 void OleComponent::CloseObject()
916 if ( m_pNativeImpl
->m_pOleObject
&& OleIsRunning( m_pNativeImpl
->m_pOleObject
) )
917 m_pNativeImpl
->m_pOleObject
->Close( OLECLOSE_NOSAVE
); // must be saved before
921 uno::Sequence
< embed::VerbDescriptor
> OleComponent::GetVerbList()
923 if ( !m_pNativeImpl
->m_pOleObject
)
924 throw embed::WrongStateException(); // TODO: the object is in wrong state
926 if( !m_aVerbList
.getLength() )
928 sal::systools::COMReference
< IEnumOLEVERB
> pEnum
;
929 if( SUCCEEDED( m_pNativeImpl
->m_pOleObject
->EnumVerbs( &pEnum
) ) )
931 OLEVERB szEle
[ MAX_ENUM_ELE
];
933 sal_Int32 nSeqSize
= 0;
937 HRESULT hr
= pEnum
->Next( MAX_ENUM_ELE
, szEle
, &nNum
);
938 if( hr
== S_OK
|| hr
== S_FALSE
)
940 m_aVerbList
.realloc( nSeqSize
+= nNum
);
941 auto pVerbList
= m_aVerbList
.getArray();
942 for( sal_uInt32 nInd
= 0; nInd
< nNum
; nInd
++ )
944 pVerbList
[nSeqSize
-nNum
+nInd
].VerbID
= szEle
[ nInd
].lVerb
;
945 pVerbList
[nSeqSize
-nNum
+nInd
].VerbName
= WinAccToVcl_Impl( o3tl::toU(szEle
[ nInd
].lpszVerbName
) );
946 pVerbList
[nSeqSize
-nNum
+nInd
].VerbFlags
= szEle
[ nInd
].fuFlags
;
947 pVerbList
[nSeqSize
-nNum
+nInd
].VerbAttributes
= szEle
[ nInd
].grfAttribs
;
953 while( nNum
== MAX_ENUM_ELE
);
961 void OleComponent::ExecuteVerb( sal_Int32 nVerbID
)
963 if ( !m_pNativeImpl
->m_pOleObject
)
964 throw embed::WrongStateException(); // TODO
966 HRESULT hr
= OleRun( m_pNativeImpl
->m_pOleObject
);
968 throw io::IOException(); // TODO: a specific exception that transport error code can be thrown here
970 // TODO: probably extents should be set here and stored in aRect
971 // TODO: probably the parent window also should be set
972 hr
= m_pNativeImpl
->m_pOleObject
->DoVerb( nVerbID
, nullptr, m_pOleWrapClientSite
, 0, nullptr, nullptr );
975 throw io::IOException(); // TODO
979 void OleComponent::SetHostName( const OUString
& aEmbDocName
)
981 if ( !m_pNativeImpl
->m_pOleObject
)
982 throw embed::WrongStateException(); // TODO: the object is in wrong state
984 m_pNativeImpl
->m_pOleObject
->SetHostNames( L
"app name", o3tl::toW( aEmbDocName
.getStr() ) );
988 void OleComponent::SetExtent( const awt::Size
& aVisAreaSize
, sal_Int64 nAspect
)
990 if ( !m_pNativeImpl
->m_pOleObject
)
991 throw embed::WrongStateException(); // TODO: the object is in wrong state
993 DWORD nMSAspect
= static_cast<DWORD
>(nAspect
); // first 32 bits are for MS aspects
995 SIZEL aSize
= { aVisAreaSize
.Width
, aVisAreaSize
.Height
};
996 HRESULT hr
= m_pNativeImpl
->m_pOleObject
->SetExtent( nMSAspect
, &aSize
);
1000 // TODO/LATER: is it correct? In future user code probably should be ready for the exception.
1001 // if the object is running but not activated, RPC_E_SERVER_DIED error code is returned by OLE package
1002 // in this case just do nothing
1003 // Also Visio returns E_FAIL on resize if it is in running state
1004 // if ( hr != RPC_E_SERVER_DIED )
1005 throw io::IOException(); // TODO
1010 awt::Size
OleComponent::GetExtent( sal_Int64 nAspect
)
1012 if ( !m_pNativeImpl
->m_pOleObject
)
1013 throw embed::WrongStateException(); // TODO: the object is in wrong state
1015 DWORD nMSAspect
= static_cast<DWORD
>(nAspect
); // first 32 bits are for MS aspects
1017 bool bGotSize
= false;
1019 if ( nMSAspect
== DVASPECT_CONTENT
)
1021 // Try to get the size from the replacement image first
1022 sal::systools::COMReference
< IDataObject
> pDataObject(m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
);
1026 FORMATETC aFormat
= pFormatTemplates
[1]; // use windows metafile format
1027 aFormat
.dwAspect
= nMSAspect
;
1029 HRESULT hr
= pDataObject
->GetData( &aFormat
, &aMedium
);
1031 if (hr
== RPC_E_WRONG_THREAD
)
1033 // Assume that the OLE object was loaded on the main thread.
1034 vcl::solarthread::syncExecute([this, &hr
, &pDataObject
, &aFormat
, &aMedium
]() {
1035 // Make sure that the current state is embed::EmbedStates::RUNNING.
1037 // Now try again on the correct thread.
1038 hr
= pDataObject
->GetData(&aFormat
, &aMedium
);
1042 if ( SUCCEEDED( hr
) && aMedium
.tymed
== TYMED_MFPICT
) // Win Metafile
1044 METAFILEPICT
* pMF
= static_cast<METAFILEPICT
*>(GlobalLock( aMedium
.hMetaFilePict
));
1047 // the object uses 0.01 mm as unit, so the metafile size should be converted to object unit
1048 o3tl::Length eFrom
= o3tl::Length::mm100
;
1052 eFrom
= o3tl::Length::in1000
;
1056 eFrom
= o3tl::Length::in100
;
1060 eFrom
= o3tl::Length::mm10
;
1064 eFrom
= o3tl::Length::twip
;
1068 case MM_ANISOTROPIC
:
1074 sal_Int64 nX
= o3tl::convert(abs( pMF
->xExt
), eFrom
, o3tl::Length::mm100
);
1075 sal_Int64 nY
= o3tl::convert(abs( pMF
->yExt
), eFrom
, o3tl::Length::mm100
);
1076 if ( nX
< SAL_MAX_INT32
&& nY
< SAL_MAX_INT32
)
1078 aSize
.Width
= static_cast<sal_Int32
>(nX
);
1079 aSize
.Height
= static_cast<sal_Int32
>(nY
);
1083 OSL_FAIL( "Unexpected size is provided!" );
1086 else if (!SUCCEEDED(hr
))
1088 SAL_WARN("embeddedobj.ole", " OleComponent::GetExtent: GetData() failed");
1090 // i113605, to release storage medium
1091 if ( SUCCEEDED( hr
) )
1092 ::ReleaseStgMedium(&aMedium
);
1097 throw lang::IllegalArgumentException();
1103 awt::Size
OleComponent::GetCachedExtent( sal_Int64 nAspect
)
1105 if ( !m_pNativeImpl
->m_pOleObject
)
1106 throw embed::WrongStateException(); // TODO: the object is in wrong state
1108 DWORD nMSAspect
= static_cast<DWORD
>(nAspect
); // first 32 bits are for MS aspects
1111 HRESULT hr
= m_pNativeImpl
->m_pViewObject2
->GetExtent( nMSAspect
, -1, nullptr, &aSize
);
1115 // TODO/LATER: is it correct?
1116 // if there is no appropriate cache for the aspect, OLE_E_BLANK error code is returned
1117 // if ( hr == OLE_E_BLANK )
1118 // throw lang::IllegalArgumentException();
1120 // throw io::IOException(); // TODO
1122 SAL_WARN("embeddedobj.ole", " OleComponent::GetCachedExtent: GetExtent() failed");
1123 throw lang::IllegalArgumentException();
1126 return awt::Size( aSize
.cx
, aSize
.cy
);
1130 awt::Size
OleComponent::GetRecommendedExtent( sal_Int64 nAspect
)
1132 if ( !m_pNativeImpl
->m_pOleObject
)
1133 throw embed::WrongStateException(); // TODO: the object is in wrong state
1135 DWORD nMSAspect
= static_cast<DWORD
>(nAspect
); // first 32 bits are for MS aspects
1137 HRESULT hr
= m_pNativeImpl
->m_pOleObject
->GetExtent( nMSAspect
, &aSize
);
1140 SAL_WARN("embeddedobj.ole", " OleComponent::GetRecommendedExtent: GetExtent() failed");
1141 throw lang::IllegalArgumentException();
1144 return awt::Size( aSize
.cx
, aSize
.cy
);
1148 sal_Int64
OleComponent::GetMiscStatus( sal_Int64 nAspect
)
1150 if ( !m_pNativeImpl
->m_pOleObject
)
1151 throw embed::WrongStateException(); // TODO: the object is in wrong state
1154 m_pNativeImpl
->m_pOleObject
->GetMiscStatus( static_cast<DWORD
>(nAspect
), &nResult
);
1155 return static_cast<sal_Int64
>(nResult
); // first 32 bits are for MS flags
1159 uno::Sequence
< sal_Int8
> OleComponent::GetCLSID()
1161 if ( !m_pNativeImpl
->m_pOleObject
)
1162 throw embed::WrongStateException(); // TODO: the object is in wrong state
1165 HRESULT hr
= m_pNativeImpl
->m_pOleObject
->GetUserClassID( &aCLSID
);
1167 throw io::IOException(); // TODO:
1169 return MimeConfigurationHelper::GetSequenceClassID( aCLSID
.Data1
, aCLSID
.Data2
, aCLSID
.Data3
,
1170 aCLSID
.Data4
[0], aCLSID
.Data4
[1],
1171 aCLSID
.Data4
[2], aCLSID
.Data4
[3],
1172 aCLSID
.Data4
[4], aCLSID
.Data4
[5],
1173 aCLSID
.Data4
[6], aCLSID
.Data4
[7] );
1177 bool OleComponent::IsDirty()
1179 if ( !m_pNativeImpl
->m_pOleObject
)
1180 throw embed::WrongStateException(); // TODO: the object is in wrong state
1182 if ( IsWorkaroundActive() )
1185 sal::systools::COMReference
< IPersistStorage
> pPersistStorage(m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
);
1186 if ( !pPersistStorage
)
1187 throw io::IOException(); // TODO
1189 HRESULT hr
= pPersistStorage
->IsDirty();
1190 return ( hr
!= S_FALSE
);
1194 void OleComponent::StoreOwnTmpIfNecessary()
1196 if ( !m_pNativeImpl
->m_pOleObject
)
1197 throw embed::WrongStateException(); // TODO: the object is in wrong state
1199 sal::systools::COMReference
< IPersistStorage
> pPersistStorage(m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
);
1200 if ( !pPersistStorage
)
1201 throw io::IOException(); // TODO
1203 if ( m_bWorkaroundActive
|| pPersistStorage
->IsDirty() != S_FALSE
)
1205 HRESULT hr
= OleSave( pPersistStorage
, m_pNativeImpl
->m_pIStorage
, TRUE
);
1208 // Till now was required only for AcrobatReader7.0.8
1210 hr
= m_pNativeImpl
->m_pOleObject
->GetUserClassID( &aCLSID
);
1213 SAL_WARN("embeddedobj.ole", "OleComponent::StoreOwnTmpIfNecessary: GetUserClassID() failed");
1214 throw io::IOException(); // TODO
1217 hr
= WriteClassStg( m_pNativeImpl
->m_pIStorage
, aCLSID
);
1219 throw io::IOException(); // TODO
1221 // the result of the following call is not checked because some objects, for example AcrobatReader7.0.8
1222 // return error even in case the saving was done correctly
1223 hr
= pPersistStorage
->Save( m_pNativeImpl
->m_pIStorage
, TRUE
);
1225 // another workaround for AcrobatReader7.0.8 object, this object might think that it is not changed
1226 // when it has been created from file, although it must be saved
1227 m_bWorkaroundActive
= true;
1230 hr
= m_pNativeImpl
->m_pIStorage
->Commit( STGC_DEFAULT
);
1232 throw io::IOException(); // TODO
1234 hr
= pPersistStorage
->SaveCompleted( nullptr );
1235 if ( FAILED( hr
) && hr
!= E_UNEXPECTED
)
1236 throw io::IOException(); // TODO
1242 bool OleComponent::SaveObject_Impl()
1244 bool bResult
= false;
1245 OleEmbeddedObject
* pLockObject
= nullptr;
1248 osl::MutexGuard
aGuard( m_aMutex
);
1249 if ( m_pUnoOleObject
)
1251 pLockObject
= m_pUnoOleObject
;
1252 pLockObject
->acquire();
1258 bResult
= pLockObject
->SaveObject_Impl();
1259 pLockObject
->release();
1266 bool OleComponent::OnShowWindow_Impl( bool bShow
)
1268 bool bResult
= false;
1269 OleEmbeddedObject
* pLockObject
= nullptr;
1272 osl::MutexGuard
aGuard( m_aMutex
);
1274 if ( m_pUnoOleObject
)
1276 pLockObject
= m_pUnoOleObject
;
1277 pLockObject
->acquire();
1283 bResult
= pLockObject
->OnShowWindow_Impl( bShow
);
1284 pLockObject
->release();
1291 void OleComponent::OnViewChange_Impl( sal_uInt32 dwAspect
)
1293 // TODO: check if it is enough or may be saving notifications are required for Visio2000
1294 ::rtl::Reference
< OleEmbeddedObject
> xLockObject
;
1297 osl::MutexGuard
aGuard( m_aMutex
);
1298 if ( m_pUnoOleObject
)
1299 xLockObject
= m_pUnoOleObject
;
1302 if ( xLockObject
.is() )
1304 uno::Reference
< awt::XRequestCallback
> xRequestCallback(
1305 m_xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.awt.AsyncCallback", m_xContext
),
1307 xRequestCallback
->addCallback( new MainThreadNotificationRequest( xLockObject
, OLECOMP_ONVIEWCHANGE
, dwAspect
), uno::Any() );
1312 void OleComponent::OnClose_Impl()
1314 ::rtl::Reference
< OleEmbeddedObject
> xLockObject
;
1317 osl::MutexGuard
aGuard( m_aMutex
);
1318 if ( m_pUnoOleObject
)
1319 xLockObject
= m_pUnoOleObject
;
1322 if ( xLockObject
.is() )
1324 uno::Reference
< awt::XRequestCallback
> xRequestCallback(
1325 m_xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.awt.AsyncCallback", m_xContext
),
1327 xRequestCallback
->addCallback( new MainThreadNotificationRequest( xLockObject
, OLECOMP_ONCLOSE
), uno::Any() );
1333 void SAL_CALL
OleComponent::close( sal_Bool bDeliverOwnership
)
1335 uno::Reference
< uno::XInterface
> xSelfHold
;
1337 osl::MutexGuard
aGuard(m_aMutex
);
1339 throw lang::DisposedException(); // TODO
1341 xSelfHold
.set(static_cast<::cppu::OWeakObject
*>(this));
1342 lang::EventObject
aSource(static_cast<::cppu::OWeakObject
*>(this));
1344 if (m_pInterfaceContainer
)
1346 comphelper::OInterfaceContainerHelper2
* pContainer
1347 = m_pInterfaceContainer
->getContainer(cppu::UnoType
<util::XCloseListener
>::get());
1348 if (pContainer
!= nullptr)
1350 comphelper::OInterfaceIteratorHelper2
pIterator(*pContainer
);
1351 while (pIterator
.hasMoreElements())
1355 static_cast<util::XCloseListener
*>(pIterator
.next())
1356 ->queryClosing(aSource
, bDeliverOwnership
);
1358 catch (const uno::RuntimeException
&)
1366 = m_pInterfaceContainer
->getContainer(cppu::UnoType
<util::XCloseListener
>::get());
1367 if (pContainer
!= nullptr)
1369 comphelper::OInterfaceIteratorHelper2
pCloseIterator(*pContainer
);
1370 while (pCloseIterator
.hasMoreElements())
1374 static_cast<util::XCloseListener
*>(pCloseIterator
.next())
1375 ->notifyClosing(aSource
);
1377 catch (const uno::RuntimeException
&)
1379 pCloseIterator
.remove();
1390 void SAL_CALL
OleComponent::addCloseListener( const uno::Reference
< util::XCloseListener
>& xListener
)
1392 ::osl::MutexGuard
aGuard( m_aMutex
);
1394 throw lang::DisposedException(); // TODO
1396 if ( !m_pInterfaceContainer
)
1397 m_pInterfaceContainer
= new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex
);
1399 m_pInterfaceContainer
->addInterface( cppu::UnoType
<util::XCloseListener
>::get(), xListener
);
1403 void SAL_CALL
OleComponent::removeCloseListener( const uno::Reference
< util::XCloseListener
>& xListener
)
1405 ::osl::MutexGuard
aGuard( m_aMutex
);
1407 throw lang::DisposedException(); // TODO
1409 if ( m_pInterfaceContainer
)
1410 m_pInterfaceContainer
->removeInterface( cppu::UnoType
<util::XCloseListener
>::get(),
1416 uno::Any SAL_CALL
OleComponent::getTransferData( const datatransfer::DataFlavor
& aFlavor
)
1418 ::osl::MutexGuard
aGuard( m_aMutex
);
1420 throw lang::DisposedException(); // TODO
1422 if ( !m_pNativeImpl
->m_pOleObject
)
1423 throw embed::WrongStateException(); // TODO: the object is in wrong state
1426 bool bSupportedFlavor
= false;
1428 if ( m_pNativeImpl
->GraphicalFlavor( aFlavor
) )
1430 DWORD nRequestedAspect
= GetAspectFromFlavor( aFlavor
);
1431 // if own icon is set and icon aspect is requested the own icon can be returned directly
1433 sal::systools::COMReference
< IDataObject
> pDataObject(m_pNativeImpl
->m_pObj
, sal::systools::COM_QUERY
);
1435 throw io::IOException(); // TODO: transport error code
1437 // The following optimization does not make much sense currently just because
1438 // only one aspect is supported, and only three formats for the aspect are supported
1439 // and moreover it is not guaranteed that the once returned format will be supported further
1441 // TODO/LATER: bring the optimization back when other aspects are supported
1443 // FORMATETC* pFormatEtc = m_pNativeImpl->GetSupportedFormatForAspect( nRequestedAspect );
1444 // if ( pFormatEtc )
1446 // STGMEDIUM aMedium;
1447 // hr = pDataObject->GetData( pFormatEtc, &aMedium );
1448 // if ( SUCCEEDED( hr ) )
1449 // bSupportedFlavor = m_pNativeImpl->ConvertDataForFlavor( aMedium, aFlavor, aResult );
1453 // the supported format of the application is still not found, find one
1454 for ( sal_Int32 nInd
= 0; nInd
< FORMATS_NUM
; nInd
++ )
1457 FORMATETC aFormat
= pFormatTemplates
[nInd
];
1458 aFormat
.dwAspect
= nRequestedAspect
;
1460 HRESULT hr
= pDataObject
->GetData( &aFormat
, &aMedium
);
1461 if ( SUCCEEDED( hr
) )
1463 bSupportedFlavor
= m_pNativeImpl
->ConvertDataForFlavor( aMedium
, aFlavor
, aResult
);
1464 ::ReleaseStgMedium(&aMedium
); // i113605, to release storage medium
1465 if ( bSupportedFlavor
)
1467 // TODO/LATER: bring the optimization back when other aspects are supported
1468 // m_pNativeImpl->AddSupportedFormat( aFormat );
1475 // If the replacement could not be retrieved, the cached representation should be used
1476 // currently it is not necessary to retrieve it here, so it is implemented in the object itself
1478 // TODO: Investigate if there is already the format name
1479 // and whether this format is really required
1480 else if ( aFlavor
.DataType
== cppu::UnoType
<io::XInputStream
>::get()
1481 && aFlavor
.MimeType
== "application/x-openoffice-contentstream" )
1483 // allow to retrieve stream-representation of the object persistence
1484 bSupportedFlavor
= true;
1485 uno::Reference
< io::XStream
> xTempFileStream(
1486 io::TempFile::create(m_xContext
),
1487 uno::UNO_QUERY_THROW
);
1489 uno::Reference
< io::XOutputStream
> xTempOutStream
= xTempFileStream
->getOutputStream();
1490 uno::Reference
< io::XInputStream
> xTempInStream
= xTempFileStream
->getInputStream();
1491 if ( !(xTempOutStream
.is() && xTempInStream
.is()) )
1492 throw io::IOException(); // TODO:
1494 OSL_ENSURE( m_pUnoOleObject
, "Unexpected object absence!" );
1495 if ( !m_pUnoOleObject
)
1496 throw uno::RuntimeException();
1498 m_pUnoOleObject
->StoreObjectToStream( xTempOutStream
);
1500 xTempOutStream
->closeOutput();
1501 xTempOutStream
.clear();
1503 aResult
<<= xTempInStream
;
1506 if ( !bSupportedFlavor
)
1507 throw datatransfer::UnsupportedFlavorException();
1513 uno::Sequence
< datatransfer::DataFlavor
> SAL_CALL
OleComponent::getTransferDataFlavors()
1515 ::osl::MutexGuard
aGuard( m_aMutex
);
1517 throw lang::DisposedException(); // TODO
1519 if ( !m_pNativeImpl
->m_pOleObject
)
1520 throw embed::WrongStateException(); // TODO: the object is in wrong state
1522 RetrieveObjectDataFlavors_Impl();
1524 return m_aDataFlavors
;
1528 sal_Bool SAL_CALL
OleComponent::isDataFlavorSupported( const datatransfer::DataFlavor
& aFlavor
)
1530 ::osl::MutexGuard
aGuard( m_aMutex
);
1532 throw lang::DisposedException(); // TODO
1534 if ( !m_pNativeImpl
->m_pOleObject
)
1535 throw embed::WrongStateException(); // TODO: the object is in wrong state
1537 if ( !m_aDataFlavors
.getLength() )
1539 RetrieveObjectDataFlavors_Impl();
1542 for ( auto const & supportedFormat
: std::as_const(m_aDataFlavors
) )
1543 if ( supportedFormat
.MimeType
.equals( aFlavor
.MimeType
) && supportedFormat
.DataType
== aFlavor
.DataType
)
1549 void SAL_CALL
OleComponent::dispose()
1555 catch ( const uno::Exception
& )
1560 void SAL_CALL
OleComponent::addEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
1562 ::osl::MutexGuard
aGuard( m_aMutex
);
1564 throw lang::DisposedException(); // TODO
1566 if ( !m_pInterfaceContainer
)
1567 m_pInterfaceContainer
= new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex
);
1569 m_pInterfaceContainer
->addInterface( cppu::UnoType
<lang::XEventListener
>::get(), xListener
);
1573 void SAL_CALL
OleComponent::removeEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
1575 ::osl::MutexGuard
aGuard( m_aMutex
);
1577 throw lang::DisposedException(); // TODO
1579 if ( m_pInterfaceContainer
)
1580 m_pInterfaceContainer
->removeInterface( cppu::UnoType
<lang::XEventListener
>::get(),
1584 sal_Int64 SAL_CALL
OleComponent::getSomething( const css::uno::Sequence
< sal_Int8
>& aIdentifier
)
1588 uno::Sequence
< sal_Int8
> aCLSID
= GetCLSID();
1589 if ( MimeConfigurationHelper::ClassIDsEqual( aIdentifier
, aCLSID
) )
1590 return comphelper::getSomething_cast(static_cast<IUnknown
*>(m_pNativeImpl
->m_pObj
));
1592 // compatibility hack for old versions: CLSID was used in wrong order (SvGlobalName order)
1593 sal_Int32 nLength
= aIdentifier
.getLength();
1594 if ( nLength
== 16 )
1596 for ( sal_Int32 n
=8; n
<16; n
++ )
1597 if ( aIdentifier
[n
] != aCLSID
[n
] )
1599 if ( aIdentifier
[7] == aCLSID
[6] &&
1600 aIdentifier
[6] == aCLSID
[7] &&
1601 aIdentifier
[5] == aCLSID
[4] &&
1602 aIdentifier
[4] == aCLSID
[5] &&
1603 aIdentifier
[3] == aCLSID
[0] &&
1604 aIdentifier
[2] == aCLSID
[1] &&
1605 aIdentifier
[1] == aCLSID
[2] &&
1606 aIdentifier
[0] == aCLSID
[3] )
1607 return reinterpret_cast<sal_Int64
>(static_cast<IUnknown
*>(m_pNativeImpl
->m_pObj
));
1610 catch ( const uno::Exception
& )
1617 sal_Bool SAL_CALL
OleComponent::isModified()
1622 void SAL_CALL
OleComponent::setModified( sal_Bool bModified
)
1624 m_bModified
= bModified
;
1626 if ( bModified
&& m_pInterfaceContainer
)
1628 comphelper::OInterfaceContainerHelper2
* pContainer
=
1629 m_pInterfaceContainer
->getContainer( cppu::UnoType
<util::XModifyListener
>::get());
1630 if ( pContainer
!= nullptr )
1632 comphelper::OInterfaceIteratorHelper2
pIterator( *pContainer
);
1633 while ( pIterator
.hasMoreElements() )
1637 lang::EventObject
aEvent( static_cast<util::XModifiable
*>(this) );
1638 static_cast<util::XModifyListener
*>(pIterator
.next())->modified( aEvent
);
1640 catch( const uno::RuntimeException
& )
1649 void SAL_CALL
OleComponent::addModifyListener( const css::uno::Reference
< css::util::XModifyListener
>& xListener
)
1651 ::osl::MutexGuard
aGuard( m_aMutex
);
1653 throw lang::DisposedException(); // TODO
1655 if ( !m_pInterfaceContainer
)
1656 m_pInterfaceContainer
= new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex
);
1658 m_pInterfaceContainer
->addInterface( cppu::UnoType
<util::XModifyListener
>::get(), xListener
);
1661 void SAL_CALL
OleComponent::removeModifyListener( const css::uno::Reference
< css::util::XModifyListener
>& xListener
)
1663 ::osl::MutexGuard
aGuard( m_aMutex
);
1665 throw lang::DisposedException(); // TODO
1667 if ( m_pInterfaceContainer
)
1668 m_pInterfaceContainer
->removeInterface( cppu::UnoType
<util::XModifyListener
>::get(),
1672 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */