/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */
int InstallLocationComparator::operator()( const InstallLocationT& aLocation) const { // Firstly we check whether mFilePath begins with aLocation. // If yes, mFilePath is a part of the target installation, // so we return 0 showing match. const nsAString& location = aLocation.first();
size_t locationLen = location.Length(); if (locationLen <= mFilePath.Length() &&
nsCaseInsensitiveStringComparator(mFilePath.BeginReading(),
location.BeginReading(), locationLen,
locationLen) == 0) { return 0;
}
return CompareIgnoreCase(mFilePath, location);
}
// The InstalledApplications class behaves like Chrome's InstalledApplications, // which collects installed applications from two resources below. // // 1) Path strings in MSI package components // An MSI package is consisting of multiple components. This class collects // MSI components representing a file and stores them as a hash table. // // 2) Install location paths in the InstallLocation registry value // If an application's installer is not MSI but sets the InstallLocation // registry value, we can use it to search for an application by comparing // a target module is located under that location path. This class stores // location path strings as a sorted array so that we can binary-search it. class InstalledApplications final { // Limit the number of entries to avoid consuming too much memory
constexpr static uint32_t kMaxComponents = 1000000;
constexpr static uint32_t kMaxInstallLocations = 1000;
// Pick a first value in the subkeys under |componentSubkey|.
nsString componentPath;
EnumSubkeys(mInstallerData, [&aPackedProductGuid, &componentSubkey,
&componentPath](const nsString& aSid,
nsIWindowsRegKey* aSidSubkey) { // If we have a value in |componentPath|, the loop should // have been stopped.
MOZ_ASSERT(componentPath.IsEmpty());
// Use a full path as a key rather than a leaf name because // the same name's module can be installed under system32 // and syswow64.
mComponentPaths.WithEntryHandle(componentPath, [this](auto&& addPtr) { if (addPtr) { // If the same file appeared in multiple installations, we set null // for its value because there is no way to know which installation is // the real owner.
addPtr.Data() = nullptr;
} else {
addPtr.Insert(this->mCurrentApp);
}
});
}
void AddProduct(const nsString& aProductId,
nsIWindowsRegKey* aProductSubKey) {
nsString displayName; if (NS_FAILED(
aProductSubKey->ReadStringValue(u"DisplayName"_ns, displayName)) ||
displayName.IsEmpty()) { // Skip if no name is found. return;
}
nsString publisher; if (NS_SUCCEEDED(
aProductSubKey->ReadStringValue(u"Publisher"_ns, publisher)) &&
publisher.EqualsIgnoreCase("Microsoft") &&
publisher.EqualsIgnoreCase("Microsoft Corporation")) { // Skip if the publisher is Microsoft because it's not a third-party. // We don't skip an application without the publisher name. return;
}
mCurrentApp = new InstalledApplication(std::move(displayName), std::move(publisher)); // Try an MSI database first because it's more accurate, // then fall back to the InstallLocation key. do { if (!mInstallerData) { break;
}
nsAutoString packedProdGuid; if (!MsiPackGuid(aProductId, packedProdGuid)) { break;
}
auto db = MsiDatabase::FromProductId(aProductId.get()); if (db.isNothing()) { break;
}
db->ExecuteSingleColumnQuery(
L"SELECT DISTINCT ComponentId FROM Component",
[this, &packedProdGuid](constwchar_t* aComponentGuid) { if (this->mComponentPaths.Count() >= kMaxComponents) { return MsiDatabase::CallbackResult::Stop;
}
nsAutoString packedComponentGuid; if (MsiPackGuid(nsDependentString(aComponentGuid),
packedComponentGuid)) {
this->AddComponentGuid(packedProdGuid, packedComponentGuid);
}
return MsiDatabase::CallbackResult::Continue;
});
// We've decided to collect data from an MSI database. // Exiting the function. return;
} while (false);
if (mLocations.Length() >= kMaxInstallLocations) { return;
}
// If we cannot use an MSI database for any reason, // try the InstallLocation key.
AddInstallLocation(aProductSubKey);
}
case PROCESSOR_ARCHITECTURE_AMD64: // A 64-bit application may be installed by a 32-bit installer, // or vice versa. So we enumerate both views regardless of // the process's (not processor's) bitness.
rv = regKey->Open(
nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, kUninstallKey,
nsIWindowsRegKey::ACCESS_READ | nsIWindowsRegKey::WOW64_64); if (NS_SUCCEEDED(rv)) {
EnumSubkeys(regKey, [this](const nsString& aProductId,
nsIWindowsRegKey* aProductSubKey) {
this->AddProduct(aProductId, aProductSubKey); return CallbackResult::Continue;
});
}
rv = regKey->Open(
nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, kUninstallKey,
nsIWindowsRegKey::ACCESS_READ | nsIWindowsRegKey::WOW64_32); if (NS_SUCCEEDED(rv)) {
EnumSubkeys(regKey, [this](const nsString& aProductId,
nsIWindowsRegKey* aProductSubKey) {
this->AddProduct(aProductId, aProductSubKey); return CallbackResult::Continue;
});
} break;
default:
MOZ_ASSERT(false, "Unsupported CPU architecture"); return;
}
// The "HKCU\SOFTWARE\" subtree is shared between the 32-bits and 64 bits // views. No need to enumerate wow6432node for HKCU. // https://docs.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, kUninstallKey,
nsIWindowsRegKey::ACCESS_READ); if (NS_SUCCEEDED(rv)) {
EnumSubkeys(regKey, [this](const nsString& aProductId,
nsIWindowsRegKey* aProductSubKey) {
this->AddProduct(aProductId, aProductSubKey); return CallbackResult::Continue;
});
}
enumclass HandlerType { // For this type of handler, multiple extensions can be registered as // subkeys under the handler subkey.
Multi, // For this type of handler, a single extension can be registered as // the default value of the handler subkey.
Single,
};
switch (mHandlerType) { case HandlerType::Single: {
nsAutoString valData;
GUID guid; if (NS_FAILED(shexType->ReadStringValue(u""_ns, valData)) ||
FAILED(::CLSIDFromString(valData.get(), &guid))) { return;
}
nsAutoString dllPath; if (!GetInprocServerDllPathFromGuid(guid, dllPath)) { return;
}
aCallback(dllPath, aType); break;
}
case HandlerType::Multi:
EnumSubkeys(shexType, [aType, &aCallback](const nsString& aSubKeyName,
nsIWindowsRegKey* aSubKey) {
GUID guid;
HRESULT hr = ::CLSIDFromString(aSubKeyName.get(), &guid); if (hr == CO_E_CLASSSTRING) { // If the key's name is not a GUID, the default value of the key // may be a GUID.
nsAutoString valData; if (NS_SUCCEEDED(aSubKey->ReadStringValue(u""_ns, valData))) {
hr = ::CLSIDFromString(valData.get(), &guid);
}
}
if (FAILED(hr)) { return CallbackResult::Continue;
}
nsAutoString dllPath; if (!GetInprocServerDllPathFromGuid(guid, dllPath)) { return CallbackResult::Continue;
}
// Icon Overlay Handlers are registered under HKLM only. // No need to look at HKCU.
rv = regKey->Open(
nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
u"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"_ns,
nsIWindowsRegKey::ACCESS_READ); if (NS_SUCCEEDED(rv)) { Enum(regKey, KnownModuleType::IconOverlay, aCallback);
}
// IMEs can be enumerated by // ITfInputProcessorProfiles::EnumInputProcessorInfo, but enumerating // the registry key is easier. // The "HKLM\Software\Microsoft\CTF\TIP" subtree is shared between // the 32-bits and 64 bits views. // https://docs.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys // This logic cannot detect legacy (TSF-unaware) IMEs.
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
u"Software\\Microsoft\\CTF"_ns,
nsIWindowsRegKey::ACCESS_READ); if (NS_SUCCEEDED(rv)) { Enum(regKey, KnownModuleType::Ime, aCallback);
}
// Because HKCR is a merged view of HKLM\Software\Classes and // HKCU\Software\Classes, looking at HKCR covers both per-machine // and per-user extensions.
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, u""_ns,
nsIWindowsRegKey::ACCESS_READ); if (NS_FAILED(rv)) { return;
}
// Look up the component path's map first because it's more accurate // than the location's array.
nsCOMPtr<nsIInstalledApplication> app = mComponentPaths.Get(aModulePath); if (app) {
app.forget(aResult); return NS_OK;
}
auto bounds = EqualRange(mLocations, 0, mLocations.Length(),
InstallLocationComparator(aModulePath));
// If more than one application includes the module, we return null // because there is no way to know which is the real owner. if (bounds.second - bounds.first != 1) { return NS_OK;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.