aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Util/ca/netshortcuts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Util/ca/netshortcuts.cpp')
-rw-r--r--src/ext/Util/ca/netshortcuts.cpp437
1 files changed, 437 insertions, 0 deletions
diff --git a/src/ext/Util/ca/netshortcuts.cpp b/src/ext/Util/ca/netshortcuts.cpp
new file mode 100644
index 00000000..06826264
--- /dev/null
+++ b/src/ext/Util/ca/netshortcuts.cpp
@@ -0,0 +1,437 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5LPCWSTR vcsShortcutsQuery =
6 L"SELECT `Component_`, `Directory_`, `Name`, `Target`, `Attributes`, `IconFile`, `IconIndex` "
7 L"FROM `Wix4InternetShortcut`";
8enum eShortcutsQuery { esqComponent = 1, esqDirectory, esqFilename, esqTarget, esqAttributes, esqIconFile, esqIconIndex };
9enum eShortcutsAttributes { esaLink = 0, esaURL = 1 };
10
11/******************************************************************
12 WixSchedInternetShortcuts - entry point
13
14********************************************************************/
15extern "C" UINT __stdcall WixSchedInternetShortcuts(
16 __in MSIHANDLE hInstall
17 )
18{
19 HRESULT hr = S_OK;
20 UINT er = ERROR_SUCCESS;
21
22 UINT uiCost = 0;
23
24 PMSIHANDLE hView = NULL;
25 PMSIHANDLE hRec = NULL;
26
27 MSIHANDLE hCreateFolderTable = NULL;
28 MSIHANDLE hCreateFolderColumns = NULL;
29
30 LPWSTR pwzCustomActionData = NULL;
31 LPWSTR pwzComponent = NULL;
32 LPWSTR pwzDirectory = NULL;
33 LPWSTR pwzFilename = NULL;
34 LPWSTR pwzTarget = NULL;
35 LPWSTR pwzShortcutPath = NULL;
36 int iAttr = 0;
37 LPWSTR pwzIconFile = NULL;
38 int iIconIndex = 0;
39 IUniformResourceLocatorW* piURL = NULL;
40 IShellLinkW* piShellLink = NULL;
41 BOOL fInitializedCom = FALSE;
42
43 hr = WcaInitialize(hInstall, "WixSchedInternetShortcuts");
44 ExitOnFailure(hr, "failed to initialize WixSchedInternetShortcuts.");
45
46 // anything to do?
47 if (S_OK != WcaTableExists(L"Wix4InternetShortcut"))
48 {
49 WcaLog(LOGMSG_STANDARD, "Wix4InternetShortcut table doesn't exist, so there are no Internet shortcuts to process");
50 goto LExit;
51 }
52
53 // check to see if we can create a shortcut - Server Core and others may not have a shell registered.
54 hr = ::CoInitialize(NULL);
55 ExitOnFailure(hr, "failed to initialize COM");
56 fInitializedCom = TRUE;
57
58 hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL);
59 if (S_OK != hr)
60 {
61 WcaLog(LOGMSG_STANDARD, "failed to create an instance of IUniformResourceLocatorW, skipping shortcut creation");
62 ExitFunction1(hr = S_OK);
63 }
64
65 hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink);
66 if (S_OK != hr)
67 {
68 WcaLog(LOGMSG_STANDARD, "failed to create an instance of IShellLinkW, skipping shortcut creation");
69 ExitFunction1(hr = S_OK);
70 }
71
72 // query and loop through all the shortcuts
73 hr = WcaOpenExecuteView(vcsShortcutsQuery, &hView);
74 ExitOnFailure(hr, "failed to open view on Wix4InternetShortcut table");
75
76 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
77 {
78 // read column values
79 hr = WcaGetRecordString(hRec, esqComponent, &pwzComponent);
80 ExitOnFailure(hr, "failed to get shortcut component");
81 hr = WcaGetRecordString(hRec, esqDirectory, &pwzDirectory);
82 ExitOnFailure(hr, "failed to get shortcut directory");
83 hr = WcaGetRecordString(hRec, esqFilename, &pwzFilename);
84 ExitOnFailure(hr, "failed to get shortcut filename");
85 hr = WcaGetRecordFormattedString(hRec, esqTarget, &pwzTarget);
86 ExitOnFailure(hr, "failed to get shortcut target");
87 hr = WcaGetRecordInteger(hRec, esqAttributes, &iAttr);
88 ExitOnFailure(hr, "failed to get shortcut attributes");
89 hr = WcaGetRecordFormattedString(hRec, esqIconFile, &pwzIconFile);
90 ExitOnFailure(hr, "failed to get shortcut icon file");
91 hr = WcaGetRecordInteger(hRec, esqIconIndex, &iIconIndex);
92 ExitOnFailure(hr, "failed to get shortcut icon index");
93
94 // skip processing this Wix4InternetShortcut row if the component isn't being configured
95 WCA_TODO todo = WcaGetComponentToDo(pwzComponent);
96 if (WCA_TODO_UNKNOWN == todo)
97 {
98 WcaLog(LOGMSG_VERBOSE, "Skipping shortcut for null-action component '%ls'", pwzComponent);
99 continue;
100 }
101
102 // we need to create the directory where the shortcut is supposed to live; rather
103 // than doing so in our deferred custom action, use the CreateFolder table to have MSI
104 // make (and remove) them on our behalf (including the correct cleanup of parent directories).
105 MSIDBERROR dbError = MSIDBERROR_NOERROR;
106 WcaLog(LOGMSG_STANDARD, "Adding folder '%ls', component '%ls' to the CreateFolder table", pwzDirectory, pwzComponent);
107 hr = WcaAddTempRecord(&hCreateFolderTable, &hCreateFolderColumns, L"CreateFolder", &dbError, 0, 2, pwzDirectory, pwzComponent);
108 if (MSIDBERROR_DUPLICATEKEY == dbError)
109 {
110 WcaLog(LOGMSG_STANDARD, "Folder '%ls' already exists in the CreateFolder table; the above error is harmless", pwzDirectory);
111 hr = S_OK;
112 }
113 ExitOnFailure(hr, "Couldn't add temporary CreateFolder row");
114
115 // only if we're installing/reinstalling do we need to schedule the deferred CA
116 // (uninstallation is handled via permanent RemoveFile rows and temporary CreateFolder rows)
117 if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo)
118 {
119 // turn the Directory_ id into a path
120 hr = WcaGetTargetPath(pwzDirectory, &pwzShortcutPath);
121 ExitOnFailure(hr, "failed to allocate string for shortcut directory");
122
123 // append the shortcut filename
124 hr = StrAllocConcat(&pwzShortcutPath, pwzFilename, 0);
125 ExitOnFailure(hr, "failed to allocate string for shortcut filename");
126
127 // write the shortcut path and target to custom action data for deferred CAs
128 hr = WcaWriteStringToCaData(pwzShortcutPath, &pwzCustomActionData);
129 ExitOnFailure(hr, "failed to write shortcut path to custom action data");
130 hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData);
131 ExitOnFailure(hr, "failed to write shortcut target to custom action data");
132 hr = WcaWriteIntegerToCaData(iAttr, &pwzCustomActionData);
133 ExitOnFailure(hr, "failed to write shortcut attributes to custom action data");
134 hr = WcaWriteStringToCaData(pwzIconFile, &pwzCustomActionData);
135 ExitOnFailure(hr, "failed to write icon file to custom action data");
136 hr = WcaWriteIntegerToCaData(iIconIndex, &pwzCustomActionData);
137 ExitOnFailure(hr, "failed to write icon index to custom action data");
138
139 uiCost += COST_INTERNETSHORTCUT;
140 }
141 }
142
143 if (E_NOMOREITEMS == hr)
144 {
145 hr = S_OK;
146 }
147 ExitOnFailure(hr, "Failure occured while processing Wix4InternetShortcut table");
148
149 // if we have any shortcuts to install
150 if (pwzCustomActionData && *pwzCustomActionData)
151 {
152 // add cost to progress bar
153 hr = WcaProgressMessage(uiCost, TRUE);
154 ExitOnFailure(hr, "failed to extend progress bar for InternetShortcuts");
155
156 // provide custom action data to deferred and rollback CAs
157 hr = WcaSetProperty(CUSTOM_ACTION_DECORATION(L"RollbackInternetShortcuts"), pwzCustomActionData);
158 ExitOnFailure(hr, "failed to set WixRollbackInternetShortcuts rollback custom action data");
159 hr = WcaSetProperty(CUSTOM_ACTION_DECORATION(L"CreateInternetShortcuts"), pwzCustomActionData);
160 ExitOnFailure(hr, "failed to set WixCreateInternetShortcuts custom action data");
161 }
162
163LExit:
164 if (hCreateFolderTable)
165 {
166 ::MsiCloseHandle(hCreateFolderTable);
167 }
168
169 if (hCreateFolderColumns)
170 {
171 ::MsiCloseHandle(hCreateFolderColumns);
172 }
173
174 ReleaseStr(pwzCustomActionData);
175 ReleaseStr(pwzComponent);
176 ReleaseStr(pwzDirectory);
177 ReleaseStr(pwzFilename);
178 ReleaseStr(pwzTarget);
179 ReleaseStr(pwzShortcutPath);
180 ReleaseObject(piShellLink);
181 ReleaseObject(piURL);
182
183 if (fInitializedCom)
184 {
185 ::CoUninitialize();
186 }
187
188 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
189 return WcaFinalize(er);
190}
191
192
193
194/******************************************************************
195 CreateUrl - Creates a shortcut via IUniformResourceLocatorW
196
197*******************************************************************/
198static HRESULT CreateUrl(
199 __in_z LPCWSTR wzTarget,
200 __in_z LPCWSTR wzShortcutPath,
201 __in_z_opt LPCWSTR wzIconPath,
202 __in int iconIndex
203)
204{
205 HRESULT hr = S_OK;
206 IUniformResourceLocatorW* piURL = NULL;
207 IPersistFile* piPersistFile = NULL;
208 IPropertySetStorage* piProperties = NULL;
209 IPropertyStorage* piStorage = NULL;
210
211 // create an internet shortcut object
212 WcaLog(LOGMSG_STANDARD, "Creating IUniformResourceLocatorW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
213 hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL);
214 ExitOnFailure(hr, "failed to create an instance of IUniformResourceLocatorW");
215
216 // set shortcut target
217 hr = piURL->SetURL(wzTarget, 0);
218 ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
219
220 if (wzIconPath)
221 {
222 WcaLog(LOGMSG_STANDARD, "Adding icon '%ls' index '%d'", wzIconPath, iconIndex);
223
224 hr = piURL->QueryInterface(IID_IPropertySetStorage, (void **)&piProperties);
225 ExitOnFailure(hr, "failed to get IPropertySetStorage for shortcut '%ls'", wzShortcutPath);
226
227 hr = piProperties->Open(FMTID_Intshcut, STGM_WRITE, &piStorage);
228 ExitOnFailure(hr, "failed to open storage for shortcut '%ls'", wzShortcutPath);
229
230 PROPSPEC ppids[2] = { {PRSPEC_PROPID, PID_IS_ICONINDEX}, {PRSPEC_PROPID, PID_IS_ICONFILE} };
231 PROPVARIANT ppvar[2];
232
233 PropVariantInit(ppvar);
234 PropVariantInit(ppvar + 1);
235
236 ppvar[0].vt = VT_I4;
237 ppvar[0].lVal = iconIndex;
238 ppvar[1].vt = VT_LPWSTR;
239 ppvar[1].pwszVal = const_cast<LPWSTR>(wzIconPath);
240
241 hr = piStorage->WriteMultiple(2, ppids, ppvar, 0);
242 ExitOnFailure(hr, "failed to write icon storage for shortcut '%ls'", wzShortcutPath);
243
244 hr = piStorage->Commit(STGC_DEFAULT);
245 ExitOnFailure(hr, "failed to commit icon storage for shortcut '%ls'", wzShortcutPath);
246 }
247
248 // get an IPersistFile and save the shortcut
249 hr = piURL->QueryInterface(IID_IPersistFile, (void**)&piPersistFile);
250 ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath);
251
252 hr = piPersistFile->Save(wzShortcutPath, TRUE);
253 ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath);
254
255LExit:
256 ReleaseObject(piPersistFile);
257 ReleaseObject(piURL);
258 ReleaseObject(piStorage);
259 ReleaseObject(piProperties);
260
261 return hr;
262}
263
264/******************************************************************
265 CreateLink - Creates a shortcut via IShellLinkW
266
267*******************************************************************/
268static HRESULT CreateLink(
269 __in_z LPCWSTR wzTarget,
270 __in_z LPCWSTR wzShortcutPath,
271 __in_z_opt LPCWSTR wzIconPath,
272 __in int iconIndex
273)
274{
275 HRESULT hr = S_OK;
276 IShellLinkW* piShellLink = NULL;
277 IPersistFile* piPersistFile = NULL;
278
279 // create an internet shortcut object
280 WcaLog(LOGMSG_STANDARD, "Creating IShellLinkW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
281 hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink);
282 ExitOnFailure(hr, "failed to create an instance of IShellLinkW");
283
284 // set shortcut target
285 hr = piShellLink->SetPath(wzTarget);
286 ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
287
288 if (wzIconPath)
289 {
290 WcaLog(LOGMSG_STANDARD, "Adding icon '%ls' index '%d'", wzIconPath, iconIndex);
291 hr = piShellLink->SetIconLocation(wzIconPath, iconIndex);
292 ExitOnFailure(hr, "failed to set icon for shortcut '%ls'", wzShortcutPath);
293 }
294
295 // get an IPersistFile and save the shortcut
296 hr = piShellLink->QueryInterface(IID_IPersistFile, (void**)&piPersistFile);
297 ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath);
298
299 hr = piPersistFile->Save(wzShortcutPath, TRUE);
300 ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath);
301
302LExit:
303 ReleaseObject(piPersistFile);
304 ReleaseObject(piShellLink);
305
306 return hr;
307}
308
309
310
311/******************************************************************
312 WixCreateInternetShortcuts - entry point for Internet shortcuts
313 custom action
314*******************************************************************/
315extern "C" UINT __stdcall WixCreateInternetShortcuts(
316 __in MSIHANDLE hInstall
317 )
318{
319 HRESULT hr = S_OK;
320 UINT er = ERROR_SUCCESS;
321
322 LPWSTR pwz = NULL;
323 LPWSTR pwzCustomActionData = NULL;
324 LPWSTR pwzTarget = NULL;
325 LPWSTR pwzShortcutPath = NULL;
326 LPWSTR pwzIconPath = NULL;
327 BOOL fInitializedCom = FALSE;
328 int iAttr = 0;
329 int iIconIndex = 0;
330
331 // initialize
332 hr = WcaInitialize(hInstall, "WixCreateInternetShortcuts");
333 ExitOnFailure(hr, "failed to initialize WixCreateInternetShortcuts");
334
335 hr = ::CoInitialize(NULL);
336 ExitOnFailure(hr, "failed to initialize COM");
337 fInitializedCom = TRUE;
338
339 // extract the custom action data
340 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
341 ExitOnFailure(hr, "failed to get CustomActionData");
342
343 // loop through all the custom action data
344 pwz = pwzCustomActionData;
345 while (pwz && *pwz)
346 {
347 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
348 ExitOnFailure(hr, "failed to read shortcut path from custom action data");
349 hr = WcaReadStringFromCaData(&pwz, &pwzTarget);
350 ExitOnFailure(hr, "failed to read shortcut target from custom action data");
351 hr = WcaReadIntegerFromCaData(&pwz, &iAttr);
352 ExitOnFailure(hr, "failed to read shortcut attributes from custom action data");
353 hr = WcaReadStringFromCaData(&pwz, &pwzIconPath);
354 ExitOnFailure(hr, "failed to read shortcut icon path from custom action data");
355 hr = WcaReadIntegerFromCaData(&pwz, &iIconIndex);
356 ExitOnFailure(hr, "failed to read shortcut icon index from custom action data");
357
358 if ((iAttr & esaURL) == esaURL)
359 {
360 hr = CreateUrl(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex);
361 }
362 else
363 {
364 hr = CreateLink(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex);
365 }
366 ExitOnFailure(hr, "failed to create Internet shortcut");
367
368 // tick the progress bar
369 hr = WcaProgressMessage(COST_INTERNETSHORTCUT, FALSE);
370 ExitOnFailure(hr, "failed to tick progress bar for shortcut: %ls", pwzShortcutPath);
371 }
372
373LExit:
374 ReleaseStr(pwzCustomActionData);
375 ReleaseStr(pwzTarget);
376 ReleaseStr(pwzShortcutPath);
377
378 if (fInitializedCom)
379 {
380 ::CoUninitialize();
381 }
382
383 er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er;
384 return WcaFinalize(er);
385}
386
387
388
389/******************************************************************
390 WixRollbackInternetShortcuts - entry point for Internet shortcuts
391 custom action (rollback)
392*******************************************************************/
393extern "C" UINT __stdcall WixRollbackInternetShortcuts(
394 __in MSIHANDLE hInstall
395 )
396{
397 HRESULT hr = S_OK;
398 UINT er = ERROR_SUCCESS;
399
400 LPWSTR pwz = NULL;
401 LPWSTR pwzCustomActionData = NULL;
402 LPWSTR pwzShortcutPath = NULL;
403 int iAttr = 0;
404
405 // initialize
406 hr = WcaInitialize(hInstall, "WixRemoveInternetShortcuts");
407 ExitOnFailure(hr, "failed to initialize WixRemoveInternetShortcuts");
408
409 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
410 ExitOnFailure(hr, "failed to get CustomActionData");
411
412 // loop through all the custom action data
413 pwz = pwzCustomActionData;
414 while (pwz && *pwz)
415 {
416 // extract the custom action data we're interested in
417 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
418 ExitOnFailure(hr, "failed to read shortcut path from custom action data for rollback");
419
420 // delete file
421 hr = FileEnsureDelete(pwzShortcutPath);
422 ExitOnFailure(hr, "failed to delete file '%ls'", pwzShortcutPath);
423
424 // skip over the shortcut target and attributes
425 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
426 ExitOnFailure(hr, "failed to skip shortcut target from custom action data for rollback");
427 hr = WcaReadIntegerFromCaData(&pwz, &iAttr);
428 ExitOnFailure(hr, "failed to read shortcut attributes from custom action data");
429 }
430
431LExit:
432 ReleaseStr(pwzCustomActionData);
433 ReleaseStr(pwzShortcutPath);
434
435 er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er;
436 return WcaFinalize(er);
437}