From 9eaceb3bfb16590067621d2b22a5f7a79e2afd12 Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Mon, 25 Oct 2021 01:14:34 +0200 Subject: [PATCH] Steal Thrackys UWP enumarate code --- GlosSIConfig/GlosSIConfig.vcxproj | 18 ++- GlosSIConfig/UIModel.cpp | 219 +++++++++++++++++++++++++++++- GlosSIConfig/UIModel.h | 6 +- GlosSIConfig/main.cpp | 18 +-- 4 files changed, 247 insertions(+), 14 deletions(-) diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj index bb55052..48ce83e 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj +++ b/GlosSIConfig/GlosSIConfig.vcxproj @@ -60,23 +60,37 @@ - stdcpp20 + stdcpp17 /Zc:__cplusplus %(AdditionalOptions) + C:\Program Files %28x86%29\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.FoundationContract\4.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.UniversalApiContract\10.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\UnionMetadata\10.0.19041.0;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\VC\vcpackages;%(AdditionalUsingDirectories) + true + NOMINMAX;%(PreprocessorDefinitions) PerMonitorHighDPIAware $(ProjectDir)manifest.xml %(AdditionalManifestFiles) + + true + RequireAdministrator + - stdcpp20 + stdcpp17 /Zc:__cplusplus %(AdditionalOptions) + C:\Program Files %28x86%29\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.FoundationContract\4.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.UniversalApiContract\10.0.0.0;C:\Program Files %28x86%29\Windows Kits\10\UnionMetadata\10.0.19041.0;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\VC\vcpackages;%(AdditionalUsingDirectories) + true + NOMINMAX;%(PreprocessorDefinitions) PerMonitorHighDPIAware $(ProjectDir)manifest.xml %(AdditionalManifestFiles) + + true + RequireAdministrator + diff --git a/GlosSIConfig/UIModel.cpp b/GlosSIConfig/UIModel.cpp index b329c1c..6c708be 100644 --- a/GlosSIConfig/UIModel.cpp +++ b/GlosSIConfig/UIModel.cpp @@ -19,6 +19,19 @@ limitations under the License. #include #include +#ifdef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#pragma comment(lib, "Shlwapi.lib") +using namespace Windows::Management::Deployment; +using namespace Windows::Foundation::Collections; +#endif UIModel::UIModel() : QObject(nullptr) { @@ -49,7 +62,7 @@ void UIModel::readConfigs() return !entry.endsWith(".json"); }); - std::ranges::for_each(entries, [this](const auto& name) + std::for_each(entries.begin(), entries.end(), [this](const auto& name) { auto path = config_path_; path /= config_dir_name_.toStdString(); @@ -95,18 +108,218 @@ void UIModel::updateTarget(int index, QVariant shortcut) const auto json = QJsonDocument(QJsonObject::fromVariantMap(map)); auto wtf = json.toJson(QJsonDocument::Indented).toStdString(); - writeTarget(wtf, map["name"].toString()); - auto oldName = targets_[index].toMap()["name"].toString() + ".json"; auto path = config_path_; path /= config_dir_name_.toStdString(); path /= (oldName).toStdString(); std::filesystem::remove(path); + writeTarget(wtf, map["name"].toString()); + + targets_.replace(index, json.toVariant()); emit targetListChanged(); } +void UIModel::deleteTarget(int index) +{ + auto oldName = targets_[index].toMap()["name"].toString() + ".json"; + auto path = config_path_; + path /= config_dir_name_.toStdString(); + path /= (oldName).toStdString(); + std::filesystem::remove(path); + targets_.remove(index); + emit targetListChanged(); +} + +#ifdef _WIN32 +QVariantList UIModel::uwpApps() +{ + if (!IsWindows10OrGreater()) + { + return QVariantList(); + } + + 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! + + 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) + { + 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); + } + + // 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 (SUCCEEDED(hr)) { + PWSTR appNameBuf; + QString AppUMId = QString::fromWCharArray(package->Id->FamilyName->Data()); + QString AppName; + 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->Id->Name->Data()); + else + AppName = QString::fromWCharArray(appNameBuf); + free(appNameBuf); + } + else + { + appNameBuf = manifestAppName; + AppName = QString::fromWCharArray(appNameBuf); + } + + } + else { + AppName = QString::fromWCharArray(package->Id->Name->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); + + free(pathBuf); + + pairs.push_back(uwpPair); + } + } + currPackage += 1; + }); + return pairs; +} +#endif + bool UIModel::getIsWindows() const { return is_windows_; diff --git a/GlosSIConfig/UIModel.h b/GlosSIConfig/UIModel.h index 758ab5c..0e6d715 100644 --- a/GlosSIConfig/UIModel.h +++ b/GlosSIConfig/UIModel.h @@ -25,6 +25,7 @@ class UIModel : public QObject Q_PROPERTY(bool isWindows READ getIsWindows CONSTANT) Q_PROPERTY(bool hasAcrlyicEffect READ hasAcrylicEffect NOTIFY acrylicChanged) Q_PROPERTY(QVariantList targetList READ getTargetList NOTIFY targetListChanged) + Q_PROPERTY(QVariantList uwpList READ uwpApps CONSTANT) public: UIModel(); @@ -33,6 +34,10 @@ public: Q_INVOKABLE QVariantList getTargetList() const; Q_INVOKABLE void addTarget(QVariant shortcut); Q_INVOKABLE void updateTarget(int index, QVariant shortcut); + Q_INVOKABLE void deleteTarget(int index); +#ifdef _WIN32 + Q_INVOKABLE QVariantList uwpApps(); +#endif bool getIsWindows() const; [[nodiscard]] bool hasAcrylicEffect() const; @@ -57,4 +62,3 @@ private: #endif bool has_acrylic_affect_ = false; }; - diff --git a/GlosSIConfig/main.cpp b/GlosSIConfig/main.cpp index 01ca771..50e0e3d 100644 --- a/GlosSIConfig/main.cpp +++ b/GlosSIConfig/main.cpp @@ -19,7 +19,6 @@ limitations under the License. #include #ifdef _WIN32 -#define NOMINMAX #include #include #include @@ -98,19 +97,22 @@ int main(int argc, char* argv[]) SetWindowLong(hwnd, GWL_STYLE, style); // Enable blurbehind (not needed?) anyway gives nice background on win7 and 8 - DWM_BLURBEHIND bb{ .dwFlags = DWM_BB_ENABLE, .fEnable = true, .hRgnBlur = nullptr }; + DWM_BLURBEHIND bb{}; + bb.dwFlags = DWM_BB_ENABLE; bb.fEnable = true; bb.hRgnBlur = nullptr; DwmEnableBlurBehindWindow(hwnd, &bb); if (IsWindows10OrGreater()) { // undoc stuff for aero >= Win10 int color = (0 << 24) + (0x21 << 16) + (0x11 << 8) + (0x11); - AccentPolicy accPol = { .AccentState = ACCENT_ENABLE_ACRYLICBLURBEHIND, .AccentFlags = 2, .GradientColor = color, .AnimationId = 0 }; - WindowCompositionAttributeData data = { - .Attribute = WindowCompositionAttribute::WCA_ACCENT_POLICY, - .Data = &accPol, - .SizeOfData = sizeof(accPol) - }; + AccentPolicy accPol{}; + accPol.AccentState = ACCENT_ENABLE_ACRYLICBLURBEHIND; + accPol.AccentFlags = 2; accPol.GradientColor = color; + accPol.AnimationId = 0; + WindowCompositionAttributeData data{}; + data.Attribute = WindowCompositionAttribute::WCA_ACCENT_POLICY; + data.Data = &accPol; + data.SizeOfData = sizeof(accPol); auto user32dll = GetModuleHandle(L"user32.dll"); if (user32dll) { PSetWindowCompositionAttribute SetWindowCompositionAttribute = (