Backed out changeset 45ab2db62a65 (bug 1818418) for causing bustages in WindowsUserChoice.h

This commit is contained in:
Noemi Erli
2023-11-04 11:07:26 +02:00
parent 199ab9f337
commit 41830fefad
5 changed files with 130 additions and 300 deletions

View File

@@ -20,16 +20,13 @@
*/ */
#include <windows.h> #include <windows.h>
#include <appmodel.h> // for GetPackageFamilyName
#include <sddl.h> // for ConvertSidToStringSidW #include <sddl.h> // for ConvertSidToStringSidW
#include <wincrypt.h> // for CryptoAPI base64 #include <wincrypt.h> // for CryptoAPI base64
#include <bcrypt.h> // for CNG MD5 #include <bcrypt.h> // for CNG MD5
#include <winternl.h> // for NT_SUCCESS() #include <winternl.h> // for NT_SUCCESS()
#include "ErrorList.h"
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "nsDebug.h"
#include "nsWindowsHelpers.h" #include "nsWindowsHelpers.h"
#include "WindowsUserChoice.h" #include "WindowsUserChoice.h"
@@ -423,53 +420,3 @@ bool CheckProgIDExists(const wchar_t* aProgID) {
::RegCloseKey(key); ::RegCloseKey(key);
return true; return true;
} }
nsresult GetMsixProgId(const wchar_t* assoc, UniquePtr<wchar_t[]>& aProgId) {
// Retrieve the registry path to the package from registry path:
// clang-format off
// HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\[Package Full Name]\App\Capabilities\[FileAssociations | URLAssociations]\[File | URL]
// clang-format on
UINT32 pfnLen = 0;
LONG rv = GetCurrentPackageFullName(&pfnLen, nullptr);
NS_ENSURE_TRUE(rv != APPMODEL_ERROR_NO_PACKAGE, NS_ERROR_FAILURE);
auto pfn = mozilla::MakeUnique<wchar_t[]>(pfnLen);
rv = GetCurrentPackageFullName(&pfnLen, pfn.get());
NS_ENSURE_TRUE(rv == ERROR_SUCCESS, NS_ERROR_FAILURE);
const wchar_t* assocSuffix;
if (assoc[0] == L'.') {
// File association.
assocSuffix = LR"(App\Capabilities\FileAssociations)";
} else {
// URL association.
assocSuffix = LR"(App\Capabilities\URLAssociations)";
}
const wchar_t* assocPathFmt =
LR"(Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\%s\%s)";
int assocPathLen = _scwprintf(assocPathFmt, pfn.get(), assocSuffix);
assocPathLen += 1; // _scwprintf does not include the terminator
auto assocPath = MakeUnique<wchar_t[]>(assocPathLen);
_snwprintf_s(assocPath.get(), assocPathLen, _TRUNCATE, assocPathFmt,
pfn.get(), assocSuffix);
LSTATUS ls;
// Retrieve the package association's ProgID, always in the form `AppX[32 hash
// characters]`.
const size_t appxProgIdLen = 37;
auto progId = MakeUnique<wchar_t[]>(appxProgIdLen);
DWORD progIdLen = appxProgIdLen * sizeof(wchar_t);
ls = ::RegGetValueW(HKEY_CLASSES_ROOT, assocPath.get(), assoc, RRF_RT_REG_SZ,
nullptr, (LPBYTE)progId.get(), &progIdLen);
if (ls != ERROR_SUCCESS) {
return NS_ERROR_WDBA_NO_PROGID;
}
aProgId.swap(progId);
return NS_OK;
}

View File

@@ -100,17 +100,4 @@ mozilla::UniquePtr<wchar_t[]> FormatProgID(const wchar_t* aProgIDBase,
*/ */
bool CheckProgIDExists(const wchar_t* aProgID); bool CheckProgIDExists(const wchar_t* aProgID);
/*
* Get the ProgID registered by Windows for the given association.
*
* The MSIX `AppManifest.xml` declares supported protocols and file
* type associations. Upon installation, Windows generates
* corresponding ProgIDs for them, of the form `AppX*`. This function
* retrieves those generated ProgIDs (from the Windows registry).
*
* @return ProgID.
*/
nsresult GetMsixProgId(const wchar_t* assoc,
mozilla::UniquePtr<wchar_t[]>& aProgId);
#endif // SHELL_WINDOWSUSERCHOICE_H__ #endif // SHELL_WINDOWSUSERCHOICE_H__

View File

@@ -300,41 +300,10 @@ nsWindowsShellService::CheckAllProgIDsExist(bool* aResult) {
if (!mozilla::widget::WinTaskbar::GetAppUserModelID(aumid)) { if (!mozilla::widget::WinTaskbar::GetAppUserModelID(aumid)) {
return NS_OK; return NS_OK;
} }
*aResult =
if (widget::WinUtils::HasPackageIdentity()) { CheckProgIDExists(FormatProgID(L"FirefoxURL", aumid.get()).get()) &&
UniquePtr<wchar_t[]> extraProgID; CheckProgIDExists(FormatProgID(L"FirefoxHTML", aumid.get()).get()) &&
nsresult rv; CheckProgIDExists(FormatProgID(L"FirefoxPDF", aumid.get()).get());
bool result = true;
// "FirefoxURL".
rv = GetMsixProgId(L"https", extraProgID);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
result = result && CheckProgIDExists(extraProgID.get());
// "FirefoxHTML".
rv = GetMsixProgId(L".htm", extraProgID);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
result = result && CheckProgIDExists(extraProgID.get());
// "FirefoxPDF".
rv = GetMsixProgId(L".pdf", extraProgID);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
result = result && CheckProgIDExists(extraProgID.get());
*aResult = result;
} else {
*aResult =
CheckProgIDExists(FormatProgID(L"FirefoxURL", aumid.get()).get()) &&
CheckProgIDExists(FormatProgID(L"FirefoxHTML", aumid.get()).get()) &&
CheckProgIDExists(FormatProgID(L"FirefoxPDF", aumid.get()).get());
}
return NS_OK; return NS_OK;
} }

View File

@@ -198,8 +198,9 @@ def get_branding(use_official, topsrcdir, build_app, finder, log=None):
conf_vars = mozpath.join(topsrcdir, build_app, "confvars.sh") conf_vars = mozpath.join(topsrcdir, build_app, "confvars.sh")
def conf_vars_value(key): def conf_vars_value(key):
lines = [line.strip() for line in open(conf_vars).readlines()] lines = open(conf_vars).readlines()
for line in lines: for line in lines:
line = line.strip()
if line and line[0] == "#": if line and line[0] == "#":
continue continue
if key not in line: if key not in line:
@@ -832,7 +833,7 @@ def _sign_msix_win(output, force, log, verbose):
else: else:
thumbprint = None thumbprint = None
if force or not thumbprint: if not thumbprint:
thumbprint = ( thumbprint = (
powershell( powershell(
( (

View File

@@ -4,11 +4,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <windows.h> #include <windows.h>
#include <appmodel.h>
#include <shlobj.h> // for SHChangeNotify and IApplicationAssociationRegistration #include <shlobj.h> // for SHChangeNotify and IApplicationAssociationRegistration
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/WindowsVersion.h" #include "mozilla/WindowsVersion.h"
@@ -88,8 +86,50 @@ static bool CheckEqualMinutes(SYSTEMTIME aSystemTime1,
(fileTime1.dwHighDateTime == fileTime2.dwHighDateTime); (fileTime1.dwHighDateTime == fileTime2.dwHighDateTime);
} }
static bool SetUserChoiceRegistry(const wchar_t* aExt, const wchar_t* aProgID, /*
mozilla::UniquePtr<wchar_t[]> aHash) { * Set an association with a UserChoice key
*
* Removes the old key, creates a new one with ProgID and Hash set to
* enable a new asociation.
*
* @param aExt File type or protocol to associate
* @param aSid Current user's string SID
* @param aProgID ProgID to use for the asociation
*
* @return true if successful, false on error.
*/
static bool SetUserChoice(const wchar_t* aExt, const wchar_t* aSid,
const wchar_t* aProgID) {
SYSTEMTIME hashTimestamp;
::GetSystemTime(&hashTimestamp);
auto hash = GenerateUserChoiceHash(aExt, aSid, aProgID, hashTimestamp);
if (!hash) {
return false;
}
// The hash changes at the end of each minute, so check that the hash should
// be the same by the time we're done writing.
const ULONGLONG kWriteTimingThresholdMilliseconds = 100;
// Generating the hash could have taken some time, so start from now.
SYSTEMTIME writeEndTimestamp;
::GetSystemTime(&writeEndTimestamp);
if (!AddMillisecondsToSystemTime(writeEndTimestamp,
kWriteTimingThresholdMilliseconds)) {
return false;
}
if (!CheckEqualMinutes(hashTimestamp, writeEndTimestamp)) {
LOG_ERROR_MESSAGE(
L"Hash is too close to expiration, sleeping until next hash.");
::Sleep(kWriteTimingThresholdMilliseconds * 2);
// For consistency, use the current time.
::GetSystemTime(&hashTimestamp);
hash = GenerateUserChoiceHash(aExt, aSid, aProgID, hashTimestamp);
if (!hash) {
return false;
}
}
auto assocKeyPath = GetAssociationKeyPath(aExt); auto assocKeyPath = GetAssociationKeyPath(aExt);
if (!assocKeyPath) { if (!assocKeyPath) {
return false; return false;
@@ -134,9 +174,9 @@ static bool SetUserChoiceRegistry(const wchar_t* aExt, const wchar_t* aProgID,
return false; return false;
} }
DWORD hashByteCount = (::lstrlenW(aHash.get()) + 1) * sizeof(wchar_t); DWORD hashByteCount = (::lstrlenW(hash.get()) + 1) * sizeof(wchar_t);
ls = ::RegSetValueExW(userChoiceKey.get(), L"Hash", 0, REG_SZ, ls = ::RegSetValueExW(userChoiceKey.get(), L"Hash", 0, REG_SZ,
reinterpret_cast<const unsigned char*>(aHash.get()), reinterpret_cast<const unsigned char*>(hash.get()),
hashByteCount); hashByteCount);
if (ls != ERROR_SUCCESS) { if (ls != ERROR_SUCCESS) {
LOG_ERROR(HRESULT_FROM_WIN32(ls)); LOG_ERROR(HRESULT_FROM_WIN32(ls));
@@ -146,162 +186,6 @@ static bool SetUserChoiceRegistry(const wchar_t* aExt, const wchar_t* aProgID,
return true; return true;
} }
static bool LaunchReg(int aArgsLength, const wchar_t* const* aArgs) {
mozilla::UniquePtr<wchar_t[]> regPath =
mozilla::MakeUnique<wchar_t[]>(MAX_PATH + 1);
if (!ConstructSystem32Path(L"reg.exe", regPath.get(), MAX_PATH + 1)) {
LOG_ERROR_MESSAGE(L"Failed to construct path to reg.exe");
return false;
}
const wchar_t* regArgs[] = {regPath.get()};
mozilla::UniquePtr<wchar_t[]> regCmdLine(mozilla::MakeCommandLine(
mozilla::ArrayLength(regArgs), const_cast<wchar_t**>(regArgs),
aArgsLength, const_cast<wchar_t**>(aArgs)));
PROCESS_INFORMATION pi;
STARTUPINFOW si = {sizeof(si)};
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
if (!::CreateProcessW(regPath.get(), regCmdLine.get(), nullptr, nullptr,
FALSE, 0, nullptr, nullptr, &si, &pi)) {
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
LOG_ERROR(hr);
return false;
}
nsAutoHandle process(pi.hProcess);
nsAutoHandle mainThread(pi.hThread);
DWORD exitCode;
if (::WaitForSingleObject(process.get(), INFINITE) == WAIT_OBJECT_0 &&
::GetExitCodeProcess(process.get(), &exitCode)) {
// N.b.: `reg.exe` returns 0 (unchanged) or 2 (changed) on success.
bool success = (exitCode == 0 || exitCode == 2);
if (!success) {
LOG_ERROR_MESSAGE(L"%s returned failure exitCode %d", regCmdLine.get(),
exitCode);
}
return success;
}
return false;
}
static bool SetUserChoiceCommand(const wchar_t* aExt, const wchar_t* aProgID,
const wchar_t* aHash) {
auto assocKeyPath = GetAssociationKeyPath(aExt);
if (!assocKeyPath) {
return false;
}
const wchar_t* formatString = L"HKCU\\%s\\UserChoice";
int bufferSize = _scwprintf(formatString, assocKeyPath.get());
++bufferSize; // Extra character for terminating null
mozilla::UniquePtr<wchar_t[]> userChoiceKeyPath =
mozilla::MakeUnique<wchar_t[]>(bufferSize);
_snwprintf_s(userChoiceKeyPath.get(), bufferSize, _TRUNCATE, formatString,
assocKeyPath.get());
const wchar_t* deleteArgs[] = {
L"DELETE",
userChoiceKeyPath.get(),
L"/F",
};
if (!LaunchReg(mozilla::ArrayLength(deleteArgs), deleteArgs)) {
LOG_ERROR_MESSAGE(L"Failed to reg.exe DELETE; ignoring and continuing.");
}
// Like REG ADD [ROOT\]RegKey /V ValueName [/T DataType] [/S Separator] [/D
// Data] [/F] [/reg:32] [/reg:64]
const wchar_t* progIDArgs[] = {
L"ADD", userChoiceKeyPath.get(),
L"/F", L"/V",
L"ProgID", L"/T",
L"REG_SZ", L"/D",
aProgID,
};
if (!LaunchReg(mozilla::ArrayLength(progIDArgs), progIDArgs)) {
// LaunchReg will have logged an error message already.
return false;
}
const wchar_t* hashArgs[] = {
L"ADD", userChoiceKeyPath.get(),
L"/F", L"/V",
L"Hash", L"/T",
L"REG_SZ", L"/D",
aHash,
};
if (!LaunchReg(mozilla::ArrayLength(hashArgs), hashArgs)) {
// LaunchReg will have logged an error message already.
return false;
}
return true;
}
/*
* Set an association with a UserChoice key
*
* Removes the old key, creates a new one with ProgID and Hash set to
* enable a new asociation.
*
* @param aExt File type or protocol to associate
* @param aSid Current user's string SID
* @param aProgID ProgID to use for the asociation
*
* @return true if successful, false on error.
*/
static bool SetUserChoice(const wchar_t* aExt, const wchar_t* aSid,
const wchar_t* aProgID) {
// This might be slow to query, so do it before generating timestamps and
// hashes.
UINT32 pfnLen = 0;
bool inMsix =
GetCurrentPackageFullName(&pfnLen, nullptr) != APPMODEL_ERROR_NO_PACKAGE;
SYSTEMTIME hashTimestamp;
::GetSystemTime(&hashTimestamp);
auto hash = GenerateUserChoiceHash(aExt, aSid, aProgID, hashTimestamp);
if (!hash) {
return false;
}
// The hash changes at the end of each minute, so check that the hash should
// be the same by the time we're done writing.
const ULONGLONG kWriteTimingThresholdMilliseconds = 1000;
// Generating the hash could have taken some time, so start from now.
SYSTEMTIME writeEndTimestamp;
::GetSystemTime(&writeEndTimestamp);
if (!AddMillisecondsToSystemTime(writeEndTimestamp,
kWriteTimingThresholdMilliseconds)) {
return false;
}
if (!CheckEqualMinutes(hashTimestamp, writeEndTimestamp)) {
LOG_ERROR_MESSAGE(
L"Hash is too close to expiration, sleeping until next hash.");
::Sleep(kWriteTimingThresholdMilliseconds * 2);
// For consistency, use the current time.
::GetSystemTime(&hashTimestamp);
hash = GenerateUserChoiceHash(aExt, aSid, aProgID, hashTimestamp);
if (!hash) {
return false;
}
}
if (inMsix) {
// We're in an MSIX package, thus need to use reg.exe.
return SetUserChoiceCommand(aExt, aProgID, hash.get());
} else {
// We're outside of an MSIX package and can use the Win32 Registry API.
return SetUserChoiceRegistry(aExt, aProgID, std::move(hash));
}
}
static bool VerifyUserDefault(const wchar_t* aExt, const wchar_t* aProgID) { static bool VerifyUserDefault(const wchar_t* aExt, const wchar_t* aProgID) {
RefPtr<IApplicationAssociationRegistration> pAAR; RefPtr<IApplicationAssociationRegistration> pAAR;
HRESULT hr = ::CoCreateInstance( HRESULT hr = ::CoCreateInstance(
@@ -343,19 +227,29 @@ static bool VerifyUserDefault(const wchar_t* aExt, const wchar_t* aProgID) {
nsresult SetDefaultBrowserUserChoice( nsresult SetDefaultBrowserUserChoice(
const wchar_t* aAumi, const nsTArray<nsString>& aExtraFileExtensions) { const wchar_t* aAumi, const nsTArray<nsString>& aExtraFileExtensions) {
// Verify that the implementation of UserChoice hashing has not changed by auto urlProgID = FormatProgID(L"FirefoxURL", aAumi);
// computing the current default hash and comparing with the existing value. if (!CheckProgIDExists(urlProgID.get())) {
LOG_ERROR_MESSAGE(L"ProgID %s not found", urlProgID.get());
return NS_ERROR_WDBA_NO_PROGID;
}
auto htmlProgID = FormatProgID(L"FirefoxHTML", aAumi);
if (!CheckProgIDExists(htmlProgID.get())) {
LOG_ERROR_MESSAGE(L"ProgID %s not found", htmlProgID.get());
return NS_ERROR_WDBA_NO_PROGID;
}
auto pdfProgID = FormatProgID(L"FirefoxPDF", aAumi);
if (!CheckProgIDExists(pdfProgID.get())) {
LOG_ERROR_MESSAGE(L"ProgID %s not found", pdfProgID.get());
return NS_ERROR_WDBA_NO_PROGID;
}
if (!CheckBrowserUserChoiceHashes()) { if (!CheckBrowserUserChoiceHashes()) {
LOG_ERROR_MESSAGE(L"UserChoice Hash mismatch"); LOG_ERROR_MESSAGE(L"UserChoice Hash mismatch");
return NS_ERROR_WDBA_HASH_CHECK; return NS_ERROR_WDBA_HASH_CHECK;
} }
nsTArray<nsString> browserDefaults = {
u"https"_ns, u"FirefoxURL"_ns, u"http"_ns, u"FirefoxURL"_ns,
u".html"_ns, u"FirefoxHTML"_ns, u".htm"_ns, u"FirefoxHTML"_ns};
browserDefaults.AppendElements(aExtraFileExtensions);
if (!mozilla::IsWin10CreatorsUpdateOrLater()) { if (!mozilla::IsWin10CreatorsUpdateOrLater()) {
LOG_ERROR_MESSAGE(L"UserChoice hash matched, but Windows build is too old"); LOG_ERROR_MESSAGE(L"UserChoice hash matched, but Windows build is too old");
return NS_ERROR_WDBA_BUILD; return NS_ERROR_WDBA_BUILD;
@@ -366,16 +260,52 @@ nsresult SetDefaultBrowserUserChoice(
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
nsresult rv = SetDefaultExtensionHandlersUserChoiceImpl(aAumi, sid.get(), bool ok = true;
browserDefaults); bool defaultRejected = false;
if (!NS_SUCCEEDED(rv)) {
LOG_ERROR_MESSAGE(L"Failed setting default with %s", aAumi); struct {
const wchar_t* ext;
const wchar_t* progID;
} associations[] = {{L"https", urlProgID.get()},
{L"http", urlProgID.get()},
{L".html", htmlProgID.get()},
{L".htm", htmlProgID.get()}};
for (size_t i = 0; i < mozilla::ArrayLength(associations); ++i) {
if (!SetUserChoice(associations[i].ext, sid.get(),
associations[i].progID)) {
ok = false;
break;
} else if (!VerifyUserDefault(associations[i].ext,
associations[i].progID)) {
defaultRejected = true;
ok = false;
break;
}
}
if (ok) {
nsresult rv = SetDefaultExtensionHandlersUserChoiceImpl(
aAumi, sid.get(), aExtraFileExtensions);
if (rv == NS_ERROR_WDBA_REJECTED) {
ok = false;
defaultRejected = true;
} else if (rv == NS_ERROR_FAILURE) {
ok = false;
}
} }
// Notify shell to refresh icons // Notify shell to refresh icons
::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); ::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
return rv; if (!ok) {
LOG_ERROR_MESSAGE(L"Failed setting default with %s", aAumi);
if (defaultRejected) {
return NS_ERROR_WDBA_REJECTED;
}
return NS_ERROR_FAILURE;
}
return NS_OK;
} }
nsresult SetDefaultExtensionHandlersUserChoice( nsresult SetDefaultExtensionHandlersUserChoice(
@@ -385,25 +315,35 @@ nsresult SetDefaultExtensionHandlersUserChoice(
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
bool ok = true;
bool defaultRejected = false;
nsresult rv = SetDefaultExtensionHandlersUserChoiceImpl(aAumi, sid.get(), nsresult rv = SetDefaultExtensionHandlersUserChoiceImpl(aAumi, sid.get(),
aFileExtensions); aFileExtensions);
if (!NS_SUCCEEDED(rv)) { if (rv == NS_ERROR_WDBA_REJECTED) {
LOG_ERROR_MESSAGE(L"Failed setting default with %s", aAumi); ok = false;
defaultRejected = true;
} else if (rv == NS_ERROR_FAILURE) {
ok = false;
} }
// Notify shell to refresh icons // Notify shell to refresh icons
::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); ::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
return rv; if (!ok) {
LOG_ERROR_MESSAGE(L"Failed setting default with %s", aAumi);
if (defaultRejected) {
return NS_ERROR_WDBA_REJECTED;
}
return NS_ERROR_FAILURE;
}
return NS_OK;
} }
nsresult SetDefaultExtensionHandlersUserChoiceImpl( nsresult SetDefaultExtensionHandlersUserChoiceImpl(
const wchar_t* aAumi, const wchar_t* const aSid, const wchar_t* aAumi, const wchar_t* const aSid,
const nsTArray<nsString>& aFileExtensions) { const nsTArray<nsString>& aFileExtensions) {
UINT32 pfnLen = 0;
bool inMsix =
GetCurrentPackageFullName(&pfnLen, nullptr) != APPMODEL_ERROR_NO_PACKAGE;
for (size_t i = 0; i + 1 < aFileExtensions.Length(); i += 2) { for (size_t i = 0; i + 1 < aFileExtensions.Length(); i += 2) {
const wchar_t* extraFileExtension = const wchar_t* extraFileExtension =
PromiseFlatString(aFileExtensions[i]).get(); PromiseFlatString(aFileExtensions[i]).get();
@@ -411,21 +351,7 @@ nsresult SetDefaultExtensionHandlersUserChoiceImpl(
PromiseFlatString(aFileExtensions[i + 1]).get(); PromiseFlatString(aFileExtensions[i + 1]).get();
// Formatting the ProgID here prevents using this helper to target arbitrary // Formatting the ProgID here prevents using this helper to target arbitrary
// ProgIDs. // ProgIDs.
UniquePtr<wchar_t[]> extraProgID; auto extraProgID = FormatProgID(extraProgIDRoot, aAumi);
if (inMsix) {
nsresult rv = GetMsixProgId(extraFileExtension, extraProgID);
if (NS_FAILED(rv)) {
LOG_ERROR_MESSAGE(L"Failed to retrieve MSIX progID for %s",
extraFileExtension);
return rv;
}
} else {
extraProgID = FormatProgID(extraProgIDRoot, aAumi);
if (!CheckProgIDExists(extraProgID.get())) {
LOG_ERROR_MESSAGE(L"ProgID %s not found", extraProgID.get());
return NS_ERROR_WDBA_NO_PROGID;
}
}
if (!SetUserChoice(extraFileExtension, aSid, extraProgID.get())) { if (!SetUserChoice(extraFileExtension, aSid, extraProgID.get())) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;