summaryrefslogtreecommitdiff
path: root/indra/newview/llvelopack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvelopack.cpp')
-rw-r--r--indra/newview/llvelopack.cpp91
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();