From 3cd92e058498e3ab9d73ced140bbd7e490f639a7 Mon Sep 17 00:00:00 2001 From: John Simpson Date: Tue, 29 Oct 2019 13:49:12 -0400 Subject: [PATCH] Changed how UWP packages are enumerated to resolve missing packages from previous registry method. --- GloSC.sln | 46 ++++---- GloSC/GloSC.cpp | 276 ++++++++++++++++++++++++++++---------------- GloSC/GloSC.vcxproj | 12 +- 3 files changed, 210 insertions(+), 124 deletions(-) diff --git a/GloSC.sln b/GloSC.sln index 67492cd..bdd776e 100644 --- a/GloSC.sln +++ b/GloSC.sln @@ -1,12 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 -VisualStudioVersion = 16.0.29009.5 +VisualStudioVersion = 16.0.29418.71 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SteamTarget", "SteamTarget\SteamTarget.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GloSC", "GloSC\GloSC.vcxproj", "{2E7F8131-0BD8-475D-B16F-20445CCF2D16}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EnforceBindingDLL", "EnforceBindingDLL\EnforceBindingDLL.vcxproj", "{AFA0047E-7DEE-472A-AF4B-436A30459905}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GloSC_Watchdog", "GloSC_Watchdog\GloSC_Watchdog.vcxproj", "{752D3933-73A3-45E4-B139-CCB8C04BE543}" @@ -16,6 +12,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution GloSC_install_script.iss = GloSC_install_script.iss EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GloSC", "GloSC\GloSC.vcxproj", "{2E7F8131-0BD8-475D-B16F-20445CCF2D16}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SteamTarget", "SteamTarget\SteamTarget.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -24,24 +24,8 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64 - {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64 - {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.ActiveCfg = Debug|Win32 - {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.Build.0 = Debug|Win32 - {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64 - {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64 - {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.ActiveCfg = Release|Win32 - {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.Build.0 = Release|Win32 - {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Debug|x64.ActiveCfg = Debug|x64 - {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Debug|x64.Build.0 = Debug|x64 - {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Debug|x86.ActiveCfg = Debug|Win32 - {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Debug|x86.Build.0 = Debug|Win32 - {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Release|x64.ActiveCfg = Release|x64 - {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Release|x64.Build.0 = Release|x64 - {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Release|x86.ActiveCfg = Release|Win32 - {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Release|x86.Build.0 = Release|Win32 - {AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x64.ActiveCfg = Debug|x64 - {AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x64.Build.0 = Debug|x64 + {AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x64.ActiveCfg = Debug|Win32 + {AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x64.Build.0 = Debug|Win32 {AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x86.ActiveCfg = Debug|Win32 {AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x86.Build.0 = Debug|Win32 {AFA0047E-7DEE-472A-AF4B-436A30459905}.Release|x64.ActiveCfg = Release|Win32 @@ -56,6 +40,22 @@ Global {752D3933-73A3-45E4-B139-CCB8C04BE543}.Release|x64.Build.0 = Release|x64 {752D3933-73A3-45E4-B139-CCB8C04BE543}.Release|x86.ActiveCfg = Release|Win32 {752D3933-73A3-45E4-B139-CCB8C04BE543}.Release|x86.Build.0 = Release|Win32 + {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Debug|x64.ActiveCfg = Debug|x64 + {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Debug|x64.Build.0 = Debug|x64 + {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Debug|x86.ActiveCfg = Debug|Win32 + {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Debug|x86.Build.0 = Debug|Win32 + {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Release|x64.ActiveCfg = Release|x64 + {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Release|x64.Build.0 = Release|x64 + {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Release|x86.ActiveCfg = Release|Win32 + {2E7F8131-0BD8-475D-B16F-20445CCF2D16}.Release|x86.Build.0 = Release|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.ActiveCfg = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.Build.0 = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.ActiveCfg = Release|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GloSC/GloSC.cpp b/GloSC/GloSC.cpp index ea0ef12..ffab19d 100644 --- a/GloSC/GloSC.cpp +++ b/GloSC/GloSC.cpp @@ -16,6 +16,17 @@ limitations under the License. #include "GloSC.h" #include #include "UpdateChecker.h" +#include +#include +#include +#include +#include +#include +#pragma comment(lib, "Shlwapi.lib") + +using namespace Windows::Management::Deployment; +using namespace Windows::Foundation::Collections; + GloSC::GloSC(QWidget *parent) : QMainWindow(parent), updater_(this) @@ -508,139 +519,206 @@ void GloSC::on_pbSearchPath_clicked() void GloSC::on_pbUWP_clicked() { - auto settings = std::make_unique(R"(HKEY_CLASSES_ROOT\Extensions\ContractId\Windows.Launch\PackageId)", QSettings::NativeFormat); - QStringList childs = settings->childGroups(); - QStringList packages; - - for (auto& child : childs) - { - packages << child; - } + PackageManager^ packageManager = ref new PackageManager(); + IIterable^ packages = packageManager->FindPackages(); + int packageCount = 0; + // Only way to get the count of packages is to iterate through the whole collection first + std::for_each(Windows::Foundation::Collections::begin(packages), Windows::Foundation::Collections::end(packages), + [&](Windows::ApplicationModel::Package^ package) + { + packageCount += 1; + }); - QProgressDialog progDialog("Searching for UWP apps...", "Cancel", 0, packages.size(), this); + QProgressDialog progDialog("Searching for UWP apps...", "Cancel", 0, packageCount, this); progDialog.setWindowModality(Qt::WindowModal); - + // Without this the progress dialog doesn't update in the lambda function. + progDialog.show(); + QApplication::processEvents(); + QList pairs; QStringList AppNames; QStringList AppUMIds; - - for (auto &package : packages) - { - progDialog.setValue(packages.indexOf(package)); - - if (progDialog.wasCanceled()) + int currPackage = 0; + // Iterate through all the packages + std::for_each(Windows::Foundation::Collections::begin(packages), Windows::Foundation::Collections::end(packages), + [&](Windows::ApplicationModel::Package^ package) { - return; - } - settings = std::make_unique(R"(HKEY_CLASSES_ROOT\Extensions\ContractId\Windows.Launch\PackageId\)" + package, QSettings::NativeFormat); + progDialog.setValue(currPackage); + progDialog.update(); + - - - for (auto& child : settings->childGroups()) - { - if (child == "ActivatableClassId") + if (progDialog.wasCanceled()) { - const auto classIDSettings = std::make_unique( - R"(HKEY_CLASSES_ROOT\Extensions\ContractId\Windows.Launch\PackageId\)" + package + "\\" + child, - QSettings::NativeFormat); - - if (classIDSettings->childGroups().length() > 0) - { - QString pkgNameCleaned = package.mid(0, package.indexOf("_")); - QStringList tmp = package.split("__"); - if (tmp.size() > 1) - { - pkgNameCleaned += "_" + tmp.at(1); - } else { - pkgNameCleaned += package.mid(package.lastIndexOf("_"), package.size()-1); - } - - - - QString AppUMId = pkgNameCleaned + "!" + classIDSettings->childGroups().at(0); - - const auto appInfoSettings = std::make_unique( - R"(HKEY_CLASSES_ROOT\Extensions\ContractId\Windows.Launch\PackageId\)" - + package + "\\" + child + "\\" + classIDSettings->childGroups().at(0), - QSettings::NativeFormat); + return; + } + HRESULT hr = S_OK; + IStream* inputStream = NULL; + UINT32 pathLen = 0; + IAppxManifestReader* manifestReader = NULL; + IAppxFactory* appxFactory = NULL; + LPWSTR appId = NULL; + LPWSTR manifestAppName = NULL; + + // Get the package path on disk so we can load the manifest XML and get the PRAID + GetPackagePathByFullName(package->Id->FullName->Data(), &pathLen, NULL); + + if (pathLen > 0) { + + // Length of the path + "\\AppxManifest.xml" that we'll be appending + UINT32 manifestLen = pathLen + 20; + PWSTR pathBuf = (PWSTR)malloc(manifestLen * sizeof(wchar_t)); + + GetPackagePathByFullName(package->Id->FullName->Data(), &pathLen, pathBuf); + PWSTR manifest_xml = L"\\AppxManifest.xml"; + + hr = StringCchCatW(pathBuf, manifestLen, manifest_xml); + + // Let's ignore a bunch of built in apps and such + if (wcsstr(pathBuf, L"SystemApps")) { + hr = E_FAIL; + } + else if (wcsstr(pathBuf, L".NET.Native.")) + hr = E_FAIL; + else if (wcsstr(pathBuf, L".VCLibs.")) + hr = E_FAIL; + else if (wcsstr(pathBuf, L"Microsoft.UI")) + hr = E_FAIL; + else if (wcsstr(pathBuf, L"Microsoft.Advertising")) + hr = E_FAIL; + else if (wcsstr(pathBuf, L"Microsoft.Services.Store")) + hr = E_FAIL; + + BOOL hasCurrent = FALSE; + + // Open the manifest XML + if (SUCCEEDED(hr)) { + + hr = SHCreateStreamOnFileEx( + pathBuf, + STGM_READ | STGM_SHARE_EXCLUSIVE, + 0, // default file attributes + FALSE, // do not create new file + NULL, // no template + &inputStream); + } + if (SUCCEEDED(hr)) { + + hr = CoCreateInstance( + __uuidof(AppxFactory), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IAppxFactory), + (LPVOID*)(&appxFactory)); + } + if (SUCCEEDED(hr)) { + hr = appxFactory->CreateManifestReader(inputStream, &manifestReader); + } - QString AppName = appInfoSettings->value("DisplayName").toString(); + // Grab application ID (PRAID) and DisplayName from the XML + if (SUCCEEDED(hr)) { + IAppxManifestApplicationsEnumerator* applications = NULL; + manifestReader->GetApplications(&applications); + if (SUCCEEDED(hr)) { + hr = applications->GetHasCurrent(&hasCurrent); + if (hasCurrent) { + IAppxManifestApplication* application = NULL; + hr = applications->GetCurrent(&application); + if (SUCCEEDED(hr)) { + application->GetStringValue(L"Id", &appId); + application->GetStringValue(L"DisplayName", &manifestAppName); + application->Release(); + } + } + else { + hr = S_FALSE; + } + applications->Release(); + } + manifestReader->Release(); + inputStream->Release(); + + } - if (!AppNames.contains(AppName) && !AppUMIds.contains(AppUMId) && AppUMId.size() > 0) + if (SUCCEEDED(hr)) { + PWSTR appNameBuf; + QString AppUMId = QString::fromWCharArray(package->Id->FamilyName->Data()); + QString AppName; + if (manifestAppName != NULL) { - if (AppName.size() != 0) - AppNames << AppName; - - AppUMIds << AppUMId; - - if (AppName.size() == 0) + // If the display name is an indirect string, we'll try and load it using SHLoadIndirectString + if (wcsstr(manifestAppName, L"ms-resource:")) { - AppName = "Unknown"; - } - else if (AppName.at(0) == '@') { - QString packageName = AppName.mid(AppName.indexOf('{') + 1, AppName.size() - 1); - packageName = packageName.mid(0, packageName.indexOf('?')); - QSettings settings("HKEY_CLASSES_ROOT\\Local Settings\\MrtCache", QSettings::NativeFormat); - - QStringList cachedNameChildGroups = settings.childGroups(); - - for (auto &childGroup : cachedNameChildGroups) - { - - if (childGroup.contains(packageName)) - { - QSettings settings(R"(HKEY_CLASSES_ROOT\Local Settings\MrtCache\)" + childGroup, QSettings::NativeFormat); - - QStringList allKeys = settings.allKeys(); - - AppName.replace("/", "\\"); - for (auto &key : allKeys) - { - if (key.contains(AppName)) - { - AppName = settings.value(key).toString(); - break; - } - } - - break; + PWSTR res_name = wcsdup(&manifestAppName[12]); + appNameBuf = (PWSTR)malloc(1026); + LPCWSTR resource_str = L"@{"; + std::wstring reslookup = std::wstring(resource_str) + package->Id->FullName->Data() + L"?ms-resource://" + package->Id->Name->Data() + L"/resources/" + res_name + L"}"; + PCWSTR res_str = reslookup.c_str(); + hr = SHLoadIndirectString(res_str, appNameBuf, 512, NULL); + // Try several resource paths + if (!SUCCEEDED(hr)) { + std::wstring reslookup = std::wstring(resource_str) + package->Id->FullName->Data() + L"?ms-resource://" + package->Id->Name->Data() + L"/Resources/" + res_name + L"}"; + PCWSTR res_str = reslookup.c_str(); + hr = SHLoadIndirectString(res_str, appNameBuf, 512, NULL); + // If the third one doesn't work, we give up and use the package name from PackageManager + if (!SUCCEEDED(hr)) { + std::wstring reslookup = std::wstring(resource_str) + package->Id->FullName->Data() + L"?ms-resource://" + package->Id->Name->Data() + L"/" + res_name + L"}"; + PCWSTR res_str = reslookup.c_str(); + hr = SHLoadIndirectString(res_str, appNameBuf, 512, NULL); } } - if (AppName.at(0) == '@') { - AppName = "Unknown"; + + QString PRAID = QString::fromWCharArray(appId); + CoTaskMemFree(appId); + if (!PRAID.isEmpty()) { + AppUMId = AppUMId.append("!"); + AppUMId = AppUMId.append(PRAID); } + if (!SUCCEEDED(hr)) + AppName = QString::fromWCharArray(package->Id->Name->Data()); + else + AppName = QString::fromWCharArray(appNameBuf); + free(appNameBuf); } + else + { + appNameBuf = manifestAppName; + AppName = QString::fromWCharArray(appNameBuf); - const UWPPair uwpPair = { - AppName, - AppUMId, - }; - - pairs.push_back(uwpPair); - + } + + } + else { + AppName = QString::fromWCharArray(package->Id->Name->Data()); } + + + const UWPPair uwpPair = { + AppName, + AppUMId, + }; + + + free(pathBuf); - break; + pairs.push_back(uwpPair); } - break; } - } - + currPackage += 1; + }); - } uwp_pairs_ = pairs; progDialog.close(); - UWPSelectDialog dialog(this); dialog.setUWPList(uwp_pairs_); int selection = dialog.exec(); + if (selection > -1) { diff --git a/GloSC/GloSC.vcxproj b/GloSC/GloSC.vcxproj index bf8711d..de56d15 100644 --- a/GloSC/GloSC.vcxproj +++ b/GloSC/GloSC.vcxproj @@ -21,7 +21,7 @@ {2E7F8131-0BD8-475D-B16F-20445CCF2D16} Qt4VSv1.0 - 10.0 + 10.0.18362.0 @@ -65,6 +65,8 @@ ProgramDatabase MultiThreadedDebugDLL true + C:\Program Files %28x86%29\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\8.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\UnionMetadata\10.0.18362.0;C:\Program Files %28x86%29\Microsoft Visual Studio\2019\Community\Common7\IDE\VC\vcpackages;%(AdditionalUsingDirectories) + true Windows @@ -83,6 +85,8 @@ ProgramDatabase MultiThreadedDebugDLL true + true + C:\Program Files %28x86%29\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\8.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\UnionMetadata\10.0.18362.0;C:\Program Files %28x86%29\Microsoft Visual Studio\2019\Community\Common7\IDE\VC\vcpackages;%(AdditionalUsingDirectories) Windows @@ -100,6 +104,8 @@ MultiThreadedDLL true + C:\Program Files %28x86%29\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\8.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\UnionMetadata\10.0.18362.0;C:\Program Files %28x86%29\Microsoft Visual Studio\2019\Community\Common7\IDE\VC\vcpackages;%(AdditionalUsingDirectories) + true Windows @@ -118,6 +124,8 @@ MultiThreadedDLL true + true + C:\Program Files %28x86%29\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\8.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\UnionMetadata\10.0.18362.0;C:\Program Files %28x86%29\Microsoft Visual Studio\2019\Community\Common7\IDE\VC\vcpackages;%(AdditionalUsingDirectories) Windows @@ -301,7 +309,7 @@ - + \ No newline at end of file