diff options
Diffstat (limited to 'vcl/win/app/fileregistration.cxx')
-rw-r--r-- | vcl/win/app/fileregistration.cxx | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/vcl/win/app/fileregistration.cxx b/vcl/win/app/fileregistration.cxx new file mode 100644 index 000000000000..863e66d0a3b1 --- /dev/null +++ b/vcl/win/app/fileregistration.cxx @@ -0,0 +1,198 @@ +/* -*- 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 <sal/config.h> + +#include <comphelper/scopeguard.hxx> +#include <o3tl/char16_t2wchar_t.hxx> +#include <vcl/abstdlg.hxx> +#include <vcl/fileregistration.hxx> + +#include <strings.hrc> + +#include <prewin.h> +#include <Shobjidl.h> +#include <systools/win32/comtools.hxx> +#include <versionhelpers.h> +#include <postwin.h> + +#define MAX_LONG_PATH 32767 + +namespace vcl::fileregistration +{ +static void LaunchModernSettingsDialogDefaultApps() +{ + auto pIf = sal::systools::COMReference<IApplicationActivationManager>().CoCreateInstance( + 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<IApplicationAssociationRegistration>& 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<DWORD>(MAX_LONG_PATH * sizeof(WCHAR)); + auto rc = RegGetValueW(HKEY_LOCAL_MACHINE, keyPath, nullptr, RRF_RT_REG_SZ, nullptr, + static_cast<PVOID>(szRegPath), &cbData); + if (rc != ERROR_SUCCESS) + return false; + + WCHAR szProcPath[MAX_LONG_PATH]; + if (!GetModuleFileNameW(NULL, szProcPath, MAX_LONG_PATH)) + return false; + + WCHAR szFullProcPath[MAX_LONG_PATH]; + if (!GetFullPathNameW(szProcPath, MAX_LONG_PATH, szFullProcPath, NULL)) + 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) != NULL) + return true; + + return false; +} + +void LaunchRegistrationUI() +{ + const bool bUninit = SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)); + comphelper::ScopeGuard g([bUninit]() { + if (bUninit) + CoUninitialize(); + }); + + try + { + if (IsWindows10OrGreater()) + { + LaunchModernSettingsDialogDefaultApps(); + } + else + { + auto pIf = sal::systools::COMReference<IApplicationAssociationRegistrationUI>() + .CoCreateInstance(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; + + const bool bUninit = SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)); + comphelper::ScopeGuard g([bUninit]() { + if (bUninit) + CoUninitialize(); + }); + sal::systools::COMReference<IApplicationAssociationRegistration> pAAR = nullptr; + try + { + pAAR = sal::systools::COMReference<IApplicationAssociationRegistration>().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; + } + + std::map<OUString, OUString> formats = { + { ".odp", "LibreOffice.ImpressDocument.1" }, + { ".odt", "LibreOffice.WriterDocument.1" }, + { ".ods", "LibreOffice.CalcDocument.1" }, + }; + OUString aNonDefaults; + bool isNotDefault = false; + + for (std::map<OUString, OUString>::iterator it = formats.begin(); it != formats.end(); it++) + { + if (IsPathDefaultForClass(pAAR, o3tl::toW(it->first.getStr()), + o3tl::toW(it->second.getStr())) + == S_FALSE) + { + isNotDefault = true; + aNonDefaults += it->first; + aNonDefaults += "\n"; + } + } + + if (isNotDefault) + { + OUString aMsg(VclResId(STR_FILEEXT_NONDEFAULT_ASK_MSG)); + aMsg = aMsg.replaceFirst("$1", aNonDefaults); + + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> 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: */ |