Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.msi related cherry picks for v3.x #2608

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
62 changes: 48 additions & 14 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 All @@ -32,6 +35,14 @@

<Property Id="INSTALLDIR">
<RegistrySearch Id="InstallPathRegistry"
Type="raw"
Root="HKLM"
Key="$(var.RegistryKeyPath)"
Name="InstallPath"/>
<!-- Also need to search under HKCU to support upgrading from old
versions. If we wanted to disable backward compatibility, this
second search could be deleted. -->
<RegistrySearch Id="InstallPathRegistryCU"
Type="raw"
Root="HKCU"
Key="$(var.RegistryKeyPath)"
Expand All @@ -44,8 +55,9 @@
Description="!(loc.NodeRuntime_Description)"
Absent="disallow">
<ComponentRef Id="NodeExecutable"/>
<ComponentRef Id="NodeRegistryEntries"/>
<ComponentRef Id="NodeVarsScript"/>
<ComponentRef Id="NodeStartMenuAndRegistryEntries"/>
<ComponentRef Id="NodeStartMenu"/>
<ComponentRef Id="AppData" />
<ComponentGroupRef Id="Product.Generated"/>

Expand Down Expand Up @@ -130,6 +142,20 @@
<RemoveFile Id="node.exe" Name="node.exe" On="both" />
</Component>

<Component Id="NodeRegistryEntries">
<RegistryValue Root="HKLM"
Key="$(var.RegistryKeyPath)"
Name="InstallPath"
Type="string"
Value="[INSTALLDIR]"
KeyPath="yes"/>
<RegistryValue Root="HKLM"
Key="$(var.RegistryKeyPath)"
Name="Version"
Type="string"
Value="$(var.ProductVersion)"/>
</Component>

<Component Id="NodeVarsScript">
<File Id="nodevars.bat" KeyPath="yes" Source="$(var.RepoDir)\tools\msvs\nodevars.bat"/>
</Component>
Expand All @@ -152,18 +178,15 @@
</DirectoryRef>

<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="NodeStartMenuAndRegistryEntries">
<Component Id="NodeStartMenu">
<!-- RegistryValue needed because every Component must have a KeyPath.
Because of ICE43, the Root must be HKCU. -->
<RegistryValue Root="HKCU"
Key="$(var.RegistryKeyPath)"
Name="InstallPath"
Type="string"
Value="[INSTALLDIR]"
Key="$(var.RegistryKeyPath)\Components"
Name="NodeStartMenuShortcuts"
Type="integer"
Value="1"
KeyPath="yes"/>
<RegistryValue Root="HKCU"
Key="$(var.RegistryKeyPath)"
Name="Version"
Type="string"
Value="$(var.ProductVersion)"/>
<Shortcut Id="NodeVarsScriptShortcut"
Name="io.js command prompt"
Target="[%ComSpec]"
Expand Down Expand Up @@ -269,19 +292,30 @@
Execute="deferred"
Return="check" />

<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="LinkNodeExeToIojsExe" After="InstallFiles">
$NodeAlias = 3
</Custom>
<Custom Action='SetInstallScope' Before='FindRelatedProducts'/>
<Custom Action='BroadcastEnvironmentUpdate' After='InstallFinalize'/>
</InstallExecuteSequence>

Expand Down