1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_embeddedobj.hxx"
26
27 #include <oleembobj.hxx>
28 #include <com/sun/star/embed/EmbedStates.hpp>
29 #include <com/sun/star/embed/EmbedVerbs.hpp>
30 #include <com/sun/star/embed/EntryInitModes.hpp>
31 #include <com/sun/star/embed/XStorage.hpp>
32 #include <com/sun/star/embed/ElementModes.hpp>
33 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
34 #include <com/sun/star/embed/Aspects.hpp>
35 #include <com/sun/star/embed/NeedsRunningStateException.hpp>
36 #include <com/sun/star/embed/StateChangeInProgressException.hpp>
37 #include <com/sun/star/embed/EmbedMisc.hpp>
38 #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
39 #include <com/sun/star/io/XSeekable.hpp>
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include <com/sun/star/beans/NamedValue.hpp>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/frame/XLoadable.hpp>
44 #include <com/sun/star/document/XStorageBasedDocument.hpp>
45 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
46 #include <com/sun/star/container/XNameAccess.hpp>
47 #include <com/sun/star/container/XNameContainer.hpp>
48 #include <com/sun/star/system/SystemShellExecute.hpp>
49 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
50
51 #include <rtl/logfile.hxx>
52 #include <cppuhelper/interfacecontainer.h>
53 #include <comphelper/mimeconfighelper.hxx>
54 #include <comphelper/storagehelper.hxx>
55 #include <comphelper/processfactory.hxx>
56
57 #include <targetstatecontrol.hxx>
58
59 #include <olecomponent.hxx>
60
61 #include "ownview.hxx"
62
63 using namespace ::com::sun::star;
64
65 #ifdef WNT
66 //----------------------------------------------
SwitchComponentToRunningState_Impl()67 void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
68 {
69 if ( m_pOleComponent )
70 {
71 try
72 {
73 m_pOleComponent->RunObject();
74 }
75 catch( embed::UnreachableStateException& )
76 {
77 GetRidOfComponent();
78 throw;
79 }
80 catch( embed::WrongStateException& )
81 {
82 GetRidOfComponent();
83 throw;
84 }
85 }
86 else
87 {
88 throw embed::UnreachableStateException();
89 }
90 }
91
92 //----------------------------------------------
GetReachableStatesList_Impl(const uno::Sequence<embed::VerbDescriptor> & aVerbList)93 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl(
94 const uno::Sequence< embed::VerbDescriptor >& aVerbList )
95 {
96 uno::Sequence< sal_Int32 > aStates(2);
97 aStates[0] = embed::EmbedStates::LOADED;
98 aStates[1] = embed::EmbedStates::RUNNING;
99 for ( sal_Int32 nInd = 0; nInd < aVerbList.getLength(); nInd++ )
100 if ( aVerbList[nInd].VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
101 {
102 aStates.realloc(3);
103 aStates[2] = embed::EmbedStates::ACTIVE;
104 }
105
106 return aStates;
107 }
108
109 //----------------------------------------------
GetIntermediateVerbsSequence_Impl(sal_Int32 nNewState)110 uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState )
111 {
112 OSL_ENSURE( m_nObjectState != embed::EmbedStates::LOADED, "Loaded object is switched to running state without verbs using!" );
113
114 // actually there will be only one verb
115 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
116 {
117 uno::Sequence< sal_Int32 > aVerbs( 1 );
118 aVerbs[0] = embed::EmbedVerbs::MS_OLEVERB_OPEN;
119 }
120
121 return uno::Sequence< sal_Int32 >();
122 }
123 #endif
124 //----------------------------------------------
MoveListeners()125 void OleEmbeddedObject::MoveListeners()
126 {
127 if ( m_pInterfaceContainer )
128 {
129 // move state change listeners
130 {
131 ::cppu::OInterfaceContainerHelper* pStateChangeContainer =
132 m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< embed::XStateChangeListener >*) NULL ) );
133 if ( pStateChangeContainer != NULL )
134 {
135 uno::Reference< embed::XStateChangeBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
136 if ( xWrappedObject.is() )
137 {
138 ::cppu::OInterfaceIteratorHelper pIterator( *pStateChangeContainer );
139 while ( pIterator.hasMoreElements() )
140 {
141 try
142 {
143 xWrappedObject->addStateChangeListener( (embed::XStateChangeListener*)pIterator.next() );
144 }
145 catch( uno::RuntimeException& )
146 {
147 pIterator.remove();
148 }
149 }
150 }
151 }
152 }
153
154 // move event listeners
155 {
156 ::cppu::OInterfaceContainerHelper* pEventContainer =
157 m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< document::XEventListener >*) NULL ) );
158 if ( pEventContainer != NULL )
159 {
160 uno::Reference< document::XEventBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
161 if ( xWrappedObject.is() )
162 {
163 ::cppu::OInterfaceIteratorHelper pIterator( *pEventContainer );
164 while ( pIterator.hasMoreElements() )
165 {
166 try
167 {
168 xWrappedObject->addEventListener( (document::XEventListener*)pIterator.next() );
169 }
170 catch( uno::RuntimeException& )
171 {
172 pIterator.remove();
173 }
174 }
175 }
176 }
177 }
178
179 // move close listeners
180 {
181 ::cppu::OInterfaceContainerHelper* pCloseContainer =
182 m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< util::XCloseListener >*) NULL ) );
183 if ( pCloseContainer != NULL )
184 {
185 uno::Reference< util::XCloseBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
186 if ( xWrappedObject.is() )
187 {
188 ::cppu::OInterfaceIteratorHelper pIterator( *pCloseContainer );
189 while ( pIterator.hasMoreElements() )
190 {
191 try
192 {
193 xWrappedObject->addCloseListener( (util::XCloseListener*)pIterator.next() );
194 }
195 catch( uno::RuntimeException& )
196 {
197 pIterator.remove();
198 }
199 }
200 }
201 }
202 }
203
204 delete m_pInterfaceContainer;
205 m_pInterfaceContainer = NULL;
206 }
207 }
208
209 //----------------------------------------------
CreateTemporarySubstorage(::rtl::OUString & o_aStorageName)210 uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( ::rtl::OUString& o_aStorageName )
211 {
212 uno::Reference< embed::XStorage > xResult;
213
214 for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ )
215 {
216 ::rtl::OUString aName = ::rtl::OUString::valueOf( nInd );
217 aName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TMPSTOR" ) );
218 aName += m_aEntryName;
219 if ( !m_xParentStorage->hasByName( aName ) )
220 {
221 xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE );
222 o_aStorageName = aName;
223 }
224 }
225
226 if ( !xResult.is() )
227 {
228 o_aStorageName = ::rtl::OUString();
229 throw uno::RuntimeException();
230 }
231
232 return xResult;
233 }
234
235 //----------------------------------------------
MoveToTemporarySubstream()236 ::rtl::OUString OleEmbeddedObject::MoveToTemporarySubstream()
237 {
238 ::rtl::OUString aResult;
239 for ( sal_Int32 nInd = 0; nInd < 32000 && !aResult.getLength(); nInd++ )
240 {
241 ::rtl::OUString aName = ::rtl::OUString::valueOf( nInd );
242 aName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TMPSTREAM" ) );
243 aName += m_aEntryName;
244 if ( !m_xParentStorage->hasByName( aName ) )
245 {
246 m_xParentStorage->renameElement( m_aEntryName, aName );
247 aResult = aName;
248 }
249 }
250
251 if ( !aResult.getLength() )
252 throw uno::RuntimeException();
253
254 return aResult;
255 }
256
257 //----------------------------------------------
TryToConvertToOOo()258 sal_Bool OleEmbeddedObject::TryToConvertToOOo()
259 {
260 sal_Bool bResult = sal_False;
261
262 ::rtl::OUString aStorageName;
263 ::rtl::OUString aTmpStreamName;
264 sal_Int32 nStep = 0;
265
266 if ( m_pOleComponent || m_bReadOnly )
267 return sal_False;
268
269 try
270 {
271 changeState( embed::EmbedStates::LOADED );
272
273 // the stream must be seekable
274 uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY_THROW );
275 xSeekable->seek( 0 );
276 ::rtl::OUString aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xFactory, ::rtl::OUString(), m_xObjectStream->getInputStream() );
277
278 // use the solution only for OOXML format currently
279 if ( aFilterName.getLength()
280 && ( aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "Calc MS Excel 2007 XML" ) ) )
281 || aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "Impress MS PowerPoint 2007 XML" ) ) )
282 || aFilterName.equals( ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM( "MS Word 2007 XML" ) ) ) ) )
283 {
284 uno::Reference< container::XNameAccess > xFilterFactory(
285 m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ),
286 uno::UNO_QUERY_THROW );
287
288 ::rtl::OUString aDocServiceName;
289 uno::Any aFilterAnyData = xFilterFactory->getByName( aFilterName );
290 uno::Sequence< beans::PropertyValue > aFilterData;
291 if ( aFilterAnyData >>= aFilterData )
292 {
293 for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
294 if ( aFilterData[nInd].Name.equalsAscii( "DocumentService" ) )
295 aFilterData[nInd].Value >>= aDocServiceName;
296 }
297
298 if ( aDocServiceName.getLength() )
299 {
300 // create the model
301 uno::Sequence< uno::Any > aArguments(1);
302 aArguments[0] <<= beans::NamedValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EmbeddedObject" ) ), uno::makeAny( (sal_Bool)sal_True ));
303
304 uno::Reference< util::XCloseable > xDocument( m_xFactory->createInstanceWithArguments( aDocServiceName, aArguments ), uno::UNO_QUERY_THROW );
305 uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
306 uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW );
307
308 // let the model behave as embedded one
309 uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW );
310 uno::Sequence< beans::PropertyValue > aSeq( 1 );
311 aSeq[0].Name = ::rtl::OUString::createFromAscii( "SetEmbedded" );
312 aSeq[0].Value <<= sal_True;
313 xModel->attachResource( ::rtl::OUString(), aSeq );
314
315 // load the model from the stream
316 uno::Sequence< beans::PropertyValue > aArgs( 5 );
317 aArgs[0].Name = ::rtl::OUString::createFromAscii( "HierarchicalDocumentName" );
318 aArgs[0].Value <<= m_aEntryName;
319 aArgs[1].Name = ::rtl::OUString::createFromAscii( "ReadOnly" );
320 aArgs[1].Value <<= sal_True;
321 aArgs[2].Name = ::rtl::OUString::createFromAscii( "FilterName" );
322 aArgs[2].Value <<= aFilterName;
323 aArgs[3].Name = ::rtl::OUString::createFromAscii( "URL" );
324 aArgs[3].Value <<= ::rtl::OUString::createFromAscii( "private:stream" );
325 aArgs[4].Name = ::rtl::OUString::createFromAscii( "InputStream" );
326 aArgs[4].Value <<= m_xObjectStream->getInputStream();
327
328 xSeekable->seek( 0 );
329 xLoadable->load( aArgs );
330
331 // the model is successfully loaded, create a new storage and store the model to the storage
332 uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName );
333 xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() );
334 xDocument->close( sal_True );
335 uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW );
336 ::rtl::OUString aMediaType;
337 xStorProps->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ) >>= aMediaType;
338 xTmpStorage->dispose();
339
340 // look for the related embedded object factory
341 ::comphelper::MimeConfigurationHelper aConfigHelper( m_xFactory );
342 ::rtl::OUString aEmbedFactory;
343 if ( aMediaType.getLength() )
344 aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType );
345
346 if ( !aEmbedFactory.getLength() )
347 throw uno::RuntimeException();
348
349 uno::Reference< uno::XInterface > xFact = m_xFactory->createInstance( aEmbedFactory );
350
351 uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW );
352
353 // now the object should be adjusted to become the wrapper
354 nStep = 1;
355 uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW );
356 xComp->dispose();
357 m_xObjectStream = uno::Reference< io::XStream >();
358 m_nObjectState = -1;
359
360 nStep = 2;
361 aTmpStreamName = MoveToTemporarySubstream();
362
363 nStep = 3;
364 m_xParentStorage->renameElement( aStorageName, m_aEntryName );
365
366 nStep = 4;
367 m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW );
368
369 bResult = sal_True; // the change is no more revertable
370 try
371 {
372 m_xParentStorage->removeElement( aTmpStreamName );
373 }
374 catch( uno::Exception& )
375 {
376 // the success of the removing is not so important
377 }
378 }
379 }
380 }
381 catch( uno::Exception& )
382 {
383 // repair the object if necessary
384 switch( nStep )
385 {
386 case 4:
387 case 3:
388 if ( aTmpStreamName.getLength() && aTmpStreamName != m_aEntryName )
389 try
390 {
391 if ( m_xParentStorage->hasByName( m_aEntryName ) )
392 m_xParentStorage->removeElement( m_aEntryName );
393 m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName );
394 }
395 catch ( uno::Exception& )
396 {
397 try {
398 close( sal_True );
399 } catch( uno::Exception& ) {}
400
401 m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without committing!
402 throw uno::RuntimeException(); // the repairing is not possible
403 }
404 case 2:
405 try
406 {
407 m_xObjectStream = m_xParentStorage->openStreamElement( m_aEntryName, m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
408 m_nObjectState = embed::EmbedStates::LOADED;
409 }
410 catch( uno::Exception& )
411 {
412 try {
413 close( sal_True );
414 } catch( uno::Exception& ) {}
415
416 throw uno::RuntimeException(); // the repairing is not possible
417 }
418 // no break as designed!
419
420 case 1:
421 case 0:
422 if ( aStorageName.getLength() )
423 try {
424 m_xParentStorage->removeElement( aStorageName );
425 } catch( uno::Exception& ) { OSL_ASSERT( "Can not remove temporary storage!" ); }
426 break;
427 }
428 }
429
430 if ( bResult )
431 {
432 // the conversion was done successfully, now the additional initializations should happen
433
434 MoveListeners();
435 m_xWrappedObject->setClientSite( m_xClientSite );
436 if ( m_xParent.is() )
437 {
438 uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY );
439 if ( xChild.is() )
440 xChild->setParent( m_xParent );
441 }
442
443 }
444
445 return bResult;
446 }
447
448 //----------------------------------------------
changeState(sal_Int32 nNewState)449 void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState )
450 {
451 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::changeState" );
452
453 // begin wrapping related part ====================
454 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
455 if ( xWrappedObject.is() )
456 {
457 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
458 xWrappedObject->changeState( nNewState );
459 return;
460 }
461 // end wrapping related part ====================
462
463 ::osl::ResettableMutexGuard aGuard( m_aMutex );
464
465 if ( m_bDisposed )
466 throw lang::DisposedException(); // TODO
467
468 if ( m_nObjectState == -1 )
469 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
470 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
471
472 // in case the object is already in requested state
473 if ( m_nObjectState == nNewState )
474 return;
475
476 #ifdef WNT
477 if ( m_pOleComponent )
478 {
479 if ( m_nTargetState != -1 )
480 {
481 // means that the object is currently trying to reach the target state
482 throw embed::StateChangeInProgressException( ::rtl::OUString(),
483 uno::Reference< uno::XInterface >(),
484 m_nTargetState );
485 }
486
487 TargetStateControl_Impl aControl( m_nTargetState, nNewState );
488
489 // TODO: additional verbs can be a problem, since nobody knows how the object
490 // will behave after activation
491
492 sal_Int32 nOldState = m_nObjectState;
493 aGuard.clear();
494 StateChangeNotification_Impl( sal_True, nOldState, nNewState );
495 aGuard.reset();
496
497 try
498 {
499 if ( nNewState == embed::EmbedStates::LOADED )
500 {
501 // This means just closing of the current object
502 // If component can not be closed the object stays in loaded state
503 // and it holds reference to "incomplete" component
504 // If the object is switched to running state later
505 // the component will become "complete"
506
507 // the loaded state must be set before, because of notifications!
508 m_nObjectState = nNewState;
509
510 {
511 VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
512 m_pOleComponent->CloseObject();
513 }
514
515 // GetRidOfComponent();
516 aGuard.clear();
517 StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
518 aGuard.reset();
519 }
520 else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
521 {
522 if ( m_nObjectState == embed::EmbedStates::LOADED )
523 {
524 // if the target object is in loaded state and a different state is specified
525 // as a new one the object first must be switched to running state.
526
527 // the component can exist already in nonrunning state
528 // it can be created during loading to detect type of object
529 CreateOleComponentAndLoad_Impl( m_pOleComponent );
530
531 SwitchComponentToRunningState_Impl();
532 m_nObjectState = embed::EmbedStates::RUNNING;
533 aGuard.clear();
534 StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
535 aGuard.reset();
536
537 if ( m_pOleComponent && m_bHasSizeToSet )
538 {
539 aGuard.clear();
540 try {
541 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
542 m_bHasSizeToSet = sal_False;
543 }
544 catch( uno::Exception& ) {}
545 aGuard.reset();
546 }
547
548 if ( m_nObjectState == nNewState )
549 return;
550 }
551
552 // so now the object is either switched from Active to Running state or vise versa
553 // the notification about object state change will be done asynchronously
554 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
555 {
556 // execute OPEN verb, if object does not reach active state it is an object's problem
557 aGuard.clear();
558 m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
559 aGuard.reset();
560
561 // some objects do not allow to set the size even in running state
562 if ( m_pOleComponent && m_bHasSizeToSet )
563 {
564 aGuard.clear();
565 try {
566 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
567 m_bHasSizeToSet = sal_False;
568 }
569 catch( uno::Exception& ) {}
570 aGuard.reset();
571 }
572
573 m_nObjectState = nNewState;
574 }
575 else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
576 {
577 aGuard.clear();
578 m_pOleComponent->CloseObject();
579 m_pOleComponent->RunObject(); // Should not fail, the object already was active
580 aGuard.reset();
581 m_nObjectState = nNewState;
582 }
583 else
584 {
585 throw embed::UnreachableStateException();
586 }
587 }
588 else
589 throw embed::UnreachableStateException();
590 }
591 catch( uno::Exception& )
592 {
593 aGuard.clear();
594 StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
595 throw;
596 }
597 }
598 else
599 #endif
600 {
601 throw embed::UnreachableStateException();
602 }
603 }
604
605 //----------------------------------------------
getReachableStates()606 uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
607 {
608 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getReachableStates" );
609
610 // begin wrapping related part ====================
611 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
612 if ( xWrappedObject.is() )
613 {
614 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
615 return xWrappedObject->getReachableStates();
616 }
617 // end wrapping related part ====================
618
619 ::osl::MutexGuard aGuard( m_aMutex );
620 if ( m_bDisposed )
621 throw lang::DisposedException(); // TODO
622
623 if ( m_nObjectState == -1 )
624 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
625 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
626
627 #ifdef WNT
628 if ( m_pOleComponent )
629 {
630 if ( m_nObjectState == embed::EmbedStates::LOADED )
631 {
632 // the list of supported verbs can be retrieved only when object is in running state
633 throw embed::NeedsRunningStateException(); // TODO:
634 }
635
636 // the list of states can only be guessed based on standard verbs,
637 // since there is no way to detect what additional verbs do
638 return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
639 }
640 else
641 #endif
642 {
643 return uno::Sequence< sal_Int32 >();
644 }
645 }
646
647 //----------------------------------------------
getCurrentState()648 sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState()
649 {
650 // begin wrapping related part ====================
651 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
652 if ( xWrappedObject.is() )
653 {
654 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
655 return xWrappedObject->getCurrentState();
656 }
657 // end wrapping related part ====================
658
659 ::osl::MutexGuard aGuard( m_aMutex );
660 if ( m_bDisposed )
661 throw lang::DisposedException(); // TODO
662
663 if ( m_nObjectState == -1 )
664 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
665 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
666
667 // TODO: Shouldn't we ask object? ( I guess no )
668 return m_nObjectState;
669 }
670
671 namespace
672 {
lcl_CopyStream(uno::Reference<io::XInputStream> xIn,uno::Reference<io::XOutputStream> xOut)673 bool lcl_CopyStream(uno::Reference<io::XInputStream> xIn, uno::Reference<io::XOutputStream> xOut)
674 {
675 const sal_Int32 nChunkSize = 4096;
676 uno::Sequence< sal_Int8 > aData(nChunkSize);
677 sal_Int32 nTotalRead = 0;
678 sal_Int32 nRead;
679 do
680 {
681 nRead = xIn->readBytes(aData, nChunkSize);
682 nTotalRead += nRead;
683 xOut->writeBytes(aData);
684 } while (nRead == nChunkSize);
685 return nTotalRead != 0;
686 }
687
688 //Dump the objects content to a tempfile, just the "CONTENTS" stream if
689 //there is one for non-compound documents, otherwise the whole content.
690 //
691 //On success a file is returned which must be removed by the caller
lcl_ExtractObject(::com::sun::star::uno::Reference<::com::sun::star::lang::XMultiServiceFactory> xFactory,::com::sun::star::uno::Reference<::com::sun::star::io::XStream> xObjectStream)692 rtl::OUString lcl_ExtractObject(::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory,
693 ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > xObjectStream)
694 {
695 rtl::OUString sUrl;
696
697 // the solution is only active for Unix systems
698 #ifndef WNT
699 uno::Reference <beans::XPropertySet> xNativeTempFile(
700 xFactory->createInstance(
701 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.io.TempFile"))), uno::UNO_QUERY_THROW);
702 uno::Reference < io::XStream > xStream(xNativeTempFile, uno::UNO_QUERY_THROW);
703
704 uno::Sequence< uno::Any > aArgs( 2 );
705 aArgs[0] <<= xObjectStream;
706 aArgs[1] <<= (sal_Bool)sal_True; // do not create copy
707 uno::Reference< container::XNameContainer > xNameContainer(
708 xFactory->createInstanceWithArguments(
709 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.OLESimpleStorage")),
710 aArgs ), uno::UNO_QUERY_THROW );
711
712 uno::Reference< io::XStream > xCONTENTS;
713 xNameContainer->getByName(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CONTENTS"))) >>= xCONTENTS;
714
715 sal_Bool bCopied = xCONTENTS.is() && lcl_CopyStream(xCONTENTS->getInputStream(), xStream->getOutputStream());
716
717 uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
718 if (xSeekableStor.is())
719 xSeekableStor->seek(0);
720
721 if (!bCopied)
722 bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
723
724 if (bCopied)
725 {
726 xNativeTempFile->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RemoveFile")),
727 uno::makeAny(sal_False));
728 uno::Any aUrl = xNativeTempFile->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Uri")));
729 aUrl >>= sUrl;
730
731 xNativeTempFile = uno::Reference<beans::XPropertySet>();
732
733 uno::Reference<ucb::XSimpleFileAccess> xSimpleFileAccess(
734 xFactory->createInstance(
735 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SimpleFileAccess"))),
736 uno::UNO_QUERY_THROW);
737
738 xSimpleFileAccess->setReadOnly(sUrl, sal_True);
739 }
740 else
741 {
742 xNativeTempFile->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RemoveFile")),
743 uno::makeAny(sal_True));
744 }
745 #endif
746 return sUrl;
747 }
748 }
749
750 //----------------------------------------------
doVerb(sal_Int32 nVerbID)751 void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
752 {
753 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::doVerb" );
754
755 // begin wrapping related part ====================
756 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
757 if ( xWrappedObject.is() )
758 {
759 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
760 xWrappedObject->doVerb( nVerbID );
761 return;
762 }
763 // end wrapping related part ====================
764
765 ::osl::ResettableMutexGuard aGuard( m_aMutex );
766 if ( m_bDisposed )
767 throw lang::DisposedException(); // TODO
768
769 if ( m_nObjectState == -1 )
770 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
771 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
772
773 #ifdef WNT
774 if ( m_pOleComponent )
775 {
776 sal_Int32 nOldState = m_nObjectState;
777
778 // TODO/LATER detect target state here and do a notification
779 // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
780 if ( m_nObjectState == embed::EmbedStates::LOADED )
781 {
782 // if the target object is in loaded state
783 // it must be switched to running state to execute verb
784 aGuard.clear();
785 changeState( embed::EmbedStates::RUNNING );
786 aGuard.reset();
787 }
788
789 try {
790 if ( !m_pOleComponent )
791 throw uno::RuntimeException();
792
793 // ==== the STAMPIT related solution =============================
794 m_aVerbExecutionController.StartControlExecution();
795 // ===============================================================
796
797 m_pOleComponent->ExecuteVerb( nVerbID );
798
799 // ==== the STAMPIT related solution =============================
800 sal_Bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
801
802 // this workaround is implemented for STAMPIT object
803 // if object was modified during verb execution it is saved here
804 if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
805 SaveObject_Impl();
806 // ===============================================================
807 }
808 catch( uno::Exception& )
809 {
810 // ==== the STAMPIT related solution =============================
811 m_aVerbExecutionController.EndControlExecution_WasModified();
812 // ===============================================================
813
814 aGuard.clear();
815 StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
816 throw;
817 }
818
819 // the following notification will be done asynchronously
820 // StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
821 }
822 else
823 #endif
824 {
825 if ( nVerbID == -9 )
826 {
827 // the workaround verb to show the object in case no server is available
828
829 // if it is possible, the object will be converted to OOo format
830 if ( !m_bTriedConversion )
831 {
832 m_bTriedConversion = sal_True;
833 if ( TryToConvertToOOo() )
834 {
835 changeState( embed::EmbedStates::UI_ACTIVE );
836 return;
837 }
838 }
839
840 if ( !m_pOwnView && m_xObjectStream.is() )
841 {
842 try {
843 uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
844 if ( xSeekable.is() )
845 xSeekable->seek( 0 );
846
847 m_pOwnView = new OwnView_Impl( m_xFactory, m_xObjectStream->getInputStream() );
848 m_pOwnView->acquire();
849 }
850 catch( uno::RuntimeException& )
851 {
852 throw;
853 }
854 catch( uno::Exception& )
855 {
856 }
857 }
858
859 if ( !m_pOwnView || !m_pOwnView->Open() )
860 {
861 //Make a RO copy and see if the OS can find something to at
862 //least display the content for us
863 if (!m_aTempDumpURL.getLength())
864 m_aTempDumpURL = lcl_ExtractObject(m_xFactory, m_xObjectStream);
865
866 if (m_aTempDumpURL.getLength())
867 {
868 uno::Reference< ::com::sun::star::system::XSystemShellExecute > xSystemShellExecute(
869 ::com::sun::star::system::SystemShellExecute::create(
870 ::comphelper::getProcessComponentContext() ) );
871 xSystemShellExecute->execute(m_aTempDumpURL, ::rtl::OUString(), ::com::sun::star::system::SystemShellExecuteFlags::DEFAULTS);
872 }
873 else
874 throw embed::UnreachableStateException();
875 }
876 }
877 else
878 {
879
880 throw embed::UnreachableStateException();
881 }
882 }
883 }
884
885 //----------------------------------------------
getSupportedVerbs()886 uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
887 {
888 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getSupportedVerb" );
889
890 // begin wrapping related part ====================
891 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
892 if ( xWrappedObject.is() )
893 {
894 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
895 return xWrappedObject->getSupportedVerbs();
896 }
897 // end wrapping related part ====================
898
899 ::osl::MutexGuard aGuard( m_aMutex );
900 if ( m_bDisposed )
901 throw lang::DisposedException(); // TODO
902
903 if ( m_nObjectState == -1 )
904 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
905 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
906 #ifdef WNT
907 if ( m_pOleComponent )
908 {
909 // registry could be used in this case
910 // if ( m_nObjectState == embed::EmbedStates::LOADED )
911 // {
912 // // the list of supported verbs can be retrieved only when object is in running state
913 // throw embed::NeedsRunningStateException(); // TODO:
914 // }
915
916 return m_pOleComponent->GetVerbList();
917 }
918 else
919 #endif
920 {
921 return uno::Sequence< embed::VerbDescriptor >();
922 }
923 }
924
925 //----------------------------------------------
setClientSite(const uno::Reference<embed::XEmbeddedClient> & xClient)926 void SAL_CALL OleEmbeddedObject::setClientSite(
927 const uno::Reference< embed::XEmbeddedClient >& xClient )
928 {
929 // begin wrapping related part ====================
930 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
931 if ( xWrappedObject.is() )
932 {
933 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
934 xWrappedObject->setClientSite( xClient );
935 return;
936 }
937 // end wrapping related part ====================
938
939 ::osl::MutexGuard aGuard( m_aMutex );
940 if ( m_bDisposed )
941 throw lang::DisposedException(); // TODO
942
943 if ( m_xClientSite != xClient)
944 {
945 if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
946 throw embed::WrongStateException(
947 ::rtl::OUString::createFromAscii( "The client site can not be set currently!\n" ),
948 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
949
950 m_xClientSite = xClient;
951 }
952 }
953
954 //----------------------------------------------
getClientSite()955 uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
956 {
957 // begin wrapping related part ====================
958 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
959 if ( xWrappedObject.is() )
960 {
961 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
962 return xWrappedObject->getClientSite();
963 }
964 // end wrapping related part ====================
965
966 ::osl::MutexGuard aGuard( m_aMutex );
967 if ( m_bDisposed )
968 throw lang::DisposedException(); // TODO
969
970 if ( m_nObjectState == -1 )
971 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
972 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
973
974 return m_xClientSite;
975 }
976
977 //----------------------------------------------
update()978 void SAL_CALL OleEmbeddedObject::update()
979 {
980 // begin wrapping related part ====================
981 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
982 if ( xWrappedObject.is() )
983 {
984 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
985 xWrappedObject->update();
986 return;
987 }
988 // end wrapping related part ====================
989
990 ::osl::MutexGuard aGuard( m_aMutex );
991 if ( m_bDisposed )
992 throw lang::DisposedException(); // TODO
993
994 if ( m_nObjectState == -1 )
995 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
996 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
997
998 if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
999 {
1000 // TODO: update view representation
1001 }
1002 else
1003 {
1004 // the object must be up to date
1005 OSL_ENSURE( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE, "Unknown update mode!\n" );
1006 }
1007 }
1008
1009 //----------------------------------------------
setUpdateMode(sal_Int32 nMode)1010 void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
1011 {
1012 // begin wrapping related part ====================
1013 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1014 if ( xWrappedObject.is() )
1015 {
1016 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1017 xWrappedObject->setUpdateMode( nMode );
1018 return;
1019 }
1020 // end wrapping related part ====================
1021
1022 ::osl::MutexGuard aGuard( m_aMutex );
1023 if ( m_bDisposed )
1024 throw lang::DisposedException(); // TODO
1025
1026 if ( m_nObjectState == -1 )
1027 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
1028 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1029
1030 OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
1031 || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
1032 "Unknown update mode!\n" );
1033 m_nUpdateMode = nMode;
1034 }
1035
1036 //----------------------------------------------
getStatus(sal_Int64 nAspect)1037 sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
1038 nAspect
1039 )
1040 {
1041 // begin wrapping related part ====================
1042 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1043 if ( xWrappedObject.is() )
1044 {
1045 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1046 return xWrappedObject->getStatus( nAspect );
1047 }
1048 // end wrapping related part ====================
1049
1050 ::osl::MutexGuard aGuard( m_aMutex );
1051 if ( m_bDisposed )
1052 throw lang::DisposedException(); // TODO
1053
1054 if ( m_nObjectState == -1 )
1055 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object must be in running state!\n" ),
1056 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1057
1058 sal_Int64 nResult = 0;
1059
1060 #ifdef WNT
1061 if ( m_bGotStatus && m_nStatusAspect == nAspect )
1062 nResult = m_nStatus;
1063 else if ( m_pOleComponent )
1064 {
1065 // OLE should allow to get status even in loaded state
1066 // if ( m_nObjectState == embed::EmbedStates::LOADED )
1067 // changeState( m_nObjectState == embed::EmbedStates::RUNNING );
1068
1069 m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
1070 m_nStatusAspect = nAspect;
1071 m_bGotStatus = sal_True;
1072 nResult = m_nStatus;
1073 }
1074 #endif
1075
1076 // this implementation needs size to be provided after object loading/creating to work in optimal way
1077 return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
1078 }
1079
1080 //----------------------------------------------
setContainerName(const::rtl::OUString & sName)1081 void SAL_CALL OleEmbeddedObject::setContainerName( const ::rtl::OUString& sName )
1082 {
1083 // begin wrapping related part ====================
1084 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1085 if ( xWrappedObject.is() )
1086 {
1087 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1088 xWrappedObject->setContainerName( sName );
1089 return;
1090 }
1091 // end wrapping related part ====================
1092
1093 ::osl::MutexGuard aGuard( m_aMutex );
1094 if ( m_bDisposed )
1095 throw lang::DisposedException(); // TODO
1096
1097 m_aContainerName = sName;
1098 }
1099