diff options
Diffstat (limited to 'browser/components/shell/WindowsDefaultBrowser.cpp')
-rw-r--r-- | browser/components/shell/WindowsDefaultBrowser.cpp | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/browser/components/shell/WindowsDefaultBrowser.cpp b/browser/components/shell/WindowsDefaultBrowser.cpp new file mode 100644 index 0000000000..34e00be89f --- /dev/null +++ b/browser/components/shell/WindowsDefaultBrowser.cpp @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +/** + * This file exists so that LaunchModernSettingsDialogDefaultApps can be called + * without linking to libxul. + */ +#include "WindowsDefaultBrowser.h" + +#include "city.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WindowsVersion.h" +#include "mozilla/WinHeaderOnlyUtils.h" + +// Needed for access to IApplicationActivationManager +// This must be before any other includes that might include shlobj.h +#ifdef _WIN32_WINNT +# undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 +#define INITGUID +#undef NTDDI_VERSION +#define NTDDI_VERSION NTDDI_WIN8 +#include <shlobj.h> + +#include <lm.h> +#include <shlwapi.h> +#include <wchar.h> +#include <windows.h> + +#define APP_REG_NAME_BASE L"Firefox-" + +static bool IsWindowsLogonConnected() { + WCHAR userName[UNLEN + 1]; + DWORD size = mozilla::ArrayLength(userName); + if (!GetUserNameW(userName, &size)) { + return false; + } + + LPUSER_INFO_24 info; + if (NetUserGetInfo(nullptr, userName, 24, (LPBYTE*)&info) != NERR_Success) { + return false; + } + bool connected = info->usri24_internet_identity; + NetApiBufferFree(info); + + return connected; +} + +static bool SettingsAppBelievesConnected() { + const wchar_t* keyPath = L"SOFTWARE\\Microsoft\\Windows\\Shell\\Associations"; + const wchar_t* valueName = L"IsConnectedAtLogon"; + + uint32_t value = 0; + DWORD size = sizeof(uint32_t); + LSTATUS ls = RegGetValueW(HKEY_CURRENT_USER, keyPath, valueName, RRF_RT_ANY, + nullptr, &value, &size); + if (ls != ERROR_SUCCESS) { + return false; + } + + return !!value; +} + +bool GetAppRegName(mozilla::UniquePtr<wchar_t[]>& aAppRegName) { + mozilla::UniquePtr<wchar_t[]> appDirStr; + bool success = GetInstallDirectory(appDirStr); + if (!success) { + return success; + } + + uint64_t hash = CityHash64(reinterpret_cast<char*>(appDirStr.get()), + wcslen(appDirStr.get()) * sizeof(wchar_t)); + + const wchar_t* format = L"%s%I64X"; + int bufferSize = _scwprintf(format, APP_REG_NAME_BASE, hash); + ++bufferSize; // Extra byte for terminating null + aAppRegName = mozilla::MakeUnique<wchar_t[]>(bufferSize); + + _snwprintf_s(aAppRegName.get(), bufferSize, _TRUNCATE, format, + APP_REG_NAME_BASE, hash); + + return success; +} + +bool LaunchControlPanelDefaultPrograms() { + // Build the path control.exe path safely + WCHAR controlEXEPath[MAX_PATH + 1] = {'\0'}; + if (!GetSystemDirectoryW(controlEXEPath, MAX_PATH)) { + return false; + } + LPCWSTR controlEXE = L"control.exe"; + if (wcslen(controlEXEPath) + wcslen(controlEXE) >= MAX_PATH) { + return false; + } + if (!PathAppendW(controlEXEPath, controlEXE)) { + return false; + } + + const wchar_t* paramFormat = + L"control.exe /name Microsoft.DefaultPrograms " + L"/page pageDefaultProgram\\pageAdvancedSettings?pszAppName=%s"; + mozilla::UniquePtr<wchar_t[]> appRegName; + GetAppRegName(appRegName); + int bufferSize = _scwprintf(paramFormat, appRegName.get()); + ++bufferSize; // Extra byte for terminating null + mozilla::UniquePtr<wchar_t[]> params = + mozilla::MakeUnique<wchar_t[]>(bufferSize); + _snwprintf_s(params.get(), bufferSize, _TRUNCATE, paramFormat, + appRegName.get()); + + STARTUPINFOW si = {sizeof(si), 0}; + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_SHOWDEFAULT; + PROCESS_INFORMATION pi = {0}; + if (!CreateProcessW(controlEXEPath, params.get(), nullptr, nullptr, FALSE, 0, + nullptr, nullptr, &si, &pi)) { + return false; + } + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return true; +} + +bool LaunchModernSettingsDialogDefaultApps() { + if (!mozilla::IsWindowsBuildOrLater(14965) && !IsWindowsLogonConnected() && + SettingsAppBelievesConnected()) { + // Use the classic Control Panel to work around a bug of older + // builds of Windows 10. + return LaunchControlPanelDefaultPrograms(); + } + + IApplicationActivationManager* pActivator; + HRESULT hr = CoCreateInstance( + CLSID_ApplicationActivationManager, nullptr, CLSCTX_INPROC, + IID_IApplicationActivationManager, (void**)&pActivator); + + if (SUCCEEDED(hr)) { + DWORD pid; + hr = pActivator->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. + pActivator->ActivateApplication( + L"windows.immersivecontrolpanel_cw5n1h2txyewy" + L"!microsoft.windows.immersivecontrolpanel", + L"page=SettingsPageAppsDefaults" + L"&target=SystemSettings_DefaultApps_Browser", + AO_NONE, &pid); + } + pActivator->Release(); + return SUCCEEDED(hr); + } + return true; +} |