Change how UWP Apps are enumerated

Now using powershell-script
experimental/UWP_Inject
Peter Repukat 2 years ago
parent 0b1e98a4e2
commit 6b7127e1bb

@ -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

@ -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;

@ -31,13 +31,13 @@
<Import Project="$(QtMsBuild)\qt_defaults.props" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
<QtInstall>$(DefaultQtVersion)</QtInstall>
<QtInstall>6.2.2_msvc2019_64</QtInstall>
<QtModules>quick</QtModules>
<QtBuildConfig>debug</QtBuildConfig>
<QtQMLDebugEnable>true</QtQMLDebugEnable>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
<QtInstall>$(DefaultQtVersion)</QtInstall>
<QtInstall>6.2.2_msvc2019_64</QtInstall>
<QtModules>quick</QtModules>
<QtBuildConfig>release</QtBuildConfig>
</PropertyGroup>
@ -135,6 +135,7 @@
<ClCompile Include="main.cpp" />
<ClCompile Include="UIModel.cpp" />
<None Include=".clang-format" />
<None Include="GetAUMIDs.ps1" />
<None Include="qml\AddSelectTypeDialog.qml" />
<None Include="qml\FluentTextInput.qml" />
<None Include="qml\InfoDialog.qml" />

@ -64,6 +64,7 @@
<Filter>qml</Filter>
</None>
<None Include=".clang-format" />
<None Include="GetAUMIDs.ps1" />
</ItemGroup>
<ItemGroup>
<QtMoc Include="UIModel.h">

@ -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

@ -1,23 +1,16 @@
#pragma once
#include <QVariant>
#include <QProcess>
#include <QVariantMap>
#include <VersionHelpers.h>
#include <Windows.h>
#include <appmodel.h>
#include <appxpackaging.h>
#include <collection.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <windows.h>
#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<Windows::ApplicationModel::Package ^> ^ 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<QString> 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<QString> 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

@ -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) {

@ -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

Loading…
Cancel
Save