1 #define WIN32_LEAN_AND_MEAN
2
3 #include <windows.h>
4 #include <msiquery.h>
5 #include <wcautil.h>
6
7 #define GUID_BUFFER_SIZE 39 // {8-4-4-4-12}\0
8
9
SetInstallScope(MSIHANDLE hInstall)10 extern "C" UINT WINAPI SetInstallScope(MSIHANDLE hInstall) {
11 HRESULT hr = S_OK;
12 UINT er = ERROR_SUCCESS;
13 PMSIHANDLE hDB;
14 PMSIHANDLE hView;
15 PMSIHANDLE hRecord;
16
17 hr = WcaInitialize(hInstall, "SetInstallScope");
18 ExitOnFailure(hr, "Failed to initialize");
19
20 hDB = MsiGetActiveDatabase(hInstall);
21 ExitOnNull(hDB, hr, S_FALSE, "Failed to get active database");
22
23 LPCTSTR query = TEXT("SELECT DISTINCT UpgradeCode FROM Upgrade");
24 er = MsiDatabaseOpenView(hDB, query, &hView);
25 ExitOnWin32Error(er, hr, "Failed MsiDatabaseOpenView");
26
27 er = MsiViewExecute(hView, 0);
28 ExitOnWin32Error(er, hr, "Failed MsiViewExecute");
29
30 for (;;) {
31 er = MsiViewFetch(hView, &hRecord);
32 if (er == ERROR_NO_MORE_ITEMS) break;
33 ExitOnWin32Error(er, hr, "Failed MsiViewFetch");
34
35 TCHAR upgrade_code[GUID_BUFFER_SIZE];
36 DWORD upgrade_code_len = GUID_BUFFER_SIZE;
37 er = MsiRecordGetString(hRecord, 1, upgrade_code, &upgrade_code_len);
38 ExitOnWin32Error(er, hr, "Failed to read UpgradeCode");
39
40 DWORD iProductIndex;
41 for (iProductIndex = 0;; iProductIndex++) {
42 TCHAR product_code[GUID_BUFFER_SIZE];
43 er = MsiEnumRelatedProducts(upgrade_code, 0, iProductIndex,
44 product_code);
45 if (er == ERROR_NO_MORE_ITEMS) break;
46 ExitOnWin32Error(er, hr, "Failed to get related product code");
47
48 TCHAR assignment_type[2];
49 DWORD assignment_type_len = 2;
50 er = MsiGetProductInfo(product_code, INSTALLPROPERTY_ASSIGNMENTTYPE,
51 assignment_type, &assignment_type_len);
52 ExitOnWin32Error(er, hr, "Failed to get the assignment type property "
53 "from related product");
54
55 // '0' = per-user; '1' = per-machine
56 if (assignment_type[0] == '0') {
57 /* When old versions which were installed as per-user are detected,
58 * the installation scope has to be set to per-user to be able to do
59 * an upgrade. If not, two versions will be installed side-by-side:
60 * one as per-user and the other as per-machine.
61 *
62 * If we wanted to disable backward compatibility, the installer
63 * should abort here, and request the previous version to be manually
64 * uninstalled before installing this one.
65 */
66 er = MsiSetProperty(hInstall, TEXT("ALLUSERS"), TEXT(""));
67 ExitOnWin32Error(er, hr, "Failed to set the install scope to per-user");
68 goto LExit;
69 }
70 }
71 }
72
73 LExit:
74 // Always succeed. This should not block the installation.
75 return WcaFinalize(ERROR_SUCCESS);
76 }
77
78
BroadcastEnvironmentUpdate(MSIHANDLE hInstall)79 extern "C" UINT WINAPI BroadcastEnvironmentUpdate(MSIHANDLE hInstall) {
80 HRESULT hr = S_OK;
81 UINT er = ERROR_SUCCESS;
82
83 hr = WcaInitialize(hInstall, "BroadcastEnvironmentUpdate");
84 ExitOnFailure(hr, "Failed to initialize");
85
86 SendMessageTimeoutW(HWND_BROADCAST,
87 WM_SETTINGCHANGE,
88 0,
89 (LPARAM) L"Environment",
90 SMTO_ABORTIFHUNG,
91 5000,
92 NULL);
93
94 LExit:
95 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
96 return WcaFinalize(er);
97 }
98
99
DllMain(HINSTANCE hInst,ULONG ulReason,VOID * dummy)100 extern "C" BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, VOID* dummy) {
101 switch (ulReason) {
102 case DLL_PROCESS_ATTACH:
103 WcaGlobalInitialize(hInst);
104 break;
105
106 case DLL_PROCESS_DETACH:
107 WcaGlobalFinalize();
108 break;
109 }
110
111 return TRUE;
112 }
113