#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; 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; }