diff options
| author | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2026-06-16 18:26:40 +0300 |
|---|---|---|
| committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2026-06-18 21:45:41 +0300 |
| commit | fc2e96135d0a55df5f3b668298fa72505d39413b (patch) | |
| tree | 4e4af516aa3d17cd0df61593dc3f2e5b85d5de87 | |
| parent | f8c6343c9fcd320167906c0f5a603a940f253213 (diff) | |
p#587 Taskbar icon does not expand into app when opened
| -rw-r--r-- | indra/newview/llvelopack.cpp | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/indra/newview/llvelopack.cpp b/indra/newview/llvelopack.cpp index 26f3f41db6..f76d68ed72 100644 --- a/indra/newview/llvelopack.cpp +++ b/indra/newview/llvelopack.cpp @@ -50,9 +50,12 @@ #include <shlwapi.h> #include <objbase.h> #include <filesystem> +#include <propkey.h> +#include <propvarutil.h> #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "ole32.lib") +#pragma comment(lib, "propsys.lib") #pragma comment(lib, "shell32.lib") #endif // LL_WINDOWS @@ -331,6 +334,17 @@ static std::wstring get_desktop_path() return L""; } +static std::wstring get_app_user_model_id() +{ + // Format: CompanyName.ProductName + // This ID is used for: + // 1. Registry registration (HKCU\Software\Classes\Applications\{exe}\AppUserModelID) + // 2. Shortcut property (IPropertyStore::SetValue with PKEY_AppUserModel_ID) + // 3. Runtime process ID (SetCurrentProcessExplicitAppUserModelID if needed) + // Must be consistent across all uses for proper taskbar grouping. + return L"LindenLab." + get_app_name_oneword(); +} + static HRESULT create_shortcut(const std::wstring& shortcut_path, const std::wstring& target_path, const std::wstring& arguments, @@ -355,6 +369,28 @@ static HRESULT create_shortcut(const std::wstring& shortcut_path, PathRemoveFileSpecW(work_dir); shell_link->SetWorkingDirectory(work_dir); + // Set AppUserModelID on the shortcut + IPropertyStore* prop_store = nullptr; + hr = shell_link->QueryInterface(IID_IPropertyStore, (void**)&prop_store); + if (SUCCEEDED(hr)) + { + PROPVARIANT pv; + PropVariantInit(&pv); + std::wstring app_id = get_app_user_model_id(); + hr = InitPropVariantFromString(app_id.c_str(), &pv); + if (SUCCEEDED(hr)) + { + hr = prop_store->SetValue(PKEY_AppUserModel_ID, pv); + PropVariantClear(&pv); + if (SUCCEEDED(hr)) + { + HRESULT hr_commit = prop_store->Commit(); + if (FAILED(hr_commit)) hr = hr_commit; + } + } + prop_store->Release(); + } + IPersistFile* persist_file = nullptr; hr = shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file); if (SUCCEEDED(hr)) @@ -406,6 +442,42 @@ static void register_protocol_handler(const std::wstring& protocol, } } +static void register_app_user_model_id(const std::wstring& exe_name) +{ + // Register AppUserModelID for the executable + // This allows Windows to properly group taskbar items when users drag-and-drop + // the exe to pin it, without requiring runtime calls to SetCurrentProcessExplicitAppUserModelID + std::wstring key_path = L"SOFTWARE\\Classes\\Applications\\" + exe_name; + HKEY hkey; + + if (RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL) == ERROR_SUCCESS) + { + std::wstring app_user_model_id = get_app_user_model_id(); + LSTATUS status = RegSetValueExW(hkey, L"AppUserModelID", 0, REG_SZ, + (BYTE*)app_user_model_id.c_str(), + (DWORD)((app_user_model_id.size() + 1) * sizeof(wchar_t))); + RegCloseKey(hkey); + + if (status == ERROR_SUCCESS) + { + LL_DEBUGS("Velopack") << "Registered AppUserModelID: " + << ll_convert_wide_to_string(app_user_model_id) + << " for " << ll_convert_wide_to_string(exe_name) << LL_ENDL; + } + else + { + LL_WARNS("Velopack") << "Failed to set AppUserModelID (error " << status << ") for " + << ll_convert_wide_to_string(exe_name) << LL_ENDL; + } + } + else + { + LL_WARNS("Velopack") << "Failed to register AppUserModelID for " + << ll_convert_wide_to_string(exe_name) << LL_ENDL; + } +} + static bool get_shortcut_target(const std::wstring& lnk_path, std::wstring& target_path_str) { // Resolve the shortcut to check its target @@ -718,6 +790,12 @@ static void unregister_protocol_handler(const std::wstring& protocol) RegDeleteTreeW(HKEY_CURRENT_USER, key_path.c_str()); } +static void unregister_app_user_model_id(const std::wstring& exe_name) +{ + std::wstring key_path = L"SOFTWARE\\Classes\\Applications\\" + exe_name; + RegDeleteTreeW(HKEY_CURRENT_USER, key_path.c_str()); +} + static void register_uninstall_info(const std::wstring& install_dir, const std::wstring& app_name, const std::wstring& version) @@ -794,7 +872,9 @@ static void unregister_uninstall_info() RegDeleteTreeW(HKEY_CURRENT_USER, key_path.c_str()); } -static void create_shortcuts(const std::wstring& install_dir, const std::wstring& app_name) +static void create_shortcuts( + const std::wstring& install_dir, + const std::wstring& app_name) { std::wstring exe_path = install_dir + L"\\" + get_viewer_exe_name(); std::wstring start_menu_dir = get_start_menu_path() + L"\\" + app_name; @@ -866,19 +946,26 @@ static void on_after_install(void* user_data, const char* app_version) { std::wstring install_dir = get_install_dir(); std::wstring app_name = get_app_name(); - std::wstring exe_path = install_dir + L"\\" + get_viewer_exe_name(); + std::wstring exe_name = get_viewer_exe_name(); + std::wstring exe_path = install_dir + L"\\" + exe_name; register_protocol_handler(PROTOCOL_SECONDLIFE, L"URL:Second Life", exe_path); register_protocol_handler(PROTOCOL_GRID_INFO, L"URL:Second Life", exe_path); + + // Register AppUserModelID for taskbar pinning support + register_app_user_model_id(exe_name); + create_shortcuts(install_dir, app_name); } static void on_before_uninstall(void* user_data, const char* app_version) { std::wstring app_name = get_app_name(); + std::wstring exe_name = get_viewer_exe_name(); unregister_protocol_handler(PROTOCOL_SECONDLIFE); unregister_protocol_handler(PROTOCOL_GRID_INFO); + unregister_app_user_model_id(exe_name); remove_shortcuts(app_name); std::wstring install_dir = get_install_dir(); |
