michael@0: /* michael@0: * Module : Set.cpp michael@0: * Purpose: NSIS Plug-in for setting shortcut ApplicationID property michael@0: * Created: 27/12/2009 michael@0: * Original code Copyright (c) 2009 Mike Anchor. michael@0: */ michael@0: michael@0: /* michael@0: * Additional Mozilla contributions: michael@0: * Unicode support michael@0: * Jump list deletion on uninstall michael@0: * Pinned item removal on uninstall michael@0: * contrib: michael@0: */ michael@0: michael@0: #define INITGUID michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #pragma comment (lib, "shlwapi.lib") michael@0: michael@0: #define MAX_STRLEN 1024 michael@0: michael@0: typedef struct _stack_t { michael@0: struct _stack_t *next; michael@0: TCHAR text[MAX_PATH]; michael@0: } stack_t; michael@0: michael@0: stack_t **g_stacktop; michael@0: unsigned int g_stringsize; michael@0: TCHAR *g_variables; michael@0: michael@0: // Indicates that an application supports dual desktop and immersive modes. In Windows 8, this property is only applicable for web browsers. michael@0: DEFINE_PROPERTYKEY(PKEY_AppUserModel_IsDualMode, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 11); michael@0: michael@0: int popstring(TCHAR *str, int len); michael@0: void pushstring(const TCHAR *str, int len); michael@0: michael@0: extern "C" void __declspec(dllexport) Set(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop) michael@0: { michael@0: g_stringsize = string_size; michael@0: g_stacktop = stacktop; michael@0: g_variables = variables; michael@0: michael@0: { michael@0: IPropertyStore *m_pps = NULL; michael@0: WCHAR wszPath[MAX_PATH]; michael@0: WCHAR wszAppID[MAX_PATH]; michael@0: TCHAR szPath[MAX_PATH]; michael@0: TCHAR szAppID[MAX_PATH]; michael@0: TCHAR szDualMode[MAX_PATH]; michael@0: bool success = false; michael@0: michael@0: ZeroMemory(wszPath, sizeof(wszPath)); michael@0: ZeroMemory(wszAppID, sizeof(wszAppID)); michael@0: ZeroMemory(szPath, sizeof(szPath)); michael@0: ZeroMemory(szAppID, sizeof(szAppID)); michael@0: ZeroMemory(szDualMode, sizeof(szDualMode)); michael@0: michael@0: popstring(szPath, MAX_PATH); michael@0: popstring(szAppID, MAX_PATH); michael@0: bool dualMode = (popstring(szDualMode, MAX_PATH) == 0); // optional michael@0: #if !defined(UNICODE) michael@0: MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH); michael@0: MultiByteToWideChar(CP_ACP, 0, szAppID, -1, wszAppID, MAX_PATH); michael@0: if (dualMode && stricmp(szDualMode, "true") != 0) { michael@0: dualMode = false; michael@0: } michael@0: #else michael@0: wcscpy_s(wszPath, szPath); michael@0: wcscpy_s(wszAppID, szAppID); michael@0: if (dualMode && _wcsicmp(szDualMode, L"true") != 0) { michael@0: dualMode = false; michael@0: } michael@0: #endif michael@0: michael@0: CoInitialize(NULL); michael@0: michael@0: if (SUCCEEDED(SHGetPropertyStoreFromParsingName(wszPath, NULL, GPS_READWRITE, IID_PPV_ARGS(&m_pps)))) michael@0: { michael@0: PROPVARIANT propvar; michael@0: if (SUCCEEDED(InitPropVariantFromString(wszAppID, &propvar))) { michael@0: if (SUCCEEDED(m_pps->SetValue(PKEY_AppUserModel_ID, propvar))) { michael@0: if (dualMode) { michael@0: InitPropVariantFromBoolean(true, &propvar); michael@0: m_pps->SetValue(PKEY_AppUserModel_IsDualMode, propvar); michael@0: } michael@0: if (SUCCEEDED(m_pps->Commit())) { michael@0: success = true; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: if (m_pps != NULL) michael@0: m_pps->Release(); michael@0: michael@0: CoUninitialize(); michael@0: michael@0: pushstring(success == true ? TEXT("0") : TEXT("-1"), MAX_PATH); michael@0: } michael@0: } michael@0: michael@0: extern "C" void __declspec(dllexport) UninstallJumpLists(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop) michael@0: { michael@0: g_stringsize = string_size; michael@0: g_stacktop = stacktop; michael@0: g_variables = variables; michael@0: michael@0: ICustomDestinationList *m_cdl = NULL; michael@0: WCHAR wszAppID[MAX_PATH]; michael@0: TCHAR szAppID[MAX_PATH]; michael@0: bool success = false; michael@0: michael@0: ZeroMemory(wszAppID, sizeof(wszAppID)); michael@0: ZeroMemory(szAppID, sizeof(szAppID)); michael@0: michael@0: popstring(szAppID, MAX_PATH); michael@0: michael@0: #if !defined(UNICODE) michael@0: MultiByteToWideChar(CP_ACP, 0, szAppID, -1, wszAppID, MAX_PATH); michael@0: #else michael@0: wcscpy_s(wszAppID, szAppID); michael@0: #endif michael@0: michael@0: CoInitialize(NULL); michael@0: michael@0: CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, michael@0: IID_ICustomDestinationList, (void**)&m_cdl); michael@0: michael@0: if (m_cdl) { michael@0: if (SUCCEEDED(m_cdl->DeleteList(wszAppID))) { michael@0: success = true; michael@0: } michael@0: } michael@0: michael@0: if (m_cdl) michael@0: m_cdl->Release(); michael@0: michael@0: CoUninitialize(); michael@0: michael@0: pushstring(success == true ? TEXT("0") : TEXT("-1"), MAX_PATH); michael@0: } michael@0: michael@0: extern "C" void __declspec(dllexport) UninstallPinnedItem(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop) michael@0: { michael@0: g_stringsize = string_size; michael@0: g_stacktop = stacktop; michael@0: g_variables = variables; michael@0: michael@0: IShellItem *pItem = NULL; michael@0: IStartMenuPinnedList *pPinnedList = NULL; michael@0: WCHAR wszPath[MAX_PATH]; michael@0: TCHAR szPath[MAX_PATH]; michael@0: bool success = false; michael@0: michael@0: ZeroMemory(wszPath, sizeof(wszPath)); michael@0: ZeroMemory(szPath, sizeof(szPath)); michael@0: michael@0: popstring(szPath, MAX_PATH); michael@0: michael@0: #if !defined(UNICODE) michael@0: MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH); michael@0: #else michael@0: wcscpy_s(wszPath, szPath); michael@0: #endif michael@0: michael@0: CoInitialize(NULL); michael@0: michael@0: HRESULT hr; michael@0: hr = SHCreateItemFromParsingName(wszPath, NULL, IID_PPV_ARGS(&pItem)); michael@0: michael@0: if (SUCCEEDED(hr)) { michael@0: michael@0: hr = CoCreateInstance(CLSID_StartMenuPin, michael@0: NULL, michael@0: CLSCTX_INPROC_SERVER, michael@0: IID_PPV_ARGS(&pPinnedList)); michael@0: michael@0: if (SUCCEEDED(hr)) { michael@0: hr = pPinnedList->RemoveFromList(pItem); michael@0: pPinnedList->Release(); michael@0: success = true; michael@0: } michael@0: michael@0: pItem->Release(); michael@0: } michael@0: michael@0: CoUninitialize(); michael@0: michael@0: pushstring(success == true ? TEXT("0") : TEXT("-1"), MAX_PATH); michael@0: } michael@0: michael@0: //Function: Removes the element from the top of the NSIS stack and puts it in the buffer michael@0: int popstring(TCHAR *str, int len) michael@0: { michael@0: stack_t *th; michael@0: if (!g_stacktop || !*g_stacktop) return 1; michael@0: th=(*g_stacktop); michael@0: lstrcpyn(str,th->text, len); michael@0: *g_stacktop=th->next; michael@0: GlobalFree((HGLOBAL)th); michael@0: return 0; michael@0: } michael@0: michael@0: //Function: Adds an element to the top of the NSIS stack michael@0: void pushstring(const TCHAR *str, int len) michael@0: { michael@0: stack_t *th; michael@0: michael@0: if (!g_stacktop) return; michael@0: th=(stack_t*)GlobalAlloc(GPTR, sizeof(stack_t) + len); michael@0: lstrcpyn(th->text, str, len); michael@0: th->next=*g_stacktop; michael@0: *g_stacktop=th; michael@0: }