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 <com/sun/star/embed/EmbeddedObjectCreator.hpp>
21 #include <com/sun/star/embed/XEmbeddedObject.hpp>
22 #include <com/sun/star/embed/EntryInitModes.hpp>
23 #include <com/sun/star/embed/OLEEmbeddedObjectFactory.hpp>
24 #include <com/sun/star/beans/PropertyValue.hpp>
25 #include <com/sun/star/datatransfer/DataFlavor.hpp>
26 #include <com/sun/star/lang/IllegalArgumentException.hpp>
27 #include <com/sun/star/ucb/CommandAbortedException.hpp>
28 
29 #include <osl/thread.h>
30 #include <osl/file.hxx>
31 #include <osl/module.hxx>
32 #include <comphelper/classids.hxx>
33 
34 #include "platform.h"
35 #include <comphelper/mimeconfighelper.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <cppuhelper/supportsservice.hxx>
38 
39 #include "xdialogcreator.hxx"
40 #include <oleembobj.hxx>
41 
42 
43 #ifdef _WIN32
44 
45 #include <oledlg.h>
46 #include <vcl/winscheduler.hxx>
47 
48 class InitializedOleGuard
49 {
50 public:
InitializedOleGuard()51     InitializedOleGuard()
52     {
53         if ( !SUCCEEDED( OleInitialize( nullptr ) ) )
54             throw css::uno::RuntimeException();
55     }
56 
~InitializedOleGuard()57     ~InitializedOleGuard()
58     {
59         OleUninitialize();
60     }
61 };
62 
63 extern "C" {
64 typedef UINT STDAPICALLTYPE OleUIInsertObjectA_Type(LPOLEUIINSERTOBJECTA);
65 }
66 
67 #endif
68 
69 
70 using namespace ::com::sun::star;
71 using namespace ::comphelper;
72 
GetRelatedInternalID_Impl(const uno::Sequence<sal_Int8> & aClassID)73 static uno::Sequence< sal_Int8 > GetRelatedInternalID_Impl( const uno::Sequence< sal_Int8 >& aClassID )
74 {
75     // Writer
76     if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SW_OLE_EMBED_CLASSID_60 ) )
77       || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SW_OLE_EMBED_CLASSID_8 ) ) )
78         return MimeConfigurationHelper::GetSequenceClassID( SO3_SW_CLASSID_60 );
79 
80     // Calc
81     if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SC_OLE_EMBED_CLASSID_60 ) )
82       || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SC_OLE_EMBED_CLASSID_8 ) ) )
83         return MimeConfigurationHelper::GetSequenceClassID( SO3_SC_CLASSID_60 );
84 
85     // Impress
86     if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 ) )
87       || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) ) )
88         return MimeConfigurationHelper::GetSequenceClassID( SO3_SIMPRESS_CLASSID_60 );
89 
90     // Draw
91     if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SDRAW_OLE_EMBED_CLASSID_60 ) )
92       || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) ) )
93         return MimeConfigurationHelper::GetSequenceClassID( SO3_SDRAW_CLASSID_60 );
94 
95     // Chart
96     if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SCH_OLE_EMBED_CLASSID_60 ) )
97       || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SCH_OLE_EMBED_CLASSID_8 ) ) )
98         return MimeConfigurationHelper::GetSequenceClassID( SO3_SCH_CLASSID_60 );
99 
100     // Math
101     if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SM_OLE_EMBED_CLASSID_60 ) )
102       || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SM_OLE_EMBED_CLASSID_8 ) ) )
103         return MimeConfigurationHelper::GetSequenceClassID( SO3_SM_CLASSID_60 );
104 
105     return aClassID;
106 }
107 
108 
impl_staticGetSupportedServiceNames()109 uno::Sequence< OUString > MSOLEDialogObjectCreator::impl_staticGetSupportedServiceNames()
110 {
111     uno::Sequence< OUString > aRet(2);
112     aRet[0] = "com.sun.star.embed.MSOLEObjectSystemCreator";
113     aRet[1] = "com.sun.star.comp.embed.MSOLEObjectSystemCreator";
114     return aRet;
115 }
116 
117 
impl_staticGetImplementationName()118 OUString MSOLEDialogObjectCreator::impl_staticGetImplementationName()
119 {
120     return "com.sun.star.comp.embed.MSOLEObjectSystemCreator";
121 }
122 
123 
impl_staticCreateSelfInstance(const uno::Reference<lang::XMultiServiceFactory> & xServiceManager)124 uno::Reference< uno::XInterface > MSOLEDialogObjectCreator::impl_staticCreateSelfInstance(
125             const uno::Reference< lang::XMultiServiceFactory >& xServiceManager )
126 {
127     return uno::Reference< uno::XInterface >( *new MSOLEDialogObjectCreator( xServiceManager ) );
128 }
129 
130 
createInstanceByDialog(const uno::Reference<embed::XStorage> & xStorage,const OUString & sEntName,const uno::Sequence<beans::PropertyValue> & aInObjArgs)131 embed::InsertedObjectInfo SAL_CALL MSOLEDialogObjectCreator::createInstanceByDialog(
132             const uno::Reference< embed::XStorage >& xStorage,
133             const OUString& sEntName,
134             const uno::Sequence< beans::PropertyValue >& aInObjArgs )
135 {
136     embed::InsertedObjectInfo aObjectInfo;
137     uno::Sequence< beans::PropertyValue > aObjArgs( aInObjArgs );
138 
139 #ifdef _WIN32
140 
141     if ( !xStorage.is() )
142         throw lang::IllegalArgumentException( "No parent storage is provided!",
143                                             static_cast< ::cppu::OWeakObject* >(this),
144                                             1 );
145 
146     if ( !sEntName.getLength() )
147         throw lang::IllegalArgumentException( "Empty element name is provided!",
148                                             static_cast< ::cppu::OWeakObject* >(this),
149                                             2 );
150 
151     InitializedOleGuard aGuard;
152 
153     OLEUIINSERTOBJECT io = {};
154     char szFile[MAX_PATH];
155     UINT uTemp;
156 
157     io.cbStruct = sizeof(io);
158     io.hWndOwner = GetActiveWindow();
159 
160     szFile[0] = 0;
161     io.lpszFile = szFile;
162     io.cchFile = MAX_PATH;
163 
164     io.dwFlags = IOF_SELECTCREATENEW | IOF_DISABLELINK;
165 
166 
167     ::osl::Module aOleDlgLib;
168     if( !aOleDlgLib.load( "oledlg" ))
169         throw uno::RuntimeException();
170 
171     OleUIInsertObjectA_Type * pInsertFct = reinterpret_cast<OleUIInsertObjectA_Type *>(
172                                 aOleDlgLib.getSymbol( "OleUIInsertObjectA" ));
173     if( !pInsertFct )
174         throw uno::RuntimeException();
175 
176     // Disable any event loop shortcuts by enabling a real timer.
177     // This way the native windows dialog won't block our own processing.
178     WinScheduler::SetForceRealTimer();
179 
180     uTemp=pInsertFct(&io);
181 
182     if ( OLEUI_OK != uTemp )
183         throw ucb::CommandAbortedException();
184 
185     if (io.dwFlags & IOF_SELECTCREATENEW)
186     {
187         uno::Reference< embed::XEmbeddedObjectCreator > xEmbCreator = embed::EmbeddedObjectCreator::create( comphelper::getComponentContext(m_xFactory) );
188 
189         uno::Sequence< sal_Int8 > aClassID = MimeConfigurationHelper::GetSequenceClassID( io.clsid.Data1,
190                                                                                           io.clsid.Data2,
191                                                                                           io.clsid.Data3,
192                                                                                           io.clsid.Data4[0],
193                                                                                           io.clsid.Data4[1],
194                                                                                           io.clsid.Data4[2],
195                                                                                           io.clsid.Data4[3],
196                                                                                           io.clsid.Data4[4],
197                                                                                           io.clsid.Data4[5],
198                                                                                           io.clsid.Data4[6],
199                                                                                           io.clsid.Data4[7] );
200 
201         aClassID = GetRelatedInternalID_Impl( aClassID );
202 
203         //TODO: retrieve ClassName
204         aObjectInfo.Object.set( xEmbCreator->createInstanceInitNew( aClassID, OUString(), xStorage, sEntName, aObjArgs ),
205                                 uno::UNO_QUERY );
206     }
207     else
208     {
209         OUString aFileName = OStringToOUString( OString( szFile ), osl_getThreadTextEncoding() );
210         OUString aFileURL;
211         if ( osl::FileBase::getFileURLFromSystemPath( aFileName, aFileURL ) != osl::FileBase::E_None )
212             throw uno::RuntimeException();
213 
214         uno::Sequence< beans::PropertyValue > aMediaDescr( 1 );
215         aMediaDescr[0].Name = "URL";
216         aMediaDescr[0].Value <<= aFileURL;
217 
218         // TODO: use config helper for type detection
219         uno::Reference< embed::XEmbeddedObjectCreator > xEmbCreator;
220         ::comphelper::MimeConfigurationHelper aHelper( comphelper::getComponentContext(m_xFactory) );
221 
222         if ( aHelper.AddFilterNameCheckOwnFile( aMediaDescr ) )
223             xEmbCreator = embed::EmbeddedObjectCreator::create( comphelper::getComponentContext(m_xFactory) );
224         else
225             xEmbCreator = embed::OLEEmbeddedObjectFactory::create( comphelper::getComponentContext(m_xFactory) );
226 
227         if ( !xEmbCreator.is() )
228             throw uno::RuntimeException();
229 
230         aObjectInfo.Object.set( xEmbCreator->createInstanceInitFromMediaDescriptor( xStorage, sEntName, aMediaDescr, aObjArgs ),
231                                 uno::UNO_QUERY );
232     }
233 
234     if ( ( io.dwFlags & IOF_CHECKDISPLAYASICON) && io.hMetaPict != nullptr )
235     {
236         METAFILEPICT* pMF = static_cast<METAFILEPICT*>(GlobalLock( io.hMetaPict ));
237         if ( pMF )
238         {
239             sal_uInt32 nBufSize = GetMetaFileBitsEx( pMF->hMF, 0, nullptr );
240             uno::Sequence< sal_Int8 > aMetafile( nBufSize + 22 );
241             sal_Int8* pBuf = aMetafile.getArray();
242             *reinterpret_cast<long*>( pBuf ) = 0x9ac6cdd7L;
243             *reinterpret_cast<short*>( pBuf+6 ) = SHORT(0);
244             *reinterpret_cast<short*>( pBuf+8 ) = SHORT(0);
245             *reinterpret_cast<short*>( pBuf+10 ) = static_cast<SHORT>(pMF->xExt);
246             *reinterpret_cast<short*>( pBuf+12 ) = static_cast<SHORT>(pMF->yExt);
247             *reinterpret_cast<short*>( pBuf+14 ) = USHORT(2540);
248 
249             if ( nBufSize && nBufSize == GetMetaFileBitsEx( pMF->hMF, nBufSize, pBuf+22 ) )
250             {
251                 datatransfer::DataFlavor aFlavor(
252                     "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"",
253                     "Image WMF",
254                     cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
255 
256                 aObjectInfo.Options.realloc( 2 );
257                 aObjectInfo.Options[0].Name = "Icon";
258                 aObjectInfo.Options[0].Value <<= aMetafile;
259                 aObjectInfo.Options[1].Name = "IconFormat";
260                 aObjectInfo.Options[1].Value <<= aFlavor;
261             }
262 
263             GlobalUnlock( io.hMetaPict );
264         }
265     }
266 
267     OSL_ENSURE( aObjectInfo.Object.is(), "No object was created!" );
268     if ( !aObjectInfo.Object.is() )
269         throw uno::RuntimeException();
270 
271     return aObjectInfo;
272 #else
273     throw lang::NoSupportException(); // TODO:
274 #endif
275 }
276 
277 
createInstanceInitFromClipboard(const uno::Reference<embed::XStorage> & xStorage,const OUString & sEntryName,const uno::Sequence<beans::PropertyValue> & aObjectArgs)278 embed::InsertedObjectInfo SAL_CALL MSOLEDialogObjectCreator::createInstanceInitFromClipboard(
279                 const uno::Reference< embed::XStorage >& xStorage,
280                 const OUString& sEntryName,
281                 const uno::Sequence< beans::PropertyValue >& aObjectArgs )
282 {
283     embed::InsertedObjectInfo aObjectInfo;
284 
285 #ifdef _WIN32
286     if ( !xStorage.is() )
287         throw lang::IllegalArgumentException( "No parent storage is provided!",
288                                             static_cast< ::cppu::OWeakObject* >(this),
289                                             1 );
290 
291     if ( !sEntryName.getLength() )
292         throw lang::IllegalArgumentException( "Empty element name is provided!",
293                                             static_cast< ::cppu::OWeakObject* >(this),
294                                             2 );
295 
296     uno::Reference< embed::XEmbeddedObject > xResult(
297                     static_cast< ::cppu::OWeakObject* > ( new OleEmbeddedObject( m_xFactory ) ),
298                     uno::UNO_QUERY );
299 
300     uno::Reference< embed::XEmbedPersist > xPersist( xResult, uno::UNO_QUERY_THROW );
301     xPersist->setPersistentEntry( xStorage,
302                                     sEntryName,
303                                     embed::EntryInitModes::DEFAULT_INIT,
304                                     uno::Sequence< beans::PropertyValue >(),
305                                     aObjectArgs );
306 
307     aObjectInfo.Object = xResult;
308 
309     // TODO/LATER: in case of iconify object the icon should be stored in aObjectInfo
310 
311     OSL_ENSURE( aObjectInfo.Object.is(), "No object was created!" );
312     if ( !aObjectInfo.Object.is() )
313         throw uno::RuntimeException();
314 
315     return aObjectInfo;
316 #else
317     throw lang::NoSupportException(); // TODO:
318 #endif
319 }
320 
321 
getImplementationName()322 OUString SAL_CALL MSOLEDialogObjectCreator::getImplementationName()
323 {
324     return impl_staticGetImplementationName();
325 }
326 
327 
supportsService(const OUString & ServiceName)328 sal_Bool SAL_CALL MSOLEDialogObjectCreator::supportsService( const OUString& ServiceName )
329 {
330     return cppu::supportsService(this, ServiceName);
331 }
332 
333 
getSupportedServiceNames()334 uno::Sequence< OUString > SAL_CALL MSOLEDialogObjectCreator::getSupportedServiceNames()
335 {
336     return impl_staticGetSupportedServiceNames();
337 }
338 
339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
340