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/XSystemShellExecute.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 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 successfuly 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 commiting! 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 successfuly, 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 { 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 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 //---------------------------------------------- 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( m_xFactory->createInstance( 882 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.system.SystemShellExecute"))), 883 uno::UNO_QUERY_THROW); 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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 //---------------------------------------------- 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