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>
37 #include <dp_shared.hxx>
38 #include <strings.hrc>
39 #include "cmdlineargs.hxx"
40 #include "cmdlinehelp.hxx"
41 #include "dispatchwatcher.hxx"
42 #include <lockfile.hxx>
43 #include "userinstall.hxx"
44 #include "desktopcontext.hxx"
45 #include <migration.hxx>
46 #if HAVE_FEATURE_UPDATE_MAR
47 #include "updater.hxx"
50 #include <i18nlangtag/languagetag.hxx>
51 #include <o3tl/runtimetooustring.hxx>
52 #include <svl/languageoptions.hxx>
53 #include <svtools/javacontext.hxx>
54 #include <com/sun/star/beans/XPropertySet.hpp>
55 #include <com/sun/star/frame/theAutoRecovery.hpp>
56 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
57 #include <com/sun/star/frame/SessionListener.hpp>
58 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
59 #include <com/sun/star/document/CorruptedFilterConfigurationException.hpp>
60 #include <com/sun/star/configuration/CorruptedConfigurationException.hpp>
61 #include <com/sun/star/configuration/theDefaultProvider.hpp>
62 #include <com/sun/star/util/XFlushable.hpp>
63 #include <com/sun/star/util/XModifiable.hpp>
64 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
65 #include <com/sun/star/frame/Desktop.hpp>
66 #include <com/sun/star/frame/StartModule.hpp>
67 #include <com/sun/star/view/XPrintable.hpp>
68 #include <com/sun/star/awt/XTopWindow.hpp>
69 #include <com/sun/star/util/URLTransformer.hpp>
70 #include <com/sun/star/util/XURLTransformer.hpp>
71 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
72 #include <com/sun/star/configuration/MissingBootstrapFileException.hpp>
73 #include <com/sun/star/configuration/InvalidBootstrapFileException.hpp>
74 #include <com/sun/star/configuration/InstallationIncompleteException.hpp>
75 #include <com/sun/star/configuration/backend/BackendSetupException.hpp>
76 #include <com/sun/star/configuration/backend/BackendAccessException.hpp>
77 #include <com/sun/star/task/theJobExecutor.hpp>
78 #include <com/sun/star/task/OfficeRestartManager.hpp>
79 #include <com/sun/star/task/XRestartManager.hpp>
80 #include <com/sun/star/document/XDocumentEventListener.hpp>
81 #include <com/sun/star/ui/theUIElementFactoryManager.hpp>
82 #include <com/sun/star/ui/theWindowStateConfiguration.hpp>
83 #include <com/sun/star/office/Quickstart.hpp>
84 #include <com/sun/star/system/XSystemShellExecute.hpp>
85 #include <com/sun/star/system/SystemShellExecute.hpp>
87 #include <desktop/exithelper.h>
88 #include <sal/log.hxx>
89 #include <toolkit/helper/vclunohelper.hxx>
90 #include <comphelper/configuration.hxx>
91 #include <comphelper/fileurl.hxx>
92 #include <comphelper/threadpool.hxx>
93 #include <comphelper/processfactory.hxx>
94 #include <comphelper/backupfilehelper.hxx>
95 #include <unotools/bootstrap.hxx>
96 #include <unotools/configmgr.hxx>
97 #include <unotools/moduleoptions.hxx>
98 #include <unotools/localfilehelper.hxx>
99 #include <officecfg/Office/Common.hxx>
100 #include <officecfg/Office/Recovery.hxx>
101 #include <officecfg/Office/Update.hxx>
102 #include <officecfg/Setup.hxx>
103 #include <osl/file.hxx>
104 #include <osl/process.h>
105 #include <rtl/byteseq.hxx>
106 #include <rtl/uri.hxx>
107 #include <unotools/pathoptions.hxx>
108 #include <svtools/miscopt.hxx>
109 #include <svtools/menuoptions.hxx>
110 #include <rtl/bootstrap.hxx>
111 #include <vcl/glxtestprocess.hxx>
112 #include <vcl/help.hxx>
113 #include <vcl/weld.hxx>
114 #include <vcl/settings.hxx>
115 #include <sfx2/flatpak.hxx>
116 #include <sfx2/sfxsids.hrc>
117 #include <sfx2/app.hxx>
118 #include <sfx2/safemode.hxx>
119 #include <svl/itemset.hxx>
120 #include <svl/eitem.hxx>
121 #include <basic/sbstar.hxx>
122 #include <desktop/crashreport.hxx>
123 #include <tools/urlobj.hxx>
124 #include <tools/diagnose_ex.h>
125 #include <svtools/fontsubstconfig.hxx>
126 #include <svtools/accessibilityoptions.hxx>
127 #include <svtools/apearcfg.hxx>
128 #include <vcl/graphicfilter.hxx>
129 #include <vcl/window.hxx>
130 #include "langselect.hxx"
134 #include <sys/wait.h>
138 #define WIN32_LEAN_AND_MEAN
144 #define GETPID _getpid
147 #define GETPID getpid
150 #include <strings.hxx>
152 using namespace ::com::sun::star::awt
;
153 using namespace ::com::sun::star::uno
;
154 using namespace ::com::sun::star::util
;
155 using namespace ::com::sun::star::lang
;
156 using namespace ::com::sun::star::beans
;
157 using namespace ::com::sun::star::frame
;
158 using namespace ::com::sun::star::document
;
159 using namespace ::com::sun::star::view
;
160 using namespace ::com::sun::star::task
;
161 using namespace ::com::sun::star::system
;
162 using namespace ::com::sun::star::ui
;
163 using namespace ::com::sun::star::ui::dialogs
;
164 using namespace ::com::sun::star::container
;
169 static oslSignalHandler pSignalHandler
= nullptr;
173 #if HAVE_FEATURE_EXTENSIONS
175 // Remove any existing UserInstallation's extensions cache data remaining from
176 // old installations. This addresses at least two problems:
178 // For one, apparently due to the old share/prereg/bundled mechanism (disabled
179 // since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying
180 // share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled
181 // cache could contain corrupted information (like a UNO component registered
182 // twice, which got changed from active to passive registration in one LO
183 // version, but the version of the corresponding bundled extension only
184 // incremented in a later LO version).
186 // For another, UserInstallations have been seen in the wild where no extensions
187 // were installed per-user (any longer), but user/uno_packages/cache/registry/
188 // com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files
189 // contained data nevertheless.
191 // When a LO upgrade is detected (i.e., no user/extensions/buildid or one
192 // containing an old build ID), then user/extensions and
193 // user/uno_packages/cache/registry/
194 // com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are
195 // removed. That should prevent any problems starting the service manager due
196 // to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the
197 // removed cache data is recreated.
199 // Multiple instances of soffice.bin can execute this code in parallel for a
200 // single UserInstallation, as it is called before RequestHandler is set up.
201 // Therefore, any errors here only lead to SAL_WARNs.
203 // At least in theory, this function could be removed again once no
204 // UserInstallation can be poisoned by old junk any more.
205 bool cleanExtensionCache() {
207 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":buildid}");
208 rtl::Bootstrap::expandMacros(buildId
); //TODO: detect failure
210 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap")
211 ":UserInstallation}/user/extensions");
212 rtl::Bootstrap::expandMacros(extDir
); //TODO: detect failure
213 OUString
buildIdFile(extDir
+ "/buildid");
214 osl::File
fr(buildIdFile
);
215 osl::FileBase::RC rc
= fr
.open(osl_File_OpenFlag_Read
);
217 case osl::FileBase::E_None
:
219 rtl::ByteSequence s1
;
220 rc
= fr
.readLine(s1
);
221 osl::FileBase::RC rc2
= fr
.close();
223 rc2
!= osl::FileBase::E_None
, "desktop.app",
224 "cannot close " << fr
.getURL() << " after reading: " << +rc2
);
225 // readLine returns E_AGAIN for a zero-size file:
226 if (rc
!= osl::FileBase::E_None
&& rc
!= osl::FileBase::E_AGAIN
) {
227 SAL_WARN( "desktop.app", "cannot read from " << fr
.getURL() << ": " << +rc
);
231 reinterpret_cast< char const * >(s1
.getConstArray()),
232 s1
.getLength(), RTL_TEXTENCODING_ISO_8859_1
);
233 // using ISO 8859-1 avoids any and all conversion errors; the
234 // content should only be a subset of ASCII, anyway
240 case osl::FileBase::E_NOENT
:
243 SAL_WARN( "desktop.app", "cannot open " << fr
.getURL() << " for reading: " << +rc
);
246 utl::removeTree(extDir
);
248 "$UNO_USER_PACKAGES_CACHE/registry/"
249 "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc");
250 rtl::Bootstrap::expandMacros(userRcFile
); //TODO: detect failure
251 rc
= osl::File::remove(userRcFile
);
253 rc
!= osl::FileBase::E_None
&& rc
!= osl::FileBase::E_NOENT
, "desktop.app",
254 "cannot remove file " << userRcFile
<< ": " << +rc
);
255 rc
= osl::Directory::createPath(extDir
);
257 rc
!= osl::FileBase::E_None
&& rc
!= osl::FileBase::E_EXIST
, "desktop.app",
258 "cannot create path " << extDir
<< ": " << +rc
);
259 osl::File
fw(buildIdFile
);
260 rc
= fw
.open(osl_File_OpenFlag_Write
| osl_File_OpenFlag_Create
);
261 if (rc
!= osl::FileBase::E_None
) {
262 SAL_WARN( "desktop.app", "cannot open " << fw
.getURL() << " for writing: " << +rc
);
265 OString
buf(OUStringToOString(buildId
, RTL_TEXTENCODING_UTF8
));
266 // using UTF-8 avoids almost all conversion errors (and buildid
267 // containing single surrogate halves should never happen, anyway); the
268 // content should only be a subset of ASCII, anyway
270 rc
= fw
.write(buf
.getStr(), buf
.getLength(), n
);
272 (rc
!= osl::FileBase::E_None
273 || n
!= static_cast< sal_uInt32
>(buf
.getLength())),
275 "cannot write to " << fw
.getURL() << ": " << +rc
<< ", " << n
);
278 rc
!= osl::FileBase::E_None
, "desktop.app",
279 "cannot close " << fw
.getURL() << " after writing: " << +rc
);
285 bool shouldLaunchQuickstart()
287 bool bQuickstart
= Desktop::GetCommandLineArgs().IsQuickstart();
290 const SfxPoolItem
* pItem
=nullptr;
291 SfxItemSet
aQLSet(SfxGetpApp()->GetPool(), svl::Items
<SID_ATTR_QUICKLAUNCHER
, SID_ATTR_QUICKLAUNCHER
>{});
292 SfxGetpApp()->GetOptions(aQLSet
);
293 SfxItemState eState
= aQLSet
.GetItemState(SID_ATTR_QUICKLAUNCHER
, false, &pItem
);
294 if (SfxItemState::SET
== eState
)
295 bQuickstart
= static_cast<const SfxBoolItem
*>(pItem
)->GetValue();
300 void SetRestartState() {
302 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
303 comphelper::ConfigurationChanges::create());
304 officecfg::Setup::Office::OfficeRestartInProgress::set(true, batch
);
306 } catch (css::uno::Exception
) {
307 TOOLS_WARN_EXCEPTION("desktop.app", "ignoring");
311 void DoRestartActionsIfNecessary(bool quickstart
) {
314 if (officecfg::Setup::Office::OfficeRestartInProgress::get()) {
315 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
316 comphelper::ConfigurationChanges::create());
317 officecfg::Setup::Office::OfficeRestartInProgress::set(
320 css::office::Quickstart::createStart(
321 comphelper::getProcessComponentContext(),
322 shouldLaunchQuickstart());
324 } catch (css::uno::Exception
&) {
325 TOOLS_WARN_EXCEPTION("desktop.app", "ignoring");
335 OUString
MakeStartupErrorMessage(OUString
const & aErrorMessage
)
337 return DpResId(STR_BOOTSTRAP_ERR_CANNOT_START
) + "\n" + aErrorMessage
;
340 OUString
MakeStartupConfigAccessErrorMessage( OUString
const & aInternalErrMsg
)
342 OUString aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_CFG_DATAACCESS
);
343 if ( !aInternalErrMsg
.isEmpty() )
345 aDiagnosticMessage
+= "\n\n"
346 + DpResId(STR_INTERNAL_ERRMSG
)
349 return aDiagnosticMessage
;
353 // shows a simple error box with the given message ... but exits from these process !
354 // Fatal errors can't be solved by the process ... nor any recovery can help.
355 // Mostly the installation was damaged and must be repaired manually .. or by calling
357 // On the other side we must make sure that no further actions will be possible within
358 // the current office process ! No pipe requests, no menu/toolbar/shortcut actions
359 // are allowed. Otherwise we will force a "crash inside a crash".
360 // That's why we have to use a special native message box here which does not use yield :-)
362 void FatalError(const OUString
& sMessage
)
364 OUString sProductKey
= ::utl::Bootstrap::getProductKey();
365 if ( sProductKey
.isEmpty())
367 osl_getExecutableFile( &sProductKey
.pData
);
369 ::sal_uInt32 nLastIndex
= sProductKey
.lastIndexOf('/');
370 if ( nLastIndex
> 0 )
371 sProductKey
= sProductKey
.copy( nLastIndex
+1 );
374 OUString sTitle
= sProductKey
+ " - Fatal Error";
375 Application::ShowNativeErrorBox (sTitle
, sMessage
);
376 std::cerr
<< sTitle
<< ": " << sMessage
<< std::endl
;
377 _exit(EXITHELPER_FATAL_ERROR
);
380 struct theCommandLineArgs
: public rtl::Static
< CommandLineArgs
, theCommandLineArgs
> {};
384 CommandLineArgs
& Desktop::GetCommandLineArgs()
386 return theCommandLineArgs::get();
392 : public rtl::Static
< OUString
, OOOVendor
> {};
395 OUString
ReplaceStringHookProc( const OUString
& rStr
)
397 const static OUString
sBuildId(utl::Bootstrap::getBuildIdData("development"));
398 static OUString sBrandName
, sVersion
, sAboutBoxVersion
, sAboutBoxVersionSuffix
, sExtension
;
400 static std::once_flag aInitOnce
;
401 std::call_once(aInitOnce
, []
403 sBrandName
= utl::ConfigManager::getProductName();
404 sVersion
= utl::ConfigManager::getProductVersion();
405 sAboutBoxVersion
= utl::ConfigManager::getAboutBoxProductVersion();
406 sAboutBoxVersionSuffix
= utl::ConfigManager::getAboutBoxProductVersionSuffix();
407 sExtension
= utl::ConfigManager::getProductExtension();
411 if (sRet
.indexOf("%PRODUCT") != -1 || sRet
.indexOf("%ABOUTBOX") != -1)
413 sRet
= sRet
.replaceAll( "%PRODUCTNAME", sBrandName
);
414 sRet
= sRet
.replaceAll( "%PRODUCTVERSION", sVersion
);
415 sRet
= sRet
.replaceAll( "%BUILDID", sBuildId
);
416 sRet
= sRet
.replaceAll( "%ABOUTBOXPRODUCTVERSIONSUFFIX", sAboutBoxVersionSuffix
);
417 sRet
= sRet
.replaceAll( "%ABOUTBOXPRODUCTVERSION", sAboutBoxVersion
);
418 sRet
= sRet
.replaceAll( "%PRODUCTEXTENSION", sExtension
);
421 if ( sRet
.indexOf( "%OOOVENDOR" ) != -1 )
423 OUString sOOOVendor
= OOOVendor::get();
425 if ( sOOOVendor
.isEmpty() )
427 sOOOVendor
= utl::ConfigManager::getVendor();
430 sRet
= sRet
.replaceAll( "%OOOVENDOR", sOOOVendor
);
437 : m_bCleanedExtensionCache(false)
438 , m_bServicesRegistered(false)
439 , m_aBootstrapError(BE_OK
)
440 , m_aBootstrapStatus(BS_OK
)
442 m_firstRunTimer
.SetTimeout(3000); // 3 sec.
443 m_firstRunTimer
.SetInvokeHandler(LINK(this, Desktop
, AsyncInitFirstRun
));
444 m_firstRunTimer
.SetDebugName( "desktop::Desktop m_firstRunTimer" );
453 SetBootstrapStatus(BS_OK
);
455 #if HAVE_FEATURE_EXTENSIONS
456 m_bCleanedExtensionCache
= cleanExtensionCache();
459 // We need to have service factory before going further, but see fdo#37195.
460 // Doing this will mmap common.rdb, making it not overwritable on windows,
461 // so this can't happen before the synchronization above. Lets rework this
462 // so that the above is called *from* CreateApplicationServiceManager or
463 // something to enforce this gotcha
466 InitApplicationServiceManager();
468 catch (css::uno::Exception
& e
)
470 SetBootstrapError( BE_UNO_SERVICEMANAGER
, e
.Message
);
473 // Check whether safe mode is enabled
474 const CommandLineArgs
& rCmdLineArgs
= GetCommandLineArgs();
475 // Check if we are restarting from safe mode - in that case we don't want to enter it again
476 if (sfx2::SafeMode::hasRestartFlag())
477 sfx2::SafeMode::removeRestartFlag();
478 else if (rCmdLineArgs
.IsSafeMode() || sfx2::SafeMode::hasFlag())
479 Application::EnableSafeMode();
481 // When we are in SafeMode we need to do changes before the configuration
482 // gets read (langselect::prepareLocale() by UNO API -> Components::Components)
483 // This may prepare SafeMode or restore from it by moving data in
484 // the UserConfiguration directory
485 comphelper::BackupFileHelper::reactOnSafeMode(Application::IsSafeModeEnabled());
487 if ( m_aBootstrapError
== BE_OK
)
491 if (!langselect::prepareLocale())
493 SetBootstrapError( BE_LANGUAGE_MISSING
, OUString() );
496 catch (css::uno::Exception
& e
)
498 SetBootstrapError( BE_OFFICECONFIG_BROKEN
, e
.Message
);
501 // test code for ProfileSafeMode to allow testing the fail
502 // of loading the office configuration initially. To use,
503 // either set to true and compile, or set a breakpoint
504 // in debugger and change the local bool
505 static bool bTryHardOfficeconfigBroken(false); // loplugin:constvars:ignore
507 if (bTryHardOfficeconfigBroken
)
509 SetBootstrapError(BE_OFFICECONFIG_BROKEN
, OUString());
515 // start ipc thread only for non-remote offices
516 RequestHandler::Status aStatus
= RequestHandler::Enable(true);
517 if ( aStatus
== RequestHandler::IPC_STATUS_PIPE_ERROR
)
520 // Ignore crack pipe errors on Android
522 // Keep using this oddly named BE_PATHINFO_MISSING value
523 // for pipe-related errors on other platforms. Of course
524 // this crack with two (if not more) levels of our own
525 // error codes hiding the actual system error code is
526 // broken, but that is done all over the code, let's leave
527 // reengineering that to another year.
528 SetBootstrapError( BE_PATHINFO_MISSING
, OUString() );
531 else if ( aStatus
== RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR
)
533 SetBootstrapError( BE_PATHINFO_MISSING
, OUString() );
535 else if ( aStatus
== RequestHandler::IPC_STATUS_2ND_OFFICE
)
537 // 2nd office startup should terminate after sending cmdlineargs through pipe
538 SetBootstrapStatus(BS_TERMINATE
);
540 else if ( !rCmdLineArgs
.GetUnknown().isEmpty()
541 || rCmdLineArgs
.IsHelp() || rCmdLineArgs
.IsVersion() )
543 // disable IPC thread in an instance that is just showing a help message
544 RequestHandler::Disable();
546 pSignalHandler
= osl_addSignalHandler(SalMainPipeExchangeSignal_impl
, nullptr);
550 void Desktop::InitFinished()
555 void Desktop::DeInit()
558 // instead of removing of the configManager just let it commit all the changes
559 utl::ConfigManager::storeConfigItems();
560 FlushConfiguration();
562 // close splashscreen if it's still open
564 Reference
< XComponent
>(
565 comphelper::getProcessComponentContext(), UNO_QUERY_THROW
)->
567 // nobody should get a destroyed service factory...
568 ::comphelper::setProcessServiceFactory( nullptr );
573 RequestHandler::Disable();
575 osl_removeSignalHandler( pSignalHandler
);
576 } catch (const RuntimeException
&) {
577 // someone threw an exception during shutdown
578 // this will leave some garbage behind...
582 bool Desktop::QueryExit()
586 utl::ConfigManager::storeConfigItems();
588 catch ( const RuntimeException
& )
592 const sal_Char SUSPEND_QUICKSTARTVETO
[] = "SuspendQuickstartVeto";
594 Reference
< XDesktop2
> xDesktop
= css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
595 Reference
< XPropertySet
> xPropertySet(xDesktop
, UNO_QUERY_THROW
);
596 xPropertySet
->setPropertyValue( SUSPEND_QUICKSTARTVETO
, Any(true) );
598 bool bExit
= xDesktop
->terminate();
602 xPropertySet
->setPropertyValue( SUSPEND_QUICKSTARTVETO
, Any(false) );
604 else if (!Application::IsEventTestingModeEnabled())
606 FlushConfiguration();
609 // it is no problem to call RequestHandler::Disable() more than once
610 // it also looks to be threadsafe
611 RequestHandler::Disable();
613 catch ( const RuntimeException
& )
624 void Desktop::HandleBootstrapPathErrors( ::utl::Bootstrap::Status aBootstrapStatus
, const OUString
& aDiagnosticMessage
)
626 if ( aBootstrapStatus
!= ::utl::Bootstrap::DATA_OK
)
628 OUString aProductKey
;
631 osl_getExecutableFile( &aProductKey
.pData
);
632 sal_uInt32 lastIndex
= aProductKey
.lastIndexOf('/');
634 aProductKey
= aProductKey
.copy( lastIndex
+1 );
636 aTemp
= ::utl::Bootstrap::getProductKey( aProductKey
);
637 if ( !aTemp
.isEmpty() )
640 OUString
const aMessage(aDiagnosticMessage
+ "\n");
642 std::unique_ptr
<weld::MessageDialog
> xBootstrapFailedBox(Application::CreateMessageDialog(nullptr,
643 VclMessageType::Warning
, VclButtonsType::Ok
, aMessage
));
644 xBootstrapFailedBox
->set_title(aProductKey
);
645 xBootstrapFailedBox
->run();
649 // Create an error message depending on bootstrap failure code and an optional file url
650 OUString
Desktop::CreateErrorMsgString(
651 utl::Bootstrap::FailureCode nFailureCode
,
652 const OUString
& aFileURL
)
656 bool bFileInfo
= true;
658 switch ( nFailureCode
)
660 /// the shared installation directory could not be located
661 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY
:
663 aMsg
= DpResId(STR_BOOTSTRAP_ERR_PATH_INVALID
);
668 /// the bootstrap INI file could not be found or read
669 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE
:
671 aMsg
= DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING
);
675 /// the bootstrap INI is missing a required entry
676 /// the bootstrap INI contains invalid data
677 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY
:
678 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY
:
680 aMsg
= DpResId(STR_BOOTSTRAP_ERR_FILE_CORRUPT
);
684 /// the version locator INI file could not be found or read
685 case ::utl::Bootstrap::MISSING_VERSION_FILE
:
687 aMsg
= DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING
);
691 /// the version locator INI has no entry for this version
692 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY
:
694 aMsg
= DpResId(STR_BOOTSTRAP_ERR_NO_SUPPORT
);
698 /// the user installation directory does not exist
699 case ::utl::Bootstrap::MISSING_USER_DIRECTORY
:
701 aMsg
= DpResId(STR_BOOTSTRAP_ERR_DIR_MISSING
);
705 /// some bootstrap data was invalid in unexpected ways
706 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA
:
708 aMsg
= DpResId(STR_BOOTSTRAP_ERR_INTERNAL
);
713 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY
:
715 // This needs to be improved, see #i67575#:
716 aMsg
= "Invalid version file entry";
721 case ::utl::Bootstrap::NO_FAILURE
:
730 OUString
aMsgString( aMsg
);
732 osl::File::getSystemPathFromFileURL( aFileURL
, aFilePath
);
734 aMsgString
= aMsgString
.replaceFirst( "$1", aFilePath
);
738 return MakeStartupErrorMessage( aMsg
);
741 void Desktop::HandleBootstrapErrors(
742 BootstrapError aBootstrapError
, OUString
const & aErrorMessage
)
744 if ( aBootstrapError
== BE_PATHINFO_MISSING
)
748 utl::Bootstrap::Status aBootstrapStatus
;
749 utl::Bootstrap::FailureCode nFailureCode
;
751 aBootstrapStatus
= ::utl::Bootstrap::checkBootstrapStatus( aBuffer
, nFailureCode
);
752 if ( aBootstrapStatus
!= ::utl::Bootstrap::DATA_OK
)
754 switch ( nFailureCode
)
756 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY
:
757 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA
:
759 aErrorMsg
= CreateErrorMsgString( nFailureCode
, OUString() );
763 /// the bootstrap INI file could not be found or read
764 /// the bootstrap INI is missing a required entry
765 /// the bootstrap INI contains invalid data
766 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY
:
767 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY
:
768 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE
:
770 OUString aBootstrapFileURL
;
772 utl::Bootstrap::locateBootstrapFile( aBootstrapFileURL
);
773 aErrorMsg
= CreateErrorMsgString( nFailureCode
, aBootstrapFileURL
);
777 /// the version locator INI file could not be found or read
778 /// the version locator INI has no entry for this version
779 /// the version locator INI entry is not a valid directory URL
780 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY
:
781 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY
:
782 case ::utl::Bootstrap::MISSING_VERSION_FILE
:
784 OUString aVersionFileURL
;
786 utl::Bootstrap::locateVersionFile( aVersionFileURL
);
787 aErrorMsg
= CreateErrorMsgString( nFailureCode
, aVersionFileURL
);
791 /// the user installation directory does not exist
792 case ::utl::Bootstrap::MISSING_USER_DIRECTORY
:
794 OUString aUserInstallationURL
;
796 utl::Bootstrap::locateUserInstallation( aUserInstallationURL
);
797 aErrorMsg
= CreateErrorMsgString( nFailureCode
, aUserInstallationURL
);
801 case ::utl::Bootstrap::NO_FAILURE
:
808 HandleBootstrapPathErrors( aBootstrapStatus
, aErrorMsg
);
811 else if ( aBootstrapError
== BE_UNO_SERVICEMANAGER
|| aBootstrapError
== BE_UNO_SERVICE_CONFIG_MISSING
)
813 // UNO service manager is not available. VCL needs a UNO service manager to display a message box!!!
814 // Currently we are not able to display a message box with a service manager due to this limitations inside VCL.
816 // When UNO is not properly initialized, all kinds of things can fail
817 // and cause the process to crash. To give the user a hint even if
818 // generating and displaying a message box below crashes, print a
819 // hard-coded message on stderr first:
821 << "The application cannot be started.\n"
822 // STR_BOOTSTRAP_ERR_CANNOT_START
823 << (aBootstrapError
== BE_UNO_SERVICEMANAGER
824 ? "The component manager is not available.\n"
825 // STR_BOOTSTRAP_ERR_NO_SERVICE
826 : "The configuration service is not available.\n");
827 // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE
828 if ( !aErrorMessage
.isEmpty() )
830 std::cerr
<< "(\"" << aErrorMessage
<< "\")\n";
833 // First sentence. We cannot bootstrap office further!
834 OUString aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_NO_CFG_SERVICE
) + "\n";
835 if ( !aErrorMessage
.isEmpty() )
837 aDiagnosticMessage
+= "(\"" + aErrorMessage
+ "\")\n";
840 // Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to
841 // repair the installation with the setup executable besides the office executable. Now
842 // we have to ask the user to start the setup on CD/installation directory manually!!
843 aDiagnosticMessage
+= DpResId(STR_ASK_START_SETUP_MANUALLY
);
845 FatalError(MakeStartupErrorMessage(aDiagnosticMessage
));
847 else if ( aBootstrapError
== BE_OFFICECONFIG_BROKEN
)
849 // set flag at BackupFileHelper to be able to know if _exit was called and
850 // actions are executed after this. This method we are in will not return,
851 // but end up in a _exit() call
852 comphelper::BackupFileHelper::setExitWasCalled();
854 // enter safe mode, too
855 sfx2::SafeMode::putFlag();
857 OUString
msg(DpResId(STR_CONFIG_ERR_ACCESS_GENERAL
));
858 if (!aErrorMessage
.isEmpty()) {
859 msg
+= "\n(\"" + aErrorMessage
+ "\")";
861 FatalError(MakeStartupErrorMessage(msg
));
863 else if ( aBootstrapError
== BE_USERINSTALL_FAILED
)
865 OUString aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_USERINSTALL_FAILED
);
866 FatalError(MakeStartupErrorMessage(aDiagnosticMessage
));
868 else if ( aBootstrapError
== BE_LANGUAGE_MISSING
)
870 OUString aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_LANGUAGE_MISSING
);
871 FatalError(MakeStartupErrorMessage(aDiagnosticMessage
));
873 else if (( aBootstrapError
== BE_USERINSTALL_NOTENOUGHDISKSPACE
) ||
874 ( aBootstrapError
== BE_USERINSTALL_NOWRITEACCESS
))
876 OUString aUserInstallationURL
;
877 OUString aUserInstallationPath
;
878 utl::Bootstrap::locateUserInstallation( aUserInstallationURL
);
879 osl::File::getSystemPathFromFileURL( aUserInstallationURL
, aUserInstallationPath
);
881 OUString aDiagnosticMessage
;
882 if ( aBootstrapError
== BE_USERINSTALL_NOTENOUGHDISKSPACE
)
883 aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_NOTENOUGHDISKSPACE
);
885 aDiagnosticMessage
= DpResId(STR_BOOTSTRAP_ERR_NOACCESSRIGHTS
);
886 aDiagnosticMessage
+= aUserInstallationPath
;
888 FatalError(MakeStartupErrorMessage(aDiagnosticMessage
));
896 #if HAVE_FEATURE_BREAKPAD
897 void handleCrashReport()
899 static const char SERVICENAME_CRASHREPORT
[] = "com.sun.star.comp.svx.CrashReportUI";
901 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
903 Reference
< css::frame::XSynchronousDispatch
> xRecoveryUI(
904 xContext
->getServiceManager()->createInstanceWithContext(SERVICENAME_CRASHREPORT
, xContext
),
905 css::uno::UNO_QUERY_THROW
);
907 Reference
< css::util::XURLTransformer
> xURLParser
=
908 css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
911 css::uno::Any aRet
= xRecoveryUI
->dispatchWithReturnValue(aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
918 void handleSafeMode()
920 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
922 Reference
< css::frame::XSynchronousDispatch
> xSafeModeUI(
923 xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.comp.svx.SafeModeUI", xContext
),
924 css::uno::UNO_QUERY_THROW
);
927 css::uno::Any aRet
= xSafeModeUI
->dispatchWithReturnValue(aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
933 /** @short check if recovery must be started or not.
935 @param bCrashed [boolean ... out!]
936 the office crashed last times.
937 But may be there are no recovery data.
938 Useful to trigger the error report tool without
939 showing the recovery UI.
941 @param bRecoveryDataExists [boolean ... out!]
942 there exists some recovery data.
944 @param bSessionDataExists [boolean ... out!]
945 there exists some session data.
946 Because the user may be logged out last time from its
949 void impl_checkRecoveryState(bool& bCrashed
,
950 bool& bRecoveryDataExists
,
951 bool& bSessionDataExists
)
953 bCrashed
= officecfg::Office::Recovery::RecoveryInfo::Crashed::get()
954 #if HAVE_FEATURE_BREAKPAD
955 || CrashReporter::crashReportInfoExists();
959 bool elements
= officecfg::Office::Recovery::RecoveryList::get()->
962 = officecfg::Office::Recovery::RecoveryInfo::SessionData::get();
963 bRecoveryDataExists
= elements
&& !session
;
964 bSessionDataExists
= elements
&& session
;
967 Reference
< css::frame::XSynchronousDispatch
> g_xRecoveryUI
;
973 RefClearGuard(Ref
& ref
) : m_Ref(ref
) {}
974 ~RefClearGuard() { m_Ref
.clear(); }
977 /* @short start the recovery wizard.
979 @param bEmergencySave
980 differs between EMERGENCY_SAVE and RECOVERY
982 bool impl_callRecoveryUI(bool bEmergencySave
,
983 bool bExistsRecoveryData
)
985 static const char COMMAND_EMERGENCYSAVE
[] = "vnd.sun.star.autorecovery:/doEmergencySave";
986 static const char COMMAND_RECOVERY
[] = "vnd.sun.star.autorecovery:/doAutoRecovery";
988 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
991 xContext
->getServiceManager()->createInstanceWithContext("com.sun.star.comp.svx.RecoveryUI", xContext
),
992 css::uno::UNO_QUERY_THROW
);
993 RefClearGuard
<Reference
< css::frame::XSynchronousDispatch
>> refClearGuard(g_xRecoveryUI
);
995 Reference
< css::util::XURLTransformer
> xURLParser
=
996 css::util::URLTransformer::create(xContext
);
1000 aURL
.Complete
= COMMAND_EMERGENCYSAVE
;
1001 else if (bExistsRecoveryData
)
1002 aURL
.Complete
= COMMAND_RECOVERY
;
1006 xURLParser
->parseStrict(aURL
);
1008 css::uno::Any aRet
= g_xRecoveryUI
->dispatchWithReturnValue(aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
1014 bool impl_bringToFrontRecoveryUI()
1016 Reference
< css::frame::XSynchronousDispatch
> xRecoveryUI(g_xRecoveryUI
);
1017 if (!xRecoveryUI
.is())
1020 css::util::URL aURL
;
1021 aURL
.Complete
= "vnd.sun.star.autorecovery:/doBringToFront";
1022 Reference
< css::util::XURLTransformer
> xURLParser
=
1023 css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
1024 xURLParser
->parseStrict(aURL
);
1026 css::uno::Any aRet
= xRecoveryUI
->dispatchWithReturnValue(aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
1036 void restartOnMac(bool passArguments
) {
1038 RequestHandler::Disable();
1039 #if HAVE_FEATURE_MACOSX_SANDBOX
1040 (void) passArguments
; // avoid warnings
1041 OUString aMessage
= DpResId(STR_LO_MUST_BE_RESTARTED
);
1043 std::unique_ptr
<weld::MessageDialog
> xRestartBox(Application::CreateMessageDialog(nullptr,
1044 VclMessageType::Warning
, VclButtonsType::Ok
, aMessage
));
1048 OSL_VERIFY(osl_getExecutableFile(&execUrl
.pData
) == osl_Process_E_None
);
1051 if ((osl::FileBase::getSystemPathFromFileURL(execUrl
, execPath
)
1052 != osl::FileBase::E_None
) ||
1053 !execPath
.convertToString(
1054 &execPath8
, osl_getThreadTextEncoding(),
1055 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
1056 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
1060 std::vector
< OString
> args
;
1061 args
.push_back(execPath8
);
1063 if (passArguments
) {
1064 sal_uInt32 n
= osl_getCommandArgCount();
1065 for (sal_uInt32 i
= 0; i
< n
; ++i
) {
1067 osl_getCommandArg(i
, &arg
.pData
);
1068 if (arg
.match("--accept=")) {
1072 if (!arg
.convertToString(
1073 &arg8
, osl_getThreadTextEncoding(),
1074 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
1075 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
1079 args
.push_back(arg8
);
1082 std::vector
< char const * > argPtrs
;
1083 for (auto const& elem
: args
)
1085 argPtrs
.push_back(elem
.getStr());
1087 argPtrs
.push_back(nullptr);
1088 execv(execPath8
.getStr(), const_cast< char ** >(argPtrs
.data()));
1089 if (errno
== ENOTSUP
) { // happens when multithreaded on macOS < 10.6
1092 execv(execPath8
.getStr(), const_cast< char ** >(argPtrs
.data()));
1093 } else if (pid
> 0) {
1094 // Two simultaneously running soffice processes lead to two dock
1095 // icons, so avoid waiting here unless it must be assumed that the
1096 // process invoking soffice itself wants to wait for soffice to
1102 if (waitpid(pid
, &stat
, 0) == pid
&& WIFEXITED(stat
)) {
1103 _exit(WEXITSTATUS(stat
));
1110 (void) passArguments
; // avoid warnings
1114 #if HAVE_FEATURE_UPDATE_MAR
1115 bool isTimeForUpdateCheck()
1117 sal_uInt64 nLastUpdate
= officecfg::Office::Update::Update::LastUpdateTime::get();
1118 sal_uInt64 nNow
= tools::Time::GetSystemTicks();
1120 sal_uInt64 n7DayInMS
= 1000 * 60 * 60 * 12 * 1; // 12 hours in ms
1121 if (nNow
- n7DayInMS
>= nLastUpdate
)
1130 void Desktop::Exception(ExceptionCategory nCategory
)
1132 // protect against recursive calls
1133 static bool bInException
= false;
1135 SystemWindowFlags nOldMode
= Application::GetSystemWindowMode();
1136 Application::SetSystemWindowMode( nOldMode
& ~SystemWindowFlags::NOAUTOMODE
);
1139 Application::Abort( OUString() );
1142 bInException
= true;
1143 const CommandLineArgs
& rArgs
= GetCommandLineArgs();
1145 // save all modified documents ... if it's allowed doing so.
1146 bool bRestart
= false;
1147 bool bAllowRecoveryAndSessionManagement
= (
1148 ( !rArgs
.IsNoRestore() ) && // some use cases of office must work without recovery
1149 ( !rArgs
.IsHeadless() ) &&
1150 ( nCategory
!= ExceptionCategory::UserInterface
) && // recovery can't work without UI ... but UI layer seems to be the reason for this crash
1151 ( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicate a corrupted installation...)
1153 if ( bAllowRecoveryAndSessionManagement
)
1155 // Save all open documents so they will be reopened
1156 // the next time the application is started
1157 // returns true if at least one document could be saved...
1158 bRestart
= impl_callRecoveryUI(
1159 true , // force emergency save
1163 FlushConfiguration();
1167 case ExceptionCategory::ResourceNotLoaded
:
1169 Application::Abort( OUString() );
1175 m_xLockfile
.reset();
1179 RequestHandler::Disable();
1180 if( pSignalHandler
)
1181 osl_removeSignalHandler( pSignalHandler
);
1183 restartOnMac(false);
1184 if ( m_rSplashScreen
.is() )
1185 m_rSplashScreen
->reset();
1187 _exit( EXITHELPER_CRASH_WITH_RESTART
);
1191 Application::Abort( OUString() );
1198 OSL_ASSERT(false); // unreachable
1201 void Desktop::AppEvent( const ApplicationEvent
& rAppEvent
)
1203 HandleAppEvent( rAppEvent
);
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
;
1215 : bRestartRequested( false )
1216 , bUseSystemFileDialog( true )
1220 static ExecuteGlobals
* pExecGlobals
= nullptr;
1224 pExecGlobals
= new ExecuteGlobals();
1226 // Remember current context object
1227 css::uno::ContextLayer
layer( css::uno::getCurrentContext() );
1229 if ( m_aBootstrapError
!= BE_OK
)
1231 HandleBootstrapErrors( m_aBootstrapError
, m_aBootstrapErrorMessage
);
1232 return EXIT_FAILURE
;
1235 BootstrapStatus eStatus
= GetBootstrapStatus();
1236 if (eStatus
== BS_TERMINATE
) {
1237 return EXIT_SUCCESS
;
1240 // Detect desktop environment - need to do this as early as possible
1241 css::uno::setCurrentContext( new DesktopContext( css::uno::getCurrentContext() ) );
1243 CommandLineArgs
& rCmdLineArgs
= GetCommandLineArgs();
1245 Translate::SetReadStringHook(ReplaceStringHookProc
);
1250 SetSplashScreenProgress(10);
1252 userinstall::Status inst_fin
= userinstall::finalize();
1253 if (inst_fin
!= userinstall::EXISTED
&& inst_fin
!= userinstall::CREATED
)
1255 SAL_WARN( "desktop.app", "userinstall failed");
1256 if ( inst_fin
== userinstall::ERROR_NO_SPACE
)
1257 HandleBootstrapErrors(
1258 BE_USERINSTALL_NOTENOUGHDISKSPACE
, OUString() );
1259 else if ( inst_fin
== userinstall::ERROR_CANT_WRITE
)
1260 HandleBootstrapErrors( BE_USERINSTALL_NOWRITEACCESS
, OUString() );
1262 HandleBootstrapErrors( BE_USERINSTALL_FAILED
, OUString() );
1263 return EXIT_FAILURE
;
1265 // refresh path information
1266 utl::Bootstrap::reloadData();
1267 SetSplashScreenProgress(20);
1269 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
1271 Reference
< XRestartManager
> xRestartManager( OfficeRestartManager::get(xContext
) );
1273 Reference
< XDesktop2
> xDesktop
;
1276 RegisterServices(xContext
);
1278 SetSplashScreenProgress(25);
1280 #if HAVE_FEATURE_DESKTOP
1281 // check user installation directory for lockfile so we can be sure
1282 // there is no other instance using our data files from a remote host
1284 bool bMustLockProfile
= ( getenv( "SAL_NOLOCK_PROFILE" ) == nullptr );
1285 if ( bMustLockProfile
)
1287 m_xLockfile
.reset(new Lockfile
);
1289 if ( !rCmdLineArgs
.IsHeadless() && !rCmdLineArgs
.IsInvisible() &&
1290 !rCmdLineArgs
.IsNoLockcheck() && !m_xLockfile
->check( Lockfile_execWarning
))
1292 // Lockfile exists, and user clicked 'no'
1293 return EXIT_FAILURE
;
1297 // check if accessibility is enabled but not working and allow to quit
1298 if( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() )
1300 if( !InitAccessBridge() )
1301 return EXIT_FAILURE
;
1305 // terminate if requested...
1306 if( rCmdLineArgs
.IsTerminateAfterInit() )
1307 return EXIT_SUCCESS
;
1309 // Read the common configuration items for optimization purpose
1310 if ( !InitializeConfiguration() )
1311 return EXIT_FAILURE
;
1313 #if HAVE_FEATURE_UPDATE_MAR
1314 const char* pUpdaterTestEnable
= std::getenv("LIBO_UPDATER_TEST_ENABLE");
1315 if (pUpdaterTestEnable
|| officecfg::Office::Update::Update::Enabled::get())
1317 // check if we just updated
1318 const char* pUpdaterRunning
= std::getenv("LIBO_UPDATER_TEST_RUNNING");
1319 bool bUpdateRunning
= officecfg::Office::Update::Update::UpdateRunning::get() || pUpdaterRunning
;
1322 OUString aSeeAlso
= officecfg::Office::Update::Update::SeeAlso::get();
1323 OUString aOldBuildID
= officecfg::Office::Update::Update::OldBuildID::get();
1325 OUString aBuildID
= Updater::getBuildID();
1326 if (aOldBuildID
== aBuildID
)
1328 Updater::log("Old and new Build ID are the same. No Updating took place.");
1332 if (!aSeeAlso
.isEmpty())
1334 SAL_INFO("desktop.updater", "See also: " << aSeeAlso
);
1335 Reference
< css::system::XSystemShellExecute
> xSystemShell(
1336 SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
1338 xSystemShell
->execute( aSeeAlso
, OUString(), SystemShellExecuteFlags::URIS_ONLY
);
1342 // reset all the configuration values,
1343 // all values need to be read before this code
1344 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
1345 comphelper::ConfigurationChanges::create());
1346 officecfg::Office::Update::Update::UpdateRunning::set(false, batch
);
1347 officecfg::Office::Update::Update::SeeAlso::set(OUString(), batch
);
1348 officecfg::Office::Update::Update::OldBuildID::set(OUString(), batch
);
1351 Updater::removeUpdateFiles();
1354 osl::DirectoryItem aUpdateFile
;
1355 osl::DirectoryItem::get(Updater::getUpdateFileURL(), aUpdateFile
);
1357 const char* pUpdaterTestUpdate
= std::getenv("LIBO_UPDATER_TEST_UPDATE");
1358 const char* pForcedUpdateCheck
= std::getenv("LIBO_UPDATER_TEST_UPDATE_CHECK");
1359 if (pUpdaterTestUpdate
|| aUpdateFile
.is())
1361 OUString
aBuildID("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":buildid}");
1362 rtl::Bootstrap::expandMacros(aBuildID
);
1363 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
1364 comphelper::ConfigurationChanges::create());
1365 officecfg::Office::Update::Update::OldBuildID::set(aBuildID
, batch
);
1366 officecfg::Office::Update::Update::UpdateRunning::set(true, batch
);
1369 // make sure the change is written to the configuration before we start the update
1370 css::uno::Reference
<css::util::XFlushable
> xFlushable(css::configuration::theDefaultProvider::get(xContext
), UNO_QUERY
);
1371 xFlushable
->flush();
1372 // avoid the old oosplash staying around
1373 CloseSplashScreen();
1374 bool bSuccess
= update();
1376 return EXIT_SUCCESS
;
1378 else if (isTimeForUpdateCheck() || pForcedUpdateCheck
)
1380 sal_uInt64 nNow
= tools::Time::GetSystemTicks();
1381 Updater::log("Update Check Time: " + OUString::number(nNow
));
1382 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
1383 comphelper::ConfigurationChanges::create());
1384 officecfg::Office::Update::Update::LastUpdateTime::set(nNow
, batch
);
1386 m_aUpdateThread
= std::thread(update_checker
);
1391 SetSplashScreenProgress(30);
1393 // create title string
1394 OUString
aTitle(ReplaceStringHookProc(RID_APPTITLE
));
1397 //include buildid in non product builds
1398 aTitle
+= " [" + utl::Bootstrap::getBuildIdData("development") + "]";
1401 SetDisplayName( aTitle
);
1402 SetSplashScreenProgress(35);
1403 pExecGlobals
->pPathOptions
.reset( new SvtPathOptions
);
1404 SetSplashScreenProgress(40);
1406 xDesktop
= css::frame::Desktop::create( xContext
);
1408 // create service for loading SFX (still needed in startup)
1409 pExecGlobals
->xGlobalBroadcaster
= Reference
< css::document::XDocumentEventListener
>
1410 ( css::frame::theGlobalEventBroadcaster::get(xContext
), UNO_SET_THROW
);
1412 /* ensure existence of a default window that messages can be dispatched to
1413 This is for the benefit of testtool which uses PostUserEvent extensively
1414 and else can deadlock while creating this window from another thread while
1415 the main thread is not yet in the event loop.
1417 Application::GetDefaultDevice();
1419 #if HAVE_FEATURE_EXTENSIONS
1420 // Check if bundled or shared extensions were added /removed
1421 // and process those extensions (has to be done before checking
1422 // the extension dependencies!
1423 SynchronizeExtensionRepositories(m_bCleanedExtensionCache
, this);
1424 bool bAbort
= CheckExtensionDependencies();
1426 return EXIT_FAILURE
;
1428 if (inst_fin
== userinstall::CREATED
)
1430 Migration::migrateSettingsIfNecessary();
1434 // keep a language options instance...
1435 pExecGlobals
->pLanguageOptions
.reset( new SvtLanguageOptions(true));
1437 css::document::DocumentEvent aEvent
;
1438 aEvent
.EventName
= "OnStartApp";
1439 pExecGlobals
->xGlobalBroadcaster
->documentEventOccured(aEvent
);
1441 SetSplashScreenProgress(50);
1443 // Backing Component
1444 bool bCrashed
= false;
1445 bool bExistsRecoveryData
= false;
1446 bool bExistsSessionData
= false;
1448 impl_checkRecoveryState(bCrashed
, bExistsRecoveryData
, bExistsSessionData
);
1450 OUString pidfileName
= rCmdLineArgs
.GetPidfileName();
1451 if ( !pidfileName
.isEmpty() )
1453 OUString pidfileURL
;
1455 if ( osl_getFileURLFromSystemPath(pidfileName
.pData
, &pidfileURL
.pData
) == osl_File_E_None
)
1457 osl::File
pidfile( pidfileURL
);
1458 osl::FileBase::RC rc
;
1460 osl::File::remove( pidfileURL
);
1461 if ( (rc
= pidfile
.open( osl_File_OpenFlag_Write
| osl_File_OpenFlag_Create
) ) == osl::File::E_None
)
1463 OString
pid( OString::number( GETPID() ) );
1464 sal_uInt64 written
= 0;
1465 if ( pidfile
.write(pid
.getStr(), pid
.getLength(), written
) != osl::File::E_None
)
1467 SAL_WARN("desktop.app", "cannot write pidfile " << pidfile
.getURL());
1473 SAL_WARN("desktop.app", "cannot open pidfile " << pidfile
.getURL() << rc
);
1478 SAL_WARN("desktop.app", "cannot get pidfile URL from path" << pidfileName
);
1482 if ( rCmdLineArgs
.IsHeadless() || rCmdLineArgs
.IsEventTesting() )
1484 // Ensure that we use not the system file dialogs as
1485 // headless mode relies on Application::EnableHeadlessMode()
1486 // which does only work for VCL dialogs!!
1487 SvtMiscOptions aMiscOptions
;
1488 pExecGlobals
->bUseSystemFileDialog
= aMiscOptions
.UseSystemFileDialog();
1489 aMiscOptions
.SetUseSystemFileDialog( false );
1492 pExecGlobals
->bRestartRequested
= xRestartManager
->isRestartRequested(
1494 if ( !pExecGlobals
->bRestartRequested
)
1496 if ((!rCmdLineArgs
.WantsToLoadDocument() && !rCmdLineArgs
.IsInvisible() && !rCmdLineArgs
.IsHeadless() && !rCmdLineArgs
.IsQuickstart()) &&
1497 (SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE
)) &&
1498 (!bExistsRecoveryData
) &&
1499 (!bExistsSessionData
) &&
1500 (!Application::AnyInput( VclInputFlags::APPEVENT
) ))
1502 ShowBackingComponent(this);
1506 catch ( const css::lang::WrappedTargetException
& wte
)
1508 css::uno::Exception te
;
1509 wte
.TargetException
>>= te
;
1510 FatalError( MakeStartupConfigAccessErrorMessage(wte
.Message
+ te
.Message
) );
1512 catch ( const css::uno::Exception
& e
)
1514 FatalError( MakeStartupErrorMessage(e
.Message
) );
1516 SetSplashScreenProgress(55);
1518 SvtFontSubstConfig().Apply();
1520 SvtTabAppearanceCfg aAppearanceCfg
;
1521 SvtTabAppearanceCfg::SetInitialized();
1522 aAppearanceCfg
.SetApplicationDefaults( this );
1523 SvtAccessibilityOptions aOptions
;
1524 aOptions
.SetVCLSettings();
1525 SetSplashScreenProgress(60);
1527 if ( !pExecGlobals
->bRestartRequested
)
1529 Application::SetFilterHdl( LINK( this, Desktop
, ImplInitFilterHdl
) );
1531 // Preload function depends on an initialized sfx application!
1532 SetSplashScreenProgress(75);
1534 // use system window dialogs
1535 Application::SetSystemWindowMode( SystemWindowFlags::DIALOG
);
1537 SetSplashScreenProgress(80);
1539 if ( !rCmdLineArgs
.IsInvisible() &&
1540 !rCmdLineArgs
.IsNoQuickstart() )
1541 InitializeQuickstartMode( xContext
);
1545 if ( xDesktop
.is() )
1546 xDesktop
->addTerminateListener( new RequestHandlerController
);
1547 SetSplashScreenProgress(100);
1549 catch ( const css::uno::Exception
& e
)
1551 FatalError( MakeStartupErrorMessage(e
.Message
) );
1554 // FIXME: move this somewhere sensible.
1555 #if HAVE_FEATURE_OPENCL
1556 CheckOpenCLCompute(xDesktop
);
1559 // In headless mode, reap the process started by fire_glxtest_process() early in soffice_main
1560 // (desktop/source/app/sofficemain.cxx), in a code block that needs to be covered by the same
1561 // #if condition as this code block:
1562 #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && HAVE_FEATURE_UI && HAVE_FEATURE_OPENGL
1563 if (rCmdLineArgs
.IsHeadless()) {
1564 reap_glxtest_process();
1568 // Release solar mutex just before we wait for our client to connect
1570 SolarMutexReleaser aReleaser
;
1572 // Post user event to startup first application component window
1573 // We have to send this OpenClients message short before execute() to
1574 // minimize the risk that this message overtakes type detection construction!!
1575 Application::PostUserEvent( LINK( this, Desktop
, OpenClients_Impl
) );
1577 // Post event to enable acceptors
1578 Application::PostUserEvent( LINK( this, Desktop
, EnableAcceptors_Impl
) );
1580 // Acquire solar mutex just before we enter our message loop
1583 // call Application::Execute to process messages in vcl message loop
1586 #if HAVE_FEATURE_JAVA
1587 // The JavaContext contains an interaction handler which is used when
1588 // the creation of a Java Virtual Machine fails
1589 css::uno::ContextLayer
layer2(
1590 new svt::JavaContext( css::uno::getCurrentContext() ) );
1592 // check whether the shutdown is caused by restart just before entering the Execute
1593 pExecGlobals
->bRestartRequested
= pExecGlobals
->bRestartRequested
||
1594 xRestartManager
->isRestartRequested(true);
1596 if ( !pExecGlobals
->bRestartRequested
)
1598 // if this run of the office is triggered by restart, some additional actions should be done
1599 DoRestartActionsIfNecessary( !rCmdLineArgs
.IsInvisible() && !rCmdLineArgs
.IsNoQuickstart() );
1604 catch(const css::document::CorruptedFilterConfigurationException
& exFilterCfg
)
1606 RequestHandler::SetDowning();
1607 FatalError( MakeStartupErrorMessage(exFilterCfg
.Message
) );
1609 catch(const css::configuration::CorruptedConfigurationException
& exAnyCfg
)
1611 RequestHandler::SetDowning();
1612 FatalError( MakeStartupErrorMessage(exAnyCfg
.Message
) );
1614 catch( const css::uno::Exception
& exUNO
)
1616 RequestHandler::SetDowning();
1617 FatalError( exUNO
.Message
);
1619 catch( const std::exception
& exSTD
)
1621 RequestHandler::SetDowning();
1622 FatalError(o3tl::runtimeToOUString(exSTD
.what()));
1626 RequestHandler::SetDowning();
1627 FatalError( "Caught Unknown Exception: Aborting!");
1633 xDesktop
->terminate();
1635 // CAUTION: you do not necessarily get here e.g. on the Mac.
1636 // please put all deinitialization code into doShutdown
1637 return doShutdown();
1640 int Desktop::doShutdown()
1642 if( ! pExecGlobals
)
1643 return EXIT_SUCCESS
;
1645 if (m_aUpdateThread
.joinable())
1646 m_aUpdateThread
.join();
1648 pExecGlobals
->bRestartRequested
= pExecGlobals
->bRestartRequested
||
1649 OfficeRestartManager::get(comphelper::getProcessComponentContext())->
1650 isRestartRequested(true);
1651 if ( pExecGlobals
->bRestartRequested
)
1654 // Restore old value
1655 const CommandLineArgs
& rCmdLineArgs
= GetCommandLineArgs();
1656 if ( rCmdLineArgs
.IsHeadless() || rCmdLineArgs
.IsEventTesting() )
1657 SvtMiscOptions().SetUseSystemFileDialog( pExecGlobals
->bUseSystemFileDialog
);
1659 OUString pidfileName
= rCmdLineArgs
.GetPidfileName();
1660 if ( !pidfileName
.isEmpty() )
1662 OUString pidfileURL
;
1664 if ( osl_getFileURLFromSystemPath(pidfileName
.pData
, &pidfileURL
.pData
) == osl_File_E_None
)
1666 if ( osl::File::remove( pidfileURL
) != osl::FileBase::E_None
)
1668 SAL_WARN("desktop.app", "shutdown: cannot remove pidfile " << pidfileURL
);
1673 SAL_WARN("desktop.app", "shutdown: cannot get pidfile URL from path" << pidfileName
);
1677 // remove temp directory
1678 RemoveTemporaryDirectory();
1679 flatpak::removeTemporaryHtmlDirectory();
1681 // flush evtl. configuration changes so that all config files in user
1683 FlushConfiguration();
1685 if (pExecGlobals
->bRestartRequested
)
1687 // a restart is already requested, usually due to a configuration change
1688 // that needs a restart to get active. If this is the case, do not try
1689 // to use SecureUserConfig to safe this still untested new configuration
1693 // Test if SecureUserConfig is active. If yes and we are at this point, regular shutdown
1694 // is in progress and the currently used configuration was working. Try to secure this
1695 // working configuration for later eventually necessary restores
1696 comphelper::BackupFileHelper aBackupFileHelper
;
1698 aBackupFileHelper
.tryPush();
1699 aBackupFileHelper
.tryPushExtensionInfo();
1702 // The acceptors in the AcceptorMap must be released (in DeregisterServices)
1703 // with the solar mutex unlocked, to avoid deadlock:
1705 SolarMutexReleaser aReleaser
;
1706 DeregisterServices();
1707 #if HAVE_FEATURE_SCRIPTING
1708 StarBASIC::DetachAllDocBasicItems();
1712 // be sure that path/language options gets destroyed before
1713 // UCB is deinitialized
1714 pExecGlobals
->pLanguageOptions
.reset();
1715 pExecGlobals
->pPathOptions
.reset();
1717 comphelper::ThreadPool::getSharedOptimalPool().shutdown();
1719 bool bRR
= pExecGlobals
->bRestartRequested
;
1720 delete pExecGlobals
;
1721 pExecGlobals
= nullptr;
1726 if ( m_rSplashScreen
.is() )
1727 m_rSplashScreen
->reset();
1729 return EXITHELPER_NORMAL_RESTART
;
1731 return EXIT_SUCCESS
;
1734 IMPL_STATIC_LINK( Desktop
, ImplInitFilterHdl
, ::ConvertData
&, rData
, bool )
1736 return GraphicFilter::GetGraphicFilter().GetFilterCallback().Call( rData
);
1739 bool Desktop::InitializeConfiguration()
1743 css::configuration::theDefaultProvider::get(
1744 comphelper::getProcessComponentContext() );
1747 catch( css::lang::ServiceNotRegisteredException
& e
)
1749 HandleBootstrapErrors(
1750 Desktop::BE_UNO_SERVICE_CONFIG_MISSING
, e
.Message
);
1752 catch( const css::configuration::MissingBootstrapFileException
& e
)
1754 OUString
aMsg( CreateErrorMsgString( utl::Bootstrap::MISSING_BOOTSTRAP_FILE
,
1755 e
.BootstrapFileURL
));
1756 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_USER_INSTALL
, aMsg
);
1758 catch( const css::configuration::InvalidBootstrapFileException
& e
)
1760 OUString
aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY
,
1761 e
.BootstrapFileURL
));
1762 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL
, aMsg
);
1764 catch( const css::configuration::InstallationIncompleteException
& )
1766 OUString aVersionFileURL
;
1768 utl::Bootstrap::PathStatus aPathStatus
= utl::Bootstrap::locateVersionFile( aVersionFileURL
);
1769 if ( aPathStatus
== utl::Bootstrap::PATH_EXISTS
)
1770 aMsg
= CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE_ENTRY
, aVersionFileURL
);
1772 aMsg
= CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE
, aVersionFileURL
);
1774 HandleBootstrapPathErrors( ::utl::Bootstrap::MISSING_USER_INSTALL
, aMsg
);
1776 catch ( const css::configuration::backend::BackendAccessException
& exception
)
1778 // [cm122549] It is assumed in this case that the message
1779 // coming from InitConfiguration (in fact CreateApplicationConf...)
1780 // is suitable for display directly.
1781 FatalError( MakeStartupErrorMessage( exception
.Message
) );
1783 catch ( const css::configuration::backend::BackendSetupException
& exception
)
1785 // [cm122549] It is assumed in this case that the message
1786 // coming from InitConfiguration (in fact CreateApplicationConf...)
1787 // is suitable for display directly.
1788 FatalError( MakeStartupErrorMessage( exception
.Message
) );
1790 catch ( const css::configuration::CannotLoadConfigurationException
& )
1792 OUString
aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA
,
1794 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL
, aMsg
);
1796 catch( const css::uno::Exception
& )
1798 OUString
aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA
,
1800 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL
, aMsg
);
1805 void Desktop::FlushConfiguration()
1807 css::uno::Reference
< css::util::XFlushable
>(
1808 css::configuration::theDefaultProvider::get(
1809 comphelper::getProcessComponentContext()),
1810 css::uno::UNO_QUERY_THROW
)->flush();
1813 bool Desktop::InitializeQuickstartMode( const Reference
< XComponentContext
>& rxContext
)
1817 // the shutdown icon sits in the systray and allows the user to keep
1818 // the office instance running for quicker restart
1819 // this will only be activated if --quickstart was specified on cmdline
1821 bool bQuickstart
= shouldLaunchQuickstart();
1823 // Try to instantiate quickstart service. This service is not mandatory, so
1824 // do nothing if service is not available
1826 // #i105753# the following if was invented for performance
1827 // unfortunately this broke the Mac behavior which is to always run
1828 // in quickstart mode since Mac applications do not usually quit
1829 // when the last document closes.
1830 // Note that this claim that on macOS we "always run in quickstart mode"
1831 // has nothing to do with (quick) *starting* (i.e. starting automatically
1832 // when the user logs in), though, but with not quitting when no documents
1838 css::office::Quickstart::createStart(rxContext
, bQuickstart
);
1842 catch( const css::uno::Exception
& )
1848 void Desktop::OverrideSystemSettings( AllSettings
& rSettings
)
1850 if ( !SvtTabAppearanceCfg::IsInitialized () )
1853 StyleSettings hStyleSettings
= rSettings
.GetStyleSettings();
1854 MouseSettings hMouseSettings
= rSettings
.GetMouseSettings();
1856 DragFullOptions nDragFullOptions
= hStyleSettings
.GetDragFullOptions();
1858 SvtTabAppearanceCfg aAppearanceCfg
;
1859 DragMode nDragMode
= aAppearanceCfg
.GetDragMode();
1860 switch ( nDragMode
)
1862 case DragMode::FullWindow
:
1863 nDragFullOptions
|= DragFullOptions::All
;
1865 case DragMode::Frame
:
1866 nDragFullOptions
&= ~DragFullOptions::All
;
1868 case DragMode::SystemDep
:
1873 MouseFollowFlags nFollow
= hMouseSettings
.GetFollow();
1874 hMouseSettings
.SetFollow( aAppearanceCfg
.IsMenuMouseFollow() ? (nFollow
|MouseFollowFlags::Menu
) : (nFollow
&~MouseFollowFlags::Menu
));
1875 rSettings
.SetMouseSettings(hMouseSettings
);
1877 SvtMenuOptions aMenuOpt
;
1878 hStyleSettings
.SetUseImagesInMenus(aMenuOpt
.GetMenuIconsState());
1879 hStyleSettings
.SetContextMenuShortcuts(aMenuOpt
.GetContextMenuShortcuts());
1880 hStyleSettings
.SetDragFullOptions( nDragFullOptions
);
1881 rSettings
.SetStyleSettings ( hStyleSettings
);
1885 class ExitTimer
: public Timer
1893 virtual void Invoke() override
1899 IMPL_LINK_NOARG(Desktop
, OpenClients_Impl
, void*, void)
1903 // Enable IPC thread before OpenClients
1905 // This is because it is possible for another client to connect during the OpenClients() call.
1906 // This can happen on Windows when document is printed (not opened) and another client wants to print (when printing multiple documents).
1907 // 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
1911 // Multiple clients may request simultaneous connections.
1912 // When this server closes down it attempts to recreate the pipe (in RequestHandler::Disable()).
1913 // It's possible that the client has a pending connection request.
1914 // When the IPC thread is not running, this connection locks (because maPipe.accept()) is never called
1915 RequestHandler::SetReady(true);
1918 CloseSplashScreen();
1921 // Registers a COM class factory of the service manager with the windows operating system.
1922 Reference
< XMultiServiceFactory
> xSMgr
= comphelper::getProcessServiceFactory();
1923 xSMgr
->createInstance("com.sun.star.bridge.OleApplicationRegistration");
1924 xSMgr
->createInstance("com.sun.star.comp.ole.EmbedServer");
1926 const char *pExitPostStartup
= getenv ("OOO_EXIT_POST_STARTUP");
1927 if (pExitPostStartup
&& *pExitPostStartup
)
1929 } catch (const css::uno::Exception
&e
) {
1930 Application::Abort( "UNO exception during client open: " + e
.Message
);
1934 void Desktop::OpenClients()
1937 const CommandLineArgs
& rArgs
= GetCommandLineArgs();
1939 if (!rArgs
.IsQuickstart())
1941 OUString aHelpModule
;
1942 if (rArgs
.IsHelpWriter()) {
1943 aHelpModule
= "swriter";
1944 } else if (rArgs
.IsHelpCalc()) {
1945 aHelpModule
= "scalc";
1946 } else if (rArgs
.IsHelpDraw()) {
1947 aHelpModule
= "sdraw";
1948 } else if (rArgs
.IsHelpImpress()) {
1949 aHelpModule
= "simpress";
1950 } else if (rArgs
.IsHelpBase()) {
1951 aHelpModule
= "sdatabase";
1952 } else if (rArgs
.IsHelpBasic()) {
1953 aHelpModule
= "sbasic";
1954 } else if (rArgs
.IsHelpMath()) {
1955 aHelpModule
= "smath";
1957 if (!aHelpModule
.isEmpty()) {
1958 OUString aHelpURL
= "vnd.sun.star.help://"
1960 + "/start?Language="
1961 + utl::ConfigManager::getUILocale();
1963 aHelpURL
+= "&System=UNX";
1965 aHelpURL
+= "&System=WIN";
1967 Application::GetHelp()->Start(aHelpURL
, static_cast<const vcl::Window
*>(nullptr));
1972 // Disable AutoSave feature in case "--norestore" or a similar command line switch is set on the command line.
1973 // The reason behind: AutoSave/EmergencySave/AutoRecovery share the same data.
1974 // But the require that all documents, which are saved as backup should exists inside
1975 // memory. May be this mechanism will be inconsistent if the configuration exists...
1976 // but no document inside memory corresponds to this data.
1977 // Further it's not acceptable to recover such documents without any UI. It can
1978 // need some time, where the user won't see any results and wait for finishing the office startup...
1979 bool bAllowRecoveryAndSessionManagement
= ( !rArgs
.IsNoRestore() ) && ( !rArgs
.IsHeadless() );
1981 #if !defined ANDROID
1982 // Enter safe mode if requested
1983 if (Application::IsSafeModeEnabled()) {
1988 #if HAVE_FEATURE_BREAKPAD
1989 if (officecfg::Office::Common::Misc::CrashReport::get() && CrashReporter::crashReportInfoExists())
1990 handleCrashReport();
1993 if ( ! bAllowRecoveryAndSessionManagement
)
1997 Reference
< XDispatch
> xRecovery
= css::frame::theAutoRecovery::get( ::comphelper::getProcessComponentContext() );
1998 Reference
< css::util::XURLTransformer
> xParser
= css::util::URLTransformer::create( ::comphelper::getProcessComponentContext() );
2000 css::util::URL aCmd
;
2001 aCmd
.Complete
= "vnd.sun.star.autorecovery:/disableRecovery";
2002 xParser
->parseStrict(aCmd
);
2004 xRecovery
->dispatch(aCmd
, css::uno::Sequence
< css::beans::PropertyValue
>());
2006 catch(const css::uno::Exception
&)
2008 TOOLS_WARN_EXCEPTION( "desktop.app", "Could not disable AutoRecovery.");
2013 bool bCrashed
= false;
2014 bool bExistsRecoveryData
= false;
2015 bool bExistsSessionData
= false;
2016 bool const bDisableRecovery
2017 = getenv("OOO_DISABLE_RECOVERY") != nullptr
2018 || !officecfg::Office::Recovery::RecoveryInfo::Enabled::get();
2020 impl_checkRecoveryState(bCrashed
, bExistsRecoveryData
, bExistsSessionData
);
2022 if ( !bDisableRecovery
&&
2024 bExistsRecoveryData
|| // => crash with files => recovery
2025 bCrashed
// => crash without files => error report
2031 impl_callRecoveryUI(
2032 false , // false => force recovery instead of emergency save
2033 bExistsRecoveryData
);
2035 catch(const css::uno::Exception
&)
2037 TOOLS_WARN_EXCEPTION( "desktop.app", "Error during recovery");
2041 Reference
< XSessionManagerListener2
> xSessionListener
;
2044 // specifies whether the UI-interaction on Session shutdown is allowed
2045 bool bUIOnSessionShutdownAllowed
= officecfg::Office::Recovery::SessionShutdown::DocumentStoreUIEnabled::get();
2046 xSessionListener
= SessionListener::createWithOnQuitFlag(
2047 ::comphelper::getProcessComponentContext(), bUIOnSessionShutdownAllowed
);
2049 catch(const css::uno::Exception
&)
2051 TOOLS_WARN_EXCEPTION( "desktop.app", "Registration of session listener failed");
2054 if ( !bExistsRecoveryData
&& xSessionListener
.is() )
2056 // session management
2059 xSessionListener
->doRestore();
2061 catch(const css::uno::Exception
&)
2063 TOOLS_WARN_EXCEPTION( "desktop.app", "Error in session management");
2068 // write this information here to avoid depending on vcl in the crash reporter lib
2069 CrashReporter::addKeyValue("Language", Application::GetSettings().GetLanguageTag().getBcp47(), CrashReporter::Create
);
2071 RequestHandler::EnableRequests();
2073 ProcessDocumentsRequest
aRequest(rArgs
.getCwdUrl());
2074 aRequest
.aOpenList
= rArgs
.GetOpenList();
2075 aRequest
.aViewList
= rArgs
.GetViewList();
2076 aRequest
.aStartList
= rArgs
.GetStartList();
2077 aRequest
.aPrintList
= rArgs
.GetPrintList();
2078 aRequest
.aPrintToList
= rArgs
.GetPrintToList();
2079 aRequest
.aPrinterName
= rArgs
.GetPrinterName();
2080 aRequest
.aForceOpenList
= rArgs
.GetForceOpenList();
2081 aRequest
.aForceNewList
= rArgs
.GetForceNewList();
2082 aRequest
.aConversionList
= rArgs
.GetConversionList();
2083 aRequest
.aConversionParams
= rArgs
.GetConversionParams();
2084 aRequest
.aConversionOut
= rArgs
.GetConversionOut();
2085 aRequest
.aImageConversionType
= rArgs
.GetImageConversionType();
2086 aRequest
.aInFilter
= rArgs
.GetInFilter();
2087 aRequest
.bTextCat
= rArgs
.IsTextCat();
2088 aRequest
.bScriptCat
= rArgs
.IsScriptCat();
2090 if ( !aRequest
.aOpenList
.empty() ||
2091 !aRequest
.aViewList
.empty() ||
2092 !aRequest
.aStartList
.empty() ||
2093 !aRequest
.aPrintList
.empty() ||
2094 !aRequest
.aForceOpenList
.empty() ||
2095 !aRequest
.aForceNewList
.empty() ||
2096 ( !aRequest
.aPrintToList
.empty() && !aRequest
.aPrinterName
.isEmpty() ) ||
2097 !aRequest
.aConversionList
.empty() )
2099 if ( rArgs
.HasModuleParam() )
2101 SvtModuleOptions aOpt
;
2103 // Support command line parameters to start a module (as preselection)
2104 if ( rArgs
.IsWriter() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2105 aRequest
.aModule
= aOpt
.GetFactoryName( SvtModuleOptions::EFactory::WRITER
);
2106 else if ( rArgs
.IsCalc() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::CALC
) )
2107 aRequest
.aModule
= aOpt
.GetFactoryName( SvtModuleOptions::EFactory::CALC
);
2108 else if ( rArgs
.IsImpress() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS
) )
2109 aRequest
.aModule
= aOpt
.GetFactoryName( SvtModuleOptions::EFactory::IMPRESS
);
2110 else if ( rArgs
.IsDraw() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DRAW
) )
2111 aRequest
.aModule
= aOpt
.GetFactoryName( SvtModuleOptions::EFactory::DRAW
);
2114 // check for printing disabled
2115 if( ( !(aRequest
.aPrintList
.empty() && aRequest
.aPrintToList
.empty()) )
2116 && Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
2118 aRequest
.aPrintList
.clear();
2119 aRequest
.aPrintToList
.clear();
2120 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(nullptr,
2121 VclMessageType::Warning
, VclButtonsType::Ok
,
2122 DpResId(STR_ERR_PRINTDISABLED
)));
2127 if ( RequestHandler::ExecuteCmdLineRequests(aRequest
, false) )
2129 // Don't do anything if we have successfully called terminate at desktop:
2134 // no default document if a document was loaded by recovery or by command line or if soffice is used as server
2135 Reference
< XDesktop2
> xDesktop
= css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
2136 Reference
< XElementAccess
> xList( xDesktop
->getFrames(), UNO_QUERY_THROW
);
2137 if ( xList
->hasElements() )
2140 if ( rArgs
.IsQuickstart() || rArgs
.IsInvisible() || Application::AnyInput( VclInputFlags::APPEVENT
) )
2141 // soffice was started as tray icon ...
2147 void Desktop::OpenDefault()
2150 SvtModuleOptions aOpt
;
2152 const CommandLineArgs
& rArgs
= GetCommandLineArgs();
2153 if ( rArgs
.IsNoDefault() ) return;
2154 if ( rArgs
.HasModuleParam() )
2156 // Support new command line parameters to start a module
2157 if ( rArgs
.IsWriter() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2158 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER
);
2159 else if ( rArgs
.IsCalc() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::CALC
) )
2160 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC
);
2161 else if ( rArgs
.IsImpress() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS
) )
2162 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS
);
2163 else if ( rArgs
.IsBase() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE
) )
2164 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE
);
2165 else if ( rArgs
.IsDraw() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DRAW
) )
2166 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW
);
2167 else if ( rArgs
.IsMath() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::MATH
) )
2168 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::MATH
);
2169 else if ( rArgs
.IsGlobal() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2170 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITERGLOBAL
);
2171 else if ( rArgs
.IsWeb() && aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2172 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITERWEB
);
2175 if ( aName
.isEmpty() )
2177 if (aOpt
.IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE
))
2179 ShowBackingComponent(nullptr);
2183 // Old way to create a default document
2184 if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::WRITER
) )
2185 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER
);
2186 else if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::CALC
) )
2187 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC
);
2188 else if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS
) )
2189 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS
);
2190 else if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE
) )
2191 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE
);
2192 else if ( aOpt
.IsModuleInstalled( SvtModuleOptions::EModule::DRAW
) )
2193 aName
= aOpt
.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW
);
2198 ProcessDocumentsRequest
aRequest(rArgs
.getCwdUrl());
2199 aRequest
.aOpenList
.push_back(aName
);
2200 RequestHandler::ExecuteCmdLineRequests(aRequest
, false);
2204 OUString
GetURL_Impl(
2205 const OUString
& rName
, boost::optional
< OUString
> const & cwdUrl
)
2207 // if rName is a vnd.sun.star.script URL do not attempt to parse it
2208 // as INetURLObj does not handle URLs there
2209 if (rName
.startsWith("vnd.sun.star.script"))
2214 // don't touch file urls, those should already be in internal form
2215 // they won't get better here (#112849#)
2216 if (comphelper::isFileUrl(rName
))
2221 if ( rName
.startsWith("service:"))
2226 // Add path separator to these directory and make given URL (rName) absolute by using of current working directory
2227 // Attention: "setFinalSlash()" is necessary for calling "smartRel2Abs()"!!!
2228 // Otherwise last part will be ignored and wrong result will be returned!!!
2229 // "smartRel2Abs()" interpret given URL as file not as path. So he truncate last element to get the base path ...
2230 // But if we add a separator - he doesn't do it anymore.
2233 aObj
.SetURL(*cwdUrl
);
2234 aObj
.setFinalSlash();
2237 // Use the provided parameters for smartRel2Abs to support the usage of '%' in system paths.
2238 // Otherwise this char won't get encoded and we are not able to load such files later,
2240 INetURLObject aURL
= aObj
.smartRel2Abs( rName
, bWasAbsolute
, false, INetURLObject::EncodeMechanism::WasEncoded
,
2241 RTL_TEXTENCODING_UTF8
, true );
2242 OUString aFileURL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
2244 ::osl::FileStatus
aStatus( osl_FileStatus_Mask_FileURL
);
2245 ::osl::DirectoryItem aItem
;
2246 if( ::osl::FileBase::E_None
== ::osl::DirectoryItem::get( aFileURL
, aItem
) &&
2247 ::osl::FileBase::E_None
== aItem
.getFileStatus( aStatus
) )
2248 aFileURL
= aStatus
.getFileURL();
2253 void Desktop::HandleAppEvent( const ApplicationEvent
& rAppEvent
)
2255 switch ( rAppEvent
.GetEvent() )
2257 case ApplicationEvent::Type::Accept
:
2258 // every time an accept parameter is used we create an acceptor
2259 // with the corresponding accept-string
2260 createAcceptor(rAppEvent
.GetStringData());
2262 case ApplicationEvent::Type::Appear
:
2263 if ( !GetCommandLineArgs().IsInvisible() && !impl_bringToFrontRecoveryUI() )
2265 Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2267 // find active task - the active task is always a visible task
2268 Reference
< css::frame::XDesktop2
> xDesktop
= css::frame::Desktop::create( xContext
);
2269 Reference
< css::frame::XFrame
> xTask
= xDesktop
->getActiveFrame();
2272 // get any task if there is no active one
2273 Reference
< css::container::XIndexAccess
> xList
= xDesktop
->getFrames();
2274 if ( xList
->getCount() > 0 )
2275 xList
->getByIndex(0) >>= xTask
;
2280 Reference
< css::awt::XTopWindow
> xTop( xTask
->getContainerWindow(), UNO_QUERY
);
2285 // no visible task that could be activated found
2286 Reference
< css::awt::XWindow
> xContainerWindow
;
2287 Reference
< XFrame
> xBackingFrame
= xDesktop
->findFrame( "_blank", 0);
2288 if (xBackingFrame
.is())
2289 xContainerWindow
= xBackingFrame
->getContainerWindow();
2290 if (xContainerWindow
.is())
2292 Reference
< XController
> xStartModule
= StartModule::createWithParentWindow(xContext
, xContainerWindow
);
2293 Reference
< css::awt::XWindow
> xBackingWin(xStartModule
, UNO_QUERY
);
2294 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2295 // Because the backing component set the property "IsBackingMode" of the frame
2296 // to true inside attachFrame(). But setComponent() reset this state every time ...
2297 xBackingFrame
->setComponent(xBackingWin
, xStartModule
);
2298 xStartModule
->attachFrame(xBackingFrame
);
2299 xContainerWindow
->setVisible(true);
2301 VclPtr
<vcl::Window
> pCompWindow
= VCLUnoHelper::GetWindow(xBackingFrame
->getComponentWindow());
2303 pCompWindow
->Update();
2308 case ApplicationEvent::Type::Open
:
2310 const CommandLineArgs
& rCmdLine
= GetCommandLineArgs();
2311 if ( !rCmdLine
.IsInvisible() && !rCmdLine
.IsTerminateAfterInit() )
2313 ProcessDocumentsRequest
docsRequest(rCmdLine
.getCwdUrl());
2314 std::vector
<OUString
> const & data(rAppEvent
.GetStringsData());
2315 docsRequest
.aOpenList
.insert(
2316 docsRequest
.aOpenList
.end(), data
.begin(), data
.end());
2317 RequestHandler::ExecuteCmdLineRequests(docsRequest
, false);
2321 case ApplicationEvent::Type::OpenHelpUrl
:
2322 // start help for a specific URL
2323 Application::GetHelp()->Start(rAppEvent
.GetStringData(), static_cast<vcl::Window
*>(nullptr));
2325 case ApplicationEvent::Type::Print
:
2327 const CommandLineArgs
& rCmdLine
= GetCommandLineArgs();
2328 if ( !rCmdLine
.IsInvisible() && !rCmdLine
.IsTerminateAfterInit() )
2330 ProcessDocumentsRequest
docsRequest(rCmdLine
.getCwdUrl());
2331 std::vector
<OUString
> const & data(rAppEvent
.GetStringsData());
2332 docsRequest
.aPrintList
.insert(
2333 docsRequest
.aPrintList
.end(), data
.begin(), data
.end());
2334 RequestHandler::ExecuteCmdLineRequests(docsRequest
, false);
2338 case ApplicationEvent::Type::PrivateDoShutdown
:
2340 Desktop
* pD
= dynamic_cast<Desktop
*>(GetpApp());
2341 OSL_ENSURE( pD
, "no desktop ?!?" );
2346 case ApplicationEvent::Type::QuickStart
:
2347 if ( !GetCommandLineArgs().IsInvisible() )
2349 // If the office has been started the second time its command line arguments are sent through a pipe
2350 // connection to the first office. We want to reuse the quickstart option for the first office.
2351 // NOTICE: The quickstart service must be initialized inside the "main thread", so we use the
2352 // application events to do this (they are executed inside main thread)!!!
2353 // Don't start quickstart service if the user specified "--invisible" on the command line!
2354 Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2355 css::office::Quickstart::createStart(xContext
, true/*Quickstart*/);
2358 case ApplicationEvent::Type::ShowDialog
:
2359 // ignore all errors here. It's clicking a menu entry only ...
2360 // The user will try it again, in case nothing happens .-)
2363 Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2365 Reference
< css::frame::XDesktop2
> xDesktop
= css::frame::Desktop::create( xContext
);
2367 Reference
< css::util::XURLTransformer
> xParser
= css::util::URLTransformer::create(xContext
);
2368 css::util::URL aCommand
;
2369 if( rAppEvent
.GetStringData() == "PREFERENCES" )
2370 aCommand
.Complete
= ".uno:OptionsTreeDialog";
2371 else if( rAppEvent
.GetStringData() == "ABOUT" )
2372 aCommand
.Complete
= ".uno:About";
2373 if( !aCommand
.Complete
.isEmpty() )
2375 xParser
->parseStrict(aCommand
);
2377 css::uno::Reference
< css::frame::XDispatch
> xDispatch
= xDesktop
->queryDispatch(aCommand
, OUString(), 0);
2379 xDispatch
->dispatch(aCommand
, css::uno::Sequence
< css::beans::PropertyValue
>());
2382 catch(const css::uno::Exception
&)
2385 case ApplicationEvent::Type::Unaccept
:
2386 // try to remove corresponding acceptor
2387 destroyAcceptor(rAppEvent
.GetStringData());
2390 SAL_WARN( "desktop.app", "this cannot happen");
2395 void Desktop::OpenSplashScreen()
2397 const CommandLineArgs
&rCmdLine
= GetCommandLineArgs();
2398 // Show intro only if this is normal start (e.g. no server, no quickstart, no printing )
2399 if ( !rCmdLine
.IsInvisible() &&
2400 !rCmdLine
.IsHeadless() &&
2401 !rCmdLine
.IsQuickstart() &&
2402 !rCmdLine
.IsMinimized() &&
2403 !rCmdLine
.IsNoLogo() &&
2404 !rCmdLine
.IsTerminateAfterInit() &&
2405 rCmdLine
.GetPrintList().empty() &&
2406 rCmdLine
.GetPrintToList().empty() &&
2407 rCmdLine
.GetConversionList().empty() )
2409 // Determine application name from command line parameters
2411 if ( rCmdLine
.IsWriter() )
2412 aAppName
= "writer";
2413 else if ( rCmdLine
.IsCalc() )
2415 else if ( rCmdLine
.IsDraw() )
2417 else if ( rCmdLine
.IsImpress() )
2418 aAppName
= "impress";
2419 else if ( rCmdLine
.IsBase() )
2421 else if ( rCmdLine
.IsGlobal() )
2422 aAppName
= "global";
2423 else if ( rCmdLine
.IsMath() )
2425 else if ( rCmdLine
.IsWeb() )
2428 // Which splash to use
2429 OUString
aSplashService( "com.sun.star.office.SplashScreen" );
2430 if ( rCmdLine
.HasSplashPipe() )
2431 aSplashService
= "com.sun.star.office.PipeSplashScreen";
2433 Sequence
< Any
> aSeq( 2 );
2434 aSeq
[0] <<= true; // bVisible
2435 aSeq
[1] <<= aAppName
;
2436 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2437 m_rSplashScreen
.set(
2438 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(aSplashService
, aSeq
, xContext
),
2441 if(m_rSplashScreen
.is())
2442 m_rSplashScreen
->start("SplashScreen", 100);
2447 void Desktop::SetSplashScreenProgress(sal_Int32 iProgress
)
2449 if(m_rSplashScreen
.is())
2451 m_rSplashScreen
->setValue(iProgress
);
2455 void Desktop::SetSplashScreenText( const OUString
& rText
)
2457 if( m_rSplashScreen
.is() )
2459 m_rSplashScreen
->setText( rText
);
2463 void Desktop::CloseSplashScreen()
2465 if(m_rSplashScreen
.is())
2467 m_rSplashScreen
->end();
2468 m_rSplashScreen
= nullptr;
2473 IMPL_STATIC_LINK_NOARG(Desktop
, AsyncInitFirstRun
, Timer
*, void)
2475 // does initializations which are necessary for the first run of the office
2478 Reference
< XJobExecutor
> xExecutor
= theJobExecutor::get( ::comphelper::getProcessComponentContext() );
2479 xExecutor
->trigger( "onFirstRunInitialization" );
2481 catch(const css::uno::Exception
&)
2483 TOOLS_WARN_EXCEPTION( "desktop.app", "Desktop::DoFirstRunInitializations: caught an exception while trigger job executor" );
2487 void Desktop::ShowBackingComponent(Desktop
* progress
)
2489 if (GetCommandLineArgs().IsNoDefault())
2493 Reference
< XComponentContext
> xContext
= comphelper::getProcessComponentContext();
2494 Reference
< XDesktop2
> xDesktop
= css::frame::Desktop::create(xContext
);
2495 if (progress
!= nullptr)
2497 progress
->SetSplashScreenProgress(60);
2499 Reference
< XFrame
> xBackingFrame
= xDesktop
->findFrame( "_blank", 0);
2500 Reference
< css::awt::XWindow
> xContainerWindow
;
2502 if (xBackingFrame
.is())
2503 xContainerWindow
= xBackingFrame
->getContainerWindow();
2504 if (xContainerWindow
.is())
2506 // set the WindowExtendedStyle::Document style. Normally, this is done by the TaskCreator service when a "_blank"
2507 // frame/window is created. Since we do not use the TaskCreator here, we need to mimic its behavior,
2508 // otherwise documents loaded into this frame will later on miss functionality depending on the style.
2509 VclPtr
<vcl::Window
> pContainerWindow
= VCLUnoHelper::GetWindow( xContainerWindow
);
2510 SAL_WARN_IF( !pContainerWindow
, "desktop.app", "Desktop::Main: no implementation access to the frame's container window!" );
2511 pContainerWindow
->SetExtendedStyle( pContainerWindow
->GetExtendedStyle() | WindowExtendedStyle::Document
);
2512 if (progress
!= nullptr)
2514 progress
->SetSplashScreenProgress(75);
2517 Reference
< XController
> xStartModule
= StartModule::createWithParentWindow( xContext
, xContainerWindow
);
2518 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2519 // Because the backing component set the property "IsBackingMode" of the frame
2520 // to true inside attachFrame(). But setComponent() reset this state everytimes ...
2521 xBackingFrame
->setComponent(Reference
< XWindow
>(xStartModule
, UNO_QUERY
), xStartModule
);
2522 if (progress
!= nullptr)
2524 progress
->SetSplashScreenProgress(100);
2526 xStartModule
->attachFrame(xBackingFrame
);
2527 if (progress
!= nullptr)
2529 progress
->CloseSplashScreen();
2531 xContainerWindow
->setVisible(true);
2536 void Desktop::CheckFirstRun( )
2538 if (officecfg::Office::Common::Misc::FirstRun::get())
2540 // use VCL timer, which won't trigger during shutdown if the
2541 // application exits before timeout
2542 m_firstRunTimer
.Start();
2545 // Check if Quickstarter should be started (on Windows only)
2546 WCHAR szValue
[8192];
2547 DWORD nValueSize
= sizeof(szValue
);
2549 if ( ERROR_SUCCESS
== RegOpenKeyW( HKEY_LOCAL_MACHINE
, L
"Software\\LibreOffice", &hKey
) )
2551 if ( ERROR_SUCCESS
== RegQueryValueExW( hKey
, L
"RunQuickstartAtFirstStart", nullptr, nullptr, reinterpret_cast<LPBYTE
>(szValue
), &nValueSize
) )
2553 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
2554 css::office::Quickstart::createAutoStart(xContext
, true/*Quickstart*/, true/*bAutostart*/);
2555 RegCloseKey( hKey
);
2560 std::shared_ptr
< comphelper::ConfigurationChanges
> batch(
2561 comphelper::ConfigurationChanges::create());
2562 officecfg::Office::Common::Misc::FirstRun::set(false, batch
);
2569 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */