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