From 6b7127e1bb9713185d5d08c48e0bb1f9c96f4fc4 Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Tue, 4 Jan 2022 23:37:33 +0100 Subject: [PATCH] Change how UWP Apps are enumerated Now using powershell-script --- GlosSI.sln | 2 +- GlosSIConfig/GetAUMIDs.ps1 | 40 ++++ GlosSIConfig/GlosSIConfig.vcxproj | 5 +- GlosSIConfig/GlosSIConfig.vcxproj.filters | 1 + GlosSIConfig/Resource.rc | 136 +++++++++++- GlosSIConfig/UWPFetch.h | 254 ++++------------------ GlosSIConfig/main.cpp | 1 + GlosSITarget/Resource.rc | 12 +- 8 files changed, 233 insertions(+), 218 deletions(-) create mode 100644 GlosSIConfig/GetAUMIDs.ps1 diff --git a/GlosSI.sln b/GlosSI.sln index 2c589dd..2356eb3 100644 --- a/GlosSI.sln +++ b/GlosSI.sln @@ -44,7 +44,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - Qt5Version = $(DefaultQtVersion) SolutionGuid = {789386B6-7D1E-4F9C-BF2E-9B5EDC3BB7C8} + Qt5Version = 6.2.2_msvc2019_64 EndGlobalSection EndGlobal diff --git a/GlosSIConfig/GetAUMIDs.ps1 b/GlosSIConfig/GetAUMIDs.ps1 new file mode 100644 index 0000000..2a06b8a --- /dev/null +++ b/GlosSIConfig/GetAUMIDs.ps1 @@ -0,0 +1,40 @@ +#stolen and adapted from: https://github.com/BrianLima/UWPHook/blob/master/UWPHook/Resources/GetAUMIDScript.ps1 +$installedapps = get-AppxPackage +$invalidNames = '*ms-resource*', '*DisplayName*' +$aumidList = @() + +foreach ($app in $installedapps) +{ + try { + if(-not $app.IsFramework){ + foreach ($id in (Get-AppxPackageManifest $app).package.applications.application.id) + { + $appx = Get-AppxPackageManifest $app; + $name = $appx.Package.Properties.DisplayName; + + if($name -like '*DisplayName*' -or $name -like '*ms-resource*') + { + $name = $appx.Package.Applications.Application.VisualElements.DisplayName; + } + if($name -like '*DisplayName*' -or $name -like '*ms-resource*') + { + $name = "-Error-"; + } + + $installDir = $app.InstallLocation; + $logo = $app.InstallLocation + "\" + $appx.Package.Applications.Application.VisualElements.Square150x150Logo; + + + $aumidList += $name + "|" + $installDir + "|" + $logo + "|" + + $app.packagefamilyname + "!" + $id + ";" + } + } + } + catch + { + $ErrorMessage = $_.Exception.Message + $FailedItem = $_.Exception.ItemName + } +} + +$aumidList; diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj index 6978bc5..f79136d 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj +++ b/GlosSIConfig/GlosSIConfig.vcxproj @@ -31,13 +31,13 @@ - $(DefaultQtVersion) + 6.2.2_msvc2019_64 quick debug true - $(DefaultQtVersion) + 6.2.2_msvc2019_64 quick release @@ -135,6 +135,7 @@ + diff --git a/GlosSIConfig/GlosSIConfig.vcxproj.filters b/GlosSIConfig/GlosSIConfig.vcxproj.filters index 4ee0cc0..1a4b2dd 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj.filters +++ b/GlosSIConfig/GlosSIConfig.vcxproj.filters @@ -64,6 +64,7 @@ qml + diff --git a/GlosSIConfig/Resource.rc b/GlosSIConfig/Resource.rc index b078961..28bd651 100644 --- a/GlosSIConfig/Resource.rc +++ b/GlosSIConfig/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,0,3,105001394320 - PRODUCTVERSION 0,0,3,105001394320 + FILEVERSION 0,0,3,108000010980 + PRODUCTVERSION 0,0,3,108000010980 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - Config" - VALUE "FileVersion", "0.0.3.1-5-g139432c" + VALUE "FileVersion", "0.0.3.1-8-g0b1e98a" VALUE "InternalName", "GlosSIConfig" VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSIConfig.exe" VALUE "ProductName", "GlosSi" - VALUE "ProductVersion", "0.0.3.1-5-g139432c" + VALUE "ProductVersion", "0.0.3.1-8-g0b1e98a" END END BLOCK "VarFileInfo" @@ -678,6 +678,134 @@ END + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GlosSIConfig/UWPFetch.h b/GlosSIConfig/UWPFetch.h index 330948a..91320f9 100644 --- a/GlosSIConfig/UWPFetch.h +++ b/GlosSIConfig/UWPFetch.h @@ -1,23 +1,16 @@ #pragma once #include +#include +#include + #include #include -#include -#include -#include -#include -#include -#include -#pragma comment(lib, "Shlwapi.lib") -using namespace Windows::Management::Deployment; -using namespace Windows::Foundation::Collections; namespace UWPFetch { QVariantList UWPAppList() { - // TODO really should do this async, and notify gui when complete... if (!IsWindows10OrGreater()) { return QVariantList(); } @@ -34,204 +27,51 @@ QVariantList UWPAppList() }; QVariantList pairs; - // is it considered stealing when you take code that was pull-requested by someone else into your own repo? - // Anyway... Stolen from: https://github.com/Thracky/GloSC/commit/3cd92e058498e3ab9d73ced140bbd7e490f639a7 - // https://github.com/Alia5/GloSC/commit/3cd92e058498e3ab9d73ced140bbd7e490f639a7 - - // TODO: only return apps for current user. - // TODO: I have no clue how this WinRT shit works; HELP MEH! - - // BTW: This config app needs to run as admin, in order to modify steams shortcuts.vdf - // This won't hopefully be a problem fetching UWP apps for a specific user? - - 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; - }); - - 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) { - QGuiApplication::processEvents(); - HRESULT hr = S_OK; - IStream* inputStream = NULL; - UINT32 pathLen = 0; - IAppxManifestReader* manifestReader = NULL; - IAppxFactory* appxFactory = NULL; - LPWSTR appId = NULL; - LPWSTR manifestAppName = NULL; - LPWSTR iconName = 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); - } - - // 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); - for (auto& logoNameStr : logoNames) { - application->GetStringValue(logoNameStr.c_str(), &iconName); - if (!std::wstring(iconName).empty()) { - break; - } - } - application->Release(); - } - } - else { - hr = S_FALSE; - } - applications->Release(); - } - manifestReader->Release(); - inputStream->Release(); - } - - if (SUCCEEDED(hr)) { - PWSTR appNameBuf; - QString AppUMId = QString::fromWCharArray(package->Id->FamilyName->Data()); - QString AppName; - QString Path = QString::fromWCharArray(package->EffectivePath->Data()); - // QString thumbToken = QString::fromWCharArray(package->GetThumbnailToken()->Data()); - if (manifestAppName != NULL) { - // If the display name is an indirect string, we'll try and load it using SHLoadIndirectString - if (wcsstr(manifestAppName, L"ms-resource:")) { - 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 (!SUCCEEDED(hr)) - AppName = QString::fromWCharArray(package->DisplayName->Data()); - else - AppName = QString::fromWCharArray(appNameBuf); - free(appNameBuf); - } - else { - appNameBuf = manifestAppName; - AppName = QString::fromWCharArray(appNameBuf); - } - } - else { - AppName = QString::fromWCharArray(package->DisplayName->Data()); - } - - QString PRAID = QString::fromWCharArray(appId); - CoTaskMemFree(appId); - if (!PRAID.isEmpty()) { - AppUMId = AppUMId.append("!"); - AppUMId = AppUMId.append(PRAID); - } - QVariantMap uwpPair; - uwpPair.insert("AppName", AppName); - uwpPair.insert("AppUMId", AppUMId); - uwpPair.insert("Path", Path); - - QString icoFName = Path + "/" + QString::fromWCharArray(iconName); - std::filesystem::path icoPath(icoFName.toStdString()); - - std::vector possibleextensions = {".scale-100", ".scale-125", ".scale-150", ".scale-200"}; - if (!std::filesystem::exists(icoPath)) { - for (const auto& ext : possibleextensions) { - QString maybeFname = QString(icoFName).replace(".png", ext + ".png"); - std::filesystem::path maybePath(maybeFname.toStdString()); - if (std::filesystem::exists(maybePath)) { - icoPath = maybePath; - break; - } - } - } - - uwpPair.insert("IconPath", QString::fromStdString(icoPath.string())); - - free(pathBuf); - - pairs.push_back(uwpPair); - } - } - currPackage += 1; - }); - return pairs; + QProcess proc; + proc.setProgram("powershell.exe"); + QStringList args; + args.push_back(".\\GetAUMIDs.ps1"); + proc.setArguments(args); + proc.start(); + proc.waitForFinished(300000000); + const auto baseList = QString(proc.readAllStandardOutput()).split(";"); + QVariantList list; + for (const auto& entry : baseList) { + auto subList = entry.split('|'); + if (subList.size() < 4) + continue; + auto name = QString(subList[0]).replace("\r\n", ""); + if (name == "-Error-") + continue; + qDebug() << "name: " << name << " installDir: " << subList[1] << " logo: " << subList[2] << " aumid: " + << subList[3]; + QVariantMap uwpPair; + uwpPair.insert("AppName", name); + uwpPair.insert("Path", subList[1]); + uwpPair.insert("AppUMId", subList[3]); + + + QString icoFName = subList[2]; + std::filesystem::path icoPath(icoFName.toStdString()); + + std::vector possibleextensions = {".scale-100", ".scale-125", ".scale-150", ".scale-200"}; + if (!std::filesystem::exists(icoPath)) { + for (const auto& ext : possibleextensions) { + QString maybeFname = QString(icoFName).replace(".png", ext + ".png"); + std::filesystem::path maybePath(maybeFname.toStdString()); + if (std::filesystem::exists(maybePath)) { + icoPath = maybePath; + break; + } + } + } + + uwpPair.insert("IconPath", QString::fromStdString(icoPath.string())); + + list.push_back(uwpPair); + } + return list; } } // namespace UWPFetch \ No newline at end of file diff --git a/GlosSIConfig/main.cpp b/GlosSIConfig/main.cpp index a691037..3daada3 100644 --- a/GlosSIConfig/main.cpp +++ b/GlosSIConfig/main.cpp @@ -110,6 +110,7 @@ int main(int argc, char* argv[]) { #if defined(Q_OS_WIN) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); #endif if (argc < 3) { diff --git a/GlosSITarget/Resource.rc b/GlosSITarget/Resource.rc index 813f509..8d9044e 100644 --- a/GlosSITarget/Resource.rc +++ b/GlosSITarget/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,0,3,105001394320 - PRODUCTVERSION 0,0,3,105001394320 + FILEVERSION 0,0,3,108000010980 + PRODUCTVERSION 0,0,3,108000010980 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - SteamTarget" - VALUE "FileVersion", "0.0.3.1-5-g139432c" + VALUE "FileVersion", "0.0.3.1-8-g0b1e98a" VALUE "InternalName", "GlosSITarget" VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSITarget.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.0.3.1-5-g139432c" + VALUE "ProductVersion", "0.0.3.1-8-g0b1e98a" END END BLOCK "VarFileInfo" @@ -639,6 +639,10 @@ END + + + +