// Remove any existing UserInstallation's extensions cache data remaining from // old installations. This addresses at least two problems: // // For one, apparently due to the old share/prereg/bundled mechanism (disabled // since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying // share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled // cache could contain corrupted information (like a UNO component registered // twice, which got changed from active to passive registration in one LO // version, but the version of the corresponding bundled extension only // incremented in a later LO version). // // For another, UserInstallations have been seen in the wild where no extensions // were installed per-user (any longer), but user/uno_packages/cache/registry/ // com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files // contained data nevertheless. // // When a LO upgrade is detected (i.e., no user/extensions/buildid or one // containing an old build ID), then user/extensions and // user/uno_packages/cache/registry/ // com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are // removed. That should prevent any problems starting the service manager due // to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the // removed cache data is recreated. // // Multiple instances of soffice.bin can execute this code in parallel for a // single UserInstallation, as it is called before RequestHandler is set up. // Therefore, any errors here only lead to SAL_WARNs. // // At least in theory, this function could be removed again once no // UserInstallation can be poisoned by old junk any more. bool cleanExtensionCache() {
OUString buildId(
u"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}"_ustr);
rtl::Bootstrap::expandMacros(buildId); //TODO: detect failure
OUString extDir(
u"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/user/extensions"_ustr);
rtl::Bootstrap::expandMacros(extDir); //TODO: detect failure
OUString buildIdFile(extDir + "/buildid");
osl::File fr(buildIdFile);
osl::FileBase::RC rc = fr.open(osl_File_OpenFlag_Read); switch (rc) { case osl::FileBase::E_None:
{
rtl::ByteSequence s1;
rc = fr.readLine(s1);
osl::FileBase::RC rc2 = fr.close();
SAL_WARN_IF(
rc2 != osl::FileBase::E_None, "desktop.app", "cannot close " << fr.getURL() << " after reading: " << +rc2); // readLine returns E_AGAIN for a zero-size file: if (rc != osl::FileBase::E_None && rc != osl::FileBase::E_AGAIN) {
SAL_WARN( "desktop.app", "cannot read from " << fr.getURL() << ": " << +rc); break;
}
OUString s2( reinterpret_cast< charconst * >(s1.getConstArray()),
s1.getLength(), RTL_TEXTENCODING_ISO_8859_1); // using ISO 8859-1 avoids any and all conversion errors; the // content should only be a subset of ASCII, anyway if (s2 == buildId) { returnfalse;
} break;
} case osl::FileBase::E_NOENT: break; default:
SAL_WARN( "desktop.app", "cannot open " << fr.getURL() << " for reading: " << +rc); break;
}
utl::removeTree(extDir);
OUString userRcFile(
u"$UNO_USER_PACKAGES_CACHE/registry/" "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc"_ustr);
rtl::Bootstrap::expandMacros(userRcFile); //TODO: detect failure
rc = osl::File::remove(userRcFile);
SAL_WARN_IF(
rc != osl::FileBase::E_None && rc != osl::FileBase::E_NOENT, "desktop.app", "cannot remove file " << userRcFile << ": " << +rc);
rc = osl::Directory::createPath(extDir);
SAL_WARN_IF(
rc != osl::FileBase::E_None && rc != osl::FileBase::E_EXIST, "desktop.app", "cannot create path " << extDir << ": " << +rc);
osl::File fw(buildIdFile);
rc = fw.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); if (rc != osl::FileBase::E_None) {
SAL_WARN( "desktop.app", "cannot open " << fw.getURL() << " for writing: " << +rc); returntrue;
}
OString buf(OUStringToOString(buildId, RTL_TEXTENCODING_UTF8)); // using UTF-8 avoids almost all conversion errors (and buildid // containing single surrogate halves should never happen, anyway); the // content should only be a subset of ASCII, anyway
sal_uInt64 n = 0;
rc = fw.write(buf.getStr(), buf.getLength(), n);
SAL_WARN_IF(
(rc != osl::FileBase::E_None
|| n != static_cast< sal_uInt32 >(buf.getLength())), "desktop.app", "cannot write to " << fw.getURL() << ": " << +rc << ", " << n);
rc = fw.close();
SAL_WARN_IF(
rc != osl::FileBase::E_None, "desktop.app", "cannot close " << fw.getURL() << " after writing: " << +rc); returntrue;
}
// shows a simple error box with the given message ... but exits from these process ! // Fatal errors can't be solved by the process ... nor any recovery can help. // Mostly the installation was damaged and must be repaired manually .. or by calling // setup again. // On the other side we must make sure that no further actions will be possible within // the current office process ! No pipe requests, no menu/toolbar/shortcut actions // are allowed. Otherwise we will force a "crash inside a crash". // That's why we have to use a special native message box here which does not use yield :-)
// We need to have service factory before going further, but see fdo#37195. // Doing this will mmap common.rdb, making it not overwritable on windows, // so this can't happen before the synchronization above. Let's rework this // so that the above is called *from* CreateApplicationServiceManager or // something to enforce this gotcha try
{
InitApplicationServiceManager();
} catch (css::uno::Exception & e)
{
HandleBootstrapErrors( BE_UNO_SERVICEMANAGER, e.Message );
std::abort();
}
// Check whether safe mode is enabled const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs(); // Check if we are restarting from safe mode - in that case we don't want to enter it again if (sfx2::SafeMode::hasRestartFlag())
sfx2::SafeMode::removeRestartFlag(); elseif (rCmdLineArgs.IsSafeMode() || sfx2::SafeMode::hasFlag())
Application::EnableSafeMode();
// When we are in SafeMode we need to do changes before the configuration // gets read (langselect::prepareLocale() by UNO API -> Components::Components) // This may prepare SafeMode or restore from it by moving data in // the UserConfiguration directory
comphelper::BackupFileHelper::reactOnSafeMode(Application::IsSafeModeEnabled());
// tdf117100: do not try to re-install extensions after the requested restart if (officecfg::Setup::Office::OfficeRestartInProgress::get())
{ if (!officecfg::Office::Common::Misc::FirstRun::get())
GetCommandLineArgs().RemoveFilesFromOpenListEndingWith(u".oxt"_ustr);
}
// test code for ProfileSafeMode to allow testing the fail // of loading the office configuration initially. To use, // either set to true and compile, or set a breakpoint // in debugger and change the local bool staticbool bTryHardOfficeconfigBroken(false); // loplugin:constvars:ignore
if (bTryHardOfficeconfigBroken)
{
SetBootstrapError(BE_OFFICECONFIG_BROKEN, OUString());
}
// start ipc thread only for non-remote offices
RequestHandler::Status aStatus = RequestHandler::Enable(true); if ( aStatus == RequestHandler::IPC_STATUS_PIPE_ERROR )
{ #ifdefined(ANDROID) || defined(EMSCRIPTEN) // Ignore crack pipe errors on Android #else // Keep using this oddly named BE_PATHINFO_MISSING value // for pipe-related errors on other platforms. Of course // this crack with two (if not more) levels of our own // error codes hiding the actual system error code is // broken, but that is done all over the code, let's leave // reengineering that to another year.
SetBootstrapError( BE_PATHINFO_MISSING, OUString() ); #endif
} elseif ( aStatus == RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR )
{
SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
} elseif ( aStatus == RequestHandler::IPC_STATUS_2ND_OFFICE )
{ // 2nd office startup should terminate after sending cmdlineargs through pipe if (rCmdLineArgs.IsTextCat() || rCmdLineArgs.IsScriptCat())
{
HandleBootstrapErrors( BE_2NDOFFICE_WITHCAT, OUString() );
}
SetBootstrapStatus(BS_TERMINATE);
} elseif ( !rCmdLineArgs.GetUnknown().isEmpty()
|| rCmdLineArgs.IsHelp() || rCmdLineArgs.IsVersion() )
{ // disable IPC thread in an instance that is just showing a help message
RequestHandler::Disable();
}
pSignalHandler = osl_addSignalHandler(SalMainPipeExchangeSignal_impl, nullptr);
#if HAVE_EMSCRIPTEN_PROXY_POSIX_SOCKETS
{ autoconst val = emscripten::val::module_property("uno_websocket_to_posix_socket_url"); if (val.isUndefined()) { throw std::runtime_error("Module.uno_websocket_to_posix_socket_url is undefined");
} else { autoconst url = val.as<std::string>(); if (url.find('\0') != std::string::npos) { throw std::runtime_error( "Module.uno_websocket_to_posix_socket_url contains embedded NUL");
}
SAL_INFO("desktop.app", "connecting to <" << url << ">"); staticautoconst socket = emscripten_init_websocket_to_posix_socket_bridge(
url.c_str()); // 0 is CONNECTING, 1 is OPEN, see // <https://websockets.spec.whatwg.org/#websocket-ready-state>: unsignedshort readyState = 0; do {
emscripten_websocket_get_ready_state(socket, &readyState);
emscripten_thread_sleep(100);
} while (readyState == 0); if (readyState != 1) { throw std::runtime_error("could not connect to <" + url + ">");
}
SAL_INFO("desktop.app", "connected to <" << url << ">");
}
} #endif
}
void Desktop::DeInit()
{ try { // instead of removing of the configManager just let it commit all the changes
utl::ConfigManager::storeConfigItems();
FlushConfiguration();
// close splashscreen if it's still open
CloseSplashScreen();
Reference< XComponent >(
comphelper::getProcessComponentContext(), UNO_QUERY_THROW )->
dispose(); // nobody should get a destroyed service factory...
::comphelper::setProcessServiceFactory( nullptr );
// clear lockfile
m_xLockfile.reset();
RequestHandler::Disable(); if( pSignalHandler )
osl_removeSignalHandler( pSignalHandler );
} catch (const RuntimeException&) { // someone threw an exception during shutdown // this will leave some garbage behind...
TOOLS_WARN_EXCEPTION("desktop.app", "exception throwing during shutdown, will leave some garbage behind");
}
}
if ( !bExit )
{
xPropertySet->setPropertyValue( SUSPEND_QUICKSTARTVETO, Any(false) );
} else
{
FlushConfiguration(); try
{ // it is no problem to call RequestHandler::Disable() more than once // it also looks to be threadsafe
RequestHandler::Disable();
} catch ( const RuntimeException& )
{
}
// Create an error message depending on bootstrap failure code and an optional file url
OUString Desktop::CreateErrorMsgString(
utl::Bootstrap::FailureCode nFailureCode, const OUString& aFileURL )
{
OUString aMsg; bool bFileInfo = true;
switch ( nFailureCode )
{ /// the shared installation directory could not be located case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_PATH_INVALID);
bFileInfo = false;
} break;
/// the bootstrap INI file could not be found or read case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE: /// the version locator INI file could not be found or read case ::utl::Bootstrap::MISSING_VERSION_FILE:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING);
} break;
/// the bootstrap INI is missing a required entry /// the bootstrap INI contains invalid data case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY: case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_CORRUPT);
} break;
/// the version locator INI has no entry for this version case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_NO_SUPPORT);
} break;
/// the user installation directory does not exist case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_DIR_MISSING);
} break;
/// some bootstrap data was invalid in unexpected ways case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
{
aMsg = DpResId(STR_BOOTSTRAP_ERR_INTERNAL);
bFileInfo = false;
} break;
case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
{ // This needs to be improved, see #i67575#:
aMsg = "Invalid version file entry";
bFileInfo = false;
} break;
case ::utl::Bootstrap::NO_FAILURE:
{
OSL_ASSERT(false);
} break;
}
/// the bootstrap INI file could not be found or read /// the bootstrap INI is missing a required entry /// the bootstrap INI contains invalid data case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY: case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY: case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
{
OUString aBootstrapFileURL;
/// the version locator INI file could not be found or read /// the version locator INI has no entry for this version /// the version locator INI entry is not a valid directory URL case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY: case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY: case ::utl::Bootstrap::MISSING_VERSION_FILE:
{
OUString aVersionFileURL;
case ::utl::Bootstrap::NO_FAILURE:
{
OSL_ASSERT(false);
} break;
}
HandleBootstrapPathErrors( aBootstrapStatus, aErrorMsg );
}
} elseif ( aBootstrapError == BE_UNO_SERVICEMANAGER || aBootstrapError == BE_UNO_SERVICE_CONFIG_MISSING )
{ // UNO service manager is not available. VCL needs a UNO service manager to display a message box!!! // Currently we are not able to display a message box with a service manager due to this limitations inside VCL.
// When UNO is not properly initialized, all kinds of things can fail // and cause the process to crash. To give the user a hint even if // generating and displaying a message box below crashes, print a // hard-coded message on stderr first:
std::cerr
<< "The application cannot be started.\n" // STR_BOOTSTRAP_ERR_CANNOT_START
<< (aBootstrapError == BE_UNO_SERVICEMANAGER
? "The component manager is not available.\n" // STR_BOOTSTRAP_ERR_NO_SERVICE
: "The configuration service is not available.\n"); // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE if ( !aErrorMessage.isEmpty() )
{
std::cerr << "(\"" << aErrorMessage << "\")\n";
}
// First sentence. We cannot bootstrap office further!
OUString aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_NO_CFG_SERVICE) + "\n"; if ( !aErrorMessage.isEmpty() )
{
aDiagnosticMessage += "(\"" + aErrorMessage + "\")\n";
}
// Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to // repair the installation with the setup executable besides the office executable. Now // we have to ask the user to start the setup on CD/installation directory manually!!
aDiagnosticMessage += DpResId(STR_ASK_START_SETUP_MANUALLY);
FatalError(MakeStartupErrorMessage(aDiagnosticMessage));
} elseif ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
{ // set flag at BackupFileHelper to be able to know if _exit was called and // actions are executed after this. This method we are in will not return, // but end up in a _exit() call
comphelper::BackupFileHelper::setExitWasCalled();
// enter safe mode, too
sfx2::SafeMode::putFlag();
// save all modified documents ... if it's allowed doing so. bool bRestart = false; bool bAllowRecoveryAndSessionManagement = (
( !rArgs.IsNoRestore() ) && // some use cases of office must work without recovery
( !rArgs.IsHeadless() ) &&
( nCategory != ExceptionCategory::UserInterface ) && // recovery can't work without UI ... but UI layer seems to be the reason for this crash
( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicate a corrupted installation...)
); if ( bAllowRecoveryAndSessionManagement )
{ // Save all open documents so they will be reopened // the next time the application is started // returns true if at least one document could be saved... #if !ENABLE_WASM_STRIP_RECOVERYUI
bRestart = impl_callRecoveryUI( true , // force emergency save false); #endif
}
// Detect desktop environment - need to do this as early as possible
css::uno::setCurrentContext( new DesktopContext( css::uno::getCurrentContext() ) );
if (officecfg::Office::Common::Misc::PreloadJVM::get() && pExecGlobals)
{
SAL_INFO("desktop.app", "Preload JVM");
// pre-load JVM
pExecGlobals->xJVMloadThread = new JVMloadThread();
pExecGlobals->xJVMloadThread->launch();
}
recordTime(startT, "SetSplashScreenProgress(25): time = ");
#if HAVE_FEATURE_DESKTOP && !defined(EMSCRIPTEN) // check user installation directory for lockfile so we can be sure // there is no other instance using our data files from a remote host
#if HAVE_FEATURE_UPDATE_MAR if (!rCmdLineArgs.IsHeadless()
&& (officecfg::Office::Update::Update::Enabled::get()
|| std::getenv("LIBO_UPDATER_TEST_ENABLE")))
{ // check if we just updated bool bUpdateRunning = officecfg::Office::Update::Update::UpdateRunning::get()
|| std::getenv("LIBO_UPDATER_TEST_RUNNING"); if (bUpdateRunning)
{
OUString aSeeAlso = officecfg::Office::Update::Update::SeeAlso::get();
OUString aOldBuildID = officecfg::Office::Update::Update::OldBuildID::get();
OUString aBuildID = Updater::getBuildID(); if (aOldBuildID == aBuildID)
{
Updater::log("Old and new Build ID are the same. No Updating took place.");
} else
{ if (!aSeeAlso.isEmpty())
{
SAL_INFO("desktop.updater", "See also: " << aSeeAlso);
Reference< css::system::XSystemShellExecute > xSystemShell(
SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
// reset all the configuration values, // all values need to be read before this code
std::shared_ptr< comphelper::ConfigurationChanges > batch(
comphelper::ConfigurationChanges::create());
officecfg::Office::Update::Update::UpdateRunning::set(false, batch);
officecfg::Office::Update::Update::SeeAlso::set(OUString(), batch);
officecfg::Office::Update::Update::OldBuildID::set(OUString(), batch);
batch->commit();
// make sure the change is written to the configuration before we start the update
css::uno::Reference<css::util::XFlushable> xFlushable(css::configuration::theDefaultProvider::get(xContext), UNO_QUERY);
xFlushable->flush(); // avoid the old oosplash staying around
CloseSplashScreen(); bool bSuccess = update(); if (bSuccess)
{
xDesktop->terminate(); return EXIT_SUCCESS;
}
} elseif (isTimeForUpdateCheck() || std::getenv("LIBO_UPDATER_TEST_UPDATE_CHECK"))
{
sal_uInt64 nNow = tools::Time::GetSystemTicks();
Updater::log("Update Check Time: " + OUString::number(nNow));
std::shared_ptr< comphelper::ConfigurationChanges > batch(
comphelper::ConfigurationChanges::create());
officecfg::Office::Update::Update::LastUpdateTime::set(nNow, batch);
batch->commit();
m_aUpdateThread = std::thread(update_checker);
}
} #endif
// create service for loading SFX (still needed in startup)
pExecGlobals->xGlobalBroadcaster = Reference < css::document::XDocumentEventListener >
( css::frame::theGlobalEventBroadcaster::get(xContext), UNO_SET_THROW );
/* ensure existence of a default window that messages can be dispatched to ThisisforthebenefitoftesttoolwhichusesPostUserEventextensively andelsecandeadlockwhilecreatingthiswindowfromanotherthreadwhile themainthreadisnotyetintheeventloop.
*/
Application::GetDefaultDevice();
#if HAVE_FEATURE_EXTENSIONS // Check if bundled or shared extensions were added /removed // and process those extensions (has to be done before checking // the extension dependencies!
SynchronizeExtensionRepositories(m_bCleanedExtensionCache, this); bool bAbort = CheckExtensionDependencies(); if ( bAbort ) return EXIT_FAILURE;
if (inst_fin == userinstall::CREATED)
{
Migration::migrateSettingsIfNecessary();
} #endif
// keep a language options instance...
pExecGlobals->pCTLLanguageOptions.reset( new SvtCTLOptions(true));
// Preload function depends on an initialized sfx application!
SetSplashScreenProgress(75);
recordTime(startT, "SetSplashScreenProgress(75): time = ");
// use system window dialogs
Application::SetSystemWindowMode( SystemWindowFlags::DIALOG );
SetSplashScreenProgress(80);
recordTime(startT, "SetSplashScreenProgress(80): time = ");
if ( !rCmdLineArgs.IsInvisible() &&
!rCmdLineArgs.IsNoQuickstart() )
InitializeQuickstartMode( xContext );
if ( xDesktop.is() )
xDesktop->addTerminateListener( new RequestHandlerController );
SetSplashScreenProgress(100);
recordTime(startT, "SetSplashScreenProgress(100): time = ");
// FIXME: move this somewhere sensible. #if HAVE_FEATURE_OPENCL
CheckOpenCLCompute(xDesktop); #endif
// Post user event to startup first application component window // We have to send this OpenClients message short before execute() to // minimize the risk that this message overtakes type detection construction!!
Application::PostUserEvent( LINK( this, Desktop, OpenClients_Impl ) );
// Post event to enable acceptors
Application::PostUserEvent( LINK( this, Desktop, EnableAcceptors_Impl) );
// call Application::Execute to process messages in vcl message loop #if HAVE_FEATURE_JAVA // The JavaContext contains an interaction handler which is used when // the creation of a Java Virtual Machine fails
css::uno::ContextLayer layer2( new svt::JavaContext( css::uno::getCurrentContext() ) ); #endif // check whether the shutdown is caused by restart just before entering the Execute
pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested ||
xRestartManager->isRestartRequested(true);
if ( !pExecGlobals->bRestartRequested )
{ // if this run of the office is triggered by restart, some additional actions should be done
DoRestartActionsIfNecessary( !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsNoQuickstart() );
Execute();
}
} else
{ if (xDesktop.is())
xDesktop->terminate();
} // CAUTION: you do not necessarily get here e.g. on the Mac. // please put all deinitialization code into doShutdown return doShutdown();
}
int Desktop::doShutdown()
{ if( ! pExecGlobals ) return EXIT_SUCCESS;
if (m_aUpdateThread.joinable())
m_aUpdateThread.join();
if (pExecGlobals->xJVMloadThread.is())
{
pExecGlobals->xJVMloadThread->join();
pExecGlobals->xJVMloadThread.clear();
}
// flush evtl. configuration changes so that all config files in user // dir are written
FlushConfiguration();
if (pExecGlobals->bRestartRequested)
{ // tdf#128523
RemoveIconCacheDirectory();
// a restart is already requested, usually due to a configuration change // that needs a restart to get active. If this is the case, do not try // to use SecureUserConfig to safe this still untested new configuration
} else
{ // Test if SecureUserConfig is active. If yes and we are at this point, regular shutdown // is in progress and the currently used configuration was working. Try to secure this // working configuration for later eventually necessary restores
comphelper::BackupFileHelper aBackupFileHelper;
// The acceptors in the AcceptorMap must be released (in DeregisterServices) // with the solar mutex unlocked, to avoid deadlock:
{
SolarMutexReleaser aReleaser;
DeregisterServices(); #if HAVE_FEATURE_SCRIPTING
StarBASIC::DetachAllDocBasicItems(); #endif
}
// be sure that path/language options gets destroyed before // UCB is deinitialized
pExecGlobals->pCTLLanguageOptions.reset();
pExecGlobals->pPathOptions.reset();
bool Desktop::InitializeQuickstartMode( const Reference< XComponentContext >& rxContext )
{ try
{ // the shutdown icon sits in the systray and allows the user to keep // the office instance running for quicker restart // this will only be activated if --quickstart was specified on cmdline
bool bQuickstart = shouldLaunchQuickstart();
// Try to instantiate quickstart service. This service is not mandatory, so // do nothing if service is not available
// #i105753# the following if was invented for performance // unfortunately this broke the Mac behavior which is to always run // in quickstart mode since Mac applications do not usually quit // when the last document closes. // Note that this claim that on macOS we "always run in quickstart mode" // has nothing to do with (quick) *starting* (i.e. starting automatically // when the user logs in), though, but with not quitting when no documents // are open. #ifndef MACOSX if ( bQuickstart ) #endif
{
css::office::Quickstart::createStart(rxContext, bQuickstart);
} returntrue;
} catch( const css::uno::Exception& )
{ returnfalse;
}
}
IMPL_LINK_NOARG(Desktop, OpenClients_Impl, void*, void)
{ // #i114963# // Enable IPC thread before OpenClients // // This is because it is possible for another client to connect during the OpenClients() call. // This can happen on Windows when document is printed (not opened) and another client wants to print (when printing multiple documents). // If the IPC thread is enabled after OpenClients, then the client will not be processed because the application will exit after printing. i.e RequestHandler::AreRequestsPending() will always return false // // ALSO: // // Multiple clients may request simultaneous connections. // When this server closes down it attempts to recreate the pipe (in RequestHandler::Disable()). // It's possible that the client has a pending connection request. // When the IPC thread is not running, this connection locks (because maPipe.accept()) is never called
RequestHandler::SetReady(true);
OpenClients();
CloseSplashScreen();
CheckFirstRun( ); #ifdef _WIN32 bool bDontShowDialogs
= Application::IsHeadlessModeEnabled(); // uitest.uicheck fails when the dialog is open for (sal_uInt16 i = 0; !bDontShowDialogs && i < Application::GetCommandLineParamCount(); i++)
{ if (Application::GetCommandLineParam(i) == "--nologo")
bDontShowDialogs = true;
} if (!bDontShowDialogs)
vcl::fileregistration::CheckFileExtRegistration(SfxGetpApp()->GetTopWindow()); // Registers a COM class factory of the service manager with the windows operating system.
Reference< XMultiServiceFactory > xSMgr= comphelper::getProcessServiceFactory();
xSMgr->createInstance("com.sun.star.bridge.OleApplicationRegistration");
xSMgr->createInstance("com.sun.star.comp.ole.EmbedServer"); #endif constchar *pExitPostStartup = getenv ("OOO_EXIT_POST_STARTUP"); if (pExitPostStartup && *pExitPostStartup) new ExitTimer(); constauto endTp = std::chrono::high_resolution_clock::now(); auto tMs = std::chrono::duration_cast<std::chrono::milliseconds>(endTp - startFuncTp);
SAL_INFO( "desktop.startuptime", "Total Start Up time(ms) = " << tMs.count());
}
// Disable AutoSave feature in case "--norestore" or a similar command line switch is set on the command line. // The reason behind: AutoSave/EmergencySave/AutoRecovery share the same data. // But the require that all documents, which are saved as backup should exists inside // memory. May be this mechanism will be inconsistent if the configuration exists... // but no document inside memory corresponds to this data. // Further it's not acceptable to recover such documents without any UI. It can // need some time, where the user won't see any results and wait for finishing the office startup... bool bAllowRecoveryAndSessionManagement = ( !rArgs.IsNoRestore() ) && ( !rArgs.IsHeadless() );
#if !defined ANDROID // Enter safe mode if requested if (Application::IsSafeModeEnabled()) {
handleSafeMode();
} #endif
#if HAVE_FEATURE_BREAKPAD if (officecfg::Office::Common::Misc::CrashReport::get() && CrashReporter::crashReportInfoExists())
handleCrashReport(); #endif
// write this information here to avoid depending on vcl in the crash reporter lib
CrashReporter::addKeyValue(u"Language"_ustr, Application::GetSettings().GetLanguageTag().getBcp47(), CrashReporter::Create);
#ifdef MACOSX // Related: tdf#41775 show Start Center before loading documents // If LibreOffice is launched from the command line with a // document path parameter, the Start Center doesn't get // created when all of the document windows are closed. This // causes the old "File only" menubar to be displayed // instead of the Start Center's menubar. if (!rArgs.IsQuickstart() && !rArgs.IsInvisible())
{
SvtModuleOptions aOpt; if (aOpt.IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE))
ShowBackingComponent(nullptr);
} #endif // Process request if ( RequestHandler::ExecuteCmdLineRequests(aRequest, false) )
{ // Don't do anything if we have successfully called terminate at desktop: return;
}
}
// no default document if a document was loaded by recovery or by command line or if soffice is used as server
Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
Reference< XElementAccess > xList( xDesktop->getFrames(), UNO_QUERY_THROW ); if ( xList->hasElements() ) return;
if ( rArgs.IsQuickstart() || rArgs.IsInvisible() || Application::AnyInput( VclInputFlags::APPEVENT ) )
{ #ifdef MACOSX // Related: tdf#41775 show Start Center before loading documents // If LibreOffice is launched from by opening a document from the // Finder or dragging it onto the application's Dock icon, the // the Start Center doesn't get created when all of the document // windows are closed. This causes the old "File only" menubar // to be displayed instead of the Start Center's menubar. if (!rArgs.IsQuickstart() && !rArgs.IsInvisible())
{
SvtModuleOptions aOpt; if (aOpt.IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE))
ShowBackingComponent(nullptr);
} #endif
if ( aName.isEmpty() )
{ if (aOpt.IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE))
{
ShowBackingComponent(nullptr); return;
}
// Old way to create a default document if (aOpt.IsWriterInstalled())
aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER ); elseif (aOpt.IsCalcInstalled())
aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC ); elseif (aOpt.IsImpressInstalled())
aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS ); elseif (aOpt.IsDataBaseInstalled())
aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE ); elseif (aOpt.IsDrawInstalled())
aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW ); else return;
}
#ifdef MACOSX // Related: tdf#41775 show Start Center before loading documents // If LibreOffice is launched from the command line with a module // argument, the Start Center doesn't get created when all of the // document windows are closed. This causes the old "File only" // menubar to be displayed instead of the Start Center's menubar. if (aOpt.IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE))
ShowBackingComponent(nullptr); #endif
OUString GetURL_Impl( const OUString& rName, std::optional< OUString > const & cwdUrl )
{ // if rName is a vnd.sun.star.script URL do not attempt to parse it // as INetURLObj does not handle URLs there if (rName.startsWith("vnd.sun.star.script"))
{ return rName;
}
// don't touch file urls, those should already be in internal form // they won't get better here (#112849#) if (comphelper::isFileUrl(rName))
{ return rName;
}
if ( rName.startsWith("service:"))
{ return rName;
}
// Add path separator to these directory and make given URL (rName) absolute by using of current working directory // Attention: "setFinalSlash()" is necessary for calling "smartRel2Abs()"!!! // Otherwise last part will be ignored and wrong result will be returned!!! // "smartRel2Abs()" interpret given URL as file not as path. So he truncate last element to get the base path ... // But if we add a separator - he doesn't do it anymore.
INetURLObject aObj; if (cwdUrl) {
aObj.SetURL(*cwdUrl);
aObj.setFinalSlash();
}
// Use the provided parameters for smartRel2Abs to support the usage of '%' in system paths. // Otherwise this char won't get encoded and we are not able to load such files later, bool bWasAbsolute;
INetURLObject aURL = aObj.smartRel2Abs( rName, bWasAbsolute, false, INetURLObject::EncodeMechanism::WasEncoded,
RTL_TEXTENCODING_UTF8, true );
OUString aFileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
void Desktop::HandleAppEvent( const ApplicationEvent& rAppEvent )
{ switch ( rAppEvent.GetEvent() )
{ case ApplicationEvent::Type::Accept: // every time an accept parameter is used we create an acceptor // with the corresponding accept-string
createAcceptor(rAppEvent.GetStringData()); break; case ApplicationEvent::Type::Appear: if ( !GetCommandLineArgs().IsInvisible() && !impl_bringToFrontRecoveryUI() )
{ const Reference< css::uno::XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
// find active task - the active task is always a visible task
Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
Reference< css::frame::XFrame > xTask = xDesktop->getActiveFrame(); if ( !xTask.is() )
{ // get any task if there is no active one
Reference< css::container::XIndexAccess > xList = xDesktop->getFrames(); if ( xList->getCount() > 0 )
xList->getByIndex(0) >>= xTask;
}
if ( xTask.is() )
{
Reference< css::awt::XTopWindow > xTop( xTask->getContainerWindow(), UNO_QUERY );
xTop->toFront();
} else
{ // no visible task that could be activated found
Reference< css::awt::XWindow > xContainerWindow;
Reference< XFrame > xBackingFrame = xDesktop->findFrame( u"_blank"_ustr, 0); if (xBackingFrame.is())
xContainerWindow = xBackingFrame->getContainerWindow(); if (xContainerWindow.is())
{
Reference< XController > xStartModule = StartModule::createWithParentWindow(xContext, xContainerWindow);
Reference< css::awt::XWindow > xBackingWin(xStartModule, UNO_QUERY); // Attention: You MUST(!) call setComponent() before you call attachFrame(). // Because the backing component set the property "IsBackingMode" of the frame // to true inside attachFrame(). But setComponent() reset this state every time ...
xBackingFrame->setComponent(xBackingWin, xStartModule);
xStartModule->attachFrame(xBackingFrame);
xContainerWindow->setVisible(true);
VclPtr<vcl::Window> pCompWindow = VCLUnoHelper::GetWindow(xBackingFrame->getComponentWindow()); if (pCompWindow)
pCompWindow->PaintImmediately();
}
}
} break; case ApplicationEvent::Type::Open:
{ const CommandLineArgs& rCmdLine = GetCommandLineArgs(); if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() )
{
ProcessDocumentsRequest docsRequest(rCmdLine.getCwdUrl());
std::vector<OUString> const & data(rAppEvent.GetStringsData());
docsRequest.aOpenList.insert(
docsRequest.aOpenList.end(), data.begin(), data.end());
RequestHandler::ExecuteCmdLineRequests(docsRequest, false);
}
} break; case ApplicationEvent::Type::OpenHelpUrl: // start help for a specific URL
Application::GetHelp()->Start(rAppEvent.GetStringData()); break; case ApplicationEvent::Type::Print:
{ const CommandLineArgs& rCmdLine = GetCommandLineArgs(); if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() )
{
ProcessDocumentsRequest docsRequest(rCmdLine.getCwdUrl());
std::vector<OUString> const & data(rAppEvent.GetStringsData());
docsRequest.aPrintList.insert(
docsRequest.aPrintList.end(), data.begin(), data.end());
RequestHandler::ExecuteCmdLineRequests(docsRequest, false);
}
} break; case ApplicationEvent::Type::PrivateDoShutdown:
{
Desktop* pD = dynamic_cast<Desktop*>(GetpApp());
OSL_ENSURE( pD, "no desktop ?!?" ); if( pD )
pD->doShutdown();
} break; case ApplicationEvent::Type::QuickStart: if ( !GetCommandLineArgs().IsInvisible() )
{ // If the office has been started the second time its command line arguments are sent through a pipe // connection to the first office. We want to reuse the quickstart option for the first office. // NOTICE: The quickstart service must be initialized inside the "main thread", so we use the // application events to do this (they are executed inside main thread)!!! // Don't start quickstart service if the user specified "--invisible" on the command line! const Reference< css::uno::XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
css::office::Quickstart::createStart(xContext, true/*Quickstart*/);
} break; case ApplicationEvent::Type::ShowDialog: // This is only used on macOS, and only for About or Preferences. // Ignore all errors here. It's clicking a menu entry only ... // The user will try it again, in case nothing happens .-) try
{ const Reference< css::uno::XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
#if !ENABLE_WASM_STRIP_SPLASH void Desktop::OpenSplashScreen()
{ const CommandLineArgs &rCmdLine = GetCommandLineArgs(); // Show intro only if this is normal start (e.g. no server, no quickstart, no printing ) if ( !(!rCmdLine.IsInvisible() &&
!rCmdLine.IsHeadless() &&
!rCmdLine.IsQuickstart() &&
!rCmdLine.IsMinimized() &&
!rCmdLine.IsNoLogo() &&
!rCmdLine.IsTerminateAfterInit() &&
rCmdLine.GetPrintList().empty() &&
rCmdLine.GetPrintToList().empty() &&
rCmdLine.GetConversionList().empty()) ) return;
// Which splash to use
OUString aSplashService( u"com.sun.star.office.SplashScreen"_ustr ); if ( rCmdLine.HasSplashPipe() )
aSplashService = "com.sun.star.office.PipeSplashScreen";
IMPL_STATIC_LINK_NOARG(Desktop, AsyncInitFirstRun, Timer *, void)
{ // does initializations which are necessary for the first run of the office try
{
Reference< XJobExecutor > xExecutor = theJobExecutor::get( ::comphelper::getProcessComponentContext() );
xExecutor->trigger( u"onFirstRunInitialization"_ustr ); auto batch(comphelper::ConfigurationChanges::create());
officecfg::Office::Common::Misc::FirstRun::set(false, batch);
batch->commit();
} catch(const css::uno::Exception&)
{
TOOLS_WARN_EXCEPTION( "desktop.app", "Desktop::DoFirstRunInitializations: caught an exception while trigger job executor" );
}
}
if (xBackingFrame.is())
xContainerWindow = xBackingFrame->getContainerWindow(); if (!xContainerWindow.is()) return;
// set the WindowExtendedStyle::Document style. Normally, this is done by the TaskCreator service when a "_blank" // frame/window is created. Since we do not use the TaskCreator here, we need to mimic its behavior, // otherwise documents loaded into this frame will later on miss functionality depending on the style.
VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
SAL_WARN_IF( !pContainerWindow, "desktop.app", "Desktop::Main: no implementation access to the frame's container window!" );
pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WindowExtendedStyle::Document ); if (progress != nullptr)
{
progress->SetSplashScreenProgress(75);
}
Reference< XController > xStartModule = StartModule::createWithParentWindow( xContext, xContainerWindow); // Attention: You MUST(!) call setComponent() before you call attachFrame(). // Because the backing component set the property "IsBackingMode" of the frame // to true inside attachFrame(). But setComponent() reset this state everytimes ...
xBackingFrame->setComponent(Reference< XWindow >(xStartModule, UNO_QUERY), xStartModule); if (progress != nullptr)
{
progress->SetSplashScreenProgress(100);
}
xStartModule->attachFrame(xBackingFrame); if (progress != nullptr)
{
progress->CloseSplashScreen();
}
xContainerWindow->setVisible(true);
}
void Desktop::CheckFirstRun( )
{ if (!officecfg::Office::Common::Misc::FirstRun::get()) return;
// use VCL timer, which won't trigger during shutdown if the // application exits before timeout
m_firstRunTimer.Start();
#ifdef _WIN32 // Check if Quickstarter should be started (on Windows only)
OUString sRootKey = ReplaceStringHookProc("Software\\%OOOVENDOR\\%PRODUCTNAME\\%PRODUCTVERSION"); if (ERROR_SUCCESS == RegGetValueW(HKEY_LOCAL_MACHINE, o3tl::toW(sRootKey.getStr()), L"RunQuickstartAtFirstStart", RRF_RT_ANY, nullptr, nullptr, nullptr))
{
css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
css::office::Quickstart::createAutoStart(xContext, true/*Quickstart*/, true/*bAutostart*/);
} #endif
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.58Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-30)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.