diff options
Diffstat (limited to 'vcl/win/app/fileregistration.cxx')
-rw-r--r-- | vcl/win/app/fileregistration.cxx | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/vcl/win/app/fileregistration.cxx b/vcl/win/app/fileregistration.cxx new file mode 100644 index 0000000000..ec7ccbcee2 --- /dev/null +++ b/vcl/win/app/fileregistration.cxx @@ -0,0 +1,182 @@ +/* -*- 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 <officecfg/Office/Common.hxx> +#include <unotools/resmgr.hxx> +#include <vcl/abstdlg.hxx> +#include <vcl/fileregistration.hxx> + +#include <strings.hrc> +#include <svdata.hxx> + +#include <utility> + +#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() +{ + sal::systools::COMReference<IApplicationActivationManager> 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<IApplicationAssociationRegistration>& pAAR, + LPCWSTR aClassName, LPCWSTR progID) +{ + // Make sure the Prog ID matches what we have + sal::systools::CoTaskMemAllocated<wchar_t> registeredApp; + HRESULT hr + = pAAR->QueryCurrentDefault(aClassName, AT_FILEEXTENSION, AL_EFFECTIVE, ®isteredApp); + if (SUCCEEDED(hr)) + { + if (wcsnicmp(registeredApp, progID, wcslen(progID)) == 0) + hr = S_OK; + else + hr = S_FALSE; + } + + 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(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<IApplicationAssociationRegistrationUI> 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<IApplicationAssociationRegistration> 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<LPCWSTR, LPCWSTR> 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<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: */ |