1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <config_features.h>
22 #include <config_feature_desktop.h>
23 #include <config_feature_opencl.h>
24 #include <config_java.h>
25 #include <config_folders.h>
26 #include <config_extensions.h>
28 #include <sal/config.h>
31 #include <string_view>
34 #include <dp_shared.hxx>
35 #include <strings.hrc>
36 #include "cmdlineargs.hxx"
37 #include <lockfile.hxx>
38 #include "userinstall.hxx"
39 #include "desktopcontext.hxx"
40 #include <migration.hxx>
41 #include "officeipcthread.hxx"
42 #if HAVE_FEATURE_UPDATE_MAR
43 #include "updater.hxx"
46 #include <framework/desktop.hxx>
47 #include <i18nlangtag/languagetag.hxx>
48 #include <o3tl/char16_t2wchar_t.hxx>
49 #include <svl/languageoptions.hxx>
50 #include <svtools/javacontext.hxx>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/frame/theAutoRecovery.hpp>
53 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
54 #include <com/sun/star/frame/SessionListener.hpp>
55 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
56 #include <com/sun/star/configuration/theDefaultProvider.hpp>
57 #include <com/sun/star/util/XFlushable.hpp>
58 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
59 #include <com/sun/star/frame/Desktop.hpp>
60 #include <com/sun/star/frame/StartModule.hpp>
61 #include <com/sun/star/view/XPrintable.hpp>
62 #include <com/sun/star/awt/XTopWindow.hpp>
63 #include <com/sun/star/util/URLTransformer.hpp>
64 #include <com/sun/star/util/XURLTransformer.hpp>
65 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
66 #include <com/sun/star/configuration/MissingBootstrapFileException.hpp>
67 #include <com/sun/star/configuration/InvalidBootstrapFileException.hpp>
68 #include <com/sun/star/configuration/InstallationIncompleteException.hpp>
69 #include <com/sun/star/configuration/backend/BackendSetupException.hpp>
70 #include <com/sun/star/configuration/backend/BackendAccessException.hpp>
71 #include <com/sun/star/task/theJobExecutor.hpp>
72 #include <com/sun/star/task/OfficeRestartManager.hpp>
73 #include <com/sun/star/task/XRestartManager.hpp>
74 #include <com/sun/star/document/XDocumentEventListener.hpp>
75 #include <com/sun/star/office/Quickstart.hpp>
76 #include <com/sun/star/system/XSystemShellExecute.hpp>
77 #include <com/sun/star/system/SystemShellExecute.hpp>
78 #include <com/sun/star/loader/XImplementationLoader.hpp>
80 #include <desktop/exithelper.h>
81 #include <sal/log.hxx>
82 #include <toolkit/helper/vclunohelper.hxx>
83 #include <comphelper/configuration.hxx>
84 #include <comphelper/fileurl.hxx>
85 #include <comphelper/threadpool.hxx>
86 #include <comphelper/processfactory.hxx>
87 #include <comphelper/backupfilehelper.hxx>
88 #include <uno/current_context.hxx>
89 #include <unotools/bootstrap.hxx>
90 #include <unotools/configmgr.hxx>
91 #include <unotools/moduleoptions.hxx>
92 #include <unotools/localfilehelper.hxx>
93 #include <unotools/ucbhelper.hxx>
94 #include <officecfg/Office/Common.hxx>
95 #include <officecfg/Office/Recovery.hxx>
96 #include <officecfg/Office/Update.hxx>
97 #include <officecfg/Setup.hxx>
98 #include <osl/file.hxx>
99 #include <osl/process.h>
100 #include <rtl/byteseq.hxx>
101 #include <unotools/pathoptions.hxx>
102 #include <svtools/menuoptions.hxx>
103 #include <rtl/bootstrap.hxx>
104 #include <vcl/glxtestprocess.hxx>
105 #include <vcl/help.hxx>
106 #include <vcl/weld.hxx>
107 #include <vcl/settings.hxx>
108 #include <sfx2/flatpak.hxx>
109 #include <sfx2/sfxsids.hrc>
110 #include <sfx2/app.hxx>
111 #include <sfx2/safemode.hxx>
112 #include <svl/itemset.hxx>
113 #include <svl/eitem.hxx>
114 #include <basic/sbstar.hxx>
115 #include <desktop/crashreport.hxx>
116 #include <tools/urlobj.hxx>
117 #include <tools/diagnose_ex.h>
118 #include <svtools/fontsubstconfig.hxx>
119 #include <svtools/accessibilityoptions.hxx>
120 #include <svtools/apearcfg.hxx>
121 #include <vcl/graphicfilter.hxx>
122 #include <vcl/window.hxx>
123 #include "langselect.hxx"
124 #include <salhelper/thread.hxx>
128 #include <sys/wait.h>
132 #define WIN32_LEAN_AND_MEAN
134 #include <vcl/fileregistration.hxx>
139 #define GETPID _getpid
142 #define GETPID getpid
145 #include <strings.hxx>
147 using namespace ::com::sun::star::awt
;
148 using namespace ::com::sun::star::uno
;
149 using namespace ::com::sun::star::util
;
150 using namespace ::com::sun::star::lang
;
151 using namespace ::com::sun::star::beans
;
152 using namespace ::com::sun::star::frame
;
153 using namespace ::com::sun::star::document
;
154 using namespace ::com::sun::star::view
;
155 using namespace ::com::sun::star::task
;
156 using namespace ::com::sun::star::system
;
157 using namespace ::com::sun::star::ui
;
158 using namespace ::com::sun::star::ui::dialogs
;
159 using namespace ::com::sun::star::container
;
164 static oslSignalHandler pSignalHandler
= nullptr;
168 #if HAVE_FEATURE_EXTENSIONS
170 // Remove any existing UserInstallation's extensions cache data remaining from
171 // old installations. This addresses at least two problems:
173 // For one, apparently due to the old share/prereg/bundled mechanism (disabled
174 // since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying
175 // share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled
176 // cache could contain corrupted information (like a UNO component registered
177 // twice, which got changed from active to passive registration in one LO
178 // version, but the version of the corresponding bundled extension only
179 // incremented in a later LO version).
181 // For another, UserInstallations have been seen in the wild where no extensions
182 // were installed per-user (any longer), but user/uno_packages/cache/registry/
183 // com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files
184 // contained data nevertheless.
186 // When a LO upgrade is detected (i.e., no user/extensions/buildid or one
187 // containing an old build ID), then user/extensions and
188 // user/uno_packages/cache/registry/
189 // com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are
190 // removed. That should prevent any problems starting the service manager due
191 // to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the
192 // removed cache data is recreated.
194 // Multiple instances of soffice.bin can execute this code in parallel for a
195 // single UserInstallation, as it is called before RequestHandler is set up.
196 // Therefore, any errors here only lead to SAL_WARNs.
198 // At least in theory, this function could be removed again once no
199 // UserInstallation can be poisoned by old junk any more.
200 bool cleanExtensionCache() {
202 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":buildid}");
203 rtl::Bootstrap::expandMacros(buildId
); //TODO: detect failure
205 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap")
206 ":UserInstallation}/user/extensions");
207 rtl::Bootstrap::expandMacros(extDir
); //TODO: detect failure
208 OUString
buildIdFile(extDir
+ "/buildid");
209 osl::File
fr(buildIdFile
);
210 osl::FileBase::RC rc
= fr
.open(osl_File_OpenFlag_Read
);
212 case osl::FileBase::E_None
:
214 rtl::ByteSequence s1
;
215 rc
= fr
.readLine(s1
);
216 osl::FileBase::RC rc2
= fr
.close();
218 rc2
!= osl::FileBase::E_None
, "desktop.app",
219 "cannot close " << fr
.getURL() << " after reading: " << +rc2
);
220 // readLine returns E_AGAIN for a zero-size file:
221 if (rc
!= osl::FileBase::E_None
&& rc
!= osl::FileBase::E_AGAIN
) {
222 SAL_WARN( "desktop.app", "cannot read from " << fr
.getURL() << ": " << +rc
);
226 reinterpret_cast< char const * >(s1
.getConstArray()),
227 s1
.getLength(), RTL_TEXTENCODING_ISO_8859_1
);
228 // using ISO 8859-1 avoids any and all conversion errors; the
229 // content should only be a subset of ASCII, anyway
235 case osl::FileBase::E_NOENT
:
238 SAL_WARN( "desktop.app", "cannot open " << fr
.getURL() << " for reading: " << +rc
);
241 utl::removeTree(extDir
);
243 "$UNO_USER_PACKAGES_CACHE/registry/"
244 "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc");
245 rtl::Bootstrap::expandMacros(userRcFile
); //TODO: detect failure
246 rc
= osl::File::remove(userRcFile
);
248 rc
!= osl::FileBase::E_None
&& rc
!= osl::FileBase::E_NOENT
, "desktop.app",
249 "cannot remove file " << userRcFile
<< ": " << +rc
);
250 rc
= osl::Directory::createPath(extDir
);
252 rc
!= osl::FileBase::E_None
&& rc
!= osl::FileBase::E_EXIST
, "desktop.app",
253 "cannot create path " << extDir
<< ": " << +rc
);
254 osl::File
fw(buildIdFile
);
255 rc
= fw
.open(osl_File_OpenFlag_Write
| osl_File_OpenFlag_Create
);
256 if (rc
!= osl::FileBase::E_None
) {
257 SAL_WARN( "desktop.app", "cannot open " << fw
.getURL() << " for writing: " << +rc
);
260 OString
buf(OUStringToOString(buildId
, RTL_TEXTENCODING_UTF8
));
261 // using UTF-8 avoids almost all conversion errors (and buildid
262 // containing single surrogate halves should never happen, anyway); the
263 // content should only be a subset of ASCII, anyway
265 rc
= fw
.write(buf
.getStr(), buf
.getLength(), n
);
267 (rc
!= osl::FileBase::E_None
268 || n
!= static_cast< sal_uInt32
>(buf
.getLength())),
270 "cannot write to " << fw
.getURL() << ": " << +rc
<< ", " << n
);
273 rc
!= osl::FileBase::E_None
, "desktop.app",
274 "cannot close " << fw
.getURL() << " after writing: " << +rc
);
280 bool shouldLaunchQuickstart()
282 bool bQuickstart
= Desktop::GetCommandLineArgs().IsQuickstart();
285 const SfxPoolItem
* pItem
=nullptr;
286 SfxItemSet
aQLSet(SfxGetpApp()->GetPool(), svl::Items
<SID_ATTR_QUICKLAUNCHER
, SID_ATTR_QUICKLAUNCHER
>{});
287 SfxGetpApp()->GetOptions(aQLSet
);
288 SfxItemState eState
= aQLSet
.GetItemState(SID_ATTR_QUICKLAUNCHER
, false, &pItem
);
289 if (SfxItemState::SET
== eState
)
290 bQuickstart
= static_cast<const SfxBoolItem
*>(pItem
)->GetValue();
295 void SetRestartState() {
297 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
298 comphelper::ConfigurationChanges::create());
299 officecfg::Setup::Office::OfficeRestartInProgress::set(true, batch
);
301 } catch (css::uno::Exception
) {
302 TOOLS_WARN_EXCEPTION("desktop.app", "ignoring");
306 void DoRestartActionsIfNecessary(bool quickstart
) {
311 if (officecfg::Setup::Office::OfficeRestartInProgress::get()) {
312 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
313 comphelper::ConfigurationChanges::create());
314 officecfg::Setup::Office::OfficeRestartInProgress::set(
317 css::office::Quickstart::createStart(
318 comphelper::getProcessComponentContext(),
319 shouldLaunchQuickstart());
321 } catch (css::uno::Exception
&) {
322 TOOLS_WARN_EXCEPTION("desktop.app", "ignoring");
326 void RemoveIconCacheDirectory()
328 // See getIconCacheUrl in vcl/source/image/ImplImageTree.cxx
329 OUString sUrl
= "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
330 "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache";
331 rtl::Bootstrap::expandMacros(sUrl
);
332 utl::UCBContentHelper::Kill(sUrl
);
340 OUString
MakeStartupErrorMessage(std::u16string_view aErrorMessage
)
342 return DpResId(STR_BOOTSTRAP_ERR_CANNOT_START
) + "\n" + aErrorMessage
;
346 // shows a simple error box with the given message ... but exits from these process !
347 // Fatal errors can't be solved by the process ... nor any recovery can help.
348 // Mostly the installation was damaged and must be repaired manually .. or by calling
350 // On the other side we must make sure that no further actions will be possible within
351 // the current office process ! No pipe requests, no menu/toolbar/shortcut actions
352 // are allowed. Otherwise we will force a "crash inside a crash".
353 // That's why we have to use a special native message box here which does not use yield :-)
355 void FatalError(const OUString
& sMessage
)
357 OUString sProductKey
= ::utl::Bootstrap::getProductKey();
358 if ( sProductKey
.isEmpty())
360 osl_getExecutableFile( &sProductKey
.pData
);
362 ::sal_uInt32 nLastIndex
= sProductKey
.lastIndexOf('/');
363 if ( nLastIndex
> 0 )
364 sProductKey
= sProductKey
.copy( nLastIndex
+1 );
367 OUString sTitle
= sProductKey
+ " - Fatal Error";
368 Application::ShowNativeErrorBox (sTitle
, sMessage
);
369 std::cerr
<< sTitle
<< ": " << sMessage
<< std::endl
;
370 _exit(EXITHELPER_FATAL_ERROR
);
373 struct theCommandLineArgs
: public rtl::Static
< CommandLineArgs
, theCommandLineArgs
> {};
377 CommandLineArgs
& Desktop::GetCommandLineArgs()
379 return theCommandLineArgs::get();
382 OUString
ReplaceStringHookProc( const OUString
& rStr
)
384 const static OUString
sBuildId(utl::Bootstrap::getBuildIdData("development")),
385 sBrandName(utl::ConfigManager::getProductName()),
386 sVersion(utl::ConfigManager::getProductVersion()),
387 sAboutBoxVersion(utl::ConfigManager::getAboutBoxProductVersion()),
388 sAboutBoxVersionSuffix(utl::ConfigManager::getAboutBoxProductVersionSuffix()),
389 sExtension(utl::ConfigManager::getProductExtension());
392 if (sRet
.indexOf("%PRODUCT") != -1 || sRet
.indexOf("%ABOUTBOX") != -1)
394 sRet
= sRet
.replaceAll( "%PRODUCTNAME", sBrandName
);
395 sRet
= sRet
.replaceAll( "%PRODUCTVERSION", sVersion
);
396 sRet
= sRet
.replaceAll( "%BUILDID", sBuildId
);
397 sRet
= sRet
.replaceAll( "%ABOUTBOXPRODUCTVERSIONSUFFIX", sAboutBoxVersionSuffix
);
398 sRet
= sRet
.replaceAll( "%ABOUTBOXPRODUCTVERSION", sAboutBoxVersion
);
399 sRet
= sRet
.replaceAll( "%PRODUCTEXTENSION", sExtension
);
402 if ( sRet
.indexOf( "%OOOVENDOR" ) != -1 )
404 const static OUString sOOOVendor
= utl::ConfigManager::getVendor();
405 sRet
= sRet
.replaceAll( "%OOOVENDOR", sOOOVendor
);
412 : m_bCleanedExtensionCache(false)
413 , m_bServicesRegistered(false)
414 , m_aBootstrapError(BE_OK
)
415 , m_aBootstrapStatus(BS_OK
)
417 m_firstRunTimer
.SetTimeout(3000); // 3 sec.
418 m_firstRunTimer
.SetInvokeHandler(LINK(this, Desktop
, AsyncInitFirstRun
));
419 m_firstRunTimer
.SetDebugName( "desktop::Desktop m_firstRunTimer" );
428 SetBootstrapStatus(BS_OK
);
430 #if HAVE_FEATURE_EXTENSIONS
431 m_bCleanedExtensionCache
= cleanExtensionCache();
434 // We need to have service factory before going further, but see fdo#37195.
435 // Doing this will mmap common.rdb, making it not overwritable on windows,
436 // so this can't happen before the synchronization above. Lets rework this
437 // so that the above is called *from* CreateApplicationServiceManager or
438 // something to enforce this gotcha
441 InitApplicationServiceManager();
443 catch (css::uno::Exception
& e
)
445 SetBootstrapError( BE_UNO_SERVICEMANAGER
, e
.Message
);
448 // Check whether safe mode is enabled
449 const CommandLineArgs
& rCmdLineArgs
= GetCommandLineArgs();
450 // Check if we are restarting from safe mode - in that case we don't want to enter it again
451 if (sfx2::SafeMode::hasRestartFlag())
452 sfx2::SafeMode::removeRestartFlag();
453 else if (rCmdLineArgs
.IsSafeMode() || sfx2::SafeMode::hasFlag())
454 Application::EnableSafeMode();
456 // When we are in SafeMode we need to do changes before the configuration
457 // gets read (langselect::prepareLocale() by UNO API -> Components::Components)
458 // This may prepare SafeMode or restore from it by moving data in
459 // the UserConfiguration directory
460 comphelper::BackupFileHelper::reactOnSafeMode(Application::IsSafeModeEnabled());
462 if ( m_aBootstrapError
== BE_OK
)
466 if (!langselect::prepareLocale())
468 SetBootstrapError( BE_LANGUAGE_MISSING
, OUString() );
471 catch (css::uno::Exception
& e
)
473 SetBootstrapError( BE_OFFICECONFIG_BROKEN
, e
.Message
);
476 // test code for ProfileSafeMode to allow testing the fail
477 // of loading the office configuration initially. To use,
478 // either set to true and compile, or set a breakpoint
479 // in debugger and change the local bool
480 static bool bTryHardOfficeconfigBroken(false); // loplugin:constvars:ignore
482 if (bTryHardOfficeconfigBroken
)
484 SetBootstrapError(BE_OFFICECONFIG_BROKEN
, OUString());
488 // start ipc thread only for non-remote offices
489 RequestHandler::Status aStatus
= RequestHandler::Enable(true);
490 if ( aStatus
== RequestHandler::IPC_STATUS_PIPE_ERROR
)
493 // Ignore crack pipe errors on Android
495 // Keep using this oddly named BE_PATHINFO_MISSING value
496 // for pipe-related errors on other platforms. Of course
497 // this crack with two (if not more) levels of our own
498 // error codes hiding the actual system error code is
499 // broken, but that is done all over the code, let's leave
500 // reengineering that to another year.
501 SetBootstrapError( BE_PATHINFO_MISSING
, OUString() );
504 else if ( aStatus
== RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR
)
506 SetBootstrapError( BE_PATHINFO_MISSING
, OUString() );
508 else if ( aStatus
== RequestHandler::IPC_STATUS_2ND_OFFICE
)
510 // 2nd office startup should terminate after sending cmdlineargs through pipe
511 SetBootstrapStatus(BS_TERMINATE
);
513 else if ( !rCmdLineArgs
.GetUnknown().isEmpty()
514 || rCmdLineArgs
.IsHelp() || rCmdLineArgs
.IsVersion() )
516 // disable IPC thread in an instance that is just showing a help message
517 RequestHandler::Disable();
519 pSignalHandler
= osl_addSignalHandler(SalMainPipeExchangeSignal_impl
, nullptr);
522 void Desktop::InitFinished()
527 void Desktop::DeInit()
530 // instead of removing of the configManager just let it commit all the changes
531 utl::ConfigManager::storeConfigItems();
532 FlushConfiguration();
534 // close splashscreen if it's still open
536 Reference
< XComponent
>(
537 comphelper::getProcessComponentContext(), UNO_QUERY_THROW
)->
539 // nobody should get a destroyed service factory...
540 ::comphelper::setProcessServiceFactory( nullptr );
545 RequestHandler::Disable();
547 osl_removeSignalHandler( pSignalHandler
);
548 } catch (const RuntimeException
&) {
549 // someone threw an exception during shutdown
550 // this will leave some garbage behind...
551 TOOLS_WARN_EXCEPTION("desktop.app", "exception throwing during shutdown, will leave some garbage behind");
555 bool Desktop::QueryExit()
559 utl::ConfigManager::storeConfigItems();
561 catch ( const RuntimeException
& )
565 static constexpr OUStringLiteral SUSPEND_QUICKSTARTVETO
= u
"SuspendQuickstartVeto";
567 Reference
< XDesktop2
> xDesktop
= css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
568 Reference
< XPropertySet
> xPropertySet(xDesktop
, UNO_QUERY_THROW
);
569 xPropertySet
->setPropertyValue( SUSPEND_QUICKSTARTVETO
, Any(true) );
571 bool bExit
= xDesktop
->terminate();
575 xPropertySet
->setPropertyValue( SUSPEND_QUICKSTARTVETO
, Any(false) );
577 else if (!Application::IsEventTestingModeEnabled())
579 FlushConfiguration();
582 // it is no problem to call RequestHandler::Disable() more than once
583 // it also looks to be threadsafe
584 RequestHandler::Disable();
586 catch ( const RuntimeException
& )
597 void Desktop::Shutdown()
599 framework::getDesktop(::comphelper::getProcessComponentContext())->shutdown();
602 void Desktop::HandleBootstrapPathErrors( ::utl::Bootstrap::Status aBootstrapStatus
, std::u16string_view aDiagnosticMessage
)
604 if ( aBootstrapStatus
== ::utl::Bootstrap::DATA_OK
)
607 OUString aProductKey
;
610 osl_getExecutableFile( &aProductKey
.pData
);
611 sal_uInt32 lastIndex
= aProductKey
.lastIndexOf('/');
613 aProductKey
= aProductKey
.copy( lastIndex
+1 );
615 aTemp
= ::utl::Bootstrap::getProductKey( aProductKey
);
616 if ( !aTemp
.isEmpty() )
619 OUString
const aMessage(OUString::Concat(aDiagnosticMessage
) + "\n");
621 std::unique_ptr
<weld::MessageDialog
> xBootstrapFailedBox(Application::CreateMessageDialog(nullptr,
622 VclMessageType::Warning
, VclButtonsType::Ok
, aMessage
));
623 xBootstrapFailedBox
->set_title(aProductKey
);
624 xBootstrapFailedBox
->run();
627 // Create an error message depending on bootstrap failure code and an optional file url
628 OUString
Desktop::CreateErrorMsgString(
629 utl::Bootstrap::FailureCode nFailureCode
,
630 const OUString
& aFileURL
)
633 bool bFileInfo
= true;
635 switch ( nFailureCode
)
637 /// the shared installation directory could not be located
638 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY
:
640 aMsg
= DpResId(STR_BOOTSTRAP_ERR_PATH_INVALID
);
645 /// the bootstrap INI file could not be found or read
646 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE
:
648 aMsg
= DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING
);
652 /// the bootstrap INI is missing a required entry
653 /// the bootstrap INI contains invalid data
654 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY
:
655 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY
:
657 aMsg
= DpResId(STR_BOOTSTRAP_ERR_FILE_CORRUPT
);
661 /// the version locator INI file could not be found or read
662 case ::utl::Bootstrap::MISSING_VERSION_FILE
:
664 aMsg
= DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING
);
668 /// the version locator INI has no entry for this version
669 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY
:
671 aMsg
= DpResId(STR_BOOTSTRAP_ERR_NO_SUPPORT
);
675 /// the user installation directory does not exist
676 case ::utl::Bootstrap::MISSING_USER_DIRECTORY
:
678 aMsg
= DpResId(STR_BOOTSTRAP_ERR_DIR_MISSING
);
682 /// some bootstrap data was invalid in unexpected ways
683 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA
:
685 aMsg
= DpResId(STR_BOOTSTRAP_ERR_INTERNAL
);
690 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY
:
692 // This needs to be improved, see #i67575#:
693 aMsg
= "Invalid version file entry";
698 case ::utl::Bootstrap::NO_FAILURE
:
707 OUString
aMsgString( aMsg
);
710 osl::File::getSystemPathFromFileURL( aFileURL
, aFilePath
);
712 aMsgString
= aMsgString
.replaceFirst( "$1", aFilePath
);
716 return MakeStartupErrorMessage( aMsg
);
719 void Desktop::HandleBootstrapErrors(
720 BootstrapError aBootstrapError
, OUString
const & aErrorMessage
)
722 if ( aBootstrapError
== BE_PATHINFO_MISSING
)
726 utl::Bootstrap::Status aBootstrapStatus
;
727 utl::Bootstrap::FailureCode nFailureCode
;
729 aBootstrapStatus
= ::utl::Bootstrap::checkBootstrapStatus( aBuffer
, nFailureCode
);
730 if ( aBootstrapStatus
!= ::utl::Bootstrap::DATA_OK
)
732 switch ( nFailureCode
)
734 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY
:
735 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA
:
737 aErrorMsg
= CreateErrorMsgString( nFailureCode
, OUString() );
741 /// the bootstrap INI file could not be found or read
742 /// the bootstrap INI is missing a required entry
743 /// the bootstrap INI contains invalid data
744 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY
:
745 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY
:
746 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE
:
748 OUString aBootstrapFileURL
;
750 utl::Bootstrap::locateBootstrapFile( aBootstrapFileURL
);
751 aErrorMsg
= CreateErrorMsgString( nFailureCode
, aBootstrapFileURL
);
755 /// the version locator INI file could not be found or read
756 /// the version locator INI has no entry for this version
757 /// the version locator INI entry is not a valid directory URL
758 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY
:
759 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY
:
760 case ::utl::Bootstrap::MISSING_VERSION_FILE
:
762 OUString aVersionFileURL
;
764 utl::Bootstrap::locateVersionFile( aVersionFileURL
);
765 aErrorMsg
= CreateErrorMsgString( nFailureCode
, aVersionFileURL
);
769 /// the user installation directory does not exist
770 case ::utl::Bootstrap::MISSING_USER_DIRECTORY
:
772 OUString aUserInstallationURL
;
774 utl::Bootstrap::locateUserInstallation( aUserInstallationURL
);
775 aErrorMsg
= CreateErrorMsgString( nFailureCode
, aUserInstallationURL
);
779 case ::utl::Bootstrap::NO_FAILURE
:
786 HandleBootstrapPathErrors( aBootstrapStatus
, aErrorMsg
);
789 else if ( aBootstrapError
== BE_UNO_SERVICEMANAGER
|| aBootstrapError
== BE_UNO_SERVICE_CONFIG_MISSING
)
791 // UNO service manager is not available. VCL needs a UNO service manager to display a message box!!!
792 // Currently we are not able to display a message box with a service manager due to this limitations inside VCL.
794 // When UNO is not properly initialized, all kinds of things can fail
795 // and cause the process to crash. To give the user a hint even if
796 // generating and displaying a message box below crashes, print a
797 // hard-coded message on stderr first:
799 << "The application cannot be started.\n"
800 // STR_BOOTSTRAP_ERR_CANNOT_START
801 << (aBootstrapError
== BE_UNO_SERVICEMANAGER
802 ? "The component manager is not available.\n"
803 // STR_BOOTSTRAP_ERR_NO_SERVICE
804 : "The configuration service is not available.\n");
805 // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE
806 if ( !aErrorMessage
.isEmpty() )
808 std::cerr
<< "(\"" << aErrorMessage
<< "\")\n";
811 // First sentence. We cannot bootstrap office further!
812 OUString aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_NO_CFG_SERVICE
) + "\n";
813 if ( !aErrorMessage
.isEmpty() )
815 aDiagnosticMessage
+= "(\"" + aErrorMessage
+ "\")\n";
818 // Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to
819 // repair the installation with the setup executable besides the office executable. Now
820 // we have to ask the user to start the setup on CD/installation directory manually!!
821 aDiagnosticMessage
+= DpResId(STR_ASK_START_SETUP_MANUALLY
);
823 FatalError(MakeStartupErrorMessage(aDiagnosticMessage
));
825 else if ( aBootstrapError
== BE_OFFICECONFIG_BROKEN
)
827 // set flag at BackupFileHelper to be able to know if _exit was called and
828 // actions are executed after this. This method we are in will not return,
829 // but end up in a _exit() call
830 comphelper::BackupFileHelper::setExitWasCalled();
832 // enter safe mode, too
833 sfx2::SafeMode::putFlag();
835 OUString
msg(DpResId(STR_CONFIG_ERR_ACCESS_GENERAL
));
836 if (!aErrorMessage
.isEmpty()) {
837 msg
+= "\n(\"" + aErrorMessage
+ "\")";
839 FatalError(MakeStartupErrorMessage(msg
));
841 else if ( aBootstrapError
== BE_USERINSTALL_FAILED
)
843 OUString aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_USERINSTALL_FAILED
);
844 FatalError(MakeStartupErrorMessage(aDiagnosticMessage
));
846 else if ( aBootstrapError
== BE_LANGUAGE_MISSING
)
848 OUString aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_LANGUAGE_MISSING
);
849 FatalError(MakeStartupErrorMessage(aDiagnosticMessage
));
851 else if (( aBootstrapError
== BE_USERINSTALL_NOTENOUGHDISKSPACE
) ||
852 ( aBootstrapError
== BE_USERINSTALL_NOWRITEACCESS
))
854 OUString aUserInstallationURL
;
855 OUString aUserInstallationPath
;
856 utl::Bootstrap::locateUserInstallation( aUserInstallationURL
);
857 osl::File::getSystemPathFromFileURL( aUserInstallationURL
, aUserInstallationPath
);
859 OUString aDiagnosticMessage
;
860 if ( aBootstrapError
== BE_USERINSTALL_NOTENOUGHDISKSPACE
)
861 aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_NOTENOUGHDISKSPACE
);
863 aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_NOACCESSRIGHTS
);
864 aDiagnosticMessage
+= aUserInstallationPath
;
866 FatalError(MakeStartupErrorMessage(aDiagnosticMessage
));
874 #if HAVE_FEATURE_BREAKPAD
875 void handleCrashReport()
877 static constexpr OUStringLiteral SERVICENAME_CRASHREPORT
= u
"com.sun.star.comp.svx.CrashReportUI";
879 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
881 Reference
< css::frame::XSynchronousDispatch
> xRecoveryUI(
882 xContext
->getServiceManager()->createInstanceWithContext(SERVICENAME_CRASHREPORT
, xContext
),
883 css::uno::UNO_QUERY_THROW
);
885 Reference
< css::util::XURLTransformer
> xURLParser
=
886 css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
889 css::uno::Any aRet
= xRecoveryUI
->dispatchWithReturnValue(aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
896 void handleSafeMode()
898 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
900 Reference
< css::frame::XSynchronousDispatch
> xSafeModeUI(
901 xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.comp.svx.SafeModeUI", xContext
),
902 css::uno::UNO_QUERY_THROW
);
905 css::uno::Any aRet
= xSafeModeUI
->dispatchWithReturnValue(aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
911 /** @short check if recovery must be started or not.
913 @param bCrashed [boolean ... out!]
914 the office crashed last times.
915 But may be there are no recovery data.
916 Useful to trigger the error report tool without
917 showing the recovery UI.
919 @param bRecoveryDataExists [boolean ... out!]
920 there exists some recovery data.
922 @param bSessionDataExists [boolean ... out!]
923 there exists some session data.
924 Because the user may be logged out last time from its
927 void impl_checkRecoveryState(bool& bCrashed
,
928 bool& bRecoveryDataExists
,
929 bool& bSessionDataExists
)
931 bCrashed
= officecfg::Office::Recovery::RecoveryInfo::Crashed::get()
932 #if HAVE_FEATURE_BREAKPAD
933 || CrashReporter::crashReportInfoExists();
937 bool elements
= officecfg::Office::Recovery::RecoveryList::get()->
940 = officecfg::Office::Recovery::RecoveryInfo::SessionData::get();
941 bRecoveryDataExists
= elements
&& !session
;
942 bSessionDataExists
= elements
&& session
;
945 Reference
< css::frame::XSynchronousDispatch
> g_xRecoveryUI
;
951 RefClearGuard(Ref
& ref
) : m_Ref(ref
) {}
952 ~RefClearGuard() { m_Ref
.clear(); }
955 /* @short start the recovery wizard.
957 @param bEmergencySave
958 differs between EMERGENCY_SAVE and RECOVERY
960 bool impl_callRecoveryUI(bool bEmergencySave
,
961 bool bExistsRecoveryData
)
963 constexpr OUStringLiteral COMMAND_EMERGENCYSAVE
= u
"vnd.sun.star.autorecovery:/doEmergencySave";
964 constexpr OUStringLiteral COMMAND_RECOVERY
= u
"vnd.sun.star.autorecovery:/doAutoRecovery";
966 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
969 xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.comp.svx.RecoveryUI", xContext
),
970 css::uno::UNO_QUERY_THROW
);
971 RefClearGuard
<Reference
< css::frame::XSynchronousDispatch
>> refClearGuard(g_xRecoveryUI
);
973 Reference
< css::util::XURLTransformer
> xURLParser
=
974 css::util::URLTransformer::create(xContext
);
978 aURL
.Complete
= COMMAND_EMERGENCYSAVE
;
979 else if (bExistsRecoveryData
)
980 aURL
.Complete
= COMMAND_RECOVERY
;
984 xURLParser
->parseStrict(aURL
);
986 css::uno::Any aRet
= g_xRecoveryUI
->dispatchWithReturnValue(aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
992 bool impl_bringToFrontRecoveryUI()
994 Reference
< css::frame::XSynchronousDispatch
> xRecoveryUI(g_xRecoveryUI
);
995 if (!xRecoveryUI
.is())
999 aURL
.Complete
= "vnd.sun.star.autorecovery:/doBringToFront";
1000 Reference
< css::util::XURLTransformer
> xURLParser
=
1001 css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
1002 xURLParser
->parseStrict(aURL
);
1004 css::uno::Any aRet
= xRecoveryUI
->dispatchWithReturnValue(aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
1014 void restartOnMac(bool passArguments
) {
1016 RequestHandler::Disable();
1017 #if HAVE_FEATURE_MACOSX_SANDBOX
1018 (void) passArguments
; // avoid warnings
1019 OUString aMessage
= DpResId(STR_LO_MUST_BE_RESTARTED
);
1021 std::unique_ptr
<weld::MessageDialog
> xRestartBox(Application::CreateMessageDialog(nullptr,
1022 VclMessageType::Warning
, VclButtonsType::Ok
, aMessage
));
1026 OSL_VERIFY(osl_getExecutableFile(&execUrl
.pData
) == osl_Process_E_None
);
1029 if ((osl::FileBase::getSystemPathFromFileURL(execUrl
, execPath
)
1030 != osl::FileBase::E_None
) ||
1031 !execPath
.convertToString(
1032 &execPath8
, osl_getThreadTextEncoding(),
1033 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
1034 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
1038 std::vector
< OString
> args
;
1039 args
.push_back(execPath8
);
1041 if (passArguments
) {
1042 sal_uInt32 n
= osl_getCommandArgCount();
1043 for (sal_uInt32 i
= 0; i
< n
; ++i
) {
1045 osl_getCommandArg(i
, &arg
.pData
);
1046 if (arg
.match("--accept=")) {
1050 if (!arg
.convertToString(
1051 &arg8
, osl_getThreadTextEncoding(),
1052 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
1053 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
1057 args
.push_back(arg8
);
1060 std::vector
< char const * > argPtrs
;
1061 for (auto const& elem
: args
)
1063 argPtrs
.push_back(elem
.getStr());
1065 argPtrs
.push_back(nullptr);
1066 execv(execPath8
.getStr(), const_cast< char ** >(argPtrs
.data()));
1067 if (errno
== ENOTSUP
) { // happens when multithreaded on macOS < 10.6
1070 execv(execPath8
.getStr(), const_cast< char ** >(argPtrs
.data()));
1071 } else if (pid
> 0) {
1072 // Two simultaneously running soffice processes lead to two dock
1073 // icons, so avoid waiting here unless it must be assumed that the
1074 // process invoking soffice itself wants to wait for soffice to
1080 if (waitpid(pid
, &stat
, 0) == pid
&& WIFEXITED(stat
)) {
1081 _exit(WEXITSTATUS(stat
));
1088 (void) passArguments
; // avoid warnings
1092 #if HAVE_FEATURE_UPDATE_MAR
1093 bool isTimeForUpdateCheck()
1095 sal_uInt64 nLastUpdate
= officecfg::Office::Update::Update::LastUpdateTime::get();
1096 sal_uInt64 nNow
= tools::Time::GetSystemTicks();
1098 sal_uInt64 n7DayInMS
= 1000 * 60 * 60 * 12 * 1; // 12 hours in ms
1099 if (nNow
- n7DayInMS
>= nLastUpdate
)
1108 void Desktop::Exception(ExceptionCategory nCategory
)
1110 // protect against recursive calls
1111 static bool bInException
= false;
1113 #if HAVE_FEATURE_BREAKPAD
1114 CrashReporter::removeExceptionHandler(); // disallow re-entry
1117 SystemWindowFlags nOldMode
= Application::GetSystemWindowMode();
1118 Application::SetSystemWindowMode( nOldMode
& ~SystemWindowFlags::NOAUTOMODE
);
1121 Application::Abort( OUString() );
1124 bInException
= true;
1125 const CommandLineArgs
& rArgs
= GetCommandLineArgs();
1127 // save all modified documents ... if it's allowed doing so.
1128 bool bRestart
= false;
1129 bool bAllowRecoveryAndSessionManagement
= (
1130 ( !rArgs
.IsNoRestore() ) && // some use cases of office must work without recovery
1131 ( !rArgs
.IsHeadless() ) &&
1132 ( nCategory
!= ExceptionCategory::UserInterface
) && // recovery can't work without UI ... but UI layer seems to be the reason for this crash
1133 ( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicate a corrupted installation...)
1135 if ( bAllowRecoveryAndSessionManagement
)
1137 // Save all open documents so they will be reopened
1138 // the next time the application is started
1139 // returns true if at least one document could be saved...
1140 bRestart
= impl_callRecoveryUI(
1141 true , // force emergency save
1145 FlushConfiguration();
1147 m_xLockfile
.reset();
1151 RequestHandler::Disable();
1152 if( pSignalHandler
)
1153 osl_removeSignalHandler( pSignalHandler
);
1155 restartOnMac(false);
1156 if ( m_rSplashScreen
.is() )
1157 m_rSplashScreen
->reset();
1159 _exit( EXITHELPER_CRASH_WITH_RESTART
);
1163 Application::Abort( OUString() );
1166 OSL_ASSERT(false); // unreachable
1169 void Desktop::AppEvent( const ApplicationEvent
& rAppEvent
)
1171 HandleAppEvent( rAppEvent
);
1176 class JVMloadThread
: public salhelper::Thread
{
1178 JVMloadThread() : salhelper::Thread("Preload JVM thread")
1183 virtual void execute() override final
1185 Reference
< XMultiServiceFactory
> xSMgr
= comphelper::getProcessServiceFactory();
1187 Reference
< css::loader::XImplementationLoader
> xJavaComponentLoader(
1188 xSMgr
->createInstance("com.sun.star.comp.stoc.JavaComponentLoader"),
1189 css::uno::UNO_QUERY_THROW
);
1191 if (xJavaComponentLoader
.is())
1193 const css::uno::Reference
< ::com::sun::star::registry::XRegistryKey
> xRegistryKey
;
1196 xJavaComponentLoader
->activate("", "", "", xRegistryKey
);
1200 SAL_WARN("desktop.app", "Cannot activate factory during JVM preloading");
1206 struct ExecuteGlobals
1208 Reference
< css::document::XDocumentEventListener
> xGlobalBroadcaster
;
1209 bool bRestartRequested
;
1210 bool bUseSystemFileDialog
;
1211 std::unique_ptr
<SvtLanguageOptions
> pLanguageOptions
;
1212 std::unique_ptr
<SvtPathOptions
> pPathOptions
;
1213 rtl::Reference
< JVMloadThread
> xJVMloadThread
;
1216 : bRestartRequested( false )
1217 , bUseSystemFileDialog( true )
1223 static ExecuteGlobals
* pExecGlobals
= nullptr;
1227 pExecGlobals
= new ExecuteGlobals();
1229 // Remember current context object
1230 css::uno::ContextLayer
layer( css::uno::getCurrentContext() );
1232 if ( m_aBootstrapError
!= BE_OK
)
1234 HandleBootstrapErrors( m_aBootstrapError
, m_aBootstrapErrorMessage
);
1235 return EXIT_FAILURE
;
1238 BootstrapStatus eStatus
= GetBootstrapStatus();
1239 if (eStatus
== BS_TERMINATE
) {
1240 return EXIT_SUCCESS
;
1243 // Detect desktop environment - need to do this as early as possible
1244 css::uno::setCurrentContext( new DesktopContext( css::uno::getCurrentContext() ) );
1246 if (officecfg::Office::Common::Misc::PreloadJVM::get() && pExecGlobals
)
1248 SAL_INFO("desktop.app", "Preload JVM");
1251 pExecGlobals
->xJVMloadThread
= new JVMloadThread();
1252 pExecGlobals
->xJVMloadThread
->launch();
1255 CommandLineArgs
& rCmdLineArgs
= GetCommandLineArgs();
1257 Translate::SetReadStringHook(ReplaceStringHookProc
);
1262 SetSplashScreenProgress(10);
1264 userinstall::Status inst_fin
= userinstall::finalize();
1265 if (inst_fin
!= userinstall::EXISTED
&& inst_fin
!= userinstall::CREATED
)
1267 SAL_WARN( "desktop.app", "userinstall failed");
1268 if ( inst_fin
== userinstall::ERROR_NO_SPACE
)
1269 HandleBootstrapErrors(
1270 BE_USERINSTALL_NOTENOUGHDISKSPACE
, OUString() );
1271 else if ( inst_fin
== userinstall::ERROR_CANT_WRITE
)
1272 HandleBootstrapErrors( BE_USERINSTALL_NOWRITEACCESS
, OUString() );
1274 HandleBootstrapErrors( BE_USERINSTALL_FAILED
, OUString() );
1275 return EXIT_FAILURE
;
1277 // refresh path information
1278 utl::Bootstrap::reloadData();
1279 SetSplashScreenProgress(20);
1281 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
1283 Reference
< XRestartManager
> xRestartManager( OfficeRestartManager::get(xContext
) );
1285 Reference
< XDesktop2
> xDesktop
;
1287 RegisterServices(xContext
);
1289 SetSplashScreenProgress(25);
1291 #if HAVE_FEATURE_DESKTOP
1292 // check user installation directory for lockfile so we can be sure
1293 // there is no other instance using our data files from a remote host
1295 bool bMustLockProfile
= ( getenv( "SAL_NOLOCK_PROFILE" ) == nullptr );
1296 if ( bMustLockProfile
)
1298 m_xLockfile
.reset(new Lockfile
);
1300 if ( !rCmdLineArgs
.IsHeadless() && !rCmdLineArgs
.IsInvisible() &&
1301 !rCmdLineArgs
.IsNoLockcheck() && !m_xLockfile
->check( Lockfile_execWarning
))
1303 // Lockfile exists, and user clicked 'no'
1304 return EXIT_FAILURE
;
1308 // check if accessibility is enabled but not working and allow to quit
1309 if( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() )
1311 if( !InitAccessBridge() )
1312 return EXIT_FAILURE
;
1316 // terminate if requested...
1317 if( rCmdLineArgs
.IsTerminateAfterInit() )
1318 return EXIT_SUCCESS
;
1320 // Read the common configuration items for optimization purpose
1321 if ( !InitializeConfiguration() )
1322 return EXIT_FAILURE
;
1324 #if HAVE_FEATURE_UPDATE_MAR
1325 const char* pUpdaterTestEnable
= std::getenv("LIBO_UPDATER_TEST_ENABLE");
1326 if (pUpdaterTestEnable
|| officecfg::Office::Update::Update::Enabled::get())
1328 // check if we just updated
1329 const char* pUpdaterRunning
= std::getenv("LIBO_UPDATER_TEST_RUNNING");
1330 bool bUpdateRunning
= officecfg::Office::Update::Update::UpdateRunning::get() || pUpdaterRunning
;
1333 OUString aSeeAlso
= officecfg::Office::Update::Update::SeeAlso::get();
1334 OUString aOldBuildID
= officecfg::Office::Update::Update::OldBuildID::get();
1336 OUString aBuildID
= Updater::getBuildID();
1337 if (aOldBuildID
== aBuildID
)
1339 Updater::log("Old and new Build ID are the same. No Updating took place.");
1343 if (!aSeeAlso
.isEmpty())
1345 SAL_INFO("desktop.updater", "See also: " << aSeeAlso
);
1346 Reference
< css::system::XSystemShellExecute
> xSystemShell(
1347 SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
1349 xSystemShell
->execute( aSeeAlso
, OUString(), SystemShellExecuteFlags::URIS_ONLY
);
1353 // reset all the configuration values,
1354 // all values need to be read before this code
1355 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
1356 comphelper::ConfigurationChanges::create());
1357 officecfg::Office::Update::Update::UpdateRunning::set(false, batch
);
1358 officecfg::Office::Update::Update::SeeAlso::set(OUString(), batch
);
1359 officecfg::Office::Update::Update::OldBuildID::set(OUString(), batch
);
1362 Updater::removeUpdateFiles();
1365 osl::DirectoryItem aUpdateFile
;
1366 osl::DirectoryItem::get(Updater::getUpdateFileURL(), aUpdateFile
);
1368 const char* pUpdaterTestUpdate
= std::getenv("LIBO_UPDATER_TEST_UPDATE");
1369 const char* pForcedUpdateCheck
= std::getenv("LIBO_UPDATER_TEST_UPDATE_CHECK");
1370 if (pUpdaterTestUpdate
|| aUpdateFile
.is())
1372 OUString
aBuildID("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":buildid}");
1373 rtl::Bootstrap::expandMacros(aBuildID
);
1374 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
1375 comphelper::ConfigurationChanges::create());
1376 officecfg::Office::Update::Update::OldBuildID::set(aBuildID
, batch
);
1377 officecfg::Office::Update::Update::UpdateRunning::set(true, batch
);
1380 // make sure the change is written to the configuration before we start the update
1381 css::uno::Reference
<css::util::XFlushable
> xFlushable(css::configuration::theDefaultProvider::get(xContext
), UNO_QUERY
);
1382 xFlushable
->flush();
1383 // avoid the old oosplash staying around
1384 CloseSplashScreen();
1385 bool bSuccess
= update();
1387 return EXIT_SUCCESS
;
1389 else if (isTimeForUpdateCheck() || pForcedUpdateCheck
)
1391 sal_uInt64 nNow
= tools::Time::GetSystemTicks();
1392 Updater::log("Update Check Time: " + OUString::number(nNow
));
1393 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
1394 comphelper::ConfigurationChanges::create());
1395 officecfg::Office::Update::Update::LastUpdateTime::set(nNow
, batch
);
1397 m_aUpdateThread
= std::thread(update_checker
);
1402 SetSplashScreenProgress(30);
1404 // create title string
1405 OUString
aTitle(ReplaceStringHookProc(RID_APPTITLE
));
1407 //include buildid in non product builds
1408 aTitle
+= " [" + utl::Bootstrap::getBuildIdData("development") + "]";
1411 SetDisplayName( aTitle
);
1412 SetSplashScreenProgress(35);
1413 pExecGlobals
->pPathOptions
.reset( new SvtPathOptions
);
1414 SetSplashScreenProgress(40);
1416 xDesktop
= css::frame::Desktop::create( xContext
);
1418 // create service for loading SFX (still needed in startup)
1419 pExecGlobals
->xGlobalBroadcaster
= Reference
< css::document::XDocumentEventListener
>
1420 ( css::frame::theGlobalEventBroadcaster::get(xContext
), UNO_SET_THROW
);
1422 /* ensure existence of a default window that messages can be dispatched to
1423 This is for the benefit of testtool which uses PostUserEvent extensively
1424 and else can deadlock while creating this window from another thread while
1425 the main thread is not yet in the event loop.
1427 Application::GetDefaultDevice();
1429 #if HAVE_FEATURE_EXTENSIONS
1430 // Check if bundled or shared extensions were added /removed
1431 // and process those extensions (has to be done before checking
1432 // the extension dependencies!
1433 SynchronizeExtensionRepositories(m_bCleanedExtensionCache
, this);
1434 bool bAbort
= CheckExtensionDependencies();
1436 return EXIT_FAILURE
;
1438 if (inst_fin
== userinstall::CREATED
)
1440 Migration::migrateSettingsIfNecessary();
1444 // keep a language options instance...
1445 pExecGlobals
->pLanguageOptions
.reset( new SvtLanguageOptions(true));
1447 css::document::DocumentEvent aEvent
;
1448 aEvent
.EventName
= "OnStartApp";
1449 pExecGlobals
->xGlobalBroadcaster
->documentEventOccured(aEvent
);
1451 SetSplashScreenProgress(50);
1453 // Backing Component
1454 bool bCrashed
= false;
1455 bool bExistsRecoveryData
= false;
1456 bool bExistsSessionData
= false;
1458 impl_checkRecoveryState(bCrashed
, bExistsRecoveryData
, bExistsSessionData
);
1460 OUString pidfileName
= rCmdLineArgs
.GetPidfileName();
1461 if ( !pidfileName
.isEmpty() )
1463 OUString pidfileURL
;
1465 if ( osl_getFileURLFromSystemPath(pidfileName
.pData
, &pidfileURL
.pData
) == osl_File_E_None
)
1467 osl::File
pidfile( pidfileURL
);
1468 osl::FileBase::RC rc
;
1470 osl::File::remove( pidfileURL
);
1471 if ( (rc
= pidfile
.open( osl_File_OpenFlag_Write
| osl_File_OpenFlag_Create
) ) == osl::File::E_None
)
1473 OString
pid( OString::number( GETPID() ) );
1474 sal_uInt64 written
= 0;
1475 if ( pidfile
.write(pid
.getStr(), pid
.getLength(), written
) != osl::File::E_None
)
1477 SAL_WARN("desktop.app", "cannot write pidfile " << pidfile
.getURL());
1483 SAL_WARN("desktop.app", "cannot open pidfile " << pidfile
.getURL() << rc
);
1488 SAL_WARN("desktop.app", "cannot get pidfile URL from path" << pidfileName
);
1492 if ( rCmdLineArgs
.IsHeadless() || rCmdLineArgs
.IsEventTesting() )
1494 // Ensure that we use not the system file dialogs as
1495 // headless mode relies on Application::EnableHeadlessMode()
1496 // which does only work for VCL dialogs!!
1497 pExecGlobals
->bUseSystemFileDialog
= officecfg::Office::Common::Misc::UseSystemFileDialog::get();
1498 std::shared_ptr
< comphelper::ConfigurationChanges
> xChanges(
1499 comphelper::ConfigurationChanges::create());
1500 officecfg::Office::Common::Misc::UseSystemFileDialog::set( false, xChanges
);
1504 pExecGlobals
->bRestartRequested
= xRestartManager
->isRestartRequested(true);
1505 if ( !pExecGlobals
->bRestartRequested
)
1507 if ((!rCmdLineArgs
.WantsToLoadDocument() && !rCmdLineArgs
.IsInvisible() && !rCmdLineArgs
.IsHeadless() && !rCmdLineArgs
.IsQuickstart()) &&
1508 (SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE
)) &&
1509 (!bExistsRecoveryData
) &&
1510 (!bExistsSessionData
) &&
1511 (!Application::AnyInput( VclInputFlags::APPEVENT
) ))
1513 ShowBackingComponent(this);
1517 SetSplashScreenProgress(55);
1519 SvtFontSubstConfig().Apply();
1521 SvtTabAppearanceCfg aAppearanceCfg
;
1522 SvtTabAppearanceCfg::SetInitialized();
1523 aAppearanceCfg
.SetApplicationDefaults( this );
1524 SvtAccessibilityOptions aOptions
;
1525 aOptions
.SetVCLSettings();
1526 SetSplashScreenProgress(60);
1528 if ( !pExecGlobals
->bRestartRequested
)
1530 Application::SetFilterHdl( LINK( this, Desktop
, ImplInitFilterHdl
) );
1532 // Preload function depends on an initialized sfx application!
1533 SetSplashScreenProgress(75);
1535 // use system window dialogs
1536 Application::SetSystemWindowMode( SystemWindowFlags::DIALOG
);
1538 SetSplashScreenProgress(80);
1540 if ( !rCmdLineArgs
.IsInvisible() &&
1541 !rCmdLineArgs
.IsNoQuickstart() )
1542 InitializeQuickstartMode( xContext
);
1544 if ( xDesktop
.is() )
1545 xDesktop
->addTerminateListener( new RequestHandlerController
);
1546 SetSplashScreenProgress(100);
1548 // FIXME: move this somewhere sensible.
1549 #if HAVE_FEATURE_OPENCL
1550 CheckOpenCLCompute(xDesktop
);
1553 // Reap the process started by fire_glxtest_process().
1554 reap_glxtest_process();
1556 // Release solar mutex just before we wait for our client to connect
1558 SolarMutexReleaser aReleaser
;
1560 // Post user event to startup first application component window
1561 // We have to send this OpenClients message short before execute() to
1562 // minimize the risk that this message overtakes type detection construction!!
1563 Application::PostUserEvent( LINK( this, Desktop
, OpenClients_Impl
) );
1565 // Post event to enable acceptors
1566 Application::PostUserEvent( LINK( this, Desktop
, EnableAcceptors_Impl
) );
1568 // Acquire solar mutex just before we enter our message loop
1571 // call Application::Execute to process messages in vcl message loop
1572 #if HAVE_FEATURE_JAVA
1573 // The JavaContext contains an interaction handler which is used when
1574 // the creation of a Java Virtual Machine fails
1575 css::uno::ContextLayer
layer2(
1576 new svt::JavaContext( css::uno::getCurrentContext() ) );
1578 // check whether the shutdown is caused by restart just before entering the Execute
1579 pExecGlobals
->bRestartRequested
= pExecGlobals
->bRestartRequested
||
1580 xRestartManager
->isRestartRequested(true);
1582 if ( !pExecGlobals
->bRestartRequested
)
1584 // if this run of the office is triggered by restart, some additional actions should be done
1585 DoRestartActionsIfNecessary( !rCmdLineArgs
.IsInvisible() && !rCmdLineArgs
.IsNoQuickstart() );
1593 xDesktop
->terminate();
1595 // CAUTION: you do not necessarily get here e.g. on the Mac.
1596 // please put all deinitialization code into doShutdown
1597 return doShutdown();
1600 int Desktop::doShutdown()
1602 if( ! pExecGlobals
)
1603 return EXIT_SUCCESS
;
1605 if (m_aUpdateThread
.joinable())
1606 m_aUpdateThread
.join();
1608 if (pExecGlobals
->xJVMloadThread
.is())
1610 pExecGlobals
->xJVMloadThread
->join();
1611 pExecGlobals
->xJVMloadThread
.clear();
1614 pExecGlobals
->bRestartRequested
= pExecGlobals
->bRestartRequested
||
1615 OfficeRestartManager::get(comphelper::getProcessComponentContext())->
1616 isRestartRequested(true);
1617 if ( pExecGlobals
->bRestartRequested
)
1620 // Restore old value
1621 const CommandLineArgs
& rCmdLineArgs
= GetCommandLineArgs();
1622 if ( rCmdLineArgs
.IsHeadless() || rCmdLineArgs
.IsEventTesting() )
1624 std::shared_ptr
< comphelper::ConfigurationChanges
> xChanges(
1625 comphelper::ConfigurationChanges::create());
1626 officecfg::Office::Common::Misc::UseSystemFileDialog::set( pExecGlobals
->bUseSystemFileDialog
, xChanges
);
1630 OUString pidfileName
= rCmdLineArgs
.GetPidfileName();
1631 if ( !pidfileName
.isEmpty() )
1633 OUString pidfileURL
;
1635 if ( osl_getFileURLFromSystemPath(pidfileName
.pData
, &pidfileURL
.pData
) == osl_File_E_None
)
1637 if ( osl::File::remove( pidfileURL
) != osl::FileBase::E_None
)
1639 SAL_WARN("desktop.app", "shutdown: cannot remove pidfile " << pidfileURL
);
1644 SAL_WARN("desktop.app", "shutdown: cannot get pidfile URL from path" << pidfileName
);
1648 // remove temp directory
1649 RemoveTemporaryDirectory();
1650 flatpak::removeTemporaryHtmlDirectory();
1652 // flush evtl. configuration changes so that all config files in user
1654 FlushConfiguration();
1656 if (pExecGlobals
->bRestartRequested
)
1659 RemoveIconCacheDirectory();
1661 // a restart is already requested, usually due to a configuration change
1662 // that needs a restart to get active. If this is the case, do not try
1663 // to use SecureUserConfig to safe this still untested new configuration
1667 // Test if SecureUserConfig is active. If yes and we are at this point, regular shutdown
1668 // is in progress and the currently used configuration was working. Try to secure this
1669 // working configuration for later eventually necessary restores
1670 comphelper::BackupFileHelper aBackupFileHelper
;
1672 aBackupFileHelper
.tryPush();
1673 aBackupFileHelper
.tryPushExtensionInfo();
1676 // The acceptors in the AcceptorMap must be released (in DeregisterServices)
1677 // with the solar mutex unlocked, to avoid deadlock:
1679 SolarMutexReleaser aReleaser
;
1680 DeregisterServices();
1681 #if HAVE_FEATURE_SCRIPTING
1682 StarBASIC::DetachAllDocBasicItems();
1686 // be sure that path/language options gets destroyed before
1687 // UCB is deinitialized
1688 pExecGlobals
->pLanguageOptions
.reset();
1689 pExecGlobals
->pPathOptions
.reset();
1691 comphelper::ThreadPool::getSharedOptimalPool().shutdown();
1693 bool bRR
= pExecGlobals
->bRestartRequested
;
1694 delete pExecGlobals
;
1695 pExecGlobals
= nullptr;
1700 if ( m_rSplashScreen
.is() )
1701 m_rSplashScreen
->reset();
1703 return EXITHELPER_NORMAL_RESTART
;
1705 return EXIT_SUCCESS
;
1708 IMPL_STATIC_LINK( Desktop
, ImplInitFilterHdl
, ::ConvertData
&, rData
, bool )
1710 return GraphicFilter::GetGraphicFilter().GetFilterCallback().Call( rData
);
1713 bool Desktop::InitializeConfiguration()
1717 css::configuration::theDefaultProvider::get(
1718 comphelper::getProcessComponentContext() );
1721 catch( css::lang::ServiceNotRegisteredException
& e
)
1723 HandleBootstrapErrors(
1724 Desktop::BE_UNO_SERVICE_CONFIG_MISSING
, e
.Message
);
1726 catch( const css::configuration::MissingBootstrapFileException
& e
)
1728 OUString
aMsg( CreateErrorMsgString( utl::Bootstrap::MISSING_BOOTSTRAP_FILE
,
1729 e
.BootstrapFileURL
));
1730 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_USER_INSTALL
, aMsg
);
1732 catch( const css::configuration::InvalidBootstrapFileException
& e
)
1734 OUString
aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY
,
1735 e
.BootstrapFileURL
));
1736 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL
, aMsg
);
1738 catch( const css::configuration::InstallationIncompleteException
& )
1740 OUString aVersionFileURL
;
1742 utl::Bootstrap::PathStatus aPathStatus
= utl::Bootstrap::locateVersionFile( aVersionFileURL
);
1743 if ( aPathStatus
== utl::Bootstrap::PATH_EXISTS
)
1744 aMsg
= CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE_ENTRY
, aVersionFileURL
);
1746 aMsg
= CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE
, aVersionFileURL
);
1748 HandleBootstrapPathErrors( ::utl::Bootstrap::MISSING_USER_INSTALL
, aMsg
);
1750 catch ( const css::configuration::backend::BackendAccessException
& exception
)
1752 // [cm122549] It is assumed in this case that the message
1753 // coming from InitConfiguration (in fact CreateApplicationConf...)
1754 // is suitable for display directly.
1755 FatalError( MakeStartupErrorMessage( exception
.Message
) );
1757 catch ( const css::configuration::backend::BackendSetupException
& exception
)
1759 // [cm122549] It is assumed in this case that the message
1760 // coming from InitConfiguration (in fact CreateApplicationConf...)
1761 // is suitable for display directly.
1762 FatalError( MakeStartupErrorMessage( exception
.Message
) );
1764 catch ( const css::configuration::CannotLoadConfigurationException
& )
1766 OUString
aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA
,
1768 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL
, aMsg
);
1770 catch( const css::uno::Exception
& )
1772 OUString
aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA
,
1774 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL
, aMsg
);
1779 void Desktop::FlushConfiguration()
1781 css::uno::Reference
< css::util::XFlushable
>(
1782 css::configuration::theDefaultProvider::get(
1783 comphelper::getProcessComponentContext()),
1784 css::uno::UNO_QUERY_THROW
)->flush();
1787 bool Desktop::InitializeQuickstartMode( const Reference
< XComponentContext
>& rxContext
)
1791 // the shutdown icon sits in the systray and allows the user to keep
1792 // the office instance running for quicker restart
1793 // this will only be activated if --quickstart was specified on cmdline
1795 bool bQuickstart
= shouldLaunchQuickstart();
1797 // Try to instantiate quickstart service. This service is not mandatory, so
1798 // do nothing if service is not available
1800 // #i105753# the following if was invented for performance
1801 // unfortunately this broke the Mac behavior which is to always run
1802 // in quickstart mode since Mac applications do not usually quit
1803 // when the last document closes.
1804 // Note that this claim that on macOS we "always run in quickstart mode"
1805 // has nothing to do with (quick) *starting* (i.e. starting automatically
1806 // when the user logs in), though, but with not quitting when no documents
1812 css::office::Quickstart::createStart(rxContext
, bQuickstart
);
1816 catch( const css::uno::Exception
& )
1822 void Desktop::OverrideSystemSettings( AllSettings
& rSettings
)
1824 if ( !SvtTabAppearanceCfg::IsInitialized () )
1827 StyleSettings hStyleSettings
= rSettings
.GetStyleSettings();
1828 MouseSettings hMouseSettings
= rSettings
.GetMouseSettings();
1830 DragFullOptions nDragFullOptions
= hStyleSettings
.GetDragFullOptions();
1832 SvtTabAppearanceCfg aAppearanceCfg
;
1833 DragMode nDragMode
= aAppearanceCfg
.GetDragMode();
1834 switch ( nDragMode
)
1836 case DragMode::FullWindow
:
1837 nDragFullOptions
|= DragFullOptions::All
;
1839 case DragMode::Frame
:
1840 nDragFullOptions
&= ~DragFullOptions::All
;
1842 case DragMode::SystemDep
:
1847 MouseFollowFlags nFollow
= hMouseSettings
.GetFollow();
1848 hMouseSettings
.SetFollow( aAppearanceCfg
.IsMenuMouseFollow() ? (nFollow
|MouseFollowFlags::Menu
) : (nFollow
&~MouseFollowFlags::Menu
));
1849 rSettings
.SetMouseSettings(hMouseSettings
);
1851 SvtMenuOptions aMenuOpt
;
1852 hStyleSettings
.SetUseImagesInMenus(aMenuOpt
.GetMenuIconsState());
1853 hStyleSettings
.SetContextMenuShortcuts(aMenuOpt
.GetContextMenuShortcuts());
1854 hStyleSettings
.SetDragFullOptions( nDragFullOptions
);
1855 rSettings
.SetStyleSettings ( hStyleSettings
);
1860 class ExitTimer
: public Timer
1868 virtual void Invoke() override
1876 IMPL_LINK_NOARG(Desktop
, OpenClients_Impl
, void*, void)
1879 // Enable IPC thread before OpenClients
1881 // This is because it is possible for another client to connect during the OpenClients() call.
1882 // This can happen on Windows when document is printed (not opened) and another client wants to print (when printing multiple documents).
1883 // 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
1887 // Multiple clients may request simultaneous connections.
1888 // When this server closes down it attempts to recreate the pipe (in RequestHandler::Disable()).
1889 // It's possible that the client has a pending connection request.
1890 // When the IPC thread is not running, this connection locks (because maPipe.accept()) is never called
1891 RequestHandler::SetReady(true);
1894 CloseSplashScreen();
1897 bool bDontShowDialogs
1898 = Application::IsHeadlessModeEnabled(); // uitest.uicheck fails when the dialog is open
1899 for (sal_uInt16 i
= 0; !bDontShowDialogs
&& i
< Application::GetCommandLineParamCount(); i
++)
1901 if (Application::GetCommandLineParam(i
) == "--nologo")
1902 bDontShowDialogs
= true;
1904 if (!bDontShowDialogs
)
1905 vcl::fileregistration::CheckFileExtRegistration(SfxGetpApp()->GetTopWindow());
1906 // Registers a COM class factory of the service manager with the windows operating system.
1907 Reference
< XMultiServiceFactory
> xSMgr
= comphelper::getProcessServiceFactory();
1908 xSMgr
->createInstance("com.sun.star.bridge.OleApplicationRegistration");
1909 xSMgr
->createInstance("com.sun.star.comp.ole.EmbedServer");
1911 const char *pExitPostStartup
= getenv ("OOO_EXIT_POST_STARTUP");
1912 if (pExitPostStartup
&& *pExitPostStartup
)
1916 void Desktop::OpenClients()
1919 const CommandLineArgs
& rArgs
= GetCommandLineArgs();
1921 if (!rArgs
.IsQuickstart())
1923 OUString aHelpModule
;
1924 if (rArgs
.IsHelpWriter()) {
1925 aHelpModule
= "swriter";
1926 } else if (rArgs
.IsHelpCalc()) {
1927 aHelpModule
= "scalc";
1928 } else if (rArgs
.IsHelpDraw()) {
1929 aHelpModule
= "sdraw";
1930 } else if (rArgs
.IsHelpImpress()) {
1931 aHelpModule
= "simpress";
1932 } else if (rArgs
.IsHelpBase()) {
1933 aHelpModule
= "sdatabase";
1934 } else if (rArgs
.IsHelpBasic()) {
1935 aHelpModule
= "sbasic";
1936 } else if (rArgs
.IsHelpMath()) {
1937 aHelpModule
= "smath";
1939 if (!aHelpModule
.isEmpty()) {
1940 OUString aHelpURL
= "vnd.sun.star.help://"
1942 + "/start?Language="
1943 + utl::ConfigManager::getUILocale();
1945 aHelpURL
+= "&System=UNX";
1946 #elif defined _WIN32
1947 aHelpURL
+= "&System=WIN";
1949 Application::GetHelp()->Start(aHelpURL
);
1954 // Disable AutoSave feature in case "--norestore" or a similar command line switch is set on the command line.
1955 // The reason behind: AutoSave/EmergencySave/AutoRecovery share the same data.
1956 // But the require that all documents, which are saved as backup should exists inside
1957 // memory. May be this mechanism will be inconsistent if the configuration exists...
1958 // but no document inside memory corresponds to this data.
1959 // Further it's not acceptable to recover such documents without any UI. It can
1960 // need some time, where the user won't see any results and wait for finishing the office startup...
1961 bool bAllowRecoveryAndSessionManagement
= ( !rArgs
.IsNoRestore() ) && ( !rArgs
.IsHeadless() );
1963 #if !defined ANDROID
1964 // Enter safe mode if requested
1965 if (Application::IsSafeModeEnabled()) {
1970 #if HAVE_FEATURE_BREAKPAD
1971 if (officecfg::Office::Common::Misc::CrashReport::get() && CrashReporter::crashReportInfoExists())
1972 handleCrashReport();
1975 if ( ! bAllowRecoveryAndSessionManagement
)
1979 Reference
< XDispatch
> xRecovery
= css::frame::theAutoRecovery::get( ::comphelper::getProcessComponentContext() );
1980 Reference
< css::util::XURLTransformer
> xParser
= css::util::URLTransformer::create( ::comphelper::getProcessComponentContext() );
1982 css::util::URL aCmd
;
1983 aCmd
.Complete
= "vnd.sun.star.autorecovery:/disableRecovery";
1984 xParser
->parseStrict(aCmd
);
1986 xRecovery
->dispatch(aCmd
, css::uno::Sequence
< css::beans::PropertyValue
>());
1988 catch(const css::uno::Exception
&)
1990 TOOLS_WARN_EXCEPTION( "desktop.app", "Could not disable AutoRecovery.");
1995 bool bCrashed
= false;
1996 bool bExistsRecoveryData
= false;
1997 bool bExistsSessionData
= false;
1998 bool const bDisableRecovery
1999 = getenv("OOO_DISABLE_RECOVERY") != nullptr
2000 || !officecfg::Office::Recovery::RecoveryInfo::Enabled::get();
2002 impl_checkRecoveryState(bCrashed
, bExistsRecoveryData
, bExistsSessionData
);
2004 if ( !bDisableRecovery
&&
2006 bExistsRecoveryData
|| // => crash with files => recovery
2007 bCrashed
// => crash without files => error report
2013 impl_callRecoveryUI(
2014 false , // false => force recovery instead of emergency save
2015 bExistsRecoveryData
);
2017 catch(const css::uno::Exception
&)
2019 TOOLS_WARN_EXCEPTION( "desktop.app", "Error during recovery");
2023 Reference
< XSessionManagerListener2
> xSessionListener
;
2026 // specifies whether the UI-interaction on Session shutdown is allowed
2027 bool bUIOnSessionShutdownAllowed
= officecfg::Office::Recovery::SessionShutdown::DocumentStoreUIEnabled::get();
2028 xSessionListener
= SessionListener::createWithOnQuitFlag(
2029 ::comphelper::getProcessComponentContext(), bUIOnSessionShutdownAllowed
);
2031 catch(const css::uno::Exception
&)
2033 TOOLS_WARN_EXCEPTION( "desktop.app", "Registration of session listener failed");
2036 if ( !bExistsRecoveryData
&& xSessionListener
.is() )
2038 // session management
2041 xSessionListener
->doRestore();
2043 catch(const css::uno::Exception
&)
2045 TOOLS_WARN_EXCEPTION( "desktop.app", "Error in session management");
2050 // write this information here to avoid depending on vcl in the crash reporter lib
2051 CrashReporter::addKeyValue("Language", Application::GetSettings().GetLanguageTag().getBcp47(), CrashReporter::Create
);
2053 RequestHandler::EnableRequests();
2055 ProcessDocumentsRequest
aRequest(rArgs
.getCwdUrl());
2056 aRequest
.aOpenList
= rArgs
.GetOpenList();
2057 aRequest
.aViewList
= rArgs
.GetViewList();
2058 aRequest
.aStartList
= rArgs
.GetStartList();
2059 aRequest
.aPrintList
= rArgs
.GetPrintList();
2060 aRequest
.aPrintToList
= rArgs
.GetPrintToList();
2061 aRequest
.aPrinterName
= rArgs
.GetPrinterName();
2062 aRequest
.aForceOpenList
= rArgs
.GetForceOpenList();
2063 aRequest
.aForceNewList
= rArgs
.GetForceNewList();
2064 aRequest
.aConversionList
= rArgs
.GetConversionList();
2065 aRequest
.aConversionParams
= rArgs
.GetConversionParams();
2066 aRequest
.aConversionOut
= rArgs
.GetConversionOut();
2067 aRequest
.aImageConversionType
= rArgs
.GetImageConversionType();
2068 aRequest
.aInFilter
= rArgs
.GetInFilter();
2069 aRequest
.bTextCat
= rArgs
.IsTextCat();
2070 aRequest
.bScriptCat
= rArgs
.IsScriptCat();
2072 if ( !aRequest
.aOpenList
.empty() ||
2073 !aRequest
.aViewList
.empty() ||
2074 !aRequest
.aStartList
.empty() ||
2075 !aRequest
.aPrintList
.empty() ||
2076 !aRequest
.aForceOpenList
.empty() ||
2077 !aRequest
.aForceNewList
.empty() ||
2078 ( !aRequest
.aPrintToList
.empty() && !aRequest
.aPrinterName
.isEmpty() ) ||
2079 !aRequest
.aConversionList
.empty() )
2081 if ( rArgs
.HasModuleParam() )
2083 SvtModuleOptions aOpt
;
2085 // Support command line parameters to start a module (as preselection)
2086 if ( rArgs
.IsWriter() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2087 aRequest
.aModule
= aOpt
.GetFactoryName( SvtModuleOptions::EFactory::WRITER
);
2088 else if ( rArgs
.IsCalc() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::CALC
) )
2089 aRequest
.aModule
= aOpt
.GetFactoryName( SvtModuleOptions::EFactory::CALC
);
2090 else if ( rArgs
.IsImpress() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS
) )
2091 aRequest
.aModule
= aOpt
.GetFactoryName( SvtModuleOptions::EFactory::IMPRESS
);
2092 else if ( rArgs
.IsDraw() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DRAW
) )
2093 aRequest
.aModule
= aOpt
.GetFactoryName( SvtModuleOptions::EFactory::DRAW
);
2096 // check for printing disabled
2097 if( ( !(aRequest
.aPrintList
.empty() && aRequest
.aPrintToList
.empty()) )
2098 && Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
2100 aRequest
.aPrintList
.clear();
2101 aRequest
.aPrintToList
.clear();
2102 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(nullptr,
2103 VclMessageType::Warning
, VclButtonsType::Ok
,
2104 DpResId(STR_ERR_PRINTDISABLED
)));
2109 if ( RequestHandler::ExecuteCmdLineRequests(aRequest
, false) )
2111 // Don't do anything if we have successfully called terminate at desktop:
2116 // no default document if a document was loaded by recovery or by command line or if soffice is used as server
2117 Reference
< XDesktop2
> xDesktop
= css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
2118 Reference
< XElementAccess
> xList( xDesktop
->getFrames(), UNO_QUERY_THROW
);
2119 if ( xList
->hasElements() )
2122 if ( rArgs
.IsQuickstart() || rArgs
.IsInvisible() || Application::AnyInput( VclInputFlags::APPEVENT
) )
2123 // soffice was started as tray icon ...
2129 void Desktop::OpenDefault()
2132 SvtModuleOptions aOpt
;
2134 const CommandLineArgs
& rArgs
= GetCommandLineArgs();
2135 if ( rArgs
.IsNoDefault() ) return;
2136 if ( rArgs
.HasModuleParam() )
2138 // Support new command line parameters to start a module
2139 if ( rArgs
.IsWriter() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2140 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER
);
2141 else if ( rArgs
.IsCalc() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::CALC
) )
2142 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC
);
2143 else if ( rArgs
.IsImpress() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS
) )
2144 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS
);
2145 else if ( rArgs
.IsBase() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE
) )
2146 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE
);
2147 else if ( rArgs
.IsDraw() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DRAW
) )
2148 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW
);
2149 else if ( rArgs
.IsMath() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::MATH
) )
2150 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::MATH
);
2151 else if ( rArgs
.IsGlobal() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2152 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITERGLOBAL
);
2153 else if ( rArgs
.IsWeb() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2154 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITERWEB
);
2157 if ( aName
.isEmpty() )
2159 if (aOpt
.IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE
))
2161 ShowBackingComponent(nullptr);
2165 // Old way to create a default document
2166 if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2167 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER
);
2168 else if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::CALC
) )
2169 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC
);
2170 else if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS
) )
2171 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS
);
2172 else if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE
) )
2173 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE
);
2174 else if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DRAW
) )
2175 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW
);
2180 ProcessDocumentsRequest
aRequest(rArgs
.getCwdUrl());
2181 aRequest
.aOpenList
.push_back(aName
);
2182 RequestHandler::ExecuteCmdLineRequests(aRequest
, false);
2186 OUString
GetURL_Impl(
2187 const OUString
& rName
, std::optional
< OUString
> const & cwdUrl
)
2189 // if rName is a vnd.sun.star.script URL do not attempt to parse it
2190 // as INetURLObj does not handle URLs there
2191 if (rName
.startsWith("vnd.sun.star.script"))
2196 // don't touch file urls, those should already be in internal form
2197 // they won't get better here (#112849#)
2198 if (comphelper::isFileUrl(rName
))
2203 if ( rName
.startsWith("service:"))
2208 // Add path separator to these directory and make given URL (rName) absolute by using of current working directory
2209 // Attention: "setFinalSlash()" is necessary for calling "smartRel2Abs()"!!!
2210 // Otherwise last part will be ignored and wrong result will be returned!!!
2211 // "smartRel2Abs()" interpret given URL as file not as path. So he truncate last element to get the base path ...
2212 // But if we add a separator - he doesn't do it anymore.
2215 aObj
.SetURL(*cwdUrl
);
2216 aObj
.setFinalSlash();
2219 // Use the provided parameters for smartRel2Abs to support the usage of '%' in system paths.
2220 // Otherwise this char won't get encoded and we are not able to load such files later,
2222 INetURLObject aURL
= aObj
.smartRel2Abs( rName
, bWasAbsolute
, false, INetURLObject::EncodeMechanism::WasEncoded
,
2223 RTL_TEXTENCODING_UTF8
, true );
2224 OUString aFileURL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
2226 ::osl::FileStatus
aStatus( osl_FileStatus_Mask_FileURL
);
2227 ::osl::DirectoryItem aItem
;
2228 if( ::osl::FileBase::E_None
== ::osl::DirectoryItem::get( aFileURL
, aItem
) &&
2229 ::osl::FileBase::E_None
== aItem
.getFileStatus( aStatus
) )
2230 aFileURL
= aStatus
.getFileURL();
2235 void Desktop::HandleAppEvent( const ApplicationEvent
& rAppEvent
)
2237 switch ( rAppEvent
.GetEvent() )
2239 case ApplicationEvent::Type::Accept
:
2240 // every time an accept parameter is used we create an acceptor
2241 // with the corresponding accept-string
2242 createAcceptor(rAppEvent
.GetStringData());
2244 case ApplicationEvent::Type::Appear
:
2245 if ( !GetCommandLineArgs().IsInvisible() && !impl_bringToFrontRecoveryUI() )
2247 Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2249 // find active task - the active task is always a visible task
2250 Reference
< css::frame::XDesktop2
> xDesktop
= css::frame::Desktop::create( xContext
);
2251 Reference
< css::frame::XFrame
> xTask
= xDesktop
->getActiveFrame();
2254 // get any task if there is no active one
2255 Reference
< css::container::XIndexAccess
> xList
= xDesktop
->getFrames();
2256 if ( xList
->getCount() > 0 )
2257 xList
->getByIndex(0) >>= xTask
;
2262 Reference
< css::awt::XTopWindow
> xTop( xTask
->getContainerWindow(), UNO_QUERY
);
2267 // no visible task that could be activated found
2268 Reference
< css::awt::XWindow
> xContainerWindow
;
2269 Reference
< XFrame
> xBackingFrame
= xDesktop
->findFrame( "_blank", 0);
2270 if (xBackingFrame
.is())
2271 xContainerWindow
= xBackingFrame
->getContainerWindow();
2272 if (xContainerWindow
.is())
2274 Reference
< XController
> xStartModule
= StartModule::createWithParentWindow(xContext
, xContainerWindow
);
2275 Reference
< css::awt::XWindow
> xBackingWin(xStartModule
, UNO_QUERY
);
2276 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2277 // Because the backing component set the property "IsBackingMode" of the frame
2278 // to true inside attachFrame(). But setComponent() reset this state every time ...
2279 xBackingFrame
->setComponent(xBackingWin
, xStartModule
);
2280 xStartModule
->attachFrame(xBackingFrame
);
2281 xContainerWindow
->setVisible(true);
2283 VclPtr
<vcl::Window
> pCompWindow
= VCLUnoHelper::GetWindow(xBackingFrame
->getComponentWindow());
2285 pCompWindow
->PaintImmediately();
2290 case ApplicationEvent::Type::Open
:
2292 const CommandLineArgs
& rCmdLine
= GetCommandLineArgs();
2293 if ( !rCmdLine
.IsInvisible() && !rCmdLine
.IsTerminateAfterInit() )
2295 ProcessDocumentsRequest
docsRequest(rCmdLine
.getCwdUrl());
2296 std::vector
<OUString
> const & data(rAppEvent
.GetStringsData());
2297 docsRequest
.aOpenList
.insert(
2298 docsRequest
.aOpenList
.end(), data
.begin(), data
.end());
2299 RequestHandler::ExecuteCmdLineRequests(docsRequest
, false);
2303 case ApplicationEvent::Type::OpenHelpUrl
:
2304 // start help for a specific URL
2305 Application::GetHelp()->Start(rAppEvent
.GetStringData());
2307 case ApplicationEvent::Type::Print
:
2309 const CommandLineArgs
& rCmdLine
= GetCommandLineArgs();
2310 if ( !rCmdLine
.IsInvisible() && !rCmdLine
.IsTerminateAfterInit() )
2312 ProcessDocumentsRequest
docsRequest(rCmdLine
.getCwdUrl());
2313 std::vector
<OUString
> const & data(rAppEvent
.GetStringsData());
2314 docsRequest
.aPrintList
.insert(
2315 docsRequest
.aPrintList
.end(), data
.begin(), data
.end());
2316 RequestHandler::ExecuteCmdLineRequests(docsRequest
, false);
2320 case ApplicationEvent::Type::PrivateDoShutdown
:
2322 Desktop
* pD
= dynamic_cast<Desktop
*>(GetpApp());
2323 OSL_ENSURE( pD
, "no desktop ?!?" );
2328 case ApplicationEvent::Type::QuickStart
:
2329 if ( !GetCommandLineArgs().IsInvisible() )
2331 // If the office has been started the second time its command line arguments are sent through a pipe
2332 // connection to the first office. We want to reuse the quickstart option for the first office.
2333 // NOTICE: The quickstart service must be initialized inside the "main thread", so we use the
2334 // application events to do this (they are executed inside main thread)!!!
2335 // Don't start quickstart service if the user specified "--invisible" on the command line!
2336 Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2337 css::office::Quickstart::createStart(xContext
, true/*Quickstart*/);
2340 case ApplicationEvent::Type::ShowDialog
:
2341 // This is only used on macOS, and only for About or Preferences.
2342 // Ignore all errors here. It's clicking a menu entry only ...
2343 // The user will try it again, in case nothing happens .-)
2346 Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2348 Reference
< css::frame::XDesktop2
> xDesktop
= css::frame::Desktop::create( xContext
);
2350 Reference
< css::util::XURLTransformer
> xParser
= css::util::URLTransformer::create(xContext
);
2351 css::util::URL aCommand
;
2352 if( rAppEvent
.GetStringData() == "PREFERENCES" )
2353 aCommand
.Complete
= ".uno:OptionsTreeDialog";
2354 else if( rAppEvent
.GetStringData() == "ABOUT" )
2355 aCommand
.Complete
= ".uno:About";
2356 if( !aCommand
.Complete
.isEmpty() )
2358 xParser
->parseStrict(aCommand
);
2360 css::uno::Reference
< css::frame::XDispatch
> xDispatch
= xDesktop
->queryDispatch(aCommand
, OUString(), 0);
2362 xDispatch
->dispatch(aCommand
, css::uno::Sequence
< css::beans::PropertyValue
>());
2365 catch(const css::uno::Exception
&)
2367 TOOLS_WARN_EXCEPTION("desktop.app", "exception thrown by dialog");
2370 case ApplicationEvent::Type::Unaccept
:
2371 // try to remove corresponding acceptor
2372 destroyAcceptor(rAppEvent
.GetStringData());
2375 SAL_WARN( "desktop.app", "this cannot happen");
2380 void Desktop::OpenSplashScreen()
2382 const CommandLineArgs
&rCmdLine
= GetCommandLineArgs();
2383 // Show intro only if this is normal start (e.g. no server, no quickstart, no printing )
2384 if ( !(!rCmdLine
.IsInvisible() &&
2385 !rCmdLine
.IsHeadless() &&
2386 !rCmdLine
.IsQuickstart() &&
2387 !rCmdLine
.IsMinimized() &&
2388 !rCmdLine
.IsNoLogo() &&
2389 !rCmdLine
.IsTerminateAfterInit() &&
2390 rCmdLine
.GetPrintList().empty() &&
2391 rCmdLine
.GetPrintToList().empty() &&
2392 rCmdLine
.GetConversionList().empty()) )
2395 // Determine application name from command line parameters
2397 if ( rCmdLine
.IsWriter() )
2398 aAppName
= "writer";
2399 else if ( rCmdLine
.IsCalc() )
2401 else if ( rCmdLine
.IsDraw() )
2403 else if ( rCmdLine
.IsImpress() )
2404 aAppName
= "impress";
2405 else if ( rCmdLine
.IsBase() )
2407 else if ( rCmdLine
.IsGlobal() )
2408 aAppName
= "global";
2409 else if ( rCmdLine
.IsMath() )
2411 else if ( rCmdLine
.IsWeb() )
2414 // Which splash to use
2415 OUString
aSplashService( "com.sun.star.office.SplashScreen" );
2416 if ( rCmdLine
.HasSplashPipe() )
2417 aSplashService
= "com.sun.star.office.PipeSplashScreen";
2419 Sequence
< Any
> aSeq( 2 );
2420 aSeq
[0] <<= true; // bVisible
2421 aSeq
[1] <<= aAppName
;
2422 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2423 m_rSplashScreen
.set(
2424 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(aSplashService
, aSeq
, xContext
),
2427 if(m_rSplashScreen
.is())
2428 m_rSplashScreen
->start("SplashScreen", 100);
2432 void Desktop::SetSplashScreenProgress(sal_Int32 iProgress
)
2434 if(m_rSplashScreen
.is())
2436 m_rSplashScreen
->setValue(iProgress
);
2440 void Desktop::SetSplashScreenText( const OUString
& rText
)
2442 if( m_rSplashScreen
.is() )
2444 m_rSplashScreen
->setText( rText
);
2448 void Desktop::CloseSplashScreen()
2450 if(m_rSplashScreen
.is())
2452 SolarMutexGuard ensureSolarMutex
;
2453 m_rSplashScreen
->end();
2454 m_rSplashScreen
= nullptr;
2459 IMPL_STATIC_LINK_NOARG(Desktop
, AsyncInitFirstRun
, Timer
*, void)
2461 // does initializations which are necessary for the first run of the office
2464 Reference
< XJobExecutor
> xExecutor
= theJobExecutor::get( ::comphelper::getProcessComponentContext() );
2465 xExecutor
->trigger( "onFirstRunInitialization" );
2467 catch(const css::uno::Exception
&)
2469 TOOLS_WARN_EXCEPTION( "desktop.app", "Desktop::DoFirstRunInitializations: caught an exception while trigger job executor" );
2473 void Desktop::ShowBackingComponent(Desktop
* progress
)
2475 if (GetCommandLineArgs().IsNoDefault())
2479 Reference
< XComponentContext
> xContext
= comphelper::getProcessComponentContext();
2480 Reference
< XDesktop2
> xDesktop
= css::frame::Desktop::create(xContext
);
2481 if (progress
!= nullptr)
2483 progress
->SetSplashScreenProgress(60);
2485 Reference
< XFrame
> xBackingFrame
= xDesktop
->findFrame( "_blank", 0);
2486 Reference
< css::awt::XWindow
> xContainerWindow
;
2488 if (xBackingFrame
.is())
2489 xContainerWindow
= xBackingFrame
->getContainerWindow();
2490 if (!xContainerWindow
.is())
2493 // set the WindowExtendedStyle::Document style. Normally, this is done by the TaskCreator service when a "_blank"
2494 // frame/window is created. Since we do not use the TaskCreator here, we need to mimic its behavior,
2495 // otherwise documents loaded into this frame will later on miss functionality depending on the style.
2496 VclPtr
<vcl::Window
> pContainerWindow
= VCLUnoHelper::GetWindow( xContainerWindow
);
2497 SAL_WARN_IF( !pContainerWindow
, "desktop.app", "Desktop::Main: no implementation access to the frame's container window!" );
2498 pContainerWindow
->SetExtendedStyle( pContainerWindow
->GetExtendedStyle() | WindowExtendedStyle::Document
);
2499 if (progress
!= nullptr)
2501 progress
->SetSplashScreenProgress(75);
2504 Reference
< XController
> xStartModule
= StartModule::createWithParentWindow( xContext
, xContainerWindow
);
2505 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2506 // Because the backing component set the property "IsBackingMode" of the frame
2507 // to true inside attachFrame(). But setComponent() reset this state everytimes ...
2508 xBackingFrame
->setComponent(Reference
< XWindow
>(xStartModule
, UNO_QUERY
), xStartModule
);
2509 if (progress
!= nullptr)
2511 progress
->SetSplashScreenProgress(100);
2513 xStartModule
->attachFrame(xBackingFrame
);
2514 if (progress
!= nullptr)
2516 progress
->CloseSplashScreen();
2518 xContainerWindow
->setVisible(true);
2522 void Desktop::CheckFirstRun( )
2524 if (!officecfg::Office::Common::Misc::FirstRun::get())
2527 // use VCL timer, which won't trigger during shutdown if the
2528 // application exits before timeout
2529 m_firstRunTimer
.Start();
2532 // Check if Quickstarter should be started (on Windows only)
2533 OUString sRootKey
= ReplaceStringHookProc("Software\\%OOOVENDOR\\%PRODUCTNAME\\%PRODUCTVERSION");
2534 WCHAR szValue
[8192];
2535 DWORD nValueSize
= sizeof(szValue
);
2537 if (ERROR_SUCCESS
== RegOpenKeyW(HKEY_LOCAL_MACHINE
, o3tl::toW(sRootKey
.getStr()), &hKey
))
2539 if ( ERROR_SUCCESS
== RegQueryValueExW( hKey
, L
"RunQuickstartAtFirstStart", nullptr, nullptr, reinterpret_cast<LPBYTE
>(szValue
), &nValueSize
) )
2541 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2542 css::office::Quickstart::createAutoStart(xContext
, true/*Quickstart*/, true/*bAutostart*/);
2543 RegCloseKey( hKey
);
2548 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
2549 comphelper::ConfigurationChanges::create());
2550 officecfg::Office::Common::Misc::FirstRun::set(false, batch
);
2556 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */