Skip to content

Commit

Permalink
win,msi: change InstallScope to perMachine
Browse files Browse the repository at this point in the history
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 <alexis@janeasystems.com>
  Reviewed-By: Bert Belder <bertbelder@gmail.com>

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 <alexis@janeasystems.com>
  • Loading branch information
joaocgreis committed Aug 28, 2015
1 parent 422d56e commit 4cfe5eb
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 5 deletions.
72 changes: 71 additions & 1 deletion tools/msvs/msi/custom_actions.cc
Original file line number Diff line number Diff line change
@@ -1,10 +1,80 @@

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <msiquery.h>
#include <wcautil.h>

#define GUID_BUFFER_SIZE 39 // {8-4-4-4-12}\0


extern "C" UINT WINAPI SetInstallScope(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
PMSIHANDLE hDB;
PMSIHANDLE hView;
PMSIHANDLE hRecord;

hr = WcaInitialize(hInstall, "SetInstallScope");
ExitOnFailure(hr, "Failed to initialize");

hDB = MsiGetActiveDatabase(hInstall);
ExitOnNull(hDB, hr, S_FALSE, "Failed to get active database");

LPCTSTR query = TEXT("SELECT DISTINCT UpgradeCode FROM Upgrade");
er = MsiDatabaseOpenView(hDB, query, &hView);
ExitOnWin32Error(er, hr, "Failed MsiDatabaseOpenView");

er = MsiViewExecute(hView, 0);
ExitOnWin32Error(er, hr, "Failed MsiViewExecute");

for (;;) {
er = MsiViewFetch(hView, &hRecord);
if (er == ERROR_NO_MORE_ITEMS) break;
ExitOnWin32Error(er, hr, "Failed MsiViewFetch");

TCHAR upgrade_code[GUID_BUFFER_SIZE];
DWORD upgrade_code_len = GUID_BUFFER_SIZE;
er = MsiRecordGetString(hRecord, 1, upgrade_code, &upgrade_code_len);
ExitOnWin32Error(er, hr, "Failed to read UpgradeCode");

DWORD iProductIndex;
for (iProductIndex = 0;; iProductIndex++) {
TCHAR product_code[GUID_BUFFER_SIZE];
er = MsiEnumRelatedProducts(upgrade_code, 0, iProductIndex,
product_code);
if (er == ERROR_NO_MORE_ITEMS) break;
ExitOnWin32Error(er, hr, "Failed to get related product code");

TCHAR assignment_type[2];
DWORD assignment_type_len = 2;
er = MsiGetProductInfo(product_code, INSTALLPROPERTY_ASSIGNMENTTYPE,
assignment_type, &assignment_type_len);
ExitOnWin32Error(er, hr, "Failed to get the assignment type property "
"from related product");

// '0' = per-user; '1' = per-machine
if (assignment_type[0] == '0') {
/* When old versions which were installed as per-user are detected,
* the installation scope has to be set to per-user to be able to do
* an upgrade. If not, two versions will be installed side-by-side:
* one as per-user and the other as per-machine.
*
* If we wanted to disable backward compatibility, the installer
* should abort here, and request the previous version to be manually
* uninstalled before installing this one.
*/
er = MsiSetProperty(hInstall, TEXT("ALLUSERS"), TEXT(""));
ExitOnWin32Error(er, hr, "Failed to set the install scope to per-user");
goto LExit;
}
}
}

LExit:
// Always succeed. This should not block the installation.
return WcaFinalize(ERROR_SUCCESS);
}


extern "C" UINT WINAPI BroadcastEnvironmentUpdate(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
Expand Down
3 changes: 2 additions & 1 deletion tools/msvs/msi/custom_actions.def
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
LIBRARY "custom_actions"

EXPORTS
BroadcastEnvironmentUpdate
SetInstallScope
BroadcastEnvironmentUpdate
20 changes: 17 additions & 3 deletions tools/msvs/msi/product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
Manufacturer="$(var.ProductAuthor)"
UpgradeCode="47c07a3a-42ef-4213-a85d-8f5a59077c28">

<Package Languages="!(loc.LocaleId)" InstallerVersion="200" Compressed="yes"/>
<Package Languages="!(loc.LocaleId)"
InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"/>

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

Expand Down Expand Up @@ -258,16 +261,27 @@
</Component>
</DirectoryRef>

<Binary Id='BroadcastEnvironmentUpdate'
<Binary Id='CustomActionsDLL'
SourceFile='$(var.custom_actions.TargetDir)$(var.custom_actions.TargetName).dll' />

<CustomAction Id="SetInstallScope"
BinaryKey="CustomActionsDLL"
DllEntry="SetInstallScope"
Execute="immediate"
Return="check" />

<CustomAction Id="BroadcastEnvironmentUpdate"
BinaryKey="BroadcastEnvironmentUpdate"
BinaryKey="CustomActionsDLL"
DllEntry="BroadcastEnvironmentUpdate"
Execute="immediate"
Return="check" />

<InstallUISequence>
<Custom Action='SetInstallScope' Before='FindRelatedProducts'/>
</InstallUISequence>

<InstallExecuteSequence>
<Custom Action='SetInstallScope' Before='FindRelatedProducts'/>
<Custom Action='BroadcastEnvironmentUpdate' After='InstallFinalize'/>
</InstallExecuteSequence>

Expand Down

0 comments on commit 4cfe5eb

Please sign in to comment.