diff --git a/tools/msvs/msi/custom_actions.cc b/tools/msvs/msi/custom_actions.cc index 9a23d557476004..8a8417ea0b2929 100644 --- a/tools/msvs/msi/custom_actions.cc +++ b/tools/msvs/msi/custom_actions.cc @@ -1,10 +1,80 @@ - #define WIN32_LEAN_AND_MEAN #include #include #include +#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; diff --git a/tools/msvs/msi/custom_actions.def b/tools/msvs/msi/custom_actions.def index 29e0933e379a78..5f6b25fc423492 100644 --- a/tools/msvs/msi/custom_actions.def +++ b/tools/msvs/msi/custom_actions.def @@ -1,4 +1,5 @@ LIBRARY "custom_actions" EXPORTS -BroadcastEnvironmentUpdate \ No newline at end of file +SetInstallScope +BroadcastEnvironmentUpdate diff --git a/tools/msvs/msi/product.wxs b/tools/msvs/msi/product.wxs index 30de47dad94acf..bf40b8d420ace1 100755 --- a/tools/msvs/msi/product.wxs +++ b/tools/msvs/msi/product.wxs @@ -18,7 +18,10 @@ Manufacturer="$(var.ProductAuthor)" UpgradeCode="47c07a3a-42ef-4213-a85d-8f5a59077c28"> - + @@ -269,19 +272,30 @@ Execute="deferred" Return="check" /> - + + + + + + $NodeAlias = 3 +