1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
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/embed/EmbedStates.hpp>
28 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/io/TempFile.hpp>
31 #include <com/sun/star/io/XTruncate.hpp>
32 #include <com/sun/star/io/IOException.hpp>
33 #include <com/sun/star/awt/XRequestCallback.hpp>
34 
35 #include "platform.h"
36 #include <comphelper/multicontainer2.hxx>
37 #include <comphelper/mimeconfighelper.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <comphelper/servicehelper.hxx>
40 #include <comphelper/windowserrorstring.hxx>
41 #include <osl/file.hxx>
42 #include <rtl/ref.hxx>
43 #include <o3tl/char16_t2wchar_t.hxx>
44 #include <o3tl/unit_conversion.hxx>
45 #include <systools/win32/comtools.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/threadex.hxx>
48 
49 #include "graphconvert.hxx"
50 #include "olecomponent.hxx"
51 #include "olepersist.hxx"
52 #include "olewrapclient.hxx"
53 #include "advisesink.hxx"
54 #include <oleembobj.hxx>
55 #include "mtnotification.hxx"
56 #include <memory>
57 #include <string>
58 
59 using namespace ::com::sun::star;
60 using namespace ::comphelper;
61 #define     MAX_ENUM_ELE     20
62 #define     FORMATS_NUM      3
63 
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 } };
68 
69 
70 // We have at least one single-threaded apartment (STA) in the process (the VCL Main thread, which
71 // is the GUI thread), and a multithreaded apartment (MTA) for most of other threads. OLE objects
72 // may be created in either: in interactive mode, this typically happens in the STA; when serving
73 // external requests, this may be either in STA (when explicit "OnMainThread" argument is passed to
74 // loadComponentFromURL, and the instantiation of the object happens during the load), or in MTA
75 // (the thread actually serving the incoming calls).
76 //
77 // The objects typically can only be used in the apartment where they were instantiated. This means
78 // that e.g. a call to IOleObject::Close will fail, if it is performed in a different thread, when
79 // it was started in the main thread. And vice versa, opening a document in a handler thread, then
80 // trying to interact with the OLE object in GUI would fail.
81 //
82 // To handle this, several workarounds were implemented in the past; the mentioned "OnMainThread"
83 // argument is one of these, allowing open document requests be processed not in the handler threads
84 // that received the request, but in the main thread which will then be used for interaction. Also
85 // OleComponent::GetExtent was changed to check if the first call to IDataObject::GetData failed
86 // with RPC_E_WRONG_THREAD, and then retry in the main thread.
87 //
88 // But ultimately every call to the OLE object needs such checks. E.g., failing to close the object
89 // keeps the server running, effectively leaking resources, until it crashes/freezes after multiple
90 // iterations.
91 //
92 // Currently, OleComponentNative_Impl is implemented using IGlobalInterfaceTable, which allows to
93 // register an object in process-global instance of the table from the thread that instantiated the
94 // object, and obtain a "cookie" (a number); and then use that cookie from any thread to access that
95 // object. The global table will do its magic to provide either the original object (when it is
96 // requested from the same apartment as used for its registration), or a "proxy", which will marshal
97 // all calls to the proper thread, transparently for the caller. This implementation should obsolete
98 // the previous workarounds (in theory).
99 //
100 // m_pGlobalTable is the reference to the global table.
101 // The storage object gets registered in the global table immediately when it's created.
102 // But the OLE object itself can't be registered immediately, before it is run: an attempt to call
103 // RegisterInterfaceInGlobal with such a newly created OLE object fails with CO_E_OBJNOTCONNECTED.
104 // Thus, the initial reference to the OLE object (which at this stage seems to be apartment-neutral)
105 // is stored to m_pObj. Only when it is run, it is registered in the global table.
106 //
107 // Indeed, the implicit change of the thread is a blocking operation, which opens a wonderful new
108 // opportunities for shiny deadlocks. Thus, precautions are needed to avoid them.
109 //
110 // When the OLE object is accessed by m_pObj (should be only in initialization code!), no measures
111 // are taken to change locking. But when it is accessed by getObj() - which may return the proxy -
112 // the calls are guarded by a SolarMutexReleaser, to allow the other thread do its job.
113 //
114 // There are at least two other mutexes in play here. One is in OleEmbeddedObject, that holds the
115 // OleComponent. The calls to OleComponent's methods are also wrapped there into unlock/lock pairs
116 // (see OleEmbeddedObject::changeState). The other is in OleComponent itself. For now, I see no
117 // deadlocks caused by that mutex, so no unlock/lock is introduced for that. It may turn out to be
118 // required eventually.
119 class OleComponentNative_Impl
120 {
121 public:
122     sal::systools::COMReference< IUnknown > m_pObj;
123     uno::Sequence< datatransfer::DataFlavor > m_aSupportedGraphFormats;
124 
125     // The getters may return a proxy, that redirects the calls to another thread.
126     // Thus, calls to methods of returned objects must be inside solar mutex releaser.
getStorage() const127     auto getStorage() const { return getInterface<IStorage>(m_nStorage); }
getObj() const128     auto getObj() const { return m_nOleObject ? getInterface<IUnknown>(m_nOleObject) : m_pObj; }
129     template <typename T>
get() const130     auto get() const { return getObj().QueryInterface<T>(sal::systools::COM_QUERY); }
131 
registerStorage(IStorage * pStorage)132     void registerStorage(IStorage* pStorage) { registerInterface(pStorage, m_nStorage); }
registerObj()133     void registerObj() { registerInterface(m_pObj.get(), m_nOleObject); }
134 
IsStorageRegistered() const135     bool IsStorageRegistered() const { return m_nStorage != 0; }
136 
OleComponentNative_Impl()137     OleComponentNative_Impl()
138         : m_pGlobalTable(CLSID_StdGlobalInterfaceTable, nullptr, CLSCTX_INPROC_SERVER)
139     {
140         // TODO: Extend format list
141         m_aSupportedGraphFormats = {
142 
143         datatransfer::DataFlavor(
144             "application/x-openoffice-emf;windows_formatname=\"Image EMF\"",
145             "Windows Enhanced Metafile",
146             cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ),
147 
148         datatransfer::DataFlavor(
149             "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"",
150             "Windows Metafile",
151             cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ),
152 
153         datatransfer::DataFlavor(
154             "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"",
155             "Bitmap",
156             cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ),
157 
158         datatransfer::DataFlavor(
159             "image/png",
160             "PNG",
161             cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ),
162 
163         datatransfer::DataFlavor(
164             "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"",
165             "GDIMetafile",
166             cppu::UnoType<uno::Sequence< sal_Int8 >>::get() )
167         };
168     }
169 
~OleComponentNative_Impl()170     ~OleComponentNative_Impl()
171     {
172         if (m_nOleObject)
173             m_pGlobalTable->RevokeInterfaceFromGlobal(m_nOleObject);
174         if (m_nStorage)
175             m_pGlobalTable->RevokeInterfaceFromGlobal(m_nStorage);
176     }
177 
178     bool ConvertDataForFlavor( const STGMEDIUM& aMedium,
179                                     const datatransfer::DataFlavor& aFlavor,
180                                     uno::Any& aResult );
181 
182     bool GraphicalFlavor( const datatransfer::DataFlavor& aFlavor );
183 
184     uno::Sequence< datatransfer::DataFlavor > GetFlavorsForAspects( sal_uInt32 nSupportedAspects );
185 
186     sal::systools::COMReference<IStorage> CreateNewStorage(const OUString& url);
187 
188 private:
189     sal::systools::COMReference<IGlobalInterfaceTable> m_pGlobalTable;
190     DWORD m_nStorage = 0;
191     DWORD m_nOleObject = 0;
192 
getInterface(DWORD cookie) const193     template <typename T> sal::systools::COMReference<T> getInterface(DWORD cookie) const
194     {
195         sal::systools::COMReference<T> result;
196         HRESULT hr = m_pGlobalTable->GetInterfaceFromGlobal(cookie, IID_PPV_ARGS(&result));
197         SAL_WARN_IF(FAILED(hr), "embeddedobj.ole",
198                     "GetInterfaceFromGlobal failed: is cookie " << cookie << " not registered?");
199         return result;
200     }
201 
registerInterface(T * pInterface,DWORD & cookie)202     template <typename T> void registerInterface(T* pInterface, DWORD& cookie)
203     {
204         if (cookie != 0) // E.g., on subsequent RunObject calls
205             return;
206         HRESULT hr = m_pGlobalTable->RegisterInterfaceInGlobal(pInterface, __uuidof(T), &cookie);
207         SAL_WARN_IF(FAILED(hr), "embeddedobj.ole", "RegisterInterfaceInGlobal failed");
208     }
209 };
210 
GetAspectFromFlavor(const datatransfer::DataFlavor & aFlavor)211 static DWORD GetAspectFromFlavor( const datatransfer::DataFlavor& aFlavor )
212 {
213     if ( aFlavor.MimeType.indexOf( ";Aspect=THUMBNAIL" ) != -1 )
214         return DVASPECT_THUMBNAIL;
215     else if ( aFlavor.MimeType.indexOf( ";Aspect=ICON" ) != -1 )
216         return DVASPECT_ICON;
217     else if ( aFlavor.MimeType.indexOf( ";Aspect=DOCPRINT" ) != -1 )
218         return DVASPECT_DOCPRINT;
219     else
220         return DVASPECT_CONTENT;
221 }
222 
223 
GetFlavorSuffixFromAspect(DWORD nAsp)224 static OUString GetFlavorSuffixFromAspect( DWORD nAsp )
225 {
226     OUString aResult;
227 
228     if ( nAsp == DVASPECT_THUMBNAIL )
229         aResult = ";Aspect=THUMBNAIL";
230     else if ( nAsp == DVASPECT_ICON )
231         aResult = ";Aspect=ICON";
232     else if ( nAsp == DVASPECT_DOCPRINT )
233         aResult = ";Aspect=DOCPRINT";
234 
235     // no suffix for DVASPECT_CONTENT
236 
237     return aResult;
238 }
239 
240 
ConvertDataForFlavor(const STGMEDIUM & aMedium,const datatransfer::DataFlavor & aFlavor,uno::Any & aResult)241 bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM& aMedium,
242                                                         const datatransfer::DataFlavor& aFlavor,
243                                                         uno::Any& aResult )
244 {
245     bool bAnyIsReady = false;
246 
247     // try to convert data from Medium format to specified Flavor format
248     if ( aFlavor.DataType == cppu::UnoType<uno::Sequence< sal_Int8 >>::get() )
249     {
250         // first the GDI-metafile must be generated
251 
252         std::unique_ptr<sal_Int8[]> pBuf;
253         sal_uInt32 nBufSize = 0;
254         OUString aFormat;
255 
256         if ( aMedium.tymed == TYMED_MFPICT ) // Win Metafile
257         {
258             aFormat = "image/x-wmf";
259             METAFILEPICT* pMF = static_cast<METAFILEPICT*>(GlobalLock( aMedium.hMetaFilePict ));
260             if ( pMF )
261             {
262                 nBufSize = GetMetaFileBitsEx( pMF->hMF, 0, nullptr ) + 22;
263                 pBuf.reset(new sal_Int8[nBufSize]);
264 
265 
266                 // TODO/LATER: the unit size must be calculated correctly
267                 *reinterpret_cast<long*>( pBuf.get() ) = 0x9ac6cdd7L;
268                 *reinterpret_cast<short*>( pBuf.get()+6 ) = SHORT(0);
269                 *reinterpret_cast<short*>( pBuf.get()+8 ) = SHORT(0);
270                 *reinterpret_cast<short*>( pBuf.get()+10 ) = static_cast<SHORT>(pMF->xExt);
271                 *reinterpret_cast<short*>( pBuf.get()+12 ) = static_cast<SHORT>(pMF->yExt);
272                 *reinterpret_cast<short*>( pBuf.get()+14 ) = USHORT(2540);
273 
274 
275                 if ( nBufSize && nBufSize == GetMetaFileBitsEx( pMF->hMF, nBufSize - 22, pBuf.get() + 22 ) )
276                 {
277                     if ( aFlavor.MimeType.match( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ) )
278                     {
279                         aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize );
280                         bAnyIsReady = true;
281                     }
282                 }
283 
284                 GlobalUnlock( aMedium.hMetaFilePict );
285             }
286         }
287         else if ( aMedium.tymed == TYMED_ENHMF ) // Enh Metafile
288         {
289             aFormat = "image/x-emf";
290             nBufSize = GetEnhMetaFileBits( aMedium.hEnhMetaFile, 0, nullptr );
291             pBuf.reset(new sal_Int8[nBufSize]);
292             if ( nBufSize && nBufSize == GetEnhMetaFileBits( aMedium.hEnhMetaFile, nBufSize, reinterpret_cast<LPBYTE>(pBuf.get()) ) )
293             {
294                 if ( aFlavor.MimeType.match( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ) )
295                 {
296                     aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize );
297                     bAnyIsReady = true;
298                 }
299             }
300         }
301         else if ( aMedium.tymed == TYMED_GDI ) // Bitmap
302         {
303             aFormat = "image/x-MS-bmp";
304 
305             // Find out size of buffer: deprecated GetBitmapBits does not have a mode to return
306             // required buffer size
307             BITMAP aBmp;
308             GetObjectW(aMedium.hBitmap, sizeof(aBmp), &aBmp);
309             nBufSize = aBmp.bmWidthBytes * aBmp.bmHeight;
310 
311             pBuf.reset(new sal_Int8[nBufSize]);
312             if ( nBufSize && nBufSize == sal::static_int_cast< ULONG >( GetBitmapBits( aMedium.hBitmap, nBufSize, pBuf.get() ) ) )
313             {
314                 if ( aFlavor.MimeType.match( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ) )
315                 {
316                     aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize );
317                     bAnyIsReady = true;
318                 }
319             }
320         }
321 
322         if ( pBuf && !bAnyIsReady )
323         {
324             for (auto const& supportedFormat : m_aSupportedGraphFormats)
325                 if ( aFlavor.MimeType.match( supportedFormat.MimeType )
326                   && aFlavor.DataType == supportedFormat.DataType
327                   && aFlavor.DataType == cppu::UnoType<uno::Sequence< sal_Int8 >>::get() )
328                 {
329                     bAnyIsReady = ConvertBufferToFormat( pBuf.get(), nBufSize, aFormat, aResult );
330                     break;
331                 }
332         }
333     }
334 
335     return bAnyIsReady;
336 }
337 
338 
GraphicalFlavor(const datatransfer::DataFlavor & aFlavor)339 bool OleComponentNative_Impl::GraphicalFlavor( const datatransfer::DataFlavor& aFlavor )
340 {
341     // Actually all the required graphical formats must be supported
342     for (auto const& supportedFormat : m_aSupportedGraphFormats)
343          if ( aFlavor.MimeType.match( supportedFormat.MimeType )
344           && aFlavor.DataType == supportedFormat.DataType )
345             return true;
346 
347     return false;
348 }
349 
350 
GetClassIDFromSequence_Impl(uno::Sequence<sal_Int8> const & aSeq,CLSID & aResult)351 static bool GetClassIDFromSequence_Impl( uno::Sequence< sal_Int8 > const & aSeq, CLSID& aResult )
352 {
353     if ( aSeq.getLength() == 16 )
354     {
355         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]);
356         aResult.Data2 = ( static_cast<sal_uInt8>(aSeq[4]) << 8 ) + static_cast<sal_uInt8>(aSeq[5]);
357         aResult.Data3 = ( static_cast<sal_uInt8>(aSeq[6]) << 8 ) + static_cast<sal_uInt8>(aSeq[7]);
358         for( int nInd = 0; nInd < 8; nInd++ )
359             aResult.Data4[nInd] = static_cast<sal_uInt8>(aSeq[nInd+8]);
360 
361         return true;
362     }
363 
364     return false;
365 }
366 
367 
WinAccToVcl_Impl(const sal_Unicode * pStr)368 static OUString WinAccToVcl_Impl( const sal_Unicode* pStr )
369 {
370     OUString aResult;
371 
372     if( pStr )
373     {
374         while ( *pStr )
375         {
376             if ( *pStr == '&' )
377             {
378                 aResult += "~";
379                 while( *( ++pStr ) == '&' );
380             }
381             else
382             {
383                 aResult += OUStringChar( *pStr );
384                 pStr++;
385             }
386         }
387     }
388 
389     return aResult;
390 }
391 
392 
OleComponent(const uno::Reference<uno::XComponentContext> & xContext,OleEmbeddedObject * pUnoOleObject)393 OleComponent::OleComponent( const uno::Reference< uno::XComponentContext >& xContext, OleEmbeddedObject* pUnoOleObject )
394 : m_pInterfaceContainer( nullptr )
395 , m_bDisposed( false )
396 , m_bModified( false )
397 , m_pNativeImpl( std::make_unique<OleComponentNative_Impl>() )
398 , m_pUnoOleObject( pUnoOleObject )
399 , m_pOleWrapClientSite( nullptr )
400 , m_pImplAdviseSink( nullptr )
401 , m_xContext( xContext )
402 , m_bOleInitialized( false )
403 , m_bWorkaroundActive( false )
404 {
405     OSL_ENSURE( m_pUnoOleObject, "No owner object is provided!" );
406 
407     HRESULT hr = OleInitialize( nullptr );
408     if ( hr == S_OK || hr == S_FALSE )
409         m_bOleInitialized = true;
410     else
411     {
412         SAL_WARN("embeddedobj.ole", "OleComponent ctor: OleInitialize() failed with 0x"
413                                         << OUString::number(static_cast<sal_uInt32>(hr), 16) << ": "
414                                         << WindowsErrorStringFromHRESULT(hr));
415     }
416 
417     m_pOleWrapClientSite = new OleWrapperClientSite( this );
418     m_pOleWrapClientSite->AddRef();
419 
420     m_pImplAdviseSink = new OleWrapperAdviseSink( this );
421     m_pImplAdviseSink->AddRef();
422 
423 }
424 
425 
~OleComponent()426 OleComponent::~OleComponent()
427 {
428     OSL_ENSURE( !m_pOleWrapClientSite && !m_pImplAdviseSink && !m_pInterfaceContainer && !m_bOleInitialized,
429                 "The object was not closed successfully! DISASTER is possible!" );
430 
431     if ( m_pOleWrapClientSite || m_pImplAdviseSink || m_pInterfaceContainer || m_bOleInitialized )
432     {
433         osl_atomic_increment(&m_refCount);
434         try {
435             Dispose();
436         } catch( const uno::Exception& ) {}
437     }
438 }
439 
Dispose()440 void OleComponent::Dispose()
441 {
442     if ( m_bDisposed )
443         return;
444 
445     // Call CloseObject() without m_aMutex locked, since it will call
446     // IOleObject::Close(), which can call event listeners, which can run on a
447     // different thread.
448     CloseObject();
449 
450     osl::MutexGuard aGuard(m_aMutex);
451     if ( m_pOleWrapClientSite )
452     {
453         m_pOleWrapClientSite->disconnectOleComponent();
454         m_pOleWrapClientSite->Release();
455         m_pOleWrapClientSite = nullptr;
456     }
457 
458     if ( m_pImplAdviseSink )
459     {
460         m_pImplAdviseSink->disconnectOleComponent();
461         m_pImplAdviseSink->Release();
462         m_pImplAdviseSink = nullptr;
463     }
464 
465     if ( m_pInterfaceContainer )
466     {
467         lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >( this ) );
468         m_pInterfaceContainer->disposeAndClear( aEvent );
469 
470         delete m_pInterfaceContainer;
471         m_pInterfaceContainer = nullptr;
472     }
473 
474     if ( m_bOleInitialized )
475     {
476         // since the disposing can happen not only from main thread but also from a clipboard
477         // the deinitialization might lead to a disaster, SO7 does not deinitialize OLE at all
478         // so currently the same approach is selected as workaround
479         // OleUninitialize();
480         m_bOleInitialized = false;
481     }
482 
483     m_bDisposed = true;
484 }
485 
486 
disconnectEmbeddedObject()487 void OleComponent::disconnectEmbeddedObject()
488 {
489     // must not be called from destructor of UNO OLE object!!!
490     osl::MutexGuard aGuard( m_aMutex );
491     m_pUnoOleObject = nullptr;
492 }
493 
494 
getTempURL() const495 OUString OleComponent::getTempURL() const
496 {
497     OSL_ENSURE( m_pUnoOleObject, "Unexpected object absence!" );
498     if ( m_pUnoOleObject )
499         return m_pUnoOleObject->CreateTempURLEmpty_Impl();
500     else
501         return GetNewTempFileURL_Impl(m_xContext);
502 }
503 
504 
CreateNewStorage(const OUString & url)505 sal::systools::COMReference<IStorage> OleComponentNative_Impl::CreateNewStorage(const OUString& url)
506 {
507     if (IsStorageRegistered())
508         throw io::IOException(); // TODO:the object is already initialized
509     // TODO: in future a global memory could be used instead of file.
510 
511     // write the stream to the temporary file
512     if (url.isEmpty())
513         throw uno::RuntimeException(); // TODO
514 
515     // open an IStorage based on the temporary file
516     OUString aTempFilePath;
517     if (osl::FileBase::getSystemPathFromFileURL(url, aTempFilePath) != osl::FileBase::E_None)
518         throw uno::RuntimeException(); // TODO: something dangerous happened
519 
520     sal::systools::COMReference<IStorage> pStorage;
521     HRESULT hr = StgCreateDocfile( o3tl::toW(aTempFilePath.getStr()), STGM_CREATE | STGM_READWRITE | STGM_TRANSACTED | STGM_DELETEONRELEASE, 0, &pStorage );
522     if (FAILED(hr) || !pStorage)
523         throw io::IOException(); // TODO: transport error code?
524     registerStorage(pStorage);
525     return pStorage;
526 }
527 
528 
GetFlavorsForAspects(sal_uInt32 nSupportedAspects)529 uno::Sequence< datatransfer::DataFlavor > OleComponentNative_Impl::GetFlavorsForAspects( sal_uInt32 nSupportedAspects )
530 {
531     uno::Sequence< datatransfer::DataFlavor > aResult;
532     for ( sal_uInt32 nAsp = 1; nAsp <= 8; nAsp *= 2 )
533         if ( ( nSupportedAspects & nAsp ) == nAsp )
534         {
535             OUString aAspectSuffix = GetFlavorSuffixFromAspect( nAsp );
536 
537             sal_Int32 nLength = aResult.getLength();
538             aResult.realloc( nLength + m_aSupportedGraphFormats.getLength() );
539             auto pResult = aResult.getArray();
540 
541             for ( sal_Int32 nInd = 0; nInd < m_aSupportedGraphFormats.getLength(); nInd++ )
542             {
543                 pResult[nLength + nInd].MimeType = m_aSupportedGraphFormats[nInd].MimeType + aAspectSuffix;
544                 pResult[nLength + nInd].HumanPresentableName = m_aSupportedGraphFormats[nInd].HumanPresentableName;
545                 pResult[nLength + nInd].DataType = m_aSupportedGraphFormats[nInd].DataType;
546             }
547         }
548 
549     return aResult;
550 }
551 
552 
RetrieveObjectDataFlavors_Impl()553 void OleComponent::RetrieveObjectDataFlavors_Impl()
554 {
555     if (!m_pNativeImpl->m_pObj)
556         throw embed::WrongStateException(); // TODO: the object is in wrong state
557 
558     if ( !m_aDataFlavors.getLength() )
559     {
560         if (auto pDataObject = m_pNativeImpl->get<IDataObject>())
561         {
562             HRESULT hr;
563             sal::systools::COMReference< IEnumFORMATETC > pFormatEnum;
564             {
565                 SolarMutexReleaser releaser;
566                 hr = pDataObject->EnumFormatEtc(DATADIR_GET, &pFormatEnum);
567             }
568             if ( SUCCEEDED( hr ) && pFormatEnum )
569             {
570                 FORMATETC pElem[ MAX_ENUM_ELE ];
571                 ULONG nNum = 0;
572 
573                 // if it is possible to retrieve at least one supported graphical format for an aspect
574                 // this format can be converted to other supported formats
575                 sal_uInt32 nSupportedAspects = 0;
576                 do
577                 {
578                     HRESULT hr2 = pFormatEnum->Next( MAX_ENUM_ELE, pElem, &nNum );
579                     if( hr2 == S_OK || hr2 == S_FALSE )
580                     {
581                         for( sal_uInt32 nInd = 0; nInd < FORMATS_NUM; nInd++ )
582                         {
583                             if ( pElem[nInd].cfFormat == pFormatTemplates[nInd].cfFormat
584                               && pElem[nInd].tymed == pFormatTemplates[nInd].tymed )
585                                 nSupportedAspects |= pElem[nInd].dwAspect;
586                         }
587                     }
588                     else
589                         break;
590                 }
591                 while( nNum == MAX_ENUM_ELE );
592 
593                 m_aDataFlavors = m_pNativeImpl->GetFlavorsForAspects( nSupportedAspects );
594             }
595         }
596 
597         if ( !m_aDataFlavors.getLength() )
598         {
599             // TODO:
600             // for any reason the object could not provide this information
601             // try to get access to the cached representation
602         }
603     }
604 }
605 
606 
InitializeObject_Impl()607 void OleComponent::InitializeObject_Impl()
608 // There will be no static objects!
609 {
610     if ( !m_pNativeImpl->m_pObj )
611         throw embed::WrongStateException();
612 
613     // the linked object will be detected here
614     OSL_ENSURE( m_pUnoOleObject, "Unexpected object absence!" );
615     if ( m_pUnoOleObject )
616         m_pUnoOleObject->SetObjectIsLink_Impl( m_pNativeImpl->m_pObj.QueryInterface<IOleLink>(sal::systools::COM_QUERY).is() );
617 
618     auto pViewObject2(m_pNativeImpl->m_pObj.QueryInterface<IViewObject2>(sal::systools::COM_QUERY));
619     if (!pViewObject2)
620         throw uno::RuntimeException(); // TODO
621 
622     // remove all the caches
623     if ( sal::systools::COMReference< IOleCache > pIOleCache{ m_pNativeImpl->m_pObj, sal::systools::COM_QUERY } )
624     {
625         IEnumSTATDATA* pEnumSD = nullptr;
626         HRESULT hr2 = pIOleCache->EnumCache( &pEnumSD );
627 
628         if ( SUCCEEDED( hr2 ) && pEnumSD )
629         {
630             pEnumSD->Reset();
631             STATDATA aSD;
632             DWORD nNum;
633             while( SUCCEEDED( pEnumSD->Next( 1, &aSD, &nNum ) ) && nNum == 1 )
634                 hr2 = pIOleCache->Uncache( aSD.dwConnection );
635         }
636 
637         // No IDataObject implementation, caching must be used instead
638         DWORD nConn;
639         FORMATETC aFormat = { 0, nullptr, DVASPECT_CONTENT, -1, TYMED_MFPICT };
640         hr2 = pIOleCache->Cache( &aFormat, ADVFCACHE_ONSAVE, &nConn );
641     }
642 
643     auto pOleObject(m_pNativeImpl->m_pObj.QueryInterface<IOleObject>(sal::systools::COM_QUERY));
644     if (!pOleObject)
645         throw uno::RuntimeException(); // Static objects are not supported, they should be inserted as graphics
646 
647     DWORD nOLEMiscFlags(0);
648     pOleObject->GetMiscStatus(DVASPECT_CONTENT, reinterpret_cast<DWORD*>(&nOLEMiscFlags));
649     // TODO: use other misc flags also
650     // the object should have drawable aspect even in case it supports only iconic representation
651     // if ( nOLEMiscFlags & OLEMISC_ONLYICONIC )
652 
653     pOleObject->SetClientSite(m_pOleWrapClientSite);
654 
655     // the only need in this registration is workaround for close notification
656     DWORD nAdvConn(0);
657     pOleObject->Advise(m_pImplAdviseSink, reinterpret_cast<DWORD*>(&nAdvConn));
658     pViewObject2->SetAdvise(DVASPECT_CONTENT, 0, m_pImplAdviseSink);
659 
660     OleSetContainedObject(pOleObject, TRUE);
661 }
662 
663 namespace
664 {
OleLoadSeh(LPSTORAGE pIStorage,IUnknown ** ppObj)665     HRESULT OleLoadSeh(LPSTORAGE pIStorage, IUnknown** ppObj)
666     {
667         HRESULT hr = E_FAIL;
668         // tdf#119039: there is a nasty bug in OleLoad, that may call an unpaired
669         // IUnknown::Release on pIStorage on STG_E_FILENOTFOUND: see
670         // https://developercommunity.visualstudio.com/t/10144795
671         // Workaround it here to avoid crash in smart COM pointer destructor that
672         // would try to release already released object. Since we don't know if
673         // the bug appears each time STG_E_FILENOTFOUND is returned, this might
674         // potentially leak the storage object.
675         if (pIStorage)
676             pIStorage->AddRef();
677 
678         __try {
679             hr = OleLoad(pIStorage, IID_IUnknown, nullptr, IID_PPV_ARGS_Helper(ppObj));
680         } __except( EXCEPTION_EXECUTE_HANDLER ) {
681             hr = E_FAIL;
682         }
683         if (pIStorage && hr != STG_E_FILENOTFOUND)
684             pIStorage->Release();
685 
686         return hr;
687     }
688 }
689 
LoadEmbeddedObject(const OUString & aTempURL)690 void OleComponent::LoadEmbeddedObject( const OUString& aTempURL )
691 {
692     if ( !aTempURL.getLength() )
693         throw lang::IllegalArgumentException(); // TODO
694 
695     if (m_pNativeImpl->IsStorageRegistered())
696         throw io::IOException(); // TODO the object is already initialized or wrong initialization is done
697 
698     // open an IStorage based on the temporary file
699     OUString aFilePath;
700     if (osl::FileBase::getSystemPathFromFileURL(aTempURL, aFilePath) != ::osl::FileBase::E_None)
701         throw uno::RuntimeException(); // TODO: something dangerous happened
702 
703     sal::systools::COMReference<IStorage> pStorage;
704     HRESULT hr = StgOpenStorage(o3tl::toW(aFilePath.getStr()), nullptr,
705                                 STGM_READWRITE | STGM_TRANSACTED, // | STGM_DELETEONRELEASE,
706                                 nullptr, 0, &pStorage);
707     if (FAILED(hr) || !pStorage)
708         throw io::IOException(); // TODO: transport error code?
709 
710     m_pNativeImpl->registerStorage(pStorage);
711 
712     hr = OleLoadSeh(pStorage, &m_pNativeImpl->m_pObj);
713     if (FAILED(hr))
714         throw uno::RuntimeException();
715 
716     InitializeObject_Impl();
717 }
718 
719 
CreateObjectFromClipboard()720 void OleComponent::CreateObjectFromClipboard()
721 {
722     auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL()));
723     if (!pStorage)
724         throw uno::RuntimeException(); // TODO
725 
726     IDataObject * pDO = nullptr;
727     HRESULT hr = OleGetClipboard( &pDO );
728     if (FAILED(hr))
729         throw uno::RuntimeException();
730 
731     hr = OleQueryCreateFromData(pDO);
732     if (S_OK == hr)
733     {
734         hr = OleCreateFromData( pDO,
735                                 IID_IUnknown,
736                                 OLERENDER_DRAW, // OLERENDER_FORMAT
737                                 nullptr,        // &aFormat,
738                                 nullptr,
739                                 pStorage,
740                                 IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) );
741         if (FAILED(hr))
742             throw uno::RuntimeException();
743     }
744     else
745     {
746         // Static objects are not supported
747         pDO->Release();
748     }
749 
750     InitializeObject_Impl();
751 }
752 
753 
CreateNewEmbeddedObject(const uno::Sequence<sal_Int8> & aSeqCLSID)754 void OleComponent::CreateNewEmbeddedObject( const uno::Sequence< sal_Int8 >& aSeqCLSID )
755 {
756     CLSID aClsID;
757 
758     if ( !GetClassIDFromSequence_Impl( aSeqCLSID, aClsID ) )
759         throw lang::IllegalArgumentException(); // TODO
760 
761     auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL()));
762     if (!pStorage)
763         throw uno::RuntimeException(); // TODO
764 
765     // FORMATETC aFormat = { CF_METAFILEPICT, NULL, nAspect, -1, TYMED_MFPICT }; // for OLE..._DRAW should be NULL
766 
767     HRESULT hr = OleCreate( aClsID,
768                             IID_IUnknown,
769                             OLERENDER_DRAW, // OLERENDER_FORMAT
770                             nullptr,        // &aFormat,
771                             nullptr,
772                             pStorage,
773                             IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) );
774     if (FAILED(hr))
775         throw uno::RuntimeException(); // TODO
776 
777     InitializeObject_Impl();
778 
779     // TODO: getExtent???
780 }
781 
782 
CreateObjectFromData(const uno::Reference<datatransfer::XTransferable> &)783 void OleComponent::CreateObjectFromData( const uno::Reference< datatransfer::XTransferable >& )
784 // Static objects are not supported, they should be inserted as graphics
785 {
786     // TODO: May be this call is useless since there are no static objects
787     //       and nonstatic objects will be created based on OLEstorage ( stream ).
788     //       ???
789 
790     // OleQueryCreateFromData...
791 }
792 
793 
CreateObjectFromFile(const OUString & aFileURL)794 void OleComponent::CreateObjectFromFile( const OUString& aFileURL )
795 {
796     auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL()));
797     if (!pStorage)
798         throw uno::RuntimeException(); // TODO:
799 
800     OUString aFilePath;
801     if ( ::osl::FileBase::getSystemPathFromFileURL( aFileURL, aFilePath ) != ::osl::FileBase::E_None )
802         throw uno::RuntimeException(); // TODO: something dangerous happened
803 
804     HRESULT hr = OleCreateFromFile( CLSID_NULL,
805                                     o3tl::toW(aFilePath.getStr()),
806                                     IID_IUnknown,
807                                     OLERENDER_DRAW, // OLERENDER_FORMAT
808                                     nullptr,
809                                     nullptr,
810                                     pStorage,
811                                     IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) );
812     if (FAILED(hr))
813         throw uno::RuntimeException(); // TODO
814 
815     InitializeObject_Impl();
816 }
817 
818 
CreateLinkFromFile(const OUString & aFileURL)819 void OleComponent::CreateLinkFromFile( const OUString& aFileURL )
820 {
821     auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL()));
822     if (!pStorage)
823         throw uno::RuntimeException(); // TODO:
824 
825     OUString aFilePath;
826     if ( ::osl::FileBase::getSystemPathFromFileURL( aFileURL, aFilePath ) != ::osl::FileBase::E_None )
827         throw uno::RuntimeException(); // TODO: something dangerous happened
828 
829     HRESULT hr = OleCreateLinkToFile( o3tl::toW(aFilePath.getStr()),
830                                         IID_IUnknown,
831                                         OLERENDER_DRAW, // OLERENDER_FORMAT
832                                         nullptr,
833                                         nullptr,
834                                         pStorage,
835                                         IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) );
836     if (FAILED(hr))
837         throw uno::RuntimeException(); // TODO
838 
839     InitializeObject_Impl();
840 }
841 
842 
InitEmbeddedCopyOfLink(rtl::Reference<OleComponent> const & pOleLinkComponent)843 void OleComponent::InitEmbeddedCopyOfLink( rtl::Reference<OleComponent> const & pOleLinkComponent )
844 {
845     if (!pOleLinkComponent)
846         throw lang::IllegalArgumentException(); // TODO
847 
848     auto pOleLinkComponentObj(pOleLinkComponent->m_pNativeImpl->getObj());
849     if (!pOleLinkComponentObj)
850         throw lang::IllegalArgumentException();
851 
852     // the object must be already disconnected from the temporary URL
853     auto pStorage(m_pNativeImpl->CreateNewStorage(getTempURL()));
854 
855     SolarMutexReleaser releaser;
856 
857     auto pDataObject(pOleLinkComponentObj.QueryInterface<IDataObject>(sal::systools::COM_QUERY));
858     if ( pDataObject && SUCCEEDED( OleQueryCreateFromData( pDataObject ) ) )
859     {
860         if (!pStorage)
861             throw uno::RuntimeException(); // TODO:
862 
863         OleCreateFromData( pDataObject,
864                                 IID_IUnknown,
865                                 OLERENDER_DRAW,
866                                 nullptr,
867                                 nullptr,
868                                 pStorage,
869                                 IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) );
870     }
871 
872     if ( !m_pNativeImpl->m_pObj )
873     {
874         auto pOleLink(pOleLinkComponentObj.QueryInterface<IOleLink>(sal::systools::COM_QUERY));
875         if ( !pOleLink )
876             throw io::IOException(); // TODO: the object doesn't support IOleLink
877 
878         sal::systools::COMReference< IMoniker > pMoniker;
879         HRESULT hr = pOleLink->GetSourceMoniker( &pMoniker );
880         if ( FAILED( hr ) || !pMoniker )
881             throw io::IOException(); // TODO: can not retrieve moniker
882 
883         // In case of file moniker life is easy : )
884         DWORD aMonType = 0;
885         hr = pMoniker->IsSystemMoniker( &aMonType );
886         if ( SUCCEEDED( hr ) && aMonType == MKSYS_FILEMONIKER )
887         {
888             sal::systools::COMReference< IMalloc > pMalloc;
889             hr = CoGetMalloc( 1, &pMalloc ); // if fails there will be a memory leak
890             OSL_ENSURE(SUCCEEDED(hr) && pMalloc, "CoGetMalloc() failed!");
891 
892             LPOLESTR pOleStr = nullptr;
893             hr = pOleLink->GetSourceDisplayName( &pOleStr );
894             if ( SUCCEEDED( hr ) && pOleStr )
895             {
896                 std::wstring aFilePath( pOleStr );
897                 if ( pMalloc )
898                     pMalloc->Free( pOleStr );
899 
900                 hr = OleCreateFromFile( CLSID_NULL,
901                                         aFilePath.c_str(),
902                                         IID_IUnknown,
903                                         OLERENDER_DRAW, // OLERENDER_FORMAT
904                                         nullptr,
905                                         nullptr,
906                                         pStorage,
907                                         IID_PPV_ARGS_Helper(&m_pNativeImpl->m_pObj) );
908             }
909         }
910 
911         // in case of other moniker types the only way is to get storage
912         if ( !m_pNativeImpl->m_pObj )
913         {
914             sal::systools::COMReference< IBindCtx > pBindCtx;
915             hr = CreateBindCtx( 0, &pBindCtx );
916             if ( SUCCEEDED( hr ) && pBindCtx )
917             {
918                 sal::systools::COMReference< IStorage > pObjectStorage;
919                 hr = pMoniker->BindToStorage(pBindCtx, nullptr, IID_PPV_ARGS(&pObjectStorage));
920                 if ( SUCCEEDED( hr ) && pObjectStorage )
921                 {
922                     hr = pObjectStorage->CopyTo(0, nullptr, nullptr, pStorage);
923                     if ( SUCCEEDED( hr ) )
924                         hr = OleLoadSeh(pStorage, &m_pNativeImpl->m_pObj);
925                 }
926             }
927         }
928     }
929 
930     InitializeObject_Impl();
931 }
932 
933 
RunObject()934 void OleComponent::RunObject()
935 {
936     auto pOleObject(m_pNativeImpl->get<IOleObject>());
937     OSL_ENSURE(pOleObject, "The pointer can not be set to NULL here!");
938     if (!pOleObject)
939         throw embed::WrongStateException(); // TODO: the object is in wrong state
940 
941     if (!OleIsRunning(pOleObject))
942     {
943         HRESULT hr = OleRun( m_pNativeImpl->m_pObj );
944 
945         if ( FAILED( hr ) )
946         {
947             OUString error = WindowsErrorStringFromHRESULT(hr);
948             if ( hr == REGDB_E_CLASSNOTREG )
949             {
950                 if (auto pOleObj
951                     = m_pNativeImpl->m_pObj.QueryInterface<IOleObject>(sal::systools::COM_QUERY))
952                 {
953                     LPOLESTR lpUserType = nullptr;
954                     if (SUCCEEDED(pOleObj->GetUserType(USERCLASSTYPE_FULL, &lpUserType)))
955                     {
956                         error += OUString::Concat("\n") + o3tl::toU(lpUserType);
957                         sal::systools::COMReference<IMalloc> pMalloc;
958                         hr = CoGetMalloc(1, &pMalloc); // if fails there will be a memory leak
959                         SAL_WARN_IF(FAILED(hr) || !pMalloc, "embeddedobj.ole", "CoGetMalloc() failed");
960                         if (pMalloc)
961                             pMalloc->Free(lpUserType);
962                     }
963                 }
964                 throw embed::UnreachableStateException(
965                     error, getXWeak(), -1,
966                     css::embed::EmbedStates::RUNNING); // the object server is not installed
967             }
968             else
969                 throw io::IOException(error, getXWeak());
970         }
971         // Only now, when the object is activated, it can be registered in the global table;
972         // before this point, RegisterInterfaceInGlobal would return CO_E_OBJNOTCONNECTED
973         m_pNativeImpl->registerObj();
974     }
975 }
976 
977 
CalculateWithFactor(const awt::Size & aSize,const awt::Size & aMultiplier,const awt::Size & aDivisor)978 awt::Size OleComponent::CalculateWithFactor( const awt::Size& aSize,
979                                             const awt::Size& aMultiplier,
980                                             const awt::Size& aDivisor )
981 {
982     awt::Size aResult;
983 
984     sal_Int64 nWidth = static_cast<sal_Int64>(aSize.Width) * static_cast<sal_Int64>(aMultiplier.Width) / static_cast<sal_Int64>(aDivisor.Width);
985     sal_Int64 nHeight = static_cast<sal_Int64>(aSize.Height) * static_cast<sal_Int64>(aMultiplier.Height) / static_cast<sal_Int64>(aDivisor.Height);
986     OSL_ENSURE( nWidth < SAL_MAX_INT32 && nWidth > SAL_MIN_INT32
987              && nHeight < SAL_MAX_INT32 && nHeight > SAL_MIN_INT32,
988              "Unacceptable result size!" );
989 
990     aResult.Width = static_cast<sal_Int32>(nWidth);
991     aResult.Height = static_cast<sal_Int32>(nHeight);
992 
993     return aResult;
994 }
995 
996 
CloseObject()997 void OleComponent::CloseObject()
998 {
999     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1000     if (pOleObject && OleIsRunning(pOleObject))
1001     {
1002         SolarMutexReleaser releaser;
1003         HRESULT hr = pOleObject->Close(OLECLOSE_NOSAVE); // must be saved before
1004         SAL_WARN_IF(FAILED(hr), "embeddedobj.ole", "IOleObject::Close failed");
1005     }
1006 }
1007 
1008 
GetVerbList()1009 uno::Sequence< embed::VerbDescriptor > OleComponent::GetVerbList()
1010 {
1011     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1012     if (!pOleObject)
1013         throw embed::WrongStateException(); // TODO: the object is in wrong state
1014 
1015     if( !m_aVerbList.getLength() )
1016     {
1017         sal::systools::COMReference< IEnumOLEVERB > pEnum;
1018         HRESULT hr;
1019         {
1020             SolarMutexReleaser releaser;
1021             hr = pOleObject->EnumVerbs(&pEnum);
1022         }
1023         if (SUCCEEDED(hr))
1024         {
1025             OLEVERB     szEle[ MAX_ENUM_ELE ];
1026             ULONG       nNum = 0;
1027             sal_Int32   nSeqSize = 0;
1028 
1029             do
1030             {
1031                 hr = pEnum->Next(MAX_ENUM_ELE, szEle, &nNum);
1032                 if( hr == S_OK || hr == S_FALSE )
1033                 {
1034                     m_aVerbList.realloc( nSeqSize += nNum );
1035                     auto pVerbList = m_aVerbList.getArray();
1036                     for( sal_uInt32 nInd = 0; nInd < nNum; nInd++ )
1037                     {
1038                         pVerbList[nSeqSize-nNum+nInd].VerbID = szEle[ nInd ].lVerb;
1039                         pVerbList[nSeqSize-nNum+nInd].VerbName = WinAccToVcl_Impl( o3tl::toU(szEle[ nInd ].lpszVerbName) );
1040                         pVerbList[nSeqSize-nNum+nInd].VerbFlags = szEle[ nInd ].fuFlags;
1041                         pVerbList[nSeqSize-nNum+nInd].VerbAttributes = szEle[ nInd ].grfAttribs;
1042                     }
1043                 }
1044                 else
1045                     break;
1046             }
1047             while( nNum == MAX_ENUM_ELE );
1048         }
1049     }
1050 
1051     return m_aVerbList;
1052 }
1053 
1054 
ExecuteVerb(sal_Int32 nVerbID)1055 void OleComponent::ExecuteVerb( sal_Int32 nVerbID )
1056 {
1057     RunObject();
1058 
1059     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1060     if (!pOleObject)
1061         throw embed::WrongStateException(); // TODO
1062 
1063     SolarMutexReleaser releaser;
1064 
1065     // TODO: probably extents should be set here and stored in aRect
1066     // TODO: probably the parent window also should be set
1067     HRESULT hr = pOleObject->DoVerb(nVerbID, nullptr, m_pOleWrapClientSite, 0, nullptr, nullptr);
1068 
1069     if ( FAILED( hr ) )
1070         throw io::IOException(); // TODO
1071 }
1072 
1073 
SetHostName(const OUString & aEmbDocName)1074 void OleComponent::SetHostName( const OUString& aEmbDocName )
1075 {
1076     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1077     if (!pOleObject)
1078         throw embed::WrongStateException(); // TODO: the object is in wrong state
1079 
1080     SolarMutexReleaser releaser;
1081     pOleObject->SetHostNames(L"app name", o3tl::toW(aEmbDocName.getStr()));
1082 }
1083 
1084 
SetExtent(const awt::Size & aVisAreaSize,sal_Int64 nAspect)1085 void OleComponent::SetExtent( const awt::Size& aVisAreaSize, sal_Int64 nAspect )
1086 {
1087     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1088     if (!pOleObject)
1089         throw embed::WrongStateException(); // TODO: the object is in wrong state
1090 
1091     DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects
1092 
1093     SIZEL aSize = { aVisAreaSize.Width, aVisAreaSize.Height };
1094     HRESULT hr;
1095     {
1096         SolarMutexReleaser releaser;
1097         hr = pOleObject->SetExtent(nMSAspect, &aSize);
1098     }
1099 
1100     if ( FAILED( hr ) )
1101     {
1102         // TODO/LATER: is it correct? In future user code probably should be ready for the exception.
1103         // if the object is running but not activated, RPC_E_SERVER_DIED error code is returned by OLE package
1104         // in this case just do nothing
1105         // Also Visio returns E_FAIL on resize if it is in running state
1106         // if ( hr != RPC_E_SERVER_DIED )
1107         throw io::IOException(); // TODO
1108     }
1109 }
1110 
1111 
GetExtent(sal_Int64 nAspect)1112 awt::Size OleComponent::GetExtent( sal_Int64 nAspect )
1113 {
1114     if (!m_pNativeImpl->m_pObj)
1115         throw embed::WrongStateException(); // TODO: the object is in wrong state
1116 
1117     DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects
1118     awt::Size aSize;
1119     bool bGotSize = false;
1120 
1121     if ( nMSAspect == DVASPECT_CONTENT )
1122     {
1123         // Try to get the size from the replacement image first
1124         if (auto pDataObject = m_pNativeImpl->get<IDataObject>())
1125         {
1126             STGMEDIUM aMedium;
1127             FORMATETC aFormat = pFormatTemplates[1]; // use windows metafile format
1128             aFormat.dwAspect = nMSAspect;
1129 
1130             HRESULT hr;
1131             {
1132                 SolarMutexReleaser releaser;
1133                 hr = pDataObject->GetData(&aFormat, &aMedium);
1134             }
1135 
1136             if (hr == RPC_E_WRONG_THREAD)
1137             {
1138                 // Assume that the OLE object was loaded on the main thread.
1139                 vcl::solarthread::syncExecute([this, &hr, &pDataObject, &aFormat, &aMedium]() {
1140                     // Make sure that the current state is embed::EmbedStates::RUNNING.
1141                     RunObject();
1142                     // Now try again on the correct thread.
1143                     hr = pDataObject->GetData(&aFormat, &aMedium);
1144                 });
1145             }
1146 
1147             if ( SUCCEEDED( hr ) && aMedium.tymed == TYMED_MFPICT ) // Win Metafile
1148             {
1149                 METAFILEPICT* pMF = static_cast<METAFILEPICT*>(GlobalLock( aMedium.hMetaFilePict ));
1150                 if ( pMF )
1151                 {
1152                     // the object uses 0.01 mm as unit, so the metafile size should be converted to object unit
1153                     o3tl::Length eFrom = o3tl::Length::mm100;
1154                     switch( pMF->mm )
1155                     {
1156                         case MM_HIENGLISH:
1157                             eFrom = o3tl::Length::in1000;
1158                             break;
1159 
1160                         case MM_LOENGLISH:
1161                             eFrom = o3tl::Length::in100;
1162                             break;
1163 
1164                         case MM_LOMETRIC:
1165                             eFrom = o3tl::Length::mm10;
1166                             break;
1167 
1168                         case MM_TWIPS:
1169                             eFrom = o3tl::Length::twip;
1170                             break;
1171 
1172                         case MM_ISOTROPIC:
1173                         case MM_ANISOTROPIC:
1174                         case MM_HIMETRIC:
1175                             // do nothing
1176                             break;
1177                     }
1178 
1179                     sal_Int64 nX = o3tl::convert(abs( pMF->xExt ), eFrom, o3tl::Length::mm100);
1180                     sal_Int64 nY = o3tl::convert(abs( pMF->yExt ), eFrom, o3tl::Length::mm100);
1181                     if (  nX < SAL_MAX_INT32 && nY < SAL_MAX_INT32 )
1182                     {
1183                         aSize.Width = static_cast<sal_Int32>(nX);
1184                         aSize.Height = static_cast<sal_Int32>(nY);
1185                         bGotSize = true;
1186                     }
1187                     else
1188                         OSL_FAIL( "Unexpected size is provided!" );
1189                 }
1190             }
1191             else if (!SUCCEEDED(hr))
1192             {
1193                 SAL_WARN("embeddedobj.ole", " OleComponent::GetExtent: GetData() failed");
1194             }
1195             // i113605, to release storage medium
1196             if ( SUCCEEDED( hr ) )
1197                 ::ReleaseStgMedium(&aMedium);
1198         }
1199     }
1200 
1201     if ( !bGotSize )
1202         throw lang::IllegalArgumentException();
1203 
1204     return aSize;
1205 }
1206 
1207 
GetCachedExtent(sal_Int64 nAspect)1208 awt::Size OleComponent::GetCachedExtent( sal_Int64 nAspect )
1209 {
1210     auto pViewObject2(m_pNativeImpl->get<IViewObject2>());
1211     if (!pViewObject2)
1212         throw embed::WrongStateException(); // TODO: the object is in wrong state
1213 
1214     DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects
1215     SIZEL aSize;
1216 
1217     HRESULT hr;
1218     {
1219         SolarMutexReleaser releaser;
1220         hr = pViewObject2->GetExtent(nMSAspect, -1, nullptr, &aSize);
1221     }
1222 
1223     if ( FAILED( hr ) )
1224     {
1225         // TODO/LATER: is it correct?
1226         // if there is no appropriate cache for the aspect, OLE_E_BLANK error code is returned
1227         // if ( hr == OLE_E_BLANK )
1228         //  throw lang::IllegalArgumentException();
1229         //else
1230         //  throw io::IOException(); // TODO
1231 
1232         SAL_WARN("embeddedobj.ole", " OleComponent::GetCachedExtent: GetExtent() failed");
1233         throw lang::IllegalArgumentException();
1234     }
1235 
1236     return awt::Size( aSize.cx, aSize.cy );
1237 }
1238 
1239 
GetRecommendedExtent(sal_Int64 nAspect)1240 awt::Size OleComponent::GetRecommendedExtent( sal_Int64 nAspect )
1241 {
1242     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1243     if (!pOleObject)
1244         throw embed::WrongStateException(); // TODO: the object is in wrong state
1245 
1246     DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects
1247     SIZEL aSize;
1248     HRESULT hr;
1249     {
1250         SolarMutexReleaser releaser;
1251         hr = pOleObject->GetExtent(nMSAspect, &aSize);
1252     }
1253     if ( FAILED( hr ) )
1254     {
1255         SAL_WARN("embeddedobj.ole", " OleComponent::GetRecommendedExtent: GetExtent() failed");
1256         throw lang::IllegalArgumentException();
1257     }
1258 
1259     return awt::Size( aSize.cx, aSize.cy );
1260 }
1261 
1262 
GetMiscStatus(sal_Int64 nAspect)1263 sal_Int64 OleComponent::GetMiscStatus( sal_Int64 nAspect )
1264 {
1265     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1266     if (!pOleObject)
1267         throw embed::WrongStateException(); // TODO: the object is in wrong state
1268 
1269     DWORD nResult = 0;
1270     {
1271         SolarMutexReleaser releaser;
1272         pOleObject->GetMiscStatus(static_cast<DWORD>(nAspect), &nResult);
1273     }
1274     return static_cast<sal_Int64>(nResult); // first 32 bits are for MS flags
1275 }
1276 
1277 
GetCLSID()1278 uno::Sequence< sal_Int8 > OleComponent::GetCLSID()
1279 {
1280     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1281     if (!pOleObject)
1282         throw embed::WrongStateException(); // TODO: the object is in wrong state
1283 
1284     GUID aCLSID;
1285     HRESULT hr;
1286     {
1287         SolarMutexReleaser releaser;
1288         hr = pOleObject->GetUserClassID(&aCLSID);
1289     }
1290     if ( FAILED( hr ) )
1291         throw io::IOException(); // TODO:
1292 
1293     return  MimeConfigurationHelper::GetSequenceClassID( aCLSID.Data1, aCLSID.Data2, aCLSID.Data3,
1294                                 aCLSID.Data4[0], aCLSID.Data4[1],
1295                                 aCLSID.Data4[2], aCLSID.Data4[3],
1296                                 aCLSID.Data4[4], aCLSID.Data4[5],
1297                                 aCLSID.Data4[6], aCLSID.Data4[7] );
1298 }
1299 
1300 
IsDirty()1301 bool OleComponent::IsDirty()
1302 {
1303     if ( IsWorkaroundActive() )
1304         return true;
1305 
1306     auto pPersistStorage(m_pNativeImpl->get<IPersistStorage>());
1307     if ( !pPersistStorage )
1308         throw io::IOException(); // TODO
1309 
1310     SolarMutexReleaser releaser;
1311     HRESULT hr = pPersistStorage->IsDirty();
1312     return ( hr != S_FALSE );
1313 }
1314 
1315 
StoreOwnTmpIfNecessary()1316 void OleComponent::StoreOwnTmpIfNecessary()
1317 {
1318     auto pOleObject(m_pNativeImpl->get<IOleObject>());
1319     if (!pOleObject)
1320         throw embed::WrongStateException(); // TODO: the object is in wrong state
1321 
1322     auto pPersistStorage(m_pNativeImpl->get<IPersistStorage>());
1323     if ( !pPersistStorage )
1324         throw io::IOException(); // TODO
1325 
1326     SolarMutexReleaser releaser;
1327 
1328     if ( m_bWorkaroundActive || pPersistStorage->IsDirty() != S_FALSE )
1329     {
1330         auto pStorage(m_pNativeImpl->getStorage());
1331         HRESULT hr = OleSave(pPersistStorage, pStorage, TRUE);
1332         if ( FAILED( hr ) )
1333         {
1334             // Till now was required only for AcrobatReader7.0.8
1335             GUID aCLSID;
1336             hr = pOleObject->GetUserClassID(&aCLSID);
1337             if ( FAILED( hr ) )
1338             {
1339                 SAL_WARN("embeddedobj.ole", "OleComponent::StoreOwnTmpIfNecessary: GetUserClassID() failed");
1340                 throw io::IOException(); // TODO
1341             }
1342 
1343             hr = WriteClassStg(pStorage, aCLSID);
1344             if ( FAILED( hr ) )
1345                 throw io::IOException(); // TODO
1346 
1347             // the result of the following call is not checked because some objects, for example AcrobatReader7.0.8
1348             // return error even in case the saving was done correctly
1349             hr = pPersistStorage->Save(pStorage, TRUE);
1350 
1351             // another workaround for AcrobatReader7.0.8 object, this object might think that it is not changed
1352             // when it has been created from file, although it must be saved
1353             m_bWorkaroundActive = true;
1354         }
1355 
1356         hr = pStorage->Commit(STGC_DEFAULT);
1357         if ( FAILED( hr ) )
1358             throw io::IOException(); // TODO
1359 
1360         hr = pPersistStorage->SaveCompleted( nullptr );
1361         if ( FAILED( hr ) && hr != E_UNEXPECTED )
1362             throw io::IOException(); // TODO
1363 
1364     }
1365 }
1366 
1367 
SaveObject_Impl()1368 bool OleComponent::SaveObject_Impl()
1369 {
1370     bool bResult = false;
1371     OleEmbeddedObject* pLockObject = nullptr;
1372 
1373     {
1374         osl::MutexGuard aGuard( m_aMutex );
1375         if ( m_pUnoOleObject )
1376         {
1377             pLockObject = m_pUnoOleObject;
1378             pLockObject->acquire();
1379         }
1380     }
1381 
1382     if ( pLockObject )
1383     {
1384         bResult = pLockObject->SaveObject_Impl();
1385         pLockObject->release();
1386     }
1387 
1388     return bResult;
1389 }
1390 
1391 
OnShowWindow_Impl(bool bShow)1392 bool OleComponent::OnShowWindow_Impl( bool bShow )
1393 {
1394     bool bResult = false;
1395     OleEmbeddedObject* pLockObject = nullptr;
1396 
1397     {
1398         osl::MutexGuard aGuard( m_aMutex );
1399 
1400         if ( m_pUnoOleObject )
1401         {
1402             pLockObject = m_pUnoOleObject;
1403             pLockObject->acquire();
1404         }
1405     }
1406 
1407     if ( pLockObject )
1408     {
1409         bResult = pLockObject->OnShowWindow_Impl( bShow );
1410         pLockObject->release();
1411     }
1412 
1413     return bResult;
1414 }
1415 
1416 
OnViewChange_Impl(sal_uInt32 dwAspect)1417 void OleComponent::OnViewChange_Impl( sal_uInt32 dwAspect )
1418 {
1419     // TODO: check if it is enough or may be saving notifications are required for Visio2000
1420     ::rtl::Reference< OleEmbeddedObject > xLockObject;
1421 
1422     {
1423         osl::MutexGuard aGuard( m_aMutex );
1424         if ( m_pUnoOleObject )
1425             xLockObject = m_pUnoOleObject;
1426     }
1427 
1428     if ( xLockObject.is() )
1429     {
1430         uno::Reference < awt::XRequestCallback > xRequestCallback(
1431             m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.awt.AsyncCallback", m_xContext),
1432              uno::UNO_QUERY );
1433         xRequestCallback->addCallback( new MainThreadNotificationRequest( xLockObject, OLECOMP_ONVIEWCHANGE, dwAspect ), uno::Any() );
1434     }
1435 }
1436 
1437 
OnClose_Impl()1438 void OleComponent::OnClose_Impl()
1439 {
1440     ::rtl::Reference< OleEmbeddedObject > xLockObject;
1441 
1442     {
1443         osl::MutexGuard aGuard( m_aMutex );
1444         if ( m_pUnoOleObject )
1445             xLockObject = m_pUnoOleObject;
1446     }
1447 
1448     if ( xLockObject.is() )
1449     {
1450         uno::Reference < awt::XRequestCallback > xRequestCallback(
1451             m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.awt.AsyncCallback", m_xContext),
1452              uno::UNO_QUERY );
1453         xRequestCallback->addCallback( new MainThreadNotificationRequest( xLockObject, OLECOMP_ONCLOSE ), uno::Any() );
1454     }
1455 }
1456 
1457 // XCloseable
1458 
close(sal_Bool bDeliverOwnership)1459 void SAL_CALL OleComponent::close( sal_Bool bDeliverOwnership )
1460 {
1461     uno::Reference< uno::XInterface > xSelfHold;
1462     {
1463         osl::MutexGuard aGuard(m_aMutex);
1464         if (m_bDisposed)
1465             throw lang::DisposedException(); // TODO
1466 
1467         xSelfHold.set(static_cast<::cppu::OWeakObject*>(this));
1468         lang::EventObject aSource(static_cast<::cppu::OWeakObject*>(this));
1469 
1470         if (m_pInterfaceContainer)
1471         {
1472             comphelper::OInterfaceContainerHelper2* pContainer
1473                 = m_pInterfaceContainer->getContainer(cppu::UnoType<util::XCloseListener>::get());
1474             if (pContainer != nullptr)
1475             {
1476                 comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
1477                 while (pIterator.hasMoreElements())
1478                 {
1479                     try
1480                     {
1481                         static_cast<util::XCloseListener*>(pIterator.next())
1482                             ->queryClosing(aSource, bDeliverOwnership);
1483                     }
1484                     catch (const uno::RuntimeException&)
1485                     {
1486                         pIterator.remove();
1487                     }
1488                 }
1489             }
1490 
1491             pContainer
1492                 = m_pInterfaceContainer->getContainer(cppu::UnoType<util::XCloseListener>::get());
1493             if (pContainer != nullptr)
1494             {
1495                 comphelper::OInterfaceIteratorHelper2 pCloseIterator(*pContainer);
1496                 while (pCloseIterator.hasMoreElements())
1497                 {
1498                     try
1499                     {
1500                         static_cast<util::XCloseListener*>(pCloseIterator.next())
1501                             ->notifyClosing(aSource);
1502                     }
1503                     catch (const uno::RuntimeException&)
1504                     {
1505                         pCloseIterator.remove();
1506                     }
1507                 }
1508             }
1509         }
1510     }
1511 
1512     Dispose();
1513 }
1514 
1515 
addCloseListener(const uno::Reference<util::XCloseListener> & xListener)1516 void SAL_CALL OleComponent::addCloseListener( const uno::Reference< util::XCloseListener >& xListener )
1517 {
1518     ::osl::MutexGuard aGuard( m_aMutex );
1519     if ( m_bDisposed )
1520         throw lang::DisposedException(); // TODO
1521 
1522     if ( !m_pInterfaceContainer )
1523         m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex );
1524 
1525     m_pInterfaceContainer->addInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
1526 }
1527 
1528 
removeCloseListener(const uno::Reference<util::XCloseListener> & xListener)1529 void SAL_CALL OleComponent::removeCloseListener( const uno::Reference< util::XCloseListener >& xListener )
1530 {
1531     ::osl::MutexGuard aGuard( m_aMutex );
1532     if ( m_bDisposed )
1533         throw lang::DisposedException(); // TODO
1534 
1535     if ( m_pInterfaceContainer )
1536         m_pInterfaceContainer->removeInterface( cppu::UnoType<util::XCloseListener>::get(),
1537                                                 xListener );
1538 }
1539 
1540 // XTransferable
1541 
getTransferData(const datatransfer::DataFlavor & aFlavor)1542 uno::Any SAL_CALL OleComponent::getTransferData( const datatransfer::DataFlavor& aFlavor )
1543 {
1544     ::osl::MutexGuard aGuard( m_aMutex );
1545     if ( m_bDisposed )
1546         throw lang::DisposedException(); // TODO
1547 
1548     if (!m_pNativeImpl->m_pObj)
1549         throw embed::WrongStateException(); // TODO: the object is in wrong state
1550 
1551     uno::Any aResult;
1552     bool bSupportedFlavor = false;
1553 
1554     if ( m_pNativeImpl->GraphicalFlavor( aFlavor ) )
1555     {
1556         DWORD nRequestedAspect = GetAspectFromFlavor( aFlavor );
1557         // if own icon is set and icon aspect is requested the own icon can be returned directly
1558 
1559         auto pDataObject(m_pNativeImpl->get<IDataObject>());
1560         if ( !pDataObject )
1561             throw io::IOException(); // TODO: transport error code
1562 
1563         // The following optimization does not make much sense currently just because
1564         // only one aspect is supported, and only three formats for the aspect are supported
1565         // and moreover it is not guaranteed that the once returned format will be supported further
1566         // example - i52106
1567         // TODO/LATER: bring the optimization back when other aspects are supported
1568 
1569         // FORMATETC* pFormatEtc = m_pNativeImpl->GetSupportedFormatForAspect( nRequestedAspect );
1570         // if ( pFormatEtc )
1571         // {
1572         //  STGMEDIUM aMedium;
1573         //  hr = pDataObject->GetData( pFormatEtc, &aMedium );
1574         //  if ( SUCCEEDED( hr ) )
1575         //      bSupportedFlavor = m_pNativeImpl->ConvertDataForFlavor( aMedium, aFlavor, aResult );
1576         // }
1577         // else
1578         {
1579             // the supported format of the application is still not found, find one
1580             for ( sal_Int32 nInd = 0; nInd < FORMATS_NUM; nInd++ )
1581             {
1582                 STGMEDIUM aMedium;
1583                 FORMATETC aFormat = pFormatTemplates[nInd];
1584                 aFormat.dwAspect = nRequestedAspect;
1585 
1586                 HRESULT hr;
1587                 {
1588                     SolarMutexReleaser releaser;
1589                     hr = pDataObject->GetData(&aFormat, &aMedium);
1590                 }
1591                 if ( SUCCEEDED( hr ) )
1592                 {
1593                     bSupportedFlavor = m_pNativeImpl->ConvertDataForFlavor( aMedium, aFlavor, aResult );
1594                     ::ReleaseStgMedium(&aMedium);     // i113605, to release storage medium
1595                     if ( bSupportedFlavor )
1596                     {
1597                         // TODO/LATER: bring the optimization back when other aspects are supported
1598                         // m_pNativeImpl->AddSupportedFormat( aFormat );
1599                         break;
1600                     }
1601                 }
1602             }
1603         }
1604 
1605         // If the replacement could not be retrieved, the cached representation should be used
1606         // currently it is not necessary to retrieve it here, so it is implemented in the object itself
1607     }
1608     // TODO: Investigate if there is already the format name
1609     //       and whether this format is really required
1610     else if ( aFlavor.DataType == cppu::UnoType<io::XInputStream>::get()
1611             && aFlavor.MimeType == "application/x-openoffice-contentstream" )
1612     {
1613         // allow to retrieve stream-representation of the object persistence
1614         bSupportedFlavor = true;
1615         uno::Reference < io::XStream > xTempFileStream(
1616             io::TempFile::create(m_xContext),
1617             uno::UNO_QUERY_THROW );
1618 
1619         uno::Reference< io::XOutputStream > xTempOutStream = xTempFileStream->getOutputStream();
1620         uno::Reference< io::XInputStream > xTempInStream = xTempFileStream->getInputStream();
1621         if ( !(xTempOutStream.is() && xTempInStream.is()) )
1622             throw io::IOException(); // TODO:
1623 
1624         OSL_ENSURE( m_pUnoOleObject, "Unexpected object absence!" );
1625         if ( !m_pUnoOleObject )
1626             throw uno::RuntimeException();
1627 
1628         m_pUnoOleObject->StoreObjectToStream( xTempOutStream );
1629 
1630         xTempOutStream->closeOutput();
1631         xTempOutStream.clear();
1632 
1633         aResult <<= xTempInStream;
1634     }
1635 
1636     if ( !bSupportedFlavor )
1637         throw datatransfer::UnsupportedFlavorException();
1638 
1639     return aResult;
1640 }
1641 
1642 
getTransferDataFlavors()1643 uno::Sequence< datatransfer::DataFlavor > SAL_CALL OleComponent::getTransferDataFlavors()
1644 {
1645     ::osl::MutexGuard aGuard( m_aMutex );
1646     if ( m_bDisposed )
1647         throw lang::DisposedException(); // TODO
1648 
1649     RetrieveObjectDataFlavors_Impl();
1650 
1651     return m_aDataFlavors;
1652 }
1653 
1654 
isDataFlavorSupported(const datatransfer::DataFlavor & aFlavor)1655 sal_Bool SAL_CALL OleComponent::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
1656 {
1657     ::osl::MutexGuard aGuard( m_aMutex );
1658     if ( m_bDisposed )
1659         throw lang::DisposedException(); // TODO
1660 
1661     RetrieveObjectDataFlavors_Impl();
1662 
1663     for (auto const& supportedFormat : m_aDataFlavors)
1664         if ( supportedFormat.MimeType.equals( aFlavor.MimeType ) && supportedFormat.DataType == aFlavor.DataType )
1665             return true;
1666 
1667     return false;
1668 }
1669 
dispose()1670 void SAL_CALL OleComponent::dispose()
1671 {
1672     try
1673     {
1674         close( true );
1675     }
1676     catch ( const uno::Exception& )
1677     {
1678     }
1679 }
1680 
addEventListener(const uno::Reference<lang::XEventListener> & xListener)1681 void SAL_CALL OleComponent::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
1682 {
1683     ::osl::MutexGuard aGuard( m_aMutex );
1684     if ( m_bDisposed )
1685         throw lang::DisposedException(); // TODO
1686 
1687     if ( !m_pInterfaceContainer )
1688         m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex );
1689 
1690     m_pInterfaceContainer->addInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
1691 }
1692 
1693 
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)1694 void SAL_CALL OleComponent::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
1695 {
1696     ::osl::MutexGuard aGuard( m_aMutex );
1697     if ( m_bDisposed )
1698         throw lang::DisposedException(); // TODO
1699 
1700     if ( m_pInterfaceContainer )
1701         m_pInterfaceContainer->removeInterface( cppu::UnoType<lang::XEventListener>::get(),
1702                                                 xListener );
1703 }
1704 
getSomething(const css::uno::Sequence<sal_Int8> & aIdentifier)1705 sal_Int64 SAL_CALL OleComponent::getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier )
1706 {
1707     try
1708     {
1709         uno::Sequence < sal_Int8 > aCLSID = GetCLSID();
1710         if ( MimeConfigurationHelper::ClassIDsEqual( aIdentifier, aCLSID ) )
1711             return comphelper::getSomething_cast(m_pNativeImpl->m_pObj.get());
1712     }
1713     catch ( const uno::Exception& )
1714     {
1715     }
1716 
1717     return 0;
1718 }
1719 
isModified()1720 sal_Bool SAL_CALL OleComponent::isModified()
1721 {
1722     return m_bModified;
1723 }
1724 
setModified(sal_Bool bModified)1725 void SAL_CALL OleComponent::setModified( sal_Bool bModified )
1726 {
1727     m_bModified = bModified;
1728 
1729     if ( bModified && m_pInterfaceContainer )
1730     {
1731         comphelper::OInterfaceContainerHelper2* pContainer =
1732             m_pInterfaceContainer->getContainer( cppu::UnoType<util::XModifyListener>::get());
1733         if ( pContainer != nullptr )
1734         {
1735             comphelper::OInterfaceIteratorHelper2 pIterator( *pContainer );
1736             while ( pIterator.hasMoreElements() )
1737             {
1738                 try
1739                 {
1740                     lang::EventObject aEvent( static_cast<util::XModifiable*>(this) );
1741                     static_cast<util::XModifyListener*>(pIterator.next())->modified( aEvent );
1742                 }
1743                 catch( const uno::RuntimeException& )
1744                 {
1745                     pIterator.remove();
1746                 }
1747             }
1748         }
1749     }
1750 }
1751 
addModifyListener(const css::uno::Reference<css::util::XModifyListener> & xListener)1752 void SAL_CALL OleComponent::addModifyListener( const css::uno::Reference < css::util::XModifyListener >& xListener )
1753 {
1754     ::osl::MutexGuard aGuard( m_aMutex );
1755     if ( m_bDisposed )
1756         throw lang::DisposedException(); // TODO
1757 
1758     if ( !m_pInterfaceContainer )
1759         m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex );
1760 
1761     m_pInterfaceContainer->addInterface( cppu::UnoType<util::XModifyListener>::get(), xListener );
1762 }
1763 
removeModifyListener(const css::uno::Reference<css::util::XModifyListener> & xListener)1764 void SAL_CALL OleComponent::removeModifyListener( const css::uno::Reference < css::util::XModifyListener >& xListener)
1765 {
1766     ::osl::MutexGuard aGuard( m_aMutex );
1767     if ( m_bDisposed )
1768         throw lang::DisposedException(); // TODO
1769 
1770     if ( m_pInterfaceContainer )
1771         m_pInterfaceContainer->removeInterface( cppu::UnoType<util::XModifyListener>::get(),
1772                                                 xListener );
1773 }
1774 
1775 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1776