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 <cppuhelper/interfacecontainer.h>
36 #include <comphelper/mimeconfighelper.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <osl/file.hxx>
39 #include <rtl/ref.hxx>
40 #include <o3tl/char16_t2wchar_t.hxx>
42 #include "graphconvert.hxx"
43 #include "olecomponent.hxx"
44 #include "olepersist.hxx"
45 #include "olewrapclient.hxx"
46 #include "advisesink.hxx"
47 #include <oleembobj.hxx>
48 #include "mtnotification.hxx"
52 using namespace ::com::sun::star
;
53 using namespace ::comphelper
;
54 #define MAX_ENUM_ELE 20
57 // ============ class ComSmart =====================
60 template< class T
> class ComSmart
68 T
* pInterface
= m_pInterface
;
69 m_pInterface
= nullptr;
70 pInterface
->Release();
76 : m_pInterface( nullptr )
79 ComSmart( const ComSmart
<T
>& rObj
)
80 : m_pInterface( rObj
.m_pInterface
)
82 if ( m_pInterface
!= NULL
)
83 m_pInterface
->AddRef();
86 ComSmart( T
* pInterface
)
87 : m_pInterface( pInterface
)
89 if ( m_pInterface
!= NULL
)
90 m_pInterface
->AddRef();
98 ComSmart
& operator=( const ComSmart
<T
>& rObj
)
105 m_pInterface
= rObj
.m_pInterface
;
107 if ( m_pInterface
!= NULL
)
108 m_pInterface
->AddRef();
113 ComSmart
<T
>& operator=( T
* pInterface
)
117 m_pInterface
= pInterface
;
119 if ( m_pInterface
!= NULL
)
120 m_pInterface
->AddRef();
132 return *m_pInterface
;
139 m_pInterface
= nullptr;
141 return &m_pInterface
;
144 T
* operator->() const
149 BOOL
operator==( const ComSmart
<T
>& rObj
) const
151 return ( m_pInterface
== rObj
.m_pInterface
);
154 BOOL
operator!=( const ComSmart
<T
>& rObj
) const
156 return ( m_pInterface
!= rObj
.m_pInterface
);
159 BOOL
operator==( const T
* pInterface
) const
161 return ( m_pInterface
== pInterface
);
164 BOOL
operator!=( const T
* pInterface
) const
166 return ( m_pInterface
!= pInterface
);
172 // ============ class ComSmart =====================
174 typedef std::vector
< FORMATETC
* > FormatEtcList
;
176 FORMATETC
const pFormatTemplates
[FORMATS_NUM
] = {
177 { CF_ENHMETAFILE
, nullptr, 0, -1, TYMED_ENHMF
},
178 { CF_METAFILEPICT
, nullptr, 0, -1, TYMED_MFPICT
},
179 { CF_BITMAP
, nullptr, 0, -1, TYMED_GDI
} };
182 struct OleComponentNative_Impl
{
183 ComSmart
< IUnknown
> m_pObj
;
184 ComSmart
< IOleObject
> m_pOleObject
;
185 ComSmart
< IViewObject2
> m_pViewObject2
;
186 ComSmart
< IStorage
> m_pIStorage
;
187 FormatEtcList m_aFormatsList
;
188 uno::Sequence
< datatransfer::DataFlavor
> m_aSupportedGraphFormats
;
190 OleComponentNative_Impl()
192 // TODO: Extend format list
193 m_aSupportedGraphFormats
.realloc( 5 );
195 m_aSupportedGraphFormats
[0] = datatransfer::DataFlavor(
196 "application/x-openoffice-emf;windows_formatname=\"Image EMF\"",
197 "Windows Enhanced Metafile",
198 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() );
200 m_aSupportedGraphFormats
[1] = datatransfer::DataFlavor(
201 "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"",
203 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() );
205 m_aSupportedGraphFormats
[2] = datatransfer::DataFlavor(
206 "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"",
208 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() );
210 m_aSupportedGraphFormats
[3] = datatransfer::DataFlavor(
213 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() );
215 m_aSupportedGraphFormats
[0] = datatransfer::DataFlavor(
216 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"",
218 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() );
221 bool ConvertDataForFlavor( const STGMEDIUM
& aMedium
,
222 const datatransfer::DataFlavor
& aFlavor
,
225 bool GraphicalFlavor( const datatransfer::DataFlavor
& aFlavor
);
227 uno::Sequence
< datatransfer::DataFlavor
> GetFlavorsForAspects( sal_uInt32 nSupportedAspects
);
231 static DWORD
GetAspectFromFlavor( const datatransfer::DataFlavor
& aFlavor
)
233 if ( aFlavor
.MimeType
.indexOf( ";Aspect=THUMBNAIL" ) != -1 )
234 return DVASPECT_THUMBNAIL
;
235 else if ( aFlavor
.MimeType
.indexOf( ";Aspect=ICON" ) != -1 )
236 return DVASPECT_ICON
;
237 else if ( aFlavor
.MimeType
.indexOf( ";Aspect=DOCPRINT" ) != -1 )
238 return DVASPECT_DOCPRINT
;
240 return DVASPECT_CONTENT
;
244 static OUString
GetFlavorSuffixFromAspect( DWORD nAsp
)
248 if ( nAsp
== DVASPECT_THUMBNAIL
)
249 aResult
= ";Aspect=THUMBNAIL";
250 else if ( nAsp
== DVASPECT_ICON
)
251 aResult
= ";Aspect=ICON";
252 else if ( nAsp
== DVASPECT_DOCPRINT
)
253 aResult
= ";Aspect=DOCPRINT";
255 // no suffix for DVASPECT_CONTENT
261 static HRESULT
OpenIStorageFromURL_Impl( const OUString
& aURL
, IStorage
** ppIStorage
)
263 OSL_ENSURE( ppIStorage
, "The pointer must not be empty!" );
266 if ( !ppIStorage
|| ::osl::FileBase::getSystemPathFromFileURL( aURL
, aFilePath
) != ::osl::FileBase::E_None
)
267 throw uno::RuntimeException(); // TODO: something dangerous happened
269 return StgOpenStorage( o3tl::toW(aFilePath
.getStr()),
271 STGM_READWRITE
| STGM_TRANSACTED
, // | STGM_DELETEONRELEASE,
278 bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM
& aMedium
,
279 const datatransfer::DataFlavor
& aFlavor
,
282 bool bAnyIsReady
= false;
284 // try to convert data from Medium format to specified Flavor format
285 if ( aFlavor
.DataType
== cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() )
287 // first the GDI-metafile must be generated
289 std::unique_ptr
<sal_Int8
[]> pBuf
;
290 sal_uInt32 nBufSize
= 0;
293 if ( aMedium
.tymed
== TYMED_MFPICT
) // Win Metafile
295 aFormat
= "image/x-wmf";
296 METAFILEPICT
* pMF
= static_cast<METAFILEPICT
*>(GlobalLock( aMedium
.hMetaFilePict
));
299 nBufSize
= GetMetaFileBitsEx( pMF
->hMF
, 0, nullptr ) + 22;
300 pBuf
.reset(new sal_Int8
[nBufSize
]);
303 // TODO/LATER: the unit size must be calculated correctly
304 *reinterpret_cast<long*>( pBuf
.get() ) = 0x9ac6cdd7L
;
305 *reinterpret_cast<short*>( pBuf
.get()+6 ) = SHORT(0);
306 *reinterpret_cast<short*>( pBuf
.get()+8 ) = SHORT(0);
307 *reinterpret_cast<short*>( pBuf
.get()+10 ) = static_cast<SHORT
>(pMF
->xExt
);
308 *reinterpret_cast<short*>( pBuf
.get()+12 ) = static_cast<SHORT
>(pMF
->yExt
);
309 *reinterpret_cast<short*>( pBuf
.get()+14 ) = USHORT(2540);
312 if ( nBufSize
&& nBufSize
== GetMetaFileBitsEx( pMF
->hMF
, nBufSize
- 22, pBuf
.get() + 22 ) )
314 if ( aFlavor
.MimeType
.matchAsciiL( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"", 57 ) )
316 aResult
<<= uno::Sequence
< sal_Int8
>( pBuf
.get(), nBufSize
);
321 GlobalUnlock( aMedium
.hMetaFilePict
);
324 else if ( aMedium
.tymed
== TYMED_ENHMF
) // Enh Metafile
326 aFormat
= "image/x-emf";
327 nBufSize
= GetEnhMetaFileBits( aMedium
.hEnhMetaFile
, 0, nullptr );
328 pBuf
.reset(new sal_Int8
[nBufSize
]);
329 if ( nBufSize
&& nBufSize
== GetEnhMetaFileBits( aMedium
.hEnhMetaFile
, nBufSize
, reinterpret_cast<LPBYTE
>(pBuf
.get()) ) )
331 if ( aFlavor
.MimeType
.matchAsciiL( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"", 57 ) )
333 aResult
<<= uno::Sequence
< sal_Int8
>( pBuf
.get(), nBufSize
);
338 else if ( aMedium
.tymed
== TYMED_GDI
) // Bitmap
340 aFormat
= "image/x-MS-bmp";
342 // Find out size of buffer: deprecated GetBitmapBits does not have a mode to return
343 // required buffer size
345 GetObjectW(aMedium
.hBitmap
, sizeof(aBmp
), &aBmp
);
346 nBufSize
= aBmp
.bmWidthBytes
* aBmp
.bmHeight
;
348 pBuf
.reset(new sal_Int8
[nBufSize
]);
349 if ( nBufSize
&& nBufSize
== sal::static_int_cast
< ULONG
>( GetBitmapBits( aMedium
.hBitmap
, nBufSize
, pBuf
.get() ) ) )
351 if ( aFlavor
.MimeType
.matchAsciiL( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"", 54 ) )
353 aResult
<<= uno::Sequence
< sal_Int8
>( pBuf
.get(), nBufSize
);
359 if ( pBuf
&& !bAnyIsReady
)
361 for ( sal_Int32 nInd
= 0; nInd
< m_aSupportedGraphFormats
.getLength(); nInd
++ )
362 if ( aFlavor
.MimeType
.match( m_aSupportedGraphFormats
[nInd
].MimeType
)
363 && aFlavor
.DataType
== m_aSupportedGraphFormats
[nInd
].DataType
364 && aFlavor
.DataType
== cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() )
366 bAnyIsReady
= ConvertBufferToFormat( pBuf
.get(), nBufSize
, aFormat
, aResult
);
376 bool OleComponentNative_Impl::GraphicalFlavor( const datatransfer::DataFlavor
& aFlavor
)
378 // Actually all the required graphical formats must be supported
379 for ( sal_Int32 nInd
= 0; nInd
< m_aSupportedGraphFormats
.getLength(); nInd
++ )
380 if ( aFlavor
.MimeType
.match( m_aSupportedGraphFormats
[nInd
].MimeType
)
381 && aFlavor
.DataType
== m_aSupportedGraphFormats
[nInd
].DataType
)
388 static bool GetClassIDFromSequence_Impl( uno::Sequence
< sal_Int8
> const & aSeq
, CLSID
& aResult
)
390 if ( aSeq
.getLength() == 16 )
392 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]);
393 aResult
.Data2
= ( static_cast<sal_uInt8
>(aSeq
[4]) << 8 ) + static_cast<sal_uInt8
>(aSeq
[5]);
394 aResult
.Data3
= ( static_cast<sal_uInt8
>(aSeq
[6]) << 8 ) + static_cast<sal_uInt8
>(aSeq
[7]);
395 for( int nInd
= 0; nInd
< 8; nInd
++ )
396 aResult
.Data4
[nInd
] = static_cast<sal_uInt8
>(aSeq
[nInd
+8]);
405 static OUString
WinAccToVcl_Impl( const sal_Unicode
* pStr
)
416 while( *( ++pStr
) == '&' );
420 aResult
+= OUString( pStr
, 1 );
430 OleComponent::OleComponent( const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
, OleEmbeddedObject
* pUnoOleObject
)
431 : m_pInterfaceContainer( nullptr )
432 , m_bDisposed( false )
433 , m_bModified( false )
434 , m_pNativeImpl( new OleComponentNative_Impl() )
435 , m_pUnoOleObject( pUnoOleObject
)
436 , m_pOleWrapClientSite( nullptr )
437 , m_pImplAdviseSink( nullptr )
438 , m_nOLEMiscFlags( 0 )
440 , m_xFactory( xFactory
)
441 , m_bOleInitialized( false )
442 , m_bWorkaroundActive( false )
444 OSL_ENSURE( m_pUnoOleObject
, "No owner object is provided!" );
446 HRESULT hr
= OleInitialize( nullptr );
447 OSL_ENSURE( hr
== S_OK
|| hr
== S_FALSE
, "The ole can not be successfully initialized" );
448 if ( hr
== S_OK
|| hr
== S_FALSE
)
449 m_bOleInitialized
= true;
451 m_pOleWrapClientSite
= new OleWrapperClientSite( this );
452 m_pOleWrapClientSite
->AddRef();
454 m_pImplAdviseSink
= new OleWrapperAdviseSink( this );
455 m_pImplAdviseSink
->AddRef();
460 OleComponent::~OleComponent()
462 OSL_ENSURE( !m_pOleWrapClientSite
&& !m_pImplAdviseSink
&& !m_pInterfaceContainer
&& !m_bOleInitialized
,
463 "The object was not closed successfully! DISASTER is possible!" );
465 if ( m_pOleWrapClientSite
|| m_pImplAdviseSink
|| m_pInterfaceContainer
|| m_bOleInitialized
)
467 osl_atomic_increment(&m_refCount
);
470 } catch( const uno::Exception
& ) {}
473 for (auto const& format
: m_pNativeImpl
->m_aFormatsList
)
477 m_pNativeImpl
->m_aFormatsList
.clear();
479 delete m_pNativeImpl
;
482 void OleComponent::Dispose()
487 // Call CloseObject() without m_aMutex locked, since it will call
488 // IOleObject::Close(), which can call event listeners, which can run on a
492 osl::MutexGuard
aGuard(m_aMutex
);
493 if ( m_pOleWrapClientSite
)
495 m_pOleWrapClientSite
->disconnectOleComponent();
496 m_pOleWrapClientSite
->Release();
497 m_pOleWrapClientSite
= nullptr;
500 if ( m_pImplAdviseSink
)
502 m_pImplAdviseSink
->disconnectOleComponent();
503 m_pImplAdviseSink
->Release();
504 m_pImplAdviseSink
= nullptr;
507 if ( m_pInterfaceContainer
)
509 lang::EventObject
aEvent( static_cast< ::cppu::OWeakObject
* >( this ) );
510 m_pInterfaceContainer
->disposeAndClear( aEvent
);
512 delete m_pInterfaceContainer
;
513 m_pInterfaceContainer
= nullptr;
516 if ( m_bOleInitialized
)
518 // since the disposing can happen not only from main thread but also from a clipboard
519 // the deinitialization might lead to a disaster, SO7 does not deinitialize OLE at all
520 // so currently the same approach is selected as workaround
521 // OleUninitialize();
522 m_bOleInitialized
= false;
529 void OleComponent::disconnectEmbeddedObject()
531 // must not be called from destructor of UNO OLE object!!!
532 osl::MutexGuard
aGuard( m_aMutex
);
533 m_pUnoOleObject
= nullptr;
537 void OleComponent::CreateNewIStorage_Impl()
539 // TODO: in future a global memory could be used instead of file.
541 // write the stream to the temporary file
544 OSL_ENSURE( m_pUnoOleObject
, "Unexpected object absence!" );
545 if ( m_pUnoOleObject
)
546 aTempURL
= m_pUnoOleObject
->CreateTempURLEmpty_Impl();
548 aTempURL
= GetNewTempFileURL_Impl( m_xFactory
);
550 if ( !aTempURL
.getLength() )
551 throw uno::RuntimeException(); // TODO
553 // open an IStorage based on the temporary file
554 OUString aTempFilePath
;
555 if ( ::osl::FileBase::getSystemPathFromFileURL( aTempURL
, aTempFilePath
) != ::osl::FileBase::E_None
)
556 throw uno::RuntimeException(); // TODO: something dangerous happened
558 HRESULT hr
= StgCreateDocfile( o3tl::toW(aTempFilePath
.getStr()), STGM_CREATE
| STGM_READWRITE
| STGM_TRANSACTED
| STGM_DELETEONRELEASE
, 0, &m_pNativeImpl
->m_pIStorage
);
559 if ( FAILED( hr
) || !m_pNativeImpl
->m_pIStorage
)
560 throw io::IOException(); // TODO: transport error code?
564 uno::Sequence
< datatransfer::DataFlavor
> OleComponentNative_Impl::GetFlavorsForAspects( sal_uInt32 nSupportedAspects
)
566 uno::Sequence
< datatransfer::DataFlavor
> aResult
;
567 for ( sal_uInt32 nAsp
= 1; nAsp
<= 8; nAsp
*= 2 )
568 if ( ( nSupportedAspects
& nAsp
) == nAsp
)
570 OUString aAspectSuffix
= GetFlavorSuffixFromAspect( nAsp
);
572 sal_Int32 nLength
= aResult
.getLength();
573 aResult
.realloc( nLength
+ m_aSupportedGraphFormats
.getLength() );
575 for ( sal_Int32 nInd
= 0; nInd
< m_aSupportedGraphFormats
.getLength(); nInd
++ )
577 aResult
[nLength
+ nInd
].MimeType
= m_aSupportedGraphFormats
[nInd
].MimeType
+ aAspectSuffix
;
578 aResult
[nLength
+ nInd
].HumanPresentableName
= m_aSupportedGraphFormats
[nInd
].HumanPresentableName
;
579 aResult
[nLength
+ nInd
].DataType
= m_aSupportedGraphFormats
[nInd
].DataType
;
587 void OleComponent::RetrieveObjectDataFlavors_Impl()
589 if ( !m_pNativeImpl
->m_pOleObject
)
590 throw embed::WrongStateException(); // TODO: the object is in wrong state
592 if ( !m_aDataFlavors
.getLength() )
594 ComSmart
< IDataObject
> pDataObject
;
595 HRESULT hr
= m_pNativeImpl
->m_pObj
->QueryInterface( IID_IDataObject
, reinterpret_cast<void**>(&pDataObject
) );
596 if ( SUCCEEDED( hr
) && pDataObject
)
598 ComSmart
< IEnumFORMATETC
> pFormatEnum
;
599 hr
= pDataObject
->EnumFormatEtc( DATADIR_GET
, &pFormatEnum
);
600 if ( SUCCEEDED( hr
) && pFormatEnum
)
602 FORMATETC pElem
[ MAX_ENUM_ELE
];
605 // if it is possible to retrieve at least one supported graphical format for an aspect
606 // this format can be converted to other supported formats
607 sal_uInt32 nSupportedAspects
= 0;
610 HRESULT hr2
= pFormatEnum
->Next( MAX_ENUM_ELE
, pElem
, &nNum
);
611 if( hr2
== S_OK
|| hr2
== S_FALSE
)
613 for( sal_uInt32 nInd
= 0; nInd
< FORMATS_NUM
; nInd
++ )
615 if ( pElem
[nInd
].cfFormat
== pFormatTemplates
[nInd
].cfFormat
616 && pElem
[nInd
].tymed
== pFormatTemplates
[nInd
].tymed
)
617 nSupportedAspects
|= pElem
[nInd
].dwAspect
;
623 while( nNum
== MAX_ENUM_ELE
);
625 m_aDataFlavors
= m_pNativeImpl
->GetFlavorsForAspects( nSupportedAspects
);
629 if ( !m_aDataFlavors
.getLength() )
632 // for any reason the object could not provide this information
633 // try to get access to the cached representation
639 bool OleComponent::InitializeObject_Impl()
640 // There will be no static objects!
642 if ( !m_pNativeImpl
->m_pObj
)
645 // the linked object will be detected here
646 ComSmart
< IOleLink
> pOleLink
;
647 HRESULT hr
= m_pNativeImpl
->m_pObj
->QueryInterface( IID_IOleLink
, reinterpret_cast<void**>(&pOleLink
) );
648 OSL_ENSURE( m_pUnoOleObject
, "Unexpected object absence!" );
649 if ( m_pUnoOleObject
)
650 m_pUnoOleObject
->SetObjectIsLink_Impl( bool( pOleLink
!= nullptr ) );
653 hr
= m_pNativeImpl
->m_pObj
->QueryInterface( IID_IViewObject2
, reinterpret_cast<void**>(&m_pNativeImpl
->m_pViewObject2
) );
654 if ( FAILED( hr
) || !m_pNativeImpl
->m_pViewObject2
)
657 // remove all the caches
658 IOleCache
* pIOleCache
= nullptr;
659 if ( SUCCEEDED( m_pNativeImpl
->m_pObj
->QueryInterface( IID_IOleCache
, reinterpret_cast<void**>(&pIOleCache
) ) ) && pIOleCache
)
661 IEnumSTATDATA
* pEnumSD
= nullptr;
662 HRESULT hr2
= pIOleCache
->EnumCache( &pEnumSD
);
664 if ( SUCCEEDED( hr2
) && pEnumSD
)
669 while( SUCCEEDED( pEnumSD
->Next( 1, &aSD
, &nNum
) ) && nNum
== 1 )
670 hr2
= pIOleCache
->Uncache( aSD
.dwConnection
);
673 // No IDataObject implementation, caching must be used instead
675 FORMATETC aFormat
= { 0, nullptr, DVASPECT_CONTENT
, -1, TYMED_MFPICT
};
676 hr2
= pIOleCache
->Cache( &aFormat
, ADVFCACHE_ONSAVE
, &nConn
);
678 pIOleCache
->Release();
679 pIOleCache
= nullptr;
682 hr
= m_pNativeImpl
->m_pObj
->QueryInterface( IID_IOleObject
, reinterpret_cast<void**>(&m_pNativeImpl
->m_pOleObject
) );
683 if ( FAILED( hr
) || !m_pNativeImpl
->m_pOleObject
)
684 return false; // Static objects are not supported, they should be inserted as graphics
686 m_pNativeImpl
->m_pOleObject
->GetMiscStatus( DVASPECT_CONTENT
, reinterpret_cast<DWORD
*>(&m_nOLEMiscFlags
) );
687 // TODO: use other misc flags also
688 // the object should have drawable aspect even in case it supports only iconic representation
689 // if ( m_nOLEMiscFlags & OLEMISC_ONLYICONIC )
691 m_pNativeImpl
->m_pOleObject
->SetClientSite( m_pOleWrapClientSite
);
693 // the only need in this registration is workaround for close notification
694 m_pNativeImpl
->m_pOleObject
->Advise( m_pImplAdviseSink
, reinterpret_cast<DWORD
*>(&m_nAdvConn
) );
695 m_pNativeImpl
->m_pViewObject2
->SetAdvise( DVASPECT_CONTENT
, 0, m_pImplAdviseSink
);
697 OleSetContainedObject( m_pNativeImpl
->m_pOleObject
, TRUE
);
704 HRESULT
OleLoadSeh(LPSTORAGE pIStorage
, LPVOID
* ppObj
)
708 hr
= OleLoad(pIStorage
, IID_IUnknown
, nullptr, ppObj
);
709 } __except( EXCEPTION_EXECUTE_HANDLER
) {
716 void OleComponent::LoadEmbeddedObject( const OUString
& aTempURL
)
718 if ( !aTempURL
.getLength() )
719 throw lang::IllegalArgumentException(); // TODO
721 if ( m_pNativeImpl
->m_pIStorage
)
722 throw io::IOException(); // TODO the object is already initialized or wrong initialization is done
724 // open an IStorage based on the temporary file
725 HRESULT hr
= OpenIStorageFromURL_Impl( aTempURL
, &m_pNativeImpl
->m_pIStorage
);
727 if ( FAILED( hr
) || !m_pNativeImpl
->m_pIStorage
)
728 throw io::IOException(); // TODO: transport error code?
730 hr
= OleLoadSeh(m_pNativeImpl
->m_pIStorage
, reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
));
731 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
733 throw uno::RuntimeException();
736 if ( !InitializeObject_Impl() )
737 throw uno::RuntimeException(); // TODO
741 void OleComponent::CreateObjectFromClipboard()
743 if ( m_pNativeImpl
->m_pIStorage
)
744 throw io::IOException(); // TODO:the object is already initialized
746 CreateNewIStorage_Impl();
747 if ( !m_pNativeImpl
->m_pIStorage
)
748 throw uno::RuntimeException(); // TODO
750 IDataObject
* pDO
= nullptr;
751 HRESULT hr
= OleGetClipboard( &pDO
);
752 if( SUCCEEDED( hr
) && pDO
)
754 hr
= OleQueryCreateFromData( pDO
);
755 if( S_OK
== GetScode( hr
) )
757 hr
= OleCreateFromData( pDO
,
759 OLERENDER_DRAW
, // OLERENDER_FORMAT
760 nullptr, // &aFormat,
762 m_pNativeImpl
->m_pIStorage
,
763 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
767 // Static objects are not supported
772 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
773 throw uno::RuntimeException();
775 if ( !InitializeObject_Impl() )
776 throw uno::RuntimeException(); // TODO
780 void OleComponent::CreateNewEmbeddedObject( const uno::Sequence
< sal_Int8
>& aSeqCLSID
)
784 if ( !GetClassIDFromSequence_Impl( aSeqCLSID
, aClsID
) )
785 throw lang::IllegalArgumentException(); // TODO
787 if ( m_pNativeImpl
->m_pIStorage
)
788 throw io::IOException(); // TODO:the object is already initialized
790 CreateNewIStorage_Impl();
791 if ( !m_pNativeImpl
->m_pIStorage
)
792 throw uno::RuntimeException(); // TODO
794 // FORMATETC aFormat = { CF_METAFILEPICT, NULL, nAspect, -1, TYMED_MFPICT }; // for OLE..._DRAW should be NULL
796 HRESULT hr
= OleCreate( aClsID
,
798 OLERENDER_DRAW
, // OLERENDER_FORMAT
799 nullptr, // &aFormat,
801 m_pNativeImpl
->m_pIStorage
,
802 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
804 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
805 throw uno::RuntimeException(); // TODO
807 if ( !InitializeObject_Impl() )
808 throw uno::RuntimeException(); // TODO
810 // TODO: getExtent???
814 void OleComponent::CreateObjectFromData( const uno::Reference
< datatransfer::XTransferable
>& )
815 // Static objects are not supported, they should be inserted as graphics
817 // TODO: May be this call is useless since there are no static objects
818 // and nonstatic objects will be created based on OLEstorage ( stream ).
821 // OleQueryCreateFromData...
825 void OleComponent::CreateObjectFromFile( const OUString
& aFileURL
)
827 if ( m_pNativeImpl
->m_pIStorage
)
828 throw io::IOException(); // TODO:the object is already initialized
830 CreateNewIStorage_Impl();
831 if ( !m_pNativeImpl
->m_pIStorage
)
832 throw uno::RuntimeException(); // TODO:
835 if ( ::osl::FileBase::getSystemPathFromFileURL( aFileURL
, aFilePath
) != ::osl::FileBase::E_None
)
836 throw uno::RuntimeException(); // TODO: something dangerous happened
838 HRESULT hr
= OleCreateFromFile( CLSID_NULL
,
839 o3tl::toW(aFilePath
.getStr()),
841 OLERENDER_DRAW
, // OLERENDER_FORMAT
844 m_pNativeImpl
->m_pIStorage
,
845 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
847 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
848 throw uno::RuntimeException(); // TODO
850 if ( !InitializeObject_Impl() )
851 throw uno::RuntimeException(); // TODO
855 void OleComponent::CreateLinkFromFile( const OUString
& aFileURL
)
857 if ( m_pNativeImpl
->m_pIStorage
)
858 throw io::IOException(); // TODO:the object is already initialized
860 CreateNewIStorage_Impl();
861 if ( !m_pNativeImpl
->m_pIStorage
)
862 throw uno::RuntimeException(); // TODO:
865 if ( ::osl::FileBase::getSystemPathFromFileURL( aFileURL
, aFilePath
) != ::osl::FileBase::E_None
)
866 throw uno::RuntimeException(); // TODO: something dangerous happened
868 HRESULT hr
= OleCreateLinkToFile( o3tl::toW(aFilePath
.getStr()),
870 OLERENDER_DRAW
, // OLERENDER_FORMAT
873 m_pNativeImpl
->m_pIStorage
,
874 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
876 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
877 throw uno::RuntimeException(); // TODO
879 if ( !InitializeObject_Impl() )
880 throw uno::RuntimeException(); // TODO
884 void OleComponent::InitEmbeddedCopyOfLink( OleComponent
const * pOleLinkComponent
)
886 if ( !pOleLinkComponent
|| !pOleLinkComponent
->m_pNativeImpl
->m_pObj
)
887 throw lang::IllegalArgumentException(); // TODO
889 if ( m_pNativeImpl
->m_pIStorage
)
890 throw io::IOException(); // TODO:the object is already initialized
892 ComSmart
< IDataObject
> pDataObject
;
893 HRESULT hr
= pOleLinkComponent
->m_pNativeImpl
->m_pObj
->QueryInterface( IID_IDataObject
, reinterpret_cast<void**>(&pDataObject
) );
894 if ( SUCCEEDED( hr
) && pDataObject
&& SUCCEEDED( OleQueryCreateFromData( pDataObject
) ) )
896 // the object must be already disconnected from the temporary URL
897 CreateNewIStorage_Impl();
898 if ( !m_pNativeImpl
->m_pIStorage
)
899 throw uno::RuntimeException(); // TODO:
901 hr
= OleCreateFromData( pDataObject
,
906 m_pNativeImpl
->m_pIStorage
,
907 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
910 if ( !m_pNativeImpl
->m_pObj
)
912 ComSmart
< IOleLink
> pOleLink
;
913 hr
= pOleLinkComponent
->m_pNativeImpl
->m_pObj
->QueryInterface( IID_IOleLink
, reinterpret_cast<void**>(&pOleLink
) );
914 if ( FAILED( hr
) || !pOleLink
)
915 throw io::IOException(); // TODO: the object doesn't support IOleLink
917 ComSmart
< IMoniker
> pMoniker
;
918 hr
= pOleLink
->GetSourceMoniker( &pMoniker
);
919 if ( FAILED( hr
) || !pMoniker
)
920 throw io::IOException(); // TODO: can not retrieve moniker
922 // In case of file moniker life is easy : )
924 hr
= pMoniker
->IsSystemMoniker( &aMonType
);
925 if ( SUCCEEDED( hr
) && aMonType
== MKSYS_FILEMONIKER
)
927 ComSmart
< IMalloc
> pMalloc
;
928 hr
= CoGetMalloc( 1, &pMalloc
); // if fails there will be a memory leak
929 OSL_ENSURE(SUCCEEDED(hr
) && pMalloc
, "CoGetMalloc() failed!");
931 LPOLESTR pOleStr
= nullptr;
932 hr
= pOleLink
->GetSourceDisplayName( &pOleStr
);
933 if ( SUCCEEDED( hr
) && pOleStr
)
935 std::wstring
aFilePath( pOleStr
);
937 pMalloc
->Free( pOleStr
);
939 hr
= OleCreateFromFile( CLSID_NULL
,
942 OLERENDER_DRAW
, // OLERENDER_FORMAT
945 m_pNativeImpl
->m_pIStorage
,
946 reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
) );
950 // in case of other moniker types the only way is to get storage
951 if ( !m_pNativeImpl
->m_pObj
)
953 ComSmart
< IBindCtx
> pBindCtx
;
954 hr
= CreateBindCtx( 0, &pBindCtx
);
955 if ( SUCCEEDED( hr
) && pBindCtx
)
957 ComSmart
< IStorage
> pObjectStorage
;
958 hr
= pMoniker
->BindToStorage( pBindCtx
, nullptr, IID_IStorage
, reinterpret_cast<void**>(&pObjectStorage
) );
959 if ( SUCCEEDED( hr
) && pObjectStorage
)
961 hr
= pObjectStorage
->CopyTo( 0, nullptr, nullptr, m_pNativeImpl
->m_pIStorage
);
962 if ( SUCCEEDED( hr
) )
963 hr
= OleLoadSeh(m_pNativeImpl
->m_pIStorage
, reinterpret_cast<void**>(&m_pNativeImpl
->m_pObj
));
969 // If object could not be created the only way is to use graphical representation
970 if ( FAILED( hr
) || !m_pNativeImpl
->m_pObj
)
971 throw uno::RuntimeException(); // TODO
973 if ( !InitializeObject_Impl() )
974 throw uno::RuntimeException(); // TODO
978 void OleComponent::RunObject()
980 OSL_ENSURE( m_pNativeImpl
->m_pOleObject
, "The pointer can not be set to NULL here!" );
981 if ( !m_pNativeImpl
->m_pOleObject
)
982 throw embed::WrongStateException(); // TODO: the object is in wrong state
984 if ( !OleIsRunning( m_pNativeImpl
->m_pOleObject
) )
986 HRESULT hr
= OleRun( m_pNativeImpl
->m_pObj
);
990 if ( hr
== REGDB_E_CLASSNOTREG
)
991 throw embed::UnreachableStateException(); // the object server is not installed
993 throw io::IOException();
999 awt::Size
OleComponent::CalculateWithFactor( const awt::Size
& aSize
,
1000 const awt::Size
& aMultiplier
,
1001 const awt::Size
& aDivisor
)
1005 sal_Int64 nWidth
= static_cast<sal_Int64
>(aSize
.Width
) * static_cast<sal_Int64
>(aMultiplier
.Width
) / static_cast<sal_Int64
>(aDivisor
.Width
);
1006 sal_Int64 nHeight
= static_cast<sal_Int64
>(aSize
.Height
) * static_cast<sal_Int64
>(aMultiplier
.Height
) / static_cast<sal_Int64
>(aDivisor
.Height
);
1007 OSL_ENSURE( nWidth
< SAL_MAX_INT32
&& nWidth
> SAL_MIN_INT32
1008 && nHeight
< SAL_MAX_INT32
&& nHeight
> SAL_MIN_INT32
,
1009 "Unacceptable result size!" );
1011 aResult
.Width
= static_cast<sal_Int32
>(nWidth
);
1012 aResult
.Height
= static_cast<sal_Int32
>(nHeight
);
1018 void OleComponent::CloseObject()
1020 if ( m_pNativeImpl
->m_pOleObject
&& OleIsRunning( m_pNativeImpl
->m_pOleObject
) )
1021 m_pNativeImpl
->m_pOleObject
->Close( OLECLOSE_NOSAVE
); // must be saved before
1025 uno::Sequence
< embed::VerbDescriptor
> OleComponent::GetVerbList()
1027 if ( !m_pNativeImpl
->m_pOleObject
)
1028 throw embed::WrongStateException(); // TODO: the object is in wrong state
1030 if( !m_aVerbList
.getLength() )
1032 ComSmart
< IEnumOLEVERB
> pEnum
;
1033 if( SUCCEEDED( m_pNativeImpl
->m_pOleObject
->EnumVerbs( &pEnum
) ) )
1035 OLEVERB szEle
[ MAX_ENUM_ELE
];
1037 sal_Int32 nSeqSize
= 0;
1041 HRESULT hr
= pEnum
->Next( MAX_ENUM_ELE
, szEle
, &nNum
);
1042 if( hr
== S_OK
|| hr
== S_FALSE
)
1044 m_aVerbList
.realloc( nSeqSize
+= nNum
);
1045 for( sal_uInt32 nInd
= 0; nInd
< nNum
; nInd
++ )
1047 m_aVerbList
[nSeqSize
-nNum
+nInd
].VerbID
= szEle
[ nInd
].lVerb
;
1048 m_aVerbList
[nSeqSize
-nNum
+nInd
].VerbName
= WinAccToVcl_Impl( o3tl::toU(szEle
[ nInd
].lpszVerbName
) );
1049 m_aVerbList
[nSeqSize
-nNum
+nInd
].VerbFlags
= szEle
[ nInd
].fuFlags
;
1050 m_aVerbList
[nSeqSize
-nNum
+nInd
].VerbAttributes
= szEle
[ nInd
].grfAttribs
;
1056 while( nNum
== MAX_ENUM_ELE
);
1064 void OleComponent::ExecuteVerb( sal_Int32 nVerbID
)
1066 if ( !m_pNativeImpl
->m_pOleObject
)
1067 throw embed::WrongStateException(); // TODO
1069 HRESULT hr
= OleRun( m_pNativeImpl
->m_pOleObject
);
1071 throw io::IOException(); // TODO: a specific exception that transport error code can be thrown here
1073 // TODO: probably extents should be set here and stored in aRect
1074 // TODO: probably the parent window also should be set
1075 hr
= m_pNativeImpl
->m_pOleObject
->DoVerb( nVerbID
, nullptr, m_pOleWrapClientSite
, 0, nullptr, nullptr );
1078 throw io::IOException(); // TODO
1082 void OleComponent::SetHostName( const OUString
&,
1083 const OUString
& aEmbDocName
)
1085 if ( !m_pNativeImpl
->m_pOleObject
)
1086 throw embed::WrongStateException(); // TODO: the object is in wrong state
1088 m_pNativeImpl
->m_pOleObject
->SetHostNames( L
"app name", o3tl::toW( aEmbDocName
.getStr() ) );
1092 void OleComponent::SetExtent( const awt::Size
& aVisAreaSize
, sal_Int64 nAspect
)
1094 if ( !m_pNativeImpl
->m_pOleObject
)
1095 throw embed::WrongStateException(); // TODO: the object is in wrong state
1097 DWORD nMSAspect
= static_cast<DWORD
>(nAspect
); // first 32 bits are for MS aspects
1099 SIZEL aSize
= { aVisAreaSize
.Width
, aVisAreaSize
.Height
};
1100 HRESULT hr
= m_pNativeImpl
->m_pOleObject
->SetExtent( nMSAspect
, &aSize
);
1104 // TODO/LATER: is it correct? In future user code probably should be ready for the exception.
1105 // if the object is running but not activated, RPC_E_SERVER_DIED error code is returned by OLE package
1106 // in this case just do nothing
1107 // Also Visio returns E_FAIL on resize if it is in running state
1108 // if ( hr != RPC_E_SERVER_DIED )
1109 throw io::IOException(); // TODO
1114 awt::Size
OleComponent::GetExtent( sal_Int64 nAspect
)
1116 if ( !m_pNativeImpl
->m_pOleObject
)
1117 throw embed::WrongStateException(); // TODO: the object is in wrong state
1119 DWORD nMSAspect
= static_cast<DWORD
>(nAspect
); // first 32 bits are for MS aspects
1121 bool bGotSize
= false;
1123 if ( nMSAspect
== DVASPECT_CONTENT
)
1125 // Try to get the size from the replacement image first
1126 ComSmart
< IDataObject
> pDataObject
;
1127 HRESULT hr
= m_pNativeImpl
->m_pObj
->QueryInterface( IID_IDataObject
, reinterpret_cast<void**>(&pDataObject
) );
1128 if ( SUCCEEDED( hr
) || pDataObject
)
1131 FORMATETC aFormat
= pFormatTemplates
[1]; // use windows metafile format
1132 aFormat
.dwAspect
= nMSAspect
;
1134 hr
= pDataObject
->GetData( &aFormat
, &aMedium
);
1135 if ( SUCCEEDED( hr
) && aMedium
.tymed
== TYMED_MFPICT
) // Win Metafile
1137 METAFILEPICT
* pMF
= static_cast<METAFILEPICT
*>(GlobalLock( aMedium
.hMetaFilePict
));
1140 // the object uses 0.01 mm as unit, so the metafile size should be converted to object unit
1141 sal_Int64 nMult
= 1;
1165 case MM_ANISOTROPIC
:
1171 sal_Int64 nX
= static_cast<sal_Int64
>(abs( pMF
->xExt
)) * nMult
/ nDiv
;
1172 sal_Int64 nY
= static_cast<sal_Int64
>(abs( pMF
->yExt
)) * nMult
/ nDiv
;
1173 if ( nX
< SAL_MAX_INT32
&& nY
< SAL_MAX_INT32
)
1175 aSize
.Width
= static_cast<sal_Int32
>(nX
);
1176 aSize
.Height
= static_cast<sal_Int32
>(nY
);
1180 OSL_FAIL( "Unexpected size is provided!" );
1183 // i113605, to release storage medium
1184 if ( SUCCEEDED( hr
) )
1185 ::ReleaseStgMedium(&aMedium
);
1190 throw lang::IllegalArgumentException();
1196 awt::Size
OleComponent::GetCachedExtent( sal_Int64 nAspect
)
1198 if ( !m_pNativeImpl
->m_pOleObject
)
1199 throw embed::WrongStateException(); // TODO: the object is in wrong state
1201 DWORD nMSAspect
= static_cast<DWORD
>(nAspect
); // first 32 bits are for MS aspects
1204 HRESULT hr
= m_pNativeImpl
->m_pViewObject2
->GetExtent( nMSAspect
, -1, nullptr, &aSize
);
1208 // TODO/LATER: is it correct?
1209 // if there is no appropriate cache for the aspect, OLE_E_BLANK error code is returned
1210 // if ( hr == OLE_E_BLANK )
1211 // throw lang::IllegalArgumentException();
1213 // throw io::IOException(); // TODO
1215 throw lang::IllegalArgumentException();
1218 return awt::Size( aSize
.cx
, aSize
.cy
);
1222 awt::Size
OleComponent::GetRecommendedExtent( sal_Int64 nAspect
)
1224 if ( !m_pNativeImpl
->m_pOleObject
)
1225 throw embed::WrongStateException(); // TODO: the object is in wrong state
1227 DWORD nMSAspect
= static_cast<DWORD
>(nAspect
); // first 32 bits are for MS aspects
1229 HRESULT hr
= m_pNativeImpl
->m_pOleObject
->GetExtent( nMSAspect
, &aSize
);
1231 throw lang::IllegalArgumentException();
1233 return awt::Size( aSize
.cx
, aSize
.cy
);
1237 sal_Int64
OleComponent::GetMiscStatus( sal_Int64 nAspect
)
1239 if ( !m_pNativeImpl
->m_pOleObject
)
1240 throw embed::WrongStateException(); // TODO: the object is in wrong state
1243 m_pNativeImpl
->m_pOleObject
->GetMiscStatus( static_cast<DWORD
>(nAspect
), &nResult
);
1244 return static_cast<sal_Int64
>(nResult
); // first 32 bits are for MS flags
1248 uno::Sequence
< sal_Int8
> OleComponent::GetCLSID()
1250 if ( !m_pNativeImpl
->m_pOleObject
)
1251 throw embed::WrongStateException(); // TODO: the object is in wrong state
1254 HRESULT hr
= m_pNativeImpl
->m_pOleObject
->GetUserClassID( &aCLSID
);
1256 throw io::IOException(); // TODO:
1258 return MimeConfigurationHelper::GetSequenceClassID( aCLSID
.Data1
, aCLSID
.Data2
, aCLSID
.Data3
,
1259 aCLSID
.Data4
[0], aCLSID
.Data4
[1],
1260 aCLSID
.Data4
[2], aCLSID
.Data4
[3],
1261 aCLSID
.Data4
[4], aCLSID
.Data4
[5],
1262 aCLSID
.Data4
[6], aCLSID
.Data4
[7] );
1266 bool OleComponent::IsDirty()
1268 if ( !m_pNativeImpl
->m_pOleObject
)
1269 throw embed::WrongStateException(); // TODO: the object is in wrong state
1271 if ( IsWorkaroundActive() )
1274 ComSmart
< IPersistStorage
> pPersistStorage
;
1275 HRESULT hr
= m_pNativeImpl
->m_pObj
->QueryInterface( IID_IPersistStorage
, reinterpret_cast<void**>(&pPersistStorage
) );
1276 if ( FAILED( hr
) || !pPersistStorage
)
1277 throw io::IOException(); // TODO
1279 hr
= pPersistStorage
->IsDirty();
1280 return ( hr
!= S_FALSE
);
1284 void OleComponent::StoreOwnTmpIfNecessary()
1286 if ( !m_pNativeImpl
->m_pOleObject
)
1287 throw embed::WrongStateException(); // TODO: the object is in wrong state
1289 ComSmart
< IPersistStorage
> pPersistStorage
;
1290 HRESULT hr
= m_pNativeImpl
->m_pObj
->QueryInterface( IID_IPersistStorage
, reinterpret_cast<void**>(&pPersistStorage
) );
1291 if ( FAILED( hr
) || !pPersistStorage
)
1292 throw io::IOException(); // TODO
1294 if ( m_bWorkaroundActive
|| pPersistStorage
->IsDirty() != S_FALSE
)
1296 hr
= OleSave( pPersistStorage
, m_pNativeImpl
->m_pIStorage
, TRUE
);
1299 // Till now was required only for AcrobatReader7.0.8
1301 hr
= m_pNativeImpl
->m_pOleObject
->GetUserClassID( &aCLSID
);
1303 throw io::IOException(); // TODO
1305 hr
= WriteClassStg( m_pNativeImpl
->m_pIStorage
, aCLSID
);
1307 throw io::IOException(); // TODO
1309 // the result of the following call is not checked because some objects, for example AcrobatReader7.0.8
1310 // return error even in case the saving was done correctly
1311 hr
= pPersistStorage
->Save( m_pNativeImpl
->m_pIStorage
, TRUE
);
1313 // another workaround for AcrobatReader7.0.8 object, this object might think that it is not changed
1314 // when it has been created from file, although it must be saved
1315 m_bWorkaroundActive
= true;
1318 hr
= m_pNativeImpl
->m_pIStorage
->Commit( STGC_DEFAULT
);
1320 throw io::IOException(); // TODO
1322 hr
= pPersistStorage
->SaveCompleted( nullptr );
1323 if ( FAILED( hr
) && hr
!= E_UNEXPECTED
)
1324 throw io::IOException(); // TODO
1330 bool OleComponent::SaveObject_Impl()
1332 bool bResult
= false;
1333 OleEmbeddedObject
* pLockObject
= nullptr;
1336 osl::MutexGuard
aGuard( m_aMutex
);
1337 if ( m_pUnoOleObject
)
1339 pLockObject
= m_pUnoOleObject
;
1340 pLockObject
->acquire();
1346 bResult
= pLockObject
->SaveObject_Impl();
1347 pLockObject
->release();
1354 bool OleComponent::OnShowWindow_Impl( bool bShow
)
1356 bool bResult
= false;
1357 OleEmbeddedObject
* pLockObject
= nullptr;
1360 osl::MutexGuard
aGuard( m_aMutex
);
1362 if ( m_pUnoOleObject
)
1364 pLockObject
= m_pUnoOleObject
;
1365 pLockObject
->acquire();
1371 bResult
= pLockObject
->OnShowWindow_Impl( bShow
);
1372 pLockObject
->release();
1379 void OleComponent::OnViewChange_Impl( sal_uInt32 dwAspect
)
1381 // TODO: check if it is enough or may be saving notifications are required for Visio2000
1382 ::rtl::Reference
< OleEmbeddedObject
> xLockObject
;
1385 osl::MutexGuard
aGuard( m_aMutex
);
1386 if ( m_pUnoOleObject
)
1387 xLockObject
= m_pUnoOleObject
;
1390 if ( xLockObject
.is() )
1392 uno::Reference
< awt::XRequestCallback
> xRequestCallback(
1393 m_xFactory
->createInstance("com.sun.star.awt.AsyncCallback"),
1395 xRequestCallback
->addCallback( new MainThreadNotificationRequest( xLockObject
, OLECOMP_ONVIEWCHANGE
, dwAspect
), uno::Any() );
1400 void OleComponent::OnClose_Impl()
1402 ::rtl::Reference
< OleEmbeddedObject
> xLockObject
;
1405 osl::MutexGuard
aGuard( m_aMutex
);
1406 if ( m_pUnoOleObject
)
1407 xLockObject
= m_pUnoOleObject
;
1410 if ( xLockObject
.is() )
1412 uno::Reference
< awt::XRequestCallback
> xRequestCallback(
1413 m_xFactory
->createInstance("com.sun.star.awt.AsyncCallback"),
1415 xRequestCallback
->addCallback( new MainThreadNotificationRequest( xLockObject
, OLECOMP_ONCLOSE
), uno::Any() );
1421 void SAL_CALL
OleComponent::close( sal_Bool bDeliverOwnership
)
1423 uno::Reference
< uno::XInterface
> xSelfHold
;
1425 osl::MutexGuard
aGuard(m_aMutex
);
1427 throw lang::DisposedException(); // TODO
1429 xSelfHold
.set(static_cast<::cppu::OWeakObject
*>(this));
1430 lang::EventObject
aSource(static_cast<::cppu::OWeakObject
*>(this));
1432 if (m_pInterfaceContainer
)
1434 ::cppu::OInterfaceContainerHelper
* pContainer
1435 = m_pInterfaceContainer
->getContainer(cppu::UnoType
<util::XCloseListener
>::get());
1436 if (pContainer
!= nullptr)
1438 ::cppu::OInterfaceIteratorHelper
pIterator(*pContainer
);
1439 while (pIterator
.hasMoreElements())
1443 static_cast<util::XCloseListener
*>(pIterator
.next())
1444 ->queryClosing(aSource
, bDeliverOwnership
);
1446 catch (const uno::RuntimeException
&)
1454 = m_pInterfaceContainer
->getContainer(cppu::UnoType
<util::XCloseListener
>::get());
1455 if (pContainer
!= nullptr)
1457 ::cppu::OInterfaceIteratorHelper
pCloseIterator(*pContainer
);
1458 while (pCloseIterator
.hasMoreElements())
1462 static_cast<util::XCloseListener
*>(pCloseIterator
.next())
1463 ->notifyClosing(aSource
);
1465 catch (const uno::RuntimeException
&)
1467 pCloseIterator
.remove();
1478 void SAL_CALL
OleComponent::addCloseListener( const uno::Reference
< util::XCloseListener
>& xListener
)
1480 ::osl::MutexGuard
aGuard( m_aMutex
);
1482 throw lang::DisposedException(); // TODO
1484 if ( !m_pInterfaceContainer
)
1485 m_pInterfaceContainer
= new ::cppu::OMultiTypeInterfaceContainerHelper( m_aMutex
);
1487 m_pInterfaceContainer
->addInterface( cppu::UnoType
<util::XCloseListener
>::get(), xListener
);
1491 void SAL_CALL
OleComponent::removeCloseListener( const uno::Reference
< util::XCloseListener
>& xListener
)
1493 ::osl::MutexGuard
aGuard( m_aMutex
);
1495 throw lang::DisposedException(); // TODO
1497 if ( m_pInterfaceContainer
)
1498 m_pInterfaceContainer
->removeInterface( cppu::UnoType
<util::XCloseListener
>::get(),
1504 uno::Any SAL_CALL
OleComponent::getTransferData( const datatransfer::DataFlavor
& aFlavor
)
1506 ::osl::MutexGuard
aGuard( m_aMutex
);
1508 throw lang::DisposedException(); // TODO
1510 if ( !m_pNativeImpl
->m_pOleObject
)
1511 throw embed::WrongStateException(); // TODO: the object is in wrong state
1514 bool bSupportedFlavor
= false;
1516 if ( m_pNativeImpl
->GraphicalFlavor( aFlavor
) )
1518 DWORD nRequestedAspect
= GetAspectFromFlavor( aFlavor
);
1519 // if own icon is set and icon aspect is requested the own icon can be returned directly
1521 ComSmart
< IDataObject
> pDataObject
;
1522 HRESULT hr
= m_pNativeImpl
->m_pObj
->QueryInterface( IID_IDataObject
, reinterpret_cast<void**>(&pDataObject
) );
1523 if ( FAILED( hr
) || !pDataObject
)
1524 throw io::IOException(); // TODO: transport error code
1526 // The following optimization does not make much sense currently just because
1527 // only one aspect is supported, and only three formats for the aspect are supported
1528 // and moreover it is not guaranteed that the once returned format will be supported further
1530 // TODO/LATER: bring the optimization back when other aspects are supported
1532 // FORMATETC* pFormatEtc = m_pNativeImpl->GetSupportedFormatForAspect( nRequestedAspect );
1533 // if ( pFormatEtc )
1535 // STGMEDIUM aMedium;
1536 // hr = pDataObject->GetData( pFormatEtc, &aMedium );
1537 // if ( SUCCEEDED( hr ) )
1538 // bSupportedFlavor = m_pNativeImpl->ConvertDataForFlavor( aMedium, aFlavor, aResult );
1542 // the supported format of the application is still not found, find one
1543 for ( sal_Int32 nInd
= 0; nInd
< FORMATS_NUM
; nInd
++ )
1546 FORMATETC aFormat
= pFormatTemplates
[nInd
];
1547 aFormat
.dwAspect
= nRequestedAspect
;
1549 hr
= pDataObject
->GetData( &aFormat
, &aMedium
);
1550 if ( SUCCEEDED( hr
) )
1552 bSupportedFlavor
= m_pNativeImpl
->ConvertDataForFlavor( aMedium
, aFlavor
, aResult
);
1553 ::ReleaseStgMedium(&aMedium
); // i113605, to release storage medium
1554 if ( bSupportedFlavor
)
1556 // TODO/LATER: bring the optimization back when other aspects are supported
1557 // m_pNativeImpl->AddSupportedFormat( aFormat );
1564 // If the replacement could not be retrieved, the cached representation should be used
1565 // currently it is not necessary to retrieve it here, so it is implemented in the object itself
1567 // TODO: Investigate if there is already the format name
1568 // and whether this format is really required
1569 else if ( aFlavor
.DataType
== cppu::UnoType
<io::XInputStream
>::get()
1570 && aFlavor
.MimeType
== "application/x-openoffice-contentstream" )
1572 // allow to retrieve stream-representation of the object persistence
1573 bSupportedFlavor
= true;
1574 uno::Reference
< io::XStream
> xTempFileStream(
1575 io::TempFile::create(comphelper::getComponentContext(m_xFactory
)),
1576 uno::UNO_QUERY_THROW
);
1578 uno::Reference
< io::XOutputStream
> xTempOutStream
= xTempFileStream
->getOutputStream();
1579 uno::Reference
< io::XInputStream
> xTempInStream
= xTempFileStream
->getInputStream();
1580 if ( !(xTempOutStream
.is() && xTempInStream
.is()) )
1581 throw io::IOException(); // TODO:
1583 OSL_ENSURE( m_pUnoOleObject
, "Unexpected object absence!" );
1584 if ( !m_pUnoOleObject
)
1585 throw uno::RuntimeException();
1587 m_pUnoOleObject
->StoreObjectToStream( xTempOutStream
);
1589 xTempOutStream
->closeOutput();
1590 xTempOutStream
.clear();
1592 aResult
<<= xTempInStream
;
1595 if ( !bSupportedFlavor
)
1596 throw datatransfer::UnsupportedFlavorException();
1602 uno::Sequence
< datatransfer::DataFlavor
> SAL_CALL
OleComponent::getTransferDataFlavors()
1604 ::osl::MutexGuard
aGuard( m_aMutex
);
1606 throw lang::DisposedException(); // TODO
1608 if ( !m_pNativeImpl
->m_pOleObject
)
1609 throw embed::WrongStateException(); // TODO: the object is in wrong state
1611 RetrieveObjectDataFlavors_Impl();
1613 return m_aDataFlavors
;
1617 sal_Bool SAL_CALL
OleComponent::isDataFlavorSupported( const datatransfer::DataFlavor
& aFlavor
)
1619 ::osl::MutexGuard
aGuard( m_aMutex
);
1621 throw lang::DisposedException(); // TODO
1623 if ( !m_pNativeImpl
->m_pOleObject
)
1624 throw embed::WrongStateException(); // TODO: the object is in wrong state
1626 if ( !m_aDataFlavors
.getLength() )
1628 RetrieveObjectDataFlavors_Impl();
1631 for ( sal_Int32 nInd
= 0; nInd
< m_aDataFlavors
.getLength(); nInd
++ )
1632 if ( m_aDataFlavors
[nInd
].MimeType
.equals( aFlavor
.MimeType
) && m_aDataFlavors
[nInd
].DataType
== aFlavor
.DataType
)
1638 void SAL_CALL
OleComponent::dispose()
1644 catch ( const uno::Exception
& )
1649 void SAL_CALL
OleComponent::addEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
1651 ::osl::MutexGuard
aGuard( m_aMutex
);
1653 throw lang::DisposedException(); // TODO
1655 if ( !m_pInterfaceContainer
)
1656 m_pInterfaceContainer
= new ::cppu::OMultiTypeInterfaceContainerHelper( m_aMutex
);
1658 m_pInterfaceContainer
->addInterface( cppu::UnoType
<lang::XEventListener
>::get(), xListener
);
1662 void SAL_CALL
OleComponent::removeEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
1664 ::osl::MutexGuard
aGuard( m_aMutex
);
1666 throw lang::DisposedException(); // TODO
1668 if ( m_pInterfaceContainer
)
1669 m_pInterfaceContainer
->removeInterface( cppu::UnoType
<lang::XEventListener
>::get(),
1673 sal_Int64 SAL_CALL
OleComponent::getSomething( const css::uno::Sequence
< sal_Int8
>& aIdentifier
)
1677 uno::Sequence
< sal_Int8
> aCLSID
= GetCLSID();
1678 if ( MimeConfigurationHelper::ClassIDsEqual( aIdentifier
, aCLSID
) )
1679 return reinterpret_cast<sal_Int64
>(static_cast<IUnknown
*>(m_pNativeImpl
->m_pObj
));
1681 // compatibility hack for old versions: CLSID was used in wrong order (SvGlobalName order)
1682 sal_Int32 nLength
= aIdentifier
.getLength();
1683 if ( nLength
== 16 )
1685 for ( sal_Int32 n
=8; n
<16; n
++ )
1686 if ( aIdentifier
[n
] != aCLSID
[n
] )
1688 if ( aIdentifier
[7] == aCLSID
[6] &&
1689 aIdentifier
[6] == aCLSID
[7] &&
1690 aIdentifier
[5] == aCLSID
[4] &&
1691 aIdentifier
[4] == aCLSID
[5] &&
1692 aIdentifier
[3] == aCLSID
[0] &&
1693 aIdentifier
[2] == aCLSID
[1] &&
1694 aIdentifier
[1] == aCLSID
[2] &&
1695 aIdentifier
[0] == aCLSID
[3] )
1696 return reinterpret_cast<sal_Int64
>(static_cast<IUnknown
*>(m_pNativeImpl
->m_pObj
));
1699 catch ( const uno::Exception
& )
1706 sal_Bool SAL_CALL
OleComponent::isModified()
1711 void SAL_CALL
OleComponent::setModified( sal_Bool bModified
)
1713 m_bModified
= bModified
;
1715 if ( bModified
&& m_pInterfaceContainer
)
1717 ::cppu::OInterfaceContainerHelper
* pContainer
=
1718 m_pInterfaceContainer
->getContainer( cppu::UnoType
<util::XModifyListener
>::get());
1719 if ( pContainer
!= nullptr )
1721 ::cppu::OInterfaceIteratorHelper
pIterator( *pContainer
);
1722 while ( pIterator
.hasMoreElements() )
1726 lang::EventObject
aEvent( static_cast<util::XModifiable
*>(this) );
1727 static_cast<util::XModifyListener
*>(pIterator
.next())->modified( aEvent
);
1729 catch( const uno::RuntimeException
& )
1738 void SAL_CALL
OleComponent::addModifyListener( const css::uno::Reference
< css::util::XModifyListener
>& xListener
)
1740 ::osl::MutexGuard
aGuard( m_aMutex
);
1742 throw lang::DisposedException(); // TODO
1744 if ( !m_pInterfaceContainer
)
1745 m_pInterfaceContainer
= new ::cppu::OMultiTypeInterfaceContainerHelper( m_aMutex
);
1747 m_pInterfaceContainer
->addInterface( cppu::UnoType
<util::XModifyListener
>::get(), xListener
);
1750 void SAL_CALL
OleComponent::removeModifyListener( const css::uno::Reference
< css::util::XModifyListener
>& xListener
)
1752 ::osl::MutexGuard
aGuard( m_aMutex
);
1754 throw lang::DisposedException(); // TODO
1756 if ( m_pInterfaceContainer
)
1757 m_pInterfaceContainer
->removeInterface( cppu::UnoType
<util::XModifyListener
>::get(),
1761 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */