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