You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
3.5 KiB

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <msiquery.h>
#include <wcautil.h>
win,msi: change InstallScope to perMachine This is an adaptation of 8e80528453aca0354422162e09c7c9f4700ddb1e. 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&#39;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 joyent/node#5849 Fixes joyent/node#7629 PR-URL: https://github.com/joyent/node/pull/25640 Reviewed-By: Alexis Campailla &lt;alexis@janeasystems.com&gt; Reviewed-By: Bert Belder &lt;bertbelder@gmail.com&gt; 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: https://github.com/nodejs/node/pull/2565 Reviewed-By: Alexis Campailla &lt;alexis@janeasystems.com&gt;
9 years ago
#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;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "BroadcastEnvironmentUpdate");
ExitOnFailure(hr, "Failed to initialize");
SendMessageTimeoutW(HWND_BROADCAST,
WM_SETTINGCHANGE,
0,
(LPARAM) L"Environment",
SMTO_ABORTIFHUNG,
5000,
NULL);
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
extern "C" BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, VOID* dummy) {
switch (ulReason) {
case DLL_PROCESS_ATTACH:
WcaGlobalInitialize(hInst);
break;
case DLL_PROCESS_DETACH:
WcaGlobalFinalize();
break;
}
return TRUE;
}