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 throw ( embed::UnreachableStateException,
451 embed::WrongStateException,
452 uno::Exception,
453 uno::RuntimeException )
454 {
455 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::changeState" );
456
457 // begin wrapping related part ====================
458 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
459 if ( xWrappedObject.is() )
460 {
461 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
462 xWrappedObject->changeState( nNewState );
463 return;
464 }
465 // end wrapping related part ====================
466
467 ::osl::ResettableMutexGuard aGuard( m_aMutex );
468
469 if ( m_bDisposed )
470 throw lang::DisposedException(); // TODO
471
472 if ( m_nObjectState == -1 )
473 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
474 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
475
476 // in case the object is already in requested state
477 if ( m_nObjectState == nNewState )
478 return;
479
480 #ifdef WNT
481 if ( m_pOleComponent )
482 {
483 if ( m_nTargetState != -1 )
484 {
485 // means that the object is currently trying to reach the target state
486 throw embed::StateChangeInProgressException( ::rtl::OUString(),
487 uno::Reference< uno::XInterface >(),
488 m_nTargetState );
489 }
490
491 TargetStateControl_Impl aControl( m_nTargetState, nNewState );
492
493 // TODO: additional verbs can be a problem, since nobody knows how the object
494 // will behave after activation
495
496 sal_Int32 nOldState = m_nObjectState;
497 aGuard.clear();
498 StateChangeNotification_Impl( sal_True, nOldState, nNewState );
499 aGuard.reset();
500
501 try
502 {
503 if ( nNewState == embed::EmbedStates::LOADED )
504 {
505 // This means just closing of the current object
506 // If component can not be closed the object stays in loaded state
507 // and it holds reference to "incomplete" component
508 // If the object is switched to running state later
509 // the component will become "complete"
510
511 // the loaded state must be set before, because of notifications!
512 m_nObjectState = nNewState;
513
514 {
515 VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
516 m_pOleComponent->CloseObject();
517 }
518
519 // GetRidOfComponent();
520 aGuard.clear();
521 StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
522 aGuard.reset();
523 }
524 else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
525 {
526 if ( m_nObjectState == embed::EmbedStates::LOADED )
527 {
528 // if the target object is in loaded state and a different state is specified
529 // as a new one the object first must be switched to running state.
530
531 // the component can exist already in nonrunning state
532 // it can be created during loading to detect type of object
533 CreateOleComponentAndLoad_Impl( m_pOleComponent );
534
535 SwitchComponentToRunningState_Impl();
536 m_nObjectState = embed::EmbedStates::RUNNING;
537 aGuard.clear();
538 StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
539 aGuard.reset();
540
541 if ( m_pOleComponent && m_bHasSizeToSet )
542 {
543 aGuard.clear();
544 try {
545 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
546 m_bHasSizeToSet = sal_False;
547 }
548 catch( uno::Exception& ) {}
549 aGuard.reset();
550 }
551
552 if ( m_nObjectState == nNewState )
553 return;
554 }
555
556 // so now the object is either switched from Active to Running state or vise versa
557 // the notification about object state change will be done asynchronously
558 if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
559 {
560 // execute OPEN verb, if object does not reach active state it is an object's problem
561 aGuard.clear();
562 m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
563 aGuard.reset();
564
565 // some objects do not allow to set the size even in running state
566 if ( m_pOleComponent && m_bHasSizeToSet )
567 {
568 aGuard.clear();
569 try {
570 m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
571 m_bHasSizeToSet = sal_False;
572 }
573 catch( uno::Exception& ) {}
574 aGuard.reset();
575 }
576
577 m_nObjectState = nNewState;
578 }
579 else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
580 {
581 aGuard.clear();
582 m_pOleComponent->CloseObject();
583 m_pOleComponent->RunObject(); // Should not fail, the object already was active
584 aGuard.reset();
585 m_nObjectState = nNewState;
586 }
587 else
588 {
589 throw embed::UnreachableStateException();
590 }
591 }
592 else
593 throw embed::UnreachableStateException();
594 }
595 catch( uno::Exception& )
596 {
597 aGuard.clear();
598 StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
599 throw;
600 }
601 }
602 else
603 #endif
604 {
605 throw embed::UnreachableStateException();
606 }
607 }
608
609 //----------------------------------------------
getReachableStates()610 uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
611 throw ( embed::WrongStateException,
612 uno::RuntimeException )
613 {
614 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getReachableStates" );
615
616 // begin wrapping related part ====================
617 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
618 if ( xWrappedObject.is() )
619 {
620 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
621 return xWrappedObject->getReachableStates();
622 }
623 // end wrapping related part ====================
624
625 ::osl::MutexGuard aGuard( m_aMutex );
626 if ( m_bDisposed )
627 throw lang::DisposedException(); // TODO
628
629 if ( m_nObjectState == -1 )
630 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
631 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
632
633 #ifdef WNT
634 if ( m_pOleComponent )
635 {
636 if ( m_nObjectState == embed::EmbedStates::LOADED )
637 {
638 // the list of supported verbs can be retrieved only when object is in running state
639 throw embed::NeedsRunningStateException(); // TODO:
640 }
641
642 // the list of states can only be guessed based on standard verbs,
643 // since there is no way to detect what additional verbs do
644 return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
645 }
646 else
647 #endif
648 {
649 return uno::Sequence< sal_Int32 >();
650 }
651 }
652
653 //----------------------------------------------
getCurrentState()654 sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState()
655 throw ( embed::WrongStateException,
656 uno::RuntimeException )
657 {
658 // begin wrapping related part ====================
659 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
660 if ( xWrappedObject.is() )
661 {
662 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
663 return xWrappedObject->getCurrentState();
664 }
665 // end wrapping related part ====================
666
667 ::osl::MutexGuard aGuard( m_aMutex );
668 if ( m_bDisposed )
669 throw lang::DisposedException(); // TODO
670
671 if ( m_nObjectState == -1 )
672 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
673 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
674
675 // TODO: Shouldn't we ask object? ( I guess no )
676 return m_nObjectState;
677 }
678
679 namespace
680 {
lcl_CopyStream(uno::Reference<io::XInputStream> xIn,uno::Reference<io::XOutputStream> xOut)681 bool lcl_CopyStream(uno::Reference<io::XInputStream> xIn, uno::Reference<io::XOutputStream> xOut)
682 {
683 const sal_Int32 nChunkSize = 4096;
684 uno::Sequence< sal_Int8 > aData(nChunkSize);
685 sal_Int32 nTotalRead = 0;
686 sal_Int32 nRead;
687 do
688 {
689 nRead = xIn->readBytes(aData, nChunkSize);
690 nTotalRead += nRead;
691 xOut->writeBytes(aData);
692 } while (nRead == nChunkSize);
693 return nTotalRead != 0;
694 }
695
696 //Dump the objects content to a tempfile, just the "CONTENTS" stream if
697 //there is one for non-compound documents, otherwise the whole content.
698 //
699 //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)700 rtl::OUString lcl_ExtractObject(::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory,
701 ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > xObjectStream)
702 {
703 rtl::OUString sUrl;
704
705 // the solution is only active for Unix systems
706 #ifndef WNT
707 uno::Reference <beans::XPropertySet> xNativeTempFile(
708 xFactory->createInstance(
709 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.io.TempFile"))), uno::UNO_QUERY_THROW);
710 uno::Reference < io::XStream > xStream(xNativeTempFile, uno::UNO_QUERY_THROW);
711
712 uno::Sequence< uno::Any > aArgs( 2 );
713 aArgs[0] <<= xObjectStream;
714 aArgs[1] <<= (sal_Bool)sal_True; // do not create copy
715 uno::Reference< container::XNameContainer > xNameContainer(
716 xFactory->createInstanceWithArguments(
717 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.OLESimpleStorage")),
718 aArgs ), uno::UNO_QUERY_THROW );
719
720 uno::Reference< io::XStream > xCONTENTS;
721 xNameContainer->getByName(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CONTENTS"))) >>= xCONTENTS;
722
723 sal_Bool bCopied = xCONTENTS.is() && lcl_CopyStream(xCONTENTS->getInputStream(), xStream->getOutputStream());
724
725 uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
726 if (xSeekableStor.is())
727 xSeekableStor->seek(0);
728
729 if (!bCopied)
730 bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
731
732 if (bCopied)
733 {
734 xNativeTempFile->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RemoveFile")),
735 uno::makeAny(sal_False));
736 uno::Any aUrl = xNativeTempFile->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Uri")));
737 aUrl >>= sUrl;
738
739 xNativeTempFile = uno::Reference<beans::XPropertySet>();
740
741 uno::Reference<ucb::XSimpleFileAccess> xSimpleFileAccess(
742 xFactory->createInstance(
743 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SimpleFileAccess"))),
744 uno::UNO_QUERY_THROW);
745
746 xSimpleFileAccess->setReadOnly(sUrl, sal_True);
747 }
748 else
749 {
750 xNativeTempFile->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RemoveFile")),
751 uno::makeAny(sal_True));
752 }
753 #endif
754 return sUrl;
755 }
756 }
757
758 //----------------------------------------------
doVerb(sal_Int32 nVerbID)759 void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
760 throw ( lang::IllegalArgumentException,
761 embed::WrongStateException,
762 embed::UnreachableStateException,
763 uno::Exception,
764 uno::RuntimeException )
765 {
766 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::doVerb" );
767
768 // begin wrapping related part ====================
769 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
770 if ( xWrappedObject.is() )
771 {
772 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
773 xWrappedObject->doVerb( nVerbID );
774 return;
775 }
776 // end wrapping related part ====================
777
778 ::osl::ResettableMutexGuard aGuard( m_aMutex );
779 if ( m_bDisposed )
780 throw lang::DisposedException(); // TODO
781
782 if ( m_nObjectState == -1 )
783 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
784 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
785
786 #ifdef WNT
787 if ( m_pOleComponent )
788 {
789 sal_Int32 nOldState = m_nObjectState;
790
791 // TODO/LATER detect target state here and do a notification
792 // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
793 if ( m_nObjectState == embed::EmbedStates::LOADED )
794 {
795 // if the target object is in loaded state
796 // it must be switched to running state to execute verb
797 aGuard.clear();
798 changeState( embed::EmbedStates::RUNNING );
799 aGuard.reset();
800 }
801
802 try {
803 if ( !m_pOleComponent )
804 throw uno::RuntimeException();
805
806 // ==== the STAMPIT related solution =============================
807 m_aVerbExecutionController.StartControlExecution();
808 // ===============================================================
809
810 m_pOleComponent->ExecuteVerb( nVerbID );
811
812 // ==== the STAMPIT related solution =============================
813 sal_Bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
814
815 // this workaround is implemented for STAMPIT object
816 // if object was modified during verb execution it is saved here
817 if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
818 SaveObject_Impl();
819 // ===============================================================
820 }
821 catch( uno::Exception& )
822 {
823 // ==== the STAMPIT related solution =============================
824 m_aVerbExecutionController.EndControlExecution_WasModified();
825 // ===============================================================
826
827 aGuard.clear();
828 StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
829 throw;
830 }
831
832 // the following notification will be done asynchronously
833 // StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
834 }
835 else
836 #endif
837 {
838 if ( nVerbID == -9 )
839 {
840 // the workaround verb to show the object in case no server is available
841
842 // if it is possible, the object will be converted to OOo format
843 if ( !m_bTriedConversion )
844 {
845 m_bTriedConversion = sal_True;
846 if ( TryToConvertToOOo() )
847 {
848 changeState( embed::EmbedStates::UI_ACTIVE );
849 return;
850 }
851 }
852
853 if ( !m_pOwnView && m_xObjectStream.is() )
854 {
855 try {
856 uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
857 if ( xSeekable.is() )
858 xSeekable->seek( 0 );
859
860 m_pOwnView = new OwnView_Impl( m_xFactory, m_xObjectStream->getInputStream() );
861 m_pOwnView->acquire();
862 }
863 catch( uno::RuntimeException& )
864 {
865 throw;
866 }
867 catch( uno::Exception& )
868 {
869 }
870 }
871
872 if ( !m_pOwnView || !m_pOwnView->Open() )
873 {
874 //Make a RO copy and see if the OS can find something to at
875 //least display the content for us
876 if (!m_aTempDumpURL.getLength())
877 m_aTempDumpURL = lcl_ExtractObject(m_xFactory, m_xObjectStream);
878
879 if (m_aTempDumpURL.getLength())
880 {
881 uno::Reference< ::com::sun::star::system::XSystemShellExecute > xSystemShellExecute(
882 ::com::sun::star::system::SystemShellExecute::create(
883 ::comphelper::getProcessComponentContext() ) );
884 xSystemShellExecute->execute(m_aTempDumpURL, ::rtl::OUString(), ::com::sun::star::system::SystemShellExecuteFlags::DEFAULTS);
885 }
886 else
887 throw embed::UnreachableStateException();
888 }
889 }
890 else
891 {
892
893 throw embed::UnreachableStateException();
894 }
895 }
896 }
897
898 //----------------------------------------------
getSupportedVerbs()899 uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
900 throw ( embed::WrongStateException,
901 uno::RuntimeException )
902 {
903 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getSupportedVerb" );
904
905 // begin wrapping related part ====================
906 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
907 if ( xWrappedObject.is() )
908 {
909 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
910 return xWrappedObject->getSupportedVerbs();
911 }
912 // end wrapping related part ====================
913
914 ::osl::MutexGuard aGuard( m_aMutex );
915 if ( m_bDisposed )
916 throw lang::DisposedException(); // TODO
917
918 if ( m_nObjectState == -1 )
919 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
920 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
921 #ifdef WNT
922 if ( m_pOleComponent )
923 {
924 // registry could be used in this case
925 // if ( m_nObjectState == embed::EmbedStates::LOADED )
926 // {
927 // // the list of supported verbs can be retrieved only when object is in running state
928 // throw embed::NeedsRunningStateException(); // TODO:
929 // }
930
931 return m_pOleComponent->GetVerbList();
932 }
933 else
934 #endif
935 {
936 return uno::Sequence< embed::VerbDescriptor >();
937 }
938 }
939
940 //----------------------------------------------
setClientSite(const uno::Reference<embed::XEmbeddedClient> & xClient)941 void SAL_CALL OleEmbeddedObject::setClientSite(
942 const uno::Reference< embed::XEmbeddedClient >& xClient )
943 throw ( embed::WrongStateException,
944 uno::RuntimeException )
945 {
946 // begin wrapping related part ====================
947 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
948 if ( xWrappedObject.is() )
949 {
950 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
951 xWrappedObject->setClientSite( xClient );
952 return;
953 }
954 // end wrapping related part ====================
955
956 ::osl::MutexGuard aGuard( m_aMutex );
957 if ( m_bDisposed )
958 throw lang::DisposedException(); // TODO
959
960 if ( m_xClientSite != xClient)
961 {
962 if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
963 throw embed::WrongStateException(
964 ::rtl::OUString::createFromAscii( "The client site can not be set currently!\n" ),
965 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
966
967 m_xClientSite = xClient;
968 }
969 }
970
971 //----------------------------------------------
getClientSite()972 uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
973 throw ( embed::WrongStateException,
974 uno::RuntimeException )
975 {
976 // begin wrapping related part ====================
977 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
978 if ( xWrappedObject.is() )
979 {
980 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
981 return xWrappedObject->getClientSite();
982 }
983 // end wrapping related part ====================
984
985 ::osl::MutexGuard aGuard( m_aMutex );
986 if ( m_bDisposed )
987 throw lang::DisposedException(); // TODO
988
989 if ( m_nObjectState == -1 )
990 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
991 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
992
993 return m_xClientSite;
994 }
995
996 //----------------------------------------------
update()997 void SAL_CALL OleEmbeddedObject::update()
998 throw ( embed::WrongStateException,
999 uno::Exception,
1000 uno::RuntimeException )
1001 {
1002 // begin wrapping related part ====================
1003 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1004 if ( xWrappedObject.is() )
1005 {
1006 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1007 xWrappedObject->update();
1008 return;
1009 }
1010 // end wrapping related part ====================
1011
1012 ::osl::MutexGuard aGuard( m_aMutex );
1013 if ( m_bDisposed )
1014 throw lang::DisposedException(); // TODO
1015
1016 if ( m_nObjectState == -1 )
1017 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
1018 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1019
1020 if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
1021 {
1022 // TODO: update view representation
1023 }
1024 else
1025 {
1026 // the object must be up to date
1027 OSL_ENSURE( m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE, "Unknown update mode!\n" );
1028 }
1029 }
1030
1031 //----------------------------------------------
setUpdateMode(sal_Int32 nMode)1032 void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
1033 throw ( embed::WrongStateException,
1034 uno::RuntimeException )
1035 {
1036 // begin wrapping related part ====================
1037 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1038 if ( xWrappedObject.is() )
1039 {
1040 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1041 xWrappedObject->setUpdateMode( nMode );
1042 return;
1043 }
1044 // end wrapping related part ====================
1045
1046 ::osl::MutexGuard aGuard( m_aMutex );
1047 if ( m_bDisposed )
1048 throw lang::DisposedException(); // TODO
1049
1050 if ( m_nObjectState == -1 )
1051 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object has no persistence!\n" ),
1052 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1053
1054 OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
1055 || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
1056 "Unknown update mode!\n" );
1057 m_nUpdateMode = nMode;
1058 }
1059
1060 //----------------------------------------------
getStatus(sal_Int64 nAspect)1061 sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
1062 nAspect
1063 )
1064 throw ( embed::WrongStateException,
1065 uno::RuntimeException )
1066 {
1067 // begin wrapping related part ====================
1068 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1069 if ( xWrappedObject.is() )
1070 {
1071 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1072 return xWrappedObject->getStatus( nAspect );
1073 }
1074 // end wrapping related part ====================
1075
1076 ::osl::MutexGuard aGuard( m_aMutex );
1077 if ( m_bDisposed )
1078 throw lang::DisposedException(); // TODO
1079
1080 if ( m_nObjectState == -1 )
1081 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object must be in running state!\n" ),
1082 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1083
1084 sal_Int64 nResult = 0;
1085
1086 #ifdef WNT
1087 if ( m_bGotStatus && m_nStatusAspect == nAspect )
1088 nResult = m_nStatus;
1089 else if ( m_pOleComponent )
1090 {
1091 // OLE should allow to get status even in loaded state
1092 // if ( m_nObjectState == embed::EmbedStates::LOADED )
1093 // changeState( m_nObjectState == embed::EmbedStates::RUNNING );
1094
1095 m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
1096 m_nStatusAspect = nAspect;
1097 m_bGotStatus = sal_True;
1098 nResult = m_nStatus;
1099 }
1100 #endif
1101
1102 // this implementation needs size to be provided after object loading/creating to work in optimal way
1103 return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
1104 }
1105
1106 //----------------------------------------------
setContainerName(const::rtl::OUString & sName)1107 void SAL_CALL OleEmbeddedObject::setContainerName( const ::rtl::OUString& sName )
1108 throw ( uno::RuntimeException )
1109 {
1110 // begin wrapping related part ====================
1111 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1112 if ( xWrappedObject.is() )
1113 {
1114 // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1115 xWrappedObject->setContainerName( sName );
1116 return;
1117 }
1118 // end wrapping related part ====================
1119
1120 ::osl::MutexGuard aGuard( m_aMutex );
1121 if ( m_bDisposed )
1122 throw lang::DisposedException(); // TODO
1123
1124 m_aContainerName = sName;
1125 }
1126
1127
1128