1 /*
2  * Module : Set.cpp
3  * Purpose: NSIS Plug-in for setting shortcut ApplicationID property
4  * Created: 27/12/2009
5  * Original code Copyright (c) 2009 Mike Anchor.
6  */
7 
8 /*
9  * Additional Mozilla contributions:
10  *  Unicode support
11  *  Jump list deletion on uninstall
12  *  Pinned item removal on uninstall
13  *  contrib: <jmathies@mozilla.com>
14  */
15 
16 #define INITGUID
17 
18 #include <windows.h>
19 #include <shlobj.h>
20 #include <propvarutil.h>
21 #include <propkey.h>
22 #include <stdio.h>
23 
24 #pragma comment (lib, "shlwapi.lib")
25 
26 #define MAX_STRLEN 1024
27 
28 typedef struct _stack_t {
29   struct _stack_t *next;
30   TCHAR text[MAX_PATH];
31 } stack_t;
32 
33 stack_t **g_stacktop;
34 unsigned int g_stringsize;
35 TCHAR *g_variables;
36 
37 // Indicates that an application supports dual desktop and immersive modes. In Windows 8, this property is only applicable for web browsers.
38 DEFINE_PROPERTYKEY(PKEY_AppUserModel_IsDualMode, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 11);
39 
40 int popstring(TCHAR *str, int len);
41 void pushstring(const TCHAR *str, int len);
42 
Set(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop)43 extern "C" void __declspec(dllexport) Set(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop)
44 {
45   g_stringsize = string_size;
46   g_stacktop   = stacktop;
47   g_variables  = variables;
48 
49   {
50     IPropertyStore *m_pps = NULL;
51     WCHAR wszPath[MAX_PATH];
52     WCHAR wszAppID[MAX_PATH];
53     TCHAR szPath[MAX_PATH];
54     TCHAR szAppID[MAX_PATH];
55     TCHAR szDualMode[MAX_PATH];
56     bool success = false;
57 
58     ZeroMemory(wszPath, sizeof(wszPath));
59     ZeroMemory(wszAppID, sizeof(wszAppID));
60     ZeroMemory(szPath, sizeof(szPath));
61     ZeroMemory(szAppID, sizeof(szAppID));
62     ZeroMemory(szDualMode, sizeof(szDualMode));
63 
64     popstring(szPath, MAX_PATH);
65     popstring(szAppID, MAX_PATH);
66     bool dualMode = (popstring(szDualMode, MAX_PATH) == 0); // optional
67 #if !defined(UNICODE)
68     MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
69     MultiByteToWideChar(CP_ACP, 0, szAppID, -1, wszAppID, MAX_PATH);
70     if (dualMode && stricmp(szDualMode, "true") != 0) {
71       dualMode = false;
72     }
73 #else
74     wcscpy_s(wszPath, szPath);
75     wcscpy_s(wszAppID, szAppID);
76     if (dualMode && _wcsicmp(szDualMode, L"true") != 0) {
77       dualMode = false;
78     }
79 #endif
80 
81     CoInitialize(NULL);
82 
83     if (SUCCEEDED(SHGetPropertyStoreFromParsingName(wszPath, NULL, GPS_READWRITE, IID_PPV_ARGS(&m_pps))))
84     {
85       PROPVARIANT propvar;
86       if (SUCCEEDED(InitPropVariantFromString(wszAppID, &propvar))) {
87         if (SUCCEEDED(m_pps->SetValue(PKEY_AppUserModel_ID, propvar))) {
88           if (dualMode) {
89             InitPropVariantFromBoolean(true, &propvar);
90             m_pps->SetValue(PKEY_AppUserModel_IsDualMode, propvar);
91           }
92           if (SUCCEEDED(m_pps->Commit())) {
93             success = true;
94           }
95         }
96       }
97     }
98     if (m_pps != NULL)
99       m_pps->Release();
100 
101     CoUninitialize();
102 
103     pushstring(success == true ? TEXT("0") : TEXT("-1"), MAX_PATH);
104   }
105 }
106 
UninstallJumpLists(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop)107 extern "C" void __declspec(dllexport) UninstallJumpLists(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop)
108 {
109   g_stringsize = string_size;
110   g_stacktop   = stacktop;
111   g_variables  = variables;
112 
113   ICustomDestinationList *m_cdl = NULL;
114   WCHAR wszAppID[MAX_PATH];
115   TCHAR szAppID[MAX_PATH];
116   bool success = false;
117 
118   ZeroMemory(wszAppID, sizeof(wszAppID));
119   ZeroMemory(szAppID, sizeof(szAppID));
120 
121   popstring(szAppID, MAX_PATH);
122 
123 #if !defined(UNICODE)
124   MultiByteToWideChar(CP_ACP, 0, szAppID, -1, wszAppID, MAX_PATH);
125 #else
126   wcscpy_s(wszAppID, szAppID);
127 #endif
128 
129   CoInitialize(NULL);
130 
131   CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER,
132                    IID_ICustomDestinationList, (void**)&m_cdl);
133 
134   if (m_cdl) {
135     if (SUCCEEDED(m_cdl->DeleteList(wszAppID))) {
136       success = true;
137     }
138   }
139 
140   if (m_cdl)
141     m_cdl->Release();
142 
143   CoUninitialize();
144 
145   pushstring(success == true ? TEXT("0") : TEXT("-1"), MAX_PATH);
146 }
147 
UninstallPinnedItem(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop)148 extern "C" void __declspec(dllexport) UninstallPinnedItem(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop)
149 {
150   g_stringsize = string_size;
151   g_stacktop   = stacktop;
152   g_variables  = variables;
153 
154   IShellItem *pItem = NULL;
155   IStartMenuPinnedList *pPinnedList = NULL;
156   WCHAR wszPath[MAX_PATH];
157   TCHAR szPath[MAX_PATH];
158   bool success = false;
159 
160   ZeroMemory(wszPath, sizeof(wszPath));
161   ZeroMemory(szPath, sizeof(szPath));
162 
163   popstring(szPath, MAX_PATH);
164 
165 #if !defined(UNICODE)
166   MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
167 #else
168   wcscpy_s(wszPath, szPath);
169 #endif
170 
171   CoInitialize(NULL);
172 
173   HRESULT hr;
174   hr = SHCreateItemFromParsingName(wszPath, NULL, IID_PPV_ARGS(&pItem));
175 
176   if (SUCCEEDED(hr)) {
177 
178       hr = CoCreateInstance(CLSID_StartMenuPin,
179                             NULL,
180                             CLSCTX_INPROC_SERVER,
181                             IID_PPV_ARGS(&pPinnedList));
182 
183       if (SUCCEEDED(hr)) {
184           hr = pPinnedList->RemoveFromList(pItem);
185           pPinnedList->Release();
186           success = true;
187       }
188 
189       pItem->Release();
190   }
191 
192   CoUninitialize();
193 
194   pushstring(success == true ? TEXT("0") : TEXT("-1"), MAX_PATH);
195 }
196 
197 //Function: Removes the element from the top of the NSIS stack and puts it in the buffer
popstring(TCHAR * str,int len)198 int popstring(TCHAR *str, int len)
199 {
200   stack_t *th;
201   if (!g_stacktop || !*g_stacktop) return 1;
202   th=(*g_stacktop);
203   lstrcpyn(str,th->text, len);
204   *g_stacktop=th->next;
205   GlobalFree((HGLOBAL)th);
206   return 0;
207 }
208 
209 //Function: Adds an element to the top of the NSIS stack
pushstring(const TCHAR * str,int len)210 void pushstring(const TCHAR *str, int len)
211 {
212   stack_t *th;
213 
214   if (!g_stacktop) return;
215   th=(stack_t*)GlobalAlloc(GPTR, sizeof(stack_t) + len);
216   lstrcpyn(th->text, str, len);
217   th->next=*g_stacktop;
218   *g_stacktop=th;
219 }
220