/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #if !defined(NTDDI_VERSION) || NTDDI_VERSION < NTDDI_WIN8 #define NTDDI_VERSION NTDDI_WIN8 // needed for IApplicationActivationManager #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_LONG_PATH 32767 namespace vcl::fileregistration { static void LaunchModernSettingsDialogDefaultApps() { sal::systools::COMReference pIf( CLSID_ApplicationActivationManager, nullptr, CLSCTX_INPROC_SERVER); DWORD pid; HRESULT hr = pIf->ActivateApplication(L"windows.immersivecontrolpanel_cw5n1h2txyewy" L"!microsoft.windows.immersivecontrolpanel", L"page=SettingsPageAppsDefaults", AO_NONE, &pid); if (SUCCEEDED(hr)) { // Do not check error because we could at least open // the "Default apps" setting. pIf->ActivateApplication(L"windows.immersivecontrolpanel_cw5n1h2txyewy" L"!microsoft.windows.immersivecontrolpanel", L"page=SettingsPageAppsDefaults" L"&target=SettingsPageAppsDefaultsDefaultAppsListView", AO_NONE, &pid); } } static HRESULT IsPathDefaultForClass(sal::systools::COMReference& pAAR, LPCWSTR aClassName, LPCWSTR progID) { // Make sure the Prog ID matches what we have LPWSTR registeredApp; HRESULT hr = pAAR->QueryCurrentDefault(aClassName, AT_FILEEXTENSION, AL_EFFECTIVE, ®isteredApp); if (FAILED(hr)) { return hr; } if (!wcsnicmp(registeredApp, progID, wcslen(progID))) hr = S_OK; else hr = S_FALSE; CoTaskMemFree(registeredApp); return hr; } static bool IsDefaultAppInstalledInReg() { const wchar_t* keyPath = L"SOFTWARE\\LibreOffice\\UNO\\InstallPath"; WCHAR szRegPath[MAX_LONG_PATH]; DWORD cbData = static_cast(MAX_LONG_PATH * sizeof(WCHAR)); auto rc = RegGetValueW(HKEY_LOCAL_MACHINE, keyPath, nullptr, RRF_RT_REG_SZ, nullptr, static_cast(szRegPath), &cbData); if (rc != ERROR_SUCCESS) return false; WCHAR szProcPath[MAX_LONG_PATH]; if (!GetModuleFileNameW(nullptr, szProcPath, MAX_LONG_PATH)) return false; WCHAR szFullProcPath[MAX_LONG_PATH]; if (!GetFullPathNameW(szProcPath, MAX_LONG_PATH, szFullProcPath, nullptr)) return false; if (!GetLongPathNameW(szFullProcPath, szFullProcPath, MAX_LONG_PATH)) return false; if (!GetLongPathNameW(szRegPath, szRegPath, MAX_LONG_PATH)) return false; if (wcslen(szRegPath) > 0 && wcsstr(szFullProcPath, szRegPath) != nullptr) return true; return false; } void LaunchRegistrationUI() { try { sal::systools::CoInitializeGuard aGuard(COINIT_APARTMENTTHREADED); if (IsWindows10OrGreater()) { LaunchModernSettingsDialogDefaultApps(); } else { sal::systools::COMReference pIf( CLSID_ApplicationAssociationRegistrationUI, nullptr, CLSCTX_INPROC_SERVER); // LaunchAdvancedAssociationUI only works for applications registered under // Software\RegisteredApplications. See scp2/source/ooo/registryitem_ooo.scp const OUString expanded = Translate::ExpandVariables("%PRODUCTNAME %PRODUCTVERSION"); pIf->LaunchAdvancedAssociationUI(o3tl::toW(expanded.getStr())); } } catch (...) { // Just ignore any error here: this is not something we need to make sure to succeed } } void CheckFileExtRegistration(weld::Window* pDialogParent) { if (!officecfg::Office::Common::Misc::PerformFileExtCheck::get()) return; if (!IsDefaultAppInstalledInReg()) return; sal::systools::CoInitializeGuard aGuard(COINIT_APARTMENTTHREADED, false, sal::systools::CoInitializeGuard::WhenFailed::NoThrow); sal::systools::COMReference pAAR; try { pAAR.CoCreateInstance(CLSID_ApplicationAssociationRegistration, nullptr, CLSCTX_INPROC_SERVER); } catch (...) { // Just return on any error here: this is not something we need to make sure to succeed return; } static const std::pair formats[] = { { L".odp", L"LibreOffice.ImpressDocument.1" }, { L".odt", L"LibreOffice.WriterDocument.1" }, { L".ods", L"LibreOffice.CalcDocument.1" }, }; OUString aNonDefaults; for (const auto & [ szExt, szProgId ] : formats) { if (IsPathDefaultForClass(pAAR, szExt, szProgId) == S_FALSE) aNonDefaults += OUString::Concat(o3tl::toU(szExt)) + "\n"; } if (!aNonDefaults.isEmpty()) { OUString aMsg(VclResId(STR_FILEEXT_NONDEFAULT_ASK_MSG).replaceFirst("$1", aNonDefaults)); VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); ScopedVclPtr pDlg(pFact->CreateFileExtCheckDialog( pDialogParent, VclResId(STR_FILEEXT_NONDEFAULT_ASK_TITLE), aMsg)); pDlg->Execute(); } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */