Skip to content

Commit 4cfe5eb

Browse files
committed
win,msi: change InstallScope to perMachine
This is an adaptation of 8e80528. Original commit message: The MSI install scope was set to the WiX default, which is per-user. However, with UAC, it could not be installed by a standard user because InstallPrivileges is elevated by default, hence the install scope should be set to per-machine. Furthermore, the default install path is a per-machine location and setting the system path requires administrator privileges. By changing the InstallScope to perMachine, Start Menu shortcuts are placed in ProgramData and not the installing user's AppData folder, making the shortcuts available to other users. This also fixes the installation when AppData is a network folder. The custom action is necessary to allow upgrades. Since a per-machine MSI cannot upgrade an application installed per-user, the custom action checks if there is going to be an upgrade to a previous version installed per-user and sets the installation as per-user to allow upgrading. Hence, the advantages of installing per-machine will only apply in fresh installations. Fixes nodejs/node-v0.x-archive#5849 Fixes nodejs/node-v0.x-archive#7629 PR-URL: nodejs/node-v0.x-archive#25640 Reviewed-By: Alexis Campailla <[email protected]> Reviewed-By: Bert Belder <[email protected]> The original commit was adapted to search all upgrade codes listed in the upgrade table, as the current installer tries to upgrade from two different upgrade codes. PR-URL: nodejs#2565 Reviewed-By: Alexis Campailla <[email protected]>
1 parent 422d56e commit 4cfe5eb

File tree

3 files changed

+90
-5
lines changed

3 files changed

+90
-5
lines changed

tools/msvs/msi/custom_actions.cc

+71-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,80 @@
1-
21
#define WIN32_LEAN_AND_MEAN
32

43
#include <windows.h>
54
#include <msiquery.h>
65
#include <wcautil.h>
76

7+
#define GUID_BUFFER_SIZE 39 // {8-4-4-4-12}\0
8+
9+
10+
extern "C" UINT WINAPI SetInstallScope(MSIHANDLE hInstall) {
11+
HRESULT hr = S_OK;
12+
UINT er = ERROR_SUCCESS;
13+
PMSIHANDLE hDB;
14+
PMSIHANDLE hView;
15+
PMSIHANDLE hRecord;
16+
17+
hr = WcaInitialize(hInstall, "SetInstallScope");
18+
ExitOnFailure(hr, "Failed to initialize");
19+
20+
hDB = MsiGetActiveDatabase(hInstall);
21+
ExitOnNull(hDB, hr, S_FALSE, "Failed to get active database");
22+
23+
LPCTSTR query = TEXT("SELECT DISTINCT UpgradeCode FROM Upgrade");
24+
er = MsiDatabaseOpenView(hDB, query, &hView);
25+
ExitOnWin32Error(er, hr, "Failed MsiDatabaseOpenView");
26+
27+
er = MsiViewExecute(hView, 0);
28+
ExitOnWin32Error(er, hr, "Failed MsiViewExecute");
29+
30+
for (;;) {
31+
er = MsiViewFetch(hView, &hRecord);
32+
if (er == ERROR_NO_MORE_ITEMS) break;
33+
ExitOnWin32Error(er, hr, "Failed MsiViewFetch");
34+
35+
TCHAR upgrade_code[GUID_BUFFER_SIZE];
36+
DWORD upgrade_code_len = GUID_BUFFER_SIZE;
37+
er = MsiRecordGetString(hRecord, 1, upgrade_code, &upgrade_code_len);
38+
ExitOnWin32Error(er, hr, "Failed to read UpgradeCode");
39+
40+
DWORD iProductIndex;
41+
for (iProductIndex = 0;; iProductIndex++) {
42+
TCHAR product_code[GUID_BUFFER_SIZE];
43+
er = MsiEnumRelatedProducts(upgrade_code, 0, iProductIndex,
44+
product_code);
45+
if (er == ERROR_NO_MORE_ITEMS) break;
46+
ExitOnWin32Error(er, hr, "Failed to get related product code");
47+
48+
TCHAR assignment_type[2];
49+
DWORD assignment_type_len = 2;
50+
er = MsiGetProductInfo(product_code, INSTALLPROPERTY_ASSIGNMENTTYPE,
51+
assignment_type, &assignment_type_len);
52+
ExitOnWin32Error(er, hr, "Failed to get the assignment type property "
53+
"from related product");
54+
55+
// '0' = per-user; '1' = per-machine
56+
if (assignment_type[0] == '0') {
57+
/* When old versions which were installed as per-user are detected,
58+
* the installation scope has to be set to per-user to be able to do
59+
* an upgrade. If not, two versions will be installed side-by-side:
60+
* one as per-user and the other as per-machine.
61+
*
62+
* If we wanted to disable backward compatibility, the installer
63+
* should abort here, and request the previous version to be manually
64+
* uninstalled before installing this one.
65+
*/
66+
er = MsiSetProperty(hInstall, TEXT("ALLUSERS"), TEXT(""));
67+
ExitOnWin32Error(er, hr, "Failed to set the install scope to per-user");
68+
goto LExit;
69+
}
70+
}
71+
}
72+
73+
LExit:
74+
// Always succeed. This should not block the installation.
75+
return WcaFinalize(ERROR_SUCCESS);
76+
}
77+
878

979
extern "C" UINT WINAPI BroadcastEnvironmentUpdate(MSIHANDLE hInstall) {
1080
HRESULT hr = S_OK;

tools/msvs/msi/custom_actions.def

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
LIBRARY "custom_actions"
22

33
EXPORTS
4-
BroadcastEnvironmentUpdate
4+
SetInstallScope
5+
BroadcastEnvironmentUpdate

tools/msvs/msi/product.wxs

+17-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
Manufacturer="$(var.ProductAuthor)"
1919
UpgradeCode="47c07a3a-42ef-4213-a85d-8f5a59077c28">
2020

21-
<Package Languages="!(loc.LocaleId)" InstallerVersion="200" Compressed="yes"/>
21+
<Package Languages="!(loc.LocaleId)"
22+
InstallerVersion="200"
23+
Compressed="yes"
24+
InstallScope="perMachine"/>
2225

2326
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>
2427

@@ -258,16 +261,27 @@
258261
</Component>
259262
</DirectoryRef>
260263

261-
<Binary Id='BroadcastEnvironmentUpdate'
264+
<Binary Id='CustomActionsDLL'
262265
SourceFile='$(var.custom_actions.TargetDir)$(var.custom_actions.TargetName).dll' />
263266

267+
<CustomAction Id="SetInstallScope"
268+
BinaryKey="CustomActionsDLL"
269+
DllEntry="SetInstallScope"
270+
Execute="immediate"
271+
Return="check" />
272+
264273
<CustomAction Id="BroadcastEnvironmentUpdate"
265-
BinaryKey="BroadcastEnvironmentUpdate"
274+
BinaryKey="CustomActionsDLL"
266275
DllEntry="BroadcastEnvironmentUpdate"
267276
Execute="immediate"
268277
Return="check" />
269278

279+
<InstallUISequence>
280+
<Custom Action='SetInstallScope' Before='FindRelatedProducts'/>
281+
</InstallUISequence>
282+
270283
<InstallExecuteSequence>
284+
<Custom Action='SetInstallScope' Before='FindRelatedProducts'/>
271285
<Custom Action='BroadcastEnvironmentUpdate' After='InstallFinalize'/>
272286
</InstallExecuteSequence>
273287

0 commit comments

Comments
 (0)