aboutsummaryrefslogtreecommitdiff
path: root/src/ca/netshortcuts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ca/netshortcuts.cpp')
-rw-r--r--src/ca/netshortcuts.cpp434
1 files changed, 434 insertions, 0 deletions
diff --git a/src/ca/netshortcuts.cpp b/src/ca/netshortcuts.cpp
new file mode 100644
index 00000000..59ef838b
--- /dev/null
+++ b/src/ca/netshortcuts.cpp
@@ -0,0 +1,434 @@
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 `WixInternetShortcut`";
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"WixInternetShortcut"))
48 {
49 WcaLog(LOGMSG_STANDARD, "WixInternetShortcut 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 WixInternetShortcut 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 WixInternetShortcut 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 WixInternetShortcut 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(PLATFORM_DECORATION(L"WixRollbackInternetShortcuts"), pwzCustomActionData);
158 ExitOnFailure(hr, "failed to set WixRollbackInternetShortcuts rollback custom action data");
159 hr = WcaSetProperty(PLATFORM_DECORATION(L"WixCreateInternetShortcuts"), 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 hr = piURL->QueryInterface(IID_IPropertySetStorage, (void **)&piProperties);
223 ExitOnFailure(hr, "failed to get IPropertySetStorage for shortcut '%ls'", wzShortcutPath);
224
225 hr = piProperties->Open(FMTID_Intshcut, STGM_WRITE, &piStorage);
226 ExitOnFailure(hr, "failed to open storage for shortcut '%ls'", wzShortcutPath);
227
228 PROPSPEC ppids[2] = { {PRSPEC_PROPID, PID_IS_ICONINDEX}, {PRSPEC_PROPID, PID_IS_ICONFILE} };
229 PROPVARIANT ppvar[2];
230
231 PropVariantInit(ppvar);
232 PropVariantInit(ppvar + 1);
233
234 ppvar[0].vt = VT_I4;
235 ppvar[0].lVal = iconIndex;
236 ppvar[1].vt = VT_LPWSTR;
237 ppvar[1].pwszVal = (LPWSTR)wzIconPath;
238
239 hr = piStorage->WriteMultiple(2, ppids, ppvar, 0);
240 ExitOnFailure(hr, "failed to write icon storage for shortcut '%ls'", wzShortcutPath);
241
242 hr = piStorage->Commit(STGC_DEFAULT);
243 ExitOnFailure(hr, "failed to commit icon storage for shortcut '%ls'", wzShortcutPath);
244 }
245
246 // get an IPersistFile and save the shortcut
247 hr = piURL->QueryInterface(IID_IPersistFile, (void**)&piPersistFile);
248 ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath);
249
250 hr = piPersistFile->Save(wzShortcutPath, TRUE);
251 ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath);
252
253LExit:
254 ReleaseObject(piPersistFile);
255 ReleaseObject(piURL);
256 ReleaseObject(piStorage);
257 ReleaseObject(piProperties);
258
259 return hr;
260}
261
262/******************************************************************
263 CreateLink - Creates a shortcut via IShellLinkW
264
265*******************************************************************/
266static HRESULT CreateLink(
267 __in_z LPCWSTR wzTarget,
268 __in_z LPCWSTR wzShortcutPath,
269 __in_z_opt LPCWSTR wzIconPath,
270 __in int iconIndex
271)
272{
273 HRESULT hr = S_OK;
274 IShellLinkW* piShellLink = NULL;
275 IPersistFile* piPersistFile = NULL;
276
277 // create an internet shortcut object
278 WcaLog(LOGMSG_STANDARD, "Creating IShellLinkW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
279 hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink);
280 ExitOnFailure(hr, "failed to create an instance of IShellLinkW");
281
282 // set shortcut target
283 hr = piShellLink->SetPath(wzTarget);
284 ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
285
286 if (wzIconPath)
287 {
288 hr = piShellLink->SetIconLocation(wzIconPath, iconIndex);
289 ExitOnFailure(hr, "failed to set icon for shortcut '%ls'", wzShortcutPath);
290 }
291
292 // get an IPersistFile and save the shortcut
293 hr = piShellLink->QueryInterface(IID_IPersistFile, (void**)&piPersistFile);
294 ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath);
295
296 hr = piPersistFile->Save(wzShortcutPath, TRUE);
297 ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath);
298
299LExit:
300 ReleaseObject(piPersistFile);
301 ReleaseObject(piShellLink);
302
303 return hr;
304}
305
306
307
308/******************************************************************
309 WixCreateInternetShortcuts - entry point for Internet shortcuts
310 custom action
311*******************************************************************/
312extern "C" UINT __stdcall WixCreateInternetShortcuts(
313 __in MSIHANDLE hInstall
314 )
315{
316 HRESULT hr = S_OK;
317 UINT er = ERROR_SUCCESS;
318
319 LPWSTR pwz = NULL;
320 LPWSTR pwzCustomActionData = NULL;
321 LPWSTR pwzTarget = NULL;
322 LPWSTR pwzShortcutPath = NULL;
323 LPWSTR pwzIconPath = NULL;
324 BOOL fInitializedCom = FALSE;
325 int iAttr = 0;
326 int iIconIndex = 0;
327
328 // initialize
329 hr = WcaInitialize(hInstall, "WixCreateInternetShortcuts");
330 ExitOnFailure(hr, "failed to initialize WixCreateInternetShortcuts");
331
332 hr = ::CoInitialize(NULL);
333 ExitOnFailure(hr, "failed to initialize COM");
334 fInitializedCom = TRUE;
335
336 // extract the custom action data
337 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
338 ExitOnFailure(hr, "failed to get CustomActionData");
339
340 // loop through all the custom action data
341 pwz = pwzCustomActionData;
342 while (pwz && *pwz)
343 {
344 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
345 ExitOnFailure(hr, "failed to read shortcut path from custom action data");
346 hr = WcaReadStringFromCaData(&pwz, &pwzTarget);
347 ExitOnFailure(hr, "failed to read shortcut target from custom action data");
348 hr = WcaReadIntegerFromCaData(&pwz, &iAttr);
349 ExitOnFailure(hr, "failed to read shortcut attributes from custom action data");
350 hr = WcaReadStringFromCaData(&pwz, &pwzIconPath);
351 ExitOnFailure(hr, "failed to read shortcut icon path from custom action data");
352 hr = WcaReadIntegerFromCaData(&pwz, &iIconIndex);
353 ExitOnFailure(hr, "failed to read shortcut icon index from custom action data");
354
355 if ((iAttr & esaURL) == esaURL)
356 {
357 hr = CreateUrl(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex);
358 }
359 else
360 {
361 hr = CreateLink(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex);
362 }
363 ExitOnFailure(hr, "failed to create Internet shortcut");
364
365 // tick the progress bar
366 hr = WcaProgressMessage(COST_INTERNETSHORTCUT, FALSE);
367 ExitOnFailure(hr, "failed to tick progress bar for shortcut: %ls", pwzShortcutPath);
368 }
369
370LExit:
371 ReleaseStr(pwzCustomActionData);
372 ReleaseStr(pwzTarget);
373 ReleaseStr(pwzShortcutPath);
374
375 if (fInitializedCom)
376 {
377 ::CoUninitialize();
378 }
379
380 er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er;
381 return WcaFinalize(er);
382}
383
384
385
386/******************************************************************
387 WixRollbackInternetShortcuts - entry point for Internet shortcuts
388 custom action (rollback)
389*******************************************************************/
390extern "C" UINT __stdcall WixRollbackInternetShortcuts(
391 __in MSIHANDLE hInstall
392 )
393{
394 HRESULT hr = S_OK;
395 UINT er = ERROR_SUCCESS;
396
397 LPWSTR pwz = NULL;
398 LPWSTR pwzCustomActionData = NULL;
399 LPWSTR pwzShortcutPath = NULL;
400 int iAttr = 0;
401
402 // initialize
403 hr = WcaInitialize(hInstall, "WixRemoveInternetShortcuts");
404 ExitOnFailure(hr, "failed to initialize WixRemoveInternetShortcuts");
405
406 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
407 ExitOnFailure(hr, "failed to get CustomActionData");
408
409 // loop through all the custom action data
410 pwz = pwzCustomActionData;
411 while (pwz && *pwz)
412 {
413 // extract the custom action data we're interested in
414 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
415 ExitOnFailure(hr, "failed to read shortcut path from custom action data for rollback");
416
417 // delete file
418 hr = FileEnsureDelete(pwzShortcutPath);
419 ExitOnFailure(hr, "failed to delete file '%ls'", pwzShortcutPath);
420
421 // skip over the shortcut target and attributes
422 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
423 ExitOnFailure(hr, "failed to skip shortcut target from custom action data for rollback");
424 hr = WcaReadIntegerFromCaData(&pwz, &iAttr);
425 ExitOnFailure(hr, "failed to read shortcut attributes from custom action data");
426 }
427
428LExit:
429 ReleaseStr(pwzCustomActionData);
430 ReleaseStr(pwzShortcutPath);
431
432 er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er;
433 return WcaFinalize(er);
434}