aboutsummaryrefslogtreecommitdiff
path: root/src/ca
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2019-02-04 20:05:54 -0600
committerSean Hall <r.sean.hall@gmail.com>2019-02-04 20:05:54 -0600
commitcbc09b6cd6d0d0b8bf095a88d4d8333616637f71 (patch)
treea0893e8b8772765747630052018312a2d77f97e4 /src/ca
parentc94f50e3d8dc958f8a0b9540e63e920a079c1779 (diff)
downloadwix-cbc09b6cd6d0d0b8bf095a88d4d8333616637f71.tar.gz
wix-cbc09b6cd6d0d0b8bf095a88d4d8333616637f71.tar.bz2
wix-cbc09b6cd6d0d0b8bf095a88d4d8333616637f71.zip
Import code from old v4 repo
Diffstat (limited to 'src/ca')
-rw-r--r--src/ca/cpappexec.cpp344
-rw-r--r--src/ca/cpappexec.h12
-rw-r--r--src/ca/cpapproleexec.cpp720
-rw-r--r--src/ca/cpapproleexec.h20
-rw-r--r--src/ca/cpapprolesched.cpp843
-rw-r--r--src/ca/cpapprolesched.h112
-rw-r--r--src/ca/cpappsched.cpp752
-rw-r--r--src/ca/cpappsched.h83
-rw-r--r--src/ca/cpasmexec.cpp1888
-rw-r--r--src/ca/cpasmexec.h20
-rw-r--r--src/ca/cpasmsched.cpp2135
-rw-r--r--src/ca/cpasmsched.h168
-rw-r--r--src/ca/cpcost.h30
-rw-r--r--src/ca/cpexec.cpp704
-rw-r--r--src/ca/cpexec.def11
-rw-r--r--src/ca/cppartexec.cpp690
-rw-r--r--src/ca/cppartexec.h20
-rw-r--r--src/ca/cppartroleexec.cpp397
-rw-r--r--src/ca/cppartroleexec.h12
-rw-r--r--src/ca/cppartrolesched.cpp421
-rw-r--r--src/ca/cppartrolesched.h76
-rw-r--r--src/ca/cppartsched.cpp912
-rw-r--r--src/ca/cppartsched.h125
-rw-r--r--src/ca/cpsched.cpp590
-rw-r--r--src/ca/cpsubsexec.cpp411
-rw-r--r--src/ca/cpsubsexec.h12
-rw-r--r--src/ca/cpsubssched.cpp606
-rw-r--r--src/ca/cpsubssched.h62
-rw-r--r--src/ca/cputilexec.cpp1881
-rw-r--r--src/ca/cputilexec.h193
-rw-r--r--src/ca/cputilsched.cpp885
-rw-r--r--src/ca/cputilsched.h144
32 files changed, 15279 insertions, 0 deletions
diff --git a/src/ca/cpappexec.cpp b/src/ca/cpappexec.cpp
new file mode 100644
index 00000000..43d6cd6d
--- /dev/null
+++ b/src/ca/cpappexec.cpp
@@ -0,0 +1,344 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_APPLICATION_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzID;
14 LPWSTR pwzName;
15 LPWSTR pwzPartID;
16 CPI_PROPERTY* pPropList;
17};
18
19
20// prototypes for private helper functions
21
22static HRESULT ReadApplicationAttributes(
23 LPWSTR* ppwzData,
24 CPI_APPLICATION_ATTRIBUTES* pAttrs
25 );
26static void FreeApplicationAttributes(
27 CPI_APPLICATION_ATTRIBUTES* pAttrs
28 );
29static HRESULT CreateApplication(
30 CPI_APPLICATION_ATTRIBUTES* pAttrs
31 );
32static HRESULT RemoveApplication(
33 CPI_APPLICATION_ATTRIBUTES* pAttrs
34 );
35
36
37// function definitions
38
39HRESULT CpiConfigureApplications(
40 LPWSTR* ppwzData,
41 HANDLE hRollbackFile
42 )
43{
44 HRESULT hr = S_OK;
45
46 CPI_APPLICATION_ATTRIBUTES attrs;
47 ::ZeroMemory(&attrs, sizeof(attrs));
48
49 // read action text
50 hr = CpiActionStartMessage(ppwzData, FALSE);
51 ExitOnFailure(hr, "Failed to send action start message");
52
53 // get count
54 int iCnt = 0;
55 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
56 ExitOnFailure(hr, "Failed to read count");
57
58 // write count to rollback file
59 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
60 ExitOnFailure(hr, "Failed to write count to rollback file");
61
62 for (int i = 0; i < iCnt; i++)
63 {
64 // read attributes from CustomActionData
65 hr = ReadApplicationAttributes(ppwzData, &attrs);
66 ExitOnFailure(hr, "Failed to read attributes");
67
68 // progress message
69 hr = CpiActionDataMessage(1, attrs.pwzName);
70 ExitOnFailure(hr, "Failed to send progress messages");
71
72 if (S_FALSE == hr)
73 ExitFunction();
74
75 // write key to rollback file
76 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
77 ExitOnFailure(hr, "Failed to write key to rollback file");
78
79 // action
80 switch (attrs.iActionType)
81 {
82 case atCreate:
83 hr = CreateApplication(&attrs);
84 ExitOnFailure(hr, "Failed to create application, key: %S", attrs.pwzKey);
85 break;
86 case atRemove:
87 hr = RemoveApplication(&attrs);
88 ExitOnFailure(hr, "Failed to remove application, key: %S", attrs.pwzKey);
89 break;
90 }
91
92 // write completion status to rollback file
93 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
94 ExitOnFailure(hr, "Failed to write completion status to rollback file");
95
96 // progress
97 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
98 ExitOnFailure(hr, "Failed to update progress");
99 }
100
101 hr = S_OK;
102
103LExit:
104 // clean up
105 FreeApplicationAttributes(&attrs);
106
107 return hr;
108}
109
110HRESULT CpiRollbackConfigureApplications(
111 LPWSTR* ppwzData,
112 CPI_ROLLBACK_DATA* pRollbackDataList
113 )
114{
115 HRESULT hr = S_OK;
116
117 int iRollbackStatus;
118
119 CPI_APPLICATION_ATTRIBUTES attrs;
120 ::ZeroMemory(&attrs, sizeof(attrs));
121
122 // read action text
123 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
124 ExitOnFailure(hr, "Failed to send action start message");
125
126 // get count
127 int iCnt = 0;
128 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
129 ExitOnFailure(hr, "Failed to read count");
130
131 for (int i = 0; i < iCnt; i++)
132 {
133 // read attributes from CustomActionData
134 hr = ReadApplicationAttributes(ppwzData, &attrs);
135 ExitOnFailure(hr, "Failed to read attributes");
136
137 // rollback status
138 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
139
140 if (S_FALSE == hr)
141 continue; // not found, nothing to rollback
142
143 // progress message
144 hr = CpiActionDataMessage(1, attrs.pwzName);
145 ExitOnFailure(hr, "Failed to send progress messages");
146
147 if (S_FALSE == hr)
148 ExitFunction();
149
150 // action
151 switch (attrs.iActionType)
152 {
153 case atCreate:
154 hr = CreateApplication(&attrs);
155 if (FAILED(hr))
156 WcaLog(LOGMSG_STANDARD, "Failed to create application, hr: 0x%x, key: %S", hr, attrs.pwzKey);
157 break;
158 case atRemove:
159 hr = RemoveApplication(&attrs);
160 if (FAILED(hr))
161 WcaLog(LOGMSG_STANDARD, "Failed to remove application, hr: 0x%x, key: %S", hr, attrs.pwzKey);
162 break;
163 }
164
165 // check rollback status
166 if (0 == iRollbackStatus)
167 continue; // operation did not complete, skip progress
168
169 // progress
170 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
171 ExitOnFailure(hr, "Failed to update progress");
172 }
173
174 hr = S_OK;
175
176LExit:
177 // clean up
178 FreeApplicationAttributes(&attrs);
179
180 return hr;
181}
182
183
184// helper function definitions
185
186static HRESULT ReadApplicationAttributes(
187 LPWSTR* ppwzData,
188 CPI_APPLICATION_ATTRIBUTES* pAttrs
189 )
190{
191 HRESULT hr = S_OK;
192
193 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
194 ExitOnFailure(hr, "Failed to read action type");
195 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
196 ExitOnFailure(hr, "Failed to read action cost");
197 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
198 ExitOnFailure(hr, "Failed to read key");
199 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID);
200 ExitOnFailure(hr, "Failed to read id");
201 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
202 ExitOnFailure(hr, "Failed to read name");
203 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
204 ExitOnFailure(hr, "Failed to read partition id");
205 hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList);
206 ExitOnFailure(hr, "Failed to read properties");
207
208 hr = S_OK;
209
210LExit:
211 return hr;
212}
213
214static void FreeApplicationAttributes(
215 CPI_APPLICATION_ATTRIBUTES* pAttrs
216 )
217{
218 ReleaseStr(pAttrs->pwzKey);
219 ReleaseStr(pAttrs->pwzID);
220 ReleaseStr(pAttrs->pwzName);
221 ReleaseStr(pAttrs->pwzPartID);
222
223 if (pAttrs->pPropList)
224 CpiFreePropertyList(pAttrs->pPropList);
225}
226
227static HRESULT CreateApplication(
228 CPI_APPLICATION_ATTRIBUTES* pAttrs
229 )
230{
231 HRESULT hr = S_OK;
232
233 ICatalogCollection* piAppColl = NULL;
234 ICatalogObject* piAppObj = NULL;
235
236 long lChanges = 0;
237
238 // log
239 WcaLog(LOGMSG_VERBOSE, "Creating application, key: %S", pAttrs->pwzKey);
240
241 // get applications collection
242 hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl);
243 if (S_FALSE == hr)
244 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
245 ExitOnFailure(hr, "Failed to get applications collection");
246
247 // check if application exists
248 hr = CpiFindCollectionObjectByStringKey(piAppColl, pAttrs->pwzID, &piAppObj);
249 ExitOnFailure(hr, "Failed to find application");
250
251 if (S_FALSE == hr)
252 {
253 // create application
254 hr = CpiAddCollectionObject(piAppColl, &piAppObj);
255 ExitOnFailure(hr, "Failed to add application to collection");
256
257 hr = CpiPutCollectionObjectValue(piAppObj, L"ID", pAttrs->pwzID);
258 ExitOnFailure(hr, "Failed to set application id property");
259
260 hr = CpiPutCollectionObjectValue(piAppObj, L"Name", pAttrs->pwzName);
261 ExitOnFailure(hr, "Failed to set application name property");
262
263 // save changes
264 hr = piAppColl->SaveChanges(&lChanges);
265 if (COMADMIN_E_OBJECTERRORS == hr)
266 CpiLogCatalogErrorInfo();
267 ExitOnFailure(hr, "Failed to add application");
268 }
269
270 // properties
271 hr = CpiPutCollectionObjectValues(piAppObj, pAttrs->pPropList);
272 ExitOnFailure(hr, "Failed to write properties");
273
274 // save changes
275 hr = piAppColl->SaveChanges(&lChanges);
276 if (COMADMIN_E_OBJECTERRORS == hr)
277 CpiLogCatalogErrorInfo();
278 ExitOnFailure(hr, "Failed to save changes");
279
280 // log
281 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
282
283 hr = S_OK;
284
285LExit:
286 // clean up
287 ReleaseObject(piAppColl);
288 ReleaseObject(piAppObj);
289
290 return hr;
291}
292
293static HRESULT RemoveApplication(
294 CPI_APPLICATION_ATTRIBUTES* pAttrs
295 )
296{
297 HRESULT hr = S_OK;
298
299 ICatalogCollection* piAppColl = NULL;
300
301 long lChanges = 0;
302
303 // log
304 WcaLog(LOGMSG_VERBOSE, "Removing application, key: %S", pAttrs->pwzKey);
305
306 // get applications collection
307 hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl);
308 ExitOnFailure(hr, "Failed to get applications collection");
309
310 if (S_FALSE == hr)
311 {
312 // applications collection not found
313 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve applications collection, nothing to delete, key: %S", pAttrs->pwzKey);
314 ExitFunction1(hr = S_OK);
315 }
316
317 // remove
318 hr = CpiRemoveCollectionObject(piAppColl, pAttrs->pwzID, NULL, TRUE);
319 ExitOnFailure(hr, "Failed to remove application");
320
321 if (S_FALSE == hr)
322 {
323 // application not found
324 WcaLog(LOGMSG_VERBOSE, "Application not found, nothing to delete, key: %S", pAttrs->pwzKey);
325 ExitFunction1(hr = S_OK);
326 }
327
328 // save changes
329 hr = piAppColl->SaveChanges(&lChanges);
330 if (COMADMIN_E_OBJECTERRORS == hr)
331 CpiLogCatalogErrorInfo();
332 ExitOnFailure(hr, "Failed to save changes");
333
334 // log
335 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
336
337 hr = S_OK;
338
339LExit:
340 // clean up
341 ReleaseObject(piAppColl);
342
343 return hr;
344}
diff --git a/src/ca/cpappexec.h b/src/ca/cpappexec.h
new file mode 100644
index 00000000..5003b046
--- /dev/null
+++ b/src/ca/cpappexec.h
@@ -0,0 +1,12 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureApplications(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureApplications(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
diff --git a/src/ca/cpapproleexec.cpp b/src/ca/cpapproleexec.cpp
new file mode 100644
index 00000000..e3b71e93
--- /dev/null
+++ b/src/ca/cpapproleexec.cpp
@@ -0,0 +1,720 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_APPLICATION_ROLE_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzName;
14 LPWSTR pwzAppID;
15 LPWSTR pwzPartID;
16 CPI_PROPERTY* pPropList;
17};
18
19struct CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES
20{
21 int iActionType;
22 int iActionCost;
23 LPWSTR pwzKey;
24 LPWSTR pwzRoleName;
25 LPWSTR pwzAccount;
26 LPWSTR pwzAppID;
27 LPWSTR pwzPartID;
28};
29
30
31// prototypes for private helper functions
32
33static HRESULT ReadApplicationRoleAttributes(
34 LPWSTR* ppwzData,
35 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
36 );
37static void FreeApplicationRoleAttributes(
38 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
39 );
40static HRESULT CreateApplicationRole(
41 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
42 );
43static HRESULT RemoveApplicationRole(
44 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
45 );
46static HRESULT ReadUsersInApplicationRoleAttributes(
47 LPWSTR* ppwzData,
48 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
49 );
50static void FreeUsersInApplicationRoleAttributes(
51 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
52 );
53static HRESULT CreateUsersInApplicationRole(
54 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
55 );
56static HRESULT RemoveUsersInApplicationRole(
57 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
58 );
59
60
61// function definitions
62
63HRESULT CpiConfigureApplicationRoles(
64 LPWSTR* ppwzData,
65 HANDLE hRollbackFile
66 )
67{
68 HRESULT hr = S_OK;
69
70 CPI_APPLICATION_ROLE_ATTRIBUTES attrs;
71 ::ZeroMemory(&attrs, sizeof(attrs));
72
73 // read action text
74 hr = CpiActionStartMessage(ppwzData, FALSE);
75 ExitOnFailure(hr, "Failed to send action start message");
76
77 // ger count
78 int iCnt = 0;
79 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
80 ExitOnFailure(hr, "Failed to read count");
81
82 // write count to rollback file
83 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
84 ExitOnFailure(hr, "Failed to write count to rollback file");
85
86 for (int i = 0; i < iCnt; i++)
87 {
88 // read attributes from CustomActionData
89 hr = ReadApplicationRoleAttributes(ppwzData, &attrs);
90 ExitOnFailure(hr, "Failed to read attributes");
91
92 // progress message
93 hr = CpiActionDataMessage(1, attrs.pwzName);
94 ExitOnFailure(hr, "Failed to send progress messages");
95
96 if (S_FALSE == hr)
97 ExitFunction();
98
99 // write key to rollback file
100 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
101 ExitOnFailure(hr, "Failed to write key to rollback file");
102
103 // action
104 switch (attrs.iActionType)
105 {
106 case atCreate:
107 hr = CreateApplicationRole(&attrs);
108 ExitOnFailure(hr, "Failed to create application role, key: %S", attrs.pwzKey);
109 break;
110 case atRemove:
111 hr = RemoveApplicationRole(&attrs);
112 ExitOnFailure(hr, "Failed to remove application role, key: %S", attrs.pwzKey);
113 break;
114 }
115
116 // write completion status to rollback file
117 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
118 ExitOnFailure(hr, "Failed to write completion status to rollback file");
119
120 // progress
121 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
122 ExitOnFailure(hr, "Failed to update progress");
123 }
124
125 hr = S_OK;
126
127LExit:
128 // clean up
129 FreeApplicationRoleAttributes(&attrs);
130
131 return hr;
132}
133
134HRESULT CpiRollbackConfigureApplicationRoles(
135 LPWSTR* ppwzData,
136 CPI_ROLLBACK_DATA* pRollbackDataList
137 )
138{
139 HRESULT hr = S_OK;
140
141 int iRollbackStatus;
142
143 CPI_APPLICATION_ROLE_ATTRIBUTES attrs;
144 ::ZeroMemory(&attrs, sizeof(attrs));
145
146 // read action text
147 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
148 ExitOnFailure(hr, "Failed to send action start message");
149
150 // get count
151 int iCnt = 0;
152 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
153 ExitOnFailure(hr, "Failed to read count");
154
155 for (int i = 0; i < iCnt; i++)
156 {
157 // read attributes from CustomActionData
158 hr = ReadApplicationRoleAttributes(ppwzData, &attrs);
159 ExitOnFailure(hr, "Failed to read attributes");
160
161 // rollback status
162 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
163
164 if (S_FALSE == hr)
165 continue; // not found, nothing to rollback
166
167 // progress message
168 hr = CpiActionDataMessage(1, attrs.pwzName);
169 ExitOnFailure(hr, "Failed to send progress messages");
170
171 if (S_FALSE == hr)
172 ExitFunction();
173
174 // action
175 switch (attrs.iActionType)
176 {
177 case atCreate:
178 hr = CreateApplicationRole(&attrs);
179 if (FAILED(hr))
180 WcaLog(LOGMSG_STANDARD, "Failed to create application role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
181 break;
182 case atRemove:
183 hr = RemoveApplicationRole(&attrs);
184 if (FAILED(hr))
185 WcaLog(LOGMSG_STANDARD, "Failed to remove application role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
186 break;
187 }
188
189 // check rollback status
190 if (0 == iRollbackStatus)
191 continue; // operation did not complete, skip progress
192
193 // progress
194 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
195 ExitOnFailure(hr, "Failed to update progress");
196 }
197
198 hr = S_OK;
199
200LExit:
201 // clean up
202 FreeApplicationRoleAttributes(&attrs);
203
204 return hr;
205}
206
207HRESULT CpiConfigureUsersInApplicationRoles(
208 LPWSTR* ppwzData,
209 HANDLE hRollbackFile
210 )
211{
212 HRESULT hr = S_OK;
213
214 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES attrs;
215 ::ZeroMemory(&attrs, sizeof(attrs));
216
217 // read action text
218 hr = CpiActionStartMessage(ppwzData, FALSE);
219 ExitOnFailure(hr, "Failed to send action start message");
220
221 // ger count
222 int iCnt = 0;
223 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
224 ExitOnFailure(hr, "Failed to read count");
225
226 // write count to rollback file
227 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
228 ExitOnFailure(hr, "Failed to write count to rollback file");
229
230 for (int i = 0; i < iCnt; i++)
231 {
232 // read attributes from CustomActionData
233 hr = ReadUsersInApplicationRoleAttributes(ppwzData, &attrs);
234 ExitOnFailure(hr, "Failed to read attributes");
235
236 // progress message
237 hr = CpiActionDataMessage(1, attrs.pwzRoleName);
238 ExitOnFailure(hr, "Failed to send progress messages");
239
240 if (S_FALSE == hr)
241 ExitFunction();
242
243 // write key to rollback file
244 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
245 ExitOnFailure(hr, "Failed to write key to rollback file");
246
247 // action
248 switch (attrs.iActionType)
249 {
250 case atCreate:
251 hr = CreateUsersInApplicationRole(&attrs);
252 ExitOnFailure(hr, "Failed to create user in application role, key: %S", attrs.pwzKey);
253 break;
254 case atRemove:
255 hr = RemoveUsersInApplicationRole(&attrs);
256 ExitOnFailure(hr, "Failed to remove user from application role, key: %S", attrs.pwzKey);
257 break;
258 }
259
260 // write completion status to rollback file
261 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
262 ExitOnFailure(hr, "Failed to write completion status to rollback file");
263
264 // progress
265 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
266 ExitOnFailure(hr, "Failed to update progress");
267 }
268
269 hr = S_OK;
270
271LExit:
272 // clean up
273 FreeUsersInApplicationRoleAttributes(&attrs);
274
275 return hr;
276}
277
278HRESULT CpiRollbackConfigureUsersInApplicationRoles(
279 LPWSTR* ppwzData,
280 CPI_ROLLBACK_DATA* pRollbackDataList
281 )
282{
283 HRESULT hr = S_OK;
284
285 int iRollbackStatus;
286
287 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES attrs;
288 ::ZeroMemory(&attrs, sizeof(attrs));
289
290 // read action text
291 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
292 ExitOnFailure(hr, "Failed to send action start message");
293
294 // get count
295 int iCnt = 0;
296 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
297 ExitOnFailure(hr, "Failed to read count");
298
299 for (int i = 0; i < iCnt; i++)
300 {
301 // read attributes from CustomActionData
302 hr = ReadUsersInApplicationRoleAttributes(ppwzData, &attrs);
303 ExitOnFailure(hr, "Failed to read attributes");
304
305 // rollback status
306 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
307
308 if (S_FALSE == hr)
309 continue; // not found, nothing to rollback
310
311 // progress message
312 hr = CpiActionDataMessage(1, attrs.pwzRoleName);
313 ExitOnFailure(hr, "Failed to send progress messages");
314
315 if (S_FALSE == hr)
316 ExitFunction();
317
318 // action
319 switch (attrs.iActionType)
320 {
321 case atCreate:
322 hr = CreateUsersInApplicationRole(&attrs);
323 if (FAILED(hr))
324 WcaLog(LOGMSG_STANDARD, "Failed to add user to application role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
325 break;
326 case atRemove:
327 hr = RemoveUsersInApplicationRole(&attrs);
328 if (FAILED(hr))
329 WcaLog(LOGMSG_STANDARD, "Failed to remove user from application role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
330 break;
331 }
332
333 // check rollback status
334 if (0 == iRollbackStatus)
335 continue; // operation did not complete, skip progress
336
337 // progress
338 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
339 ExitOnFailure(hr, "Failed to update progress");
340 }
341
342 hr = S_OK;
343
344LExit:
345 // clean up
346 FreeUsersInApplicationRoleAttributes(&attrs);
347
348 return hr;
349}
350
351
352// helper function definitions
353
354static HRESULT ReadApplicationRoleAttributes(
355 LPWSTR* ppwzData,
356 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
357 )
358{
359 HRESULT hr = S_OK;
360
361 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
362 ExitOnFailure(hr, "Failed to read action type");
363 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
364 ExitOnFailure(hr, "Failed to read action cost");
365 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
366 ExitOnFailure(hr, "Failed to read key");
367 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
368 ExitOnFailure(hr, "Failed to read name");
369 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
370 ExitOnFailure(hr, "Failed to read application id");
371 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
372 ExitOnFailure(hr, "Failed to read partition id");
373 hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList);
374 ExitOnFailure(hr, "Failed to read properties");
375
376 hr = S_OK;
377
378LExit:
379 return hr;
380}
381
382static void FreeApplicationRoleAttributes(
383 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
384 )
385{
386 ReleaseStr(pAttrs->pwzKey);
387 ReleaseStr(pAttrs->pwzName);
388 ReleaseStr(pAttrs->pwzAppID);
389 ReleaseStr(pAttrs->pwzPartID);
390
391 if (pAttrs->pPropList)
392 CpiFreePropertyList(pAttrs->pPropList);
393}
394
395static HRESULT CreateApplicationRole(
396 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
397 )
398{
399 HRESULT hr = S_OK;
400
401 ICatalogCollection* piRolesColl = NULL;
402 ICatalogObject* piRoleObj = NULL;
403
404 long lChanges = 0;
405
406 // log
407 WcaLog(LOGMSG_VERBOSE, "Creating application role, key: %S", pAttrs->pwzKey);
408
409 // get roles collection
410 hr = CpiGetRolesCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piRolesColl);
411 if (S_FALSE == hr)
412 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
413 ExitOnFailure(hr, "Failed to get roles collection");
414
415 // check if role exists
416 hr = CpiFindCollectionObjectByName(piRolesColl, pAttrs->pwzName, &piRoleObj);
417 ExitOnFailure(hr, "Failed to find role");
418
419 if (S_FALSE == hr)
420 {
421 // create role
422 hr = CpiAddCollectionObject(piRolesColl, &piRoleObj);
423 ExitOnFailure(hr, "Failed to add role to collection");
424
425 hr = CpiPutCollectionObjectValue(piRoleObj, L"Name", pAttrs->pwzName);
426 ExitOnFailure(hr, "Failed to set role name property");
427 }
428
429 // properties
430 hr = CpiPutCollectionObjectValues(piRoleObj, pAttrs->pPropList);
431 ExitOnFailure(hr, "Failed to write properties");
432
433 // save changes
434 hr = piRolesColl->SaveChanges(&lChanges);
435 if (COMADMIN_E_OBJECTERRORS == hr)
436 CpiLogCatalogErrorInfo();
437 ExitOnFailure(hr, "Failed to save changes");
438
439 // log
440 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
441
442 hr = S_OK;
443
444LExit:
445 // clean up
446 ReleaseObject(piRolesColl);
447 ReleaseObject(piRoleObj);
448
449 return hr;
450}
451
452static HRESULT RemoveApplicationRole(
453 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
454 )
455{
456 HRESULT hr = S_OK;
457
458 ICatalogCollection* piRolesColl = NULL;
459
460 long lChanges = 0;
461
462 // log
463 WcaLog(LOGMSG_VERBOSE, "Removing application role, key: %S", pAttrs->pwzKey);
464
465 // get roles collection
466 hr = CpiGetRolesCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piRolesColl);
467 ExitOnFailure(hr, "Failed to get roles collection");
468
469 if (S_FALSE == hr)
470 {
471 // roles collection not found
472 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve roles collection, nothing to delete, key: %S", pAttrs->pwzKey);
473 ExitFunction1(hr = S_OK);
474 }
475
476 // remove
477 hr = CpiRemoveCollectionObject(piRolesColl, NULL, pAttrs->pwzName, FALSE);
478 ExitOnFailure(hr, "Failed to remove role");
479
480 if (S_FALSE == hr)
481 {
482 // role not found
483 WcaLog(LOGMSG_VERBOSE, "Role not found, nothing to delete, key: %S", pAttrs->pwzKey);
484 ExitFunction1(hr = S_OK);
485 }
486
487 // save changes
488 hr = piRolesColl->SaveChanges(&lChanges);
489 if (COMADMIN_E_OBJECTERRORS == hr)
490 CpiLogCatalogErrorInfo();
491 ExitOnFailure(hr, "Failed to save changes");
492
493 // log
494 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
495
496 hr = S_OK;
497
498LExit:
499 // clean up
500 ReleaseObject(piRolesColl);
501
502 return hr;
503}
504
505static HRESULT ReadUsersInApplicationRoleAttributes(
506 LPWSTR* ppwzData,
507 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
508 )
509{
510 HRESULT hr = S_OK;
511
512 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
513 ExitOnFailure(hr, "Failed to read action type");
514 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
515 ExitOnFailure(hr, "Failed to read action cost");
516 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
517 ExitOnFailure(hr, "Failed to read key");
518 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzRoleName);
519 ExitOnFailure(hr, "Failed to read role name");
520 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount);
521 ExitOnFailure(hr, "Failed to read account name");
522 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
523 ExitOnFailure(hr, "Failed to read application id");
524 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
525 ExitOnFailure(hr, "Failed to read partition id");
526
527 hr = S_OK;
528
529LExit:
530 return hr;
531}
532
533static void FreeUsersInApplicationRoleAttributes(
534 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
535 )
536{
537 ReleaseStr(pAttrs->pwzKey);
538 ReleaseStr(pAttrs->pwzRoleName);
539 ReleaseStr(pAttrs->pwzAccount);
540 ReleaseStr(pAttrs->pwzAppID);
541 ReleaseStr(pAttrs->pwzPartID);
542}
543
544static HRESULT CreateUsersInApplicationRole(
545 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
546 )
547{
548 HRESULT hr = S_OK;
549 UINT er = ERROR_SUCCESS;
550
551 ICatalogCollection* piUsrInRoleColl = NULL;
552 ICatalogObject* piUsrInRoleObj = NULL;
553
554 PSID pSid = NULL;
555 long lChanges = 0;
556
557 // log
558 WcaLog(LOGMSG_VERBOSE, "Adding user to application role, key: %S", pAttrs->pwzKey);
559
560 // get users in role collection
561 hr = CpiGetUsersInRoleCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzRoleName, &piUsrInRoleColl);
562 if (S_FALSE == hr)
563 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
564 ExitOnFailure(hr, "Failed to get users in role collection");
565
566 // get SID for account
567 do {
568 er = ERROR_SUCCESS;
569 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
570 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
571 {
572 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
573 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
574 switch (er)
575 {
576 case IDABORT:
577 ExitFunction(); // exit with error code from CpiAccountNameToSid()
578 case IDRETRY:
579 break;
580 case IDIGNORE:
581 default:
582 ExitFunction1(hr = S_OK);
583 }
584 }
585 else
586 ExitOnFailure(hr, "Failed to get SID for account");
587 } while (IDRETRY == er);
588
589 // find any existing entry
590 hr = CpiFindUserCollectionObject(piUsrInRoleColl, pSid, NULL);
591 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
592 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
593 else
594 ExitOnFailure(hr, "Failed to find user in application role");
595
596 if (S_OK == hr)
597 {
598 WcaLog(LOGMSG_VERBOSE, "User already assigned to application role, key: %S", pAttrs->pwzKey);
599 ExitFunction(); // exit with hr = S_OK
600 }
601
602 // convert SID back to account name
603 hr = CpiSidToAccountName(pSid, &pAttrs->pwzAccount);
604 ExitOnFailure(hr, "Failed to convert SID to account name");
605
606 // add user
607 hr = CpiAddCollectionObject(piUsrInRoleColl, &piUsrInRoleObj);
608 ExitOnFailure(hr, "Failed to add user in role to collection");
609
610 hr = CpiPutCollectionObjectValue(piUsrInRoleObj, L"User", pAttrs->pwzAccount);
611 ExitOnFailure(hr, "Failed to set role name property");
612
613 // save changes
614 hr = piUsrInRoleColl->SaveChanges(&lChanges);
615 if (COMADMIN_E_OBJECTERRORS == hr)
616 CpiLogCatalogErrorInfo();
617 ExitOnFailure(hr, "Failed to save changes");
618
619 // log
620 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
621
622 hr = S_OK;
623
624LExit:
625 // clean up
626 ReleaseObject(piUsrInRoleColl);
627 ReleaseObject(piUsrInRoleObj);
628
629 if (pSid)
630 ::HeapFree(::GetProcessHeap(), 0, pSid);
631
632 return hr;
633}
634
635static HRESULT RemoveUsersInApplicationRole(
636 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
637 )
638{
639 HRESULT hr = S_OK;
640 UINT er = ERROR_SUCCESS;
641
642 ICatalogCollection* piUsrInRoleColl = NULL;
643
644 PSID pSid = NULL;
645 long lChanges = 0;
646
647 // log
648 WcaLog(LOGMSG_VERBOSE, "Removing user from application role, key: %S", pAttrs->pwzKey);
649
650 // get users in role collection
651 hr = CpiGetUsersInRoleCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzRoleName, &piUsrInRoleColl);
652 ExitOnFailure(hr, "Failed to get users in role collection");
653
654 if (S_FALSE == hr)
655 {
656 // users in role collection not found
657 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve users in role collection, nothing to delete, key: %S", pAttrs->pwzKey);
658 ExitFunction1(hr = S_OK);
659 }
660
661 // get SID for account
662 do {
663 er = ERROR_SUCCESS;
664 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
665 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
666 {
667 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
668 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
669 switch (er)
670 {
671 case IDABORT:
672 ExitFunction(); // exit with error code from CpiAccountNameToSid()
673 case IDRETRY:
674 break;
675 case IDIGNORE:
676 default:
677 ExitFunction1(hr = S_OK);
678 }
679 }
680 else
681 ExitOnFailure(hr, "Failed to get SID for account");
682 } while (IDRETRY == er);
683
684 // remove
685 hr = CpiRemoveUserCollectionObject(piUsrInRoleColl, pSid);
686 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
687 {
688 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
689 hr = S_FALSE;
690 }
691 else
692 ExitOnFailure(hr, "Failed to remove user");
693
694 if (S_FALSE == hr)
695 {
696 // role not found
697 WcaLog(LOGMSG_VERBOSE, "User not found for application role, nothing to delete, key: %S", pAttrs->pwzKey);
698 ExitFunction1(hr = S_OK);
699 }
700
701 // save changes
702 hr = piUsrInRoleColl->SaveChanges(&lChanges);
703 if (COMADMIN_E_OBJECTERRORS == hr)
704 CpiLogCatalogErrorInfo();
705 ExitOnFailure(hr, "Failed to save changes");
706
707 // log
708 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
709
710 hr = S_OK;
711
712LExit:
713 // clean up
714 ReleaseObject(piUsrInRoleColl);
715
716 if (pSid)
717 ::HeapFree(::GetProcessHeap(), 0, pSid);
718
719 return hr;
720}
diff --git a/src/ca/cpapproleexec.h b/src/ca/cpapproleexec.h
new file mode 100644
index 00000000..1251cbdb
--- /dev/null
+++ b/src/ca/cpapproleexec.h
@@ -0,0 +1,20 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureApplicationRoles(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureApplicationRoles(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
13HRESULT CpiConfigureUsersInApplicationRoles(
14 LPWSTR* ppwzData,
15 HANDLE hRollbackFile
16 );
17HRESULT CpiRollbackConfigureUsersInApplicationRoles(
18 LPWSTR* ppwzData,
19 CPI_ROLLBACK_DATA* pRollbackDataList
20 );
diff --git a/src/ca/cpapprolesched.cpp b/src/ca/cpapprolesched.cpp
new file mode 100644
index 00000000..a268d156
--- /dev/null
+++ b/src/ca/cpapprolesched.cpp
@@ -0,0 +1,843 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsApplicationRoleQuery =
9 L"SELECT `ApplicationRole`, `Application_`, `Component_`, `Name` FROM `ComPlusApplicationRole`";
10enum eApplicationRoleQuery { arqApplicationRole = 1, arqApplication, arqComponent, arqName };
11
12LPCWSTR vcsUserInApplicationRoleQuery =
13 L"SELECT `UserInApplicationRole`, `ApplicationRole_`, `ComPlusUserInApplicationRole`.`Component_`, `Domain`, `Name` FROM `ComPlusUserInApplicationRole`, `User` WHERE `User_` = `User`";
14LPCWSTR vcsGroupInApplicationRoleQuery =
15 L"SELECT `GroupInApplicationRole`, `ApplicationRole_`, `ComPlusGroupInApplicationRole`.`Component_`, `Domain`, `Name` FROM `ComPlusGroupInApplicationRole`, `Group` WHERE `Group_` = `Group`";
16enum eTrusteeInApplicationRoleQuery { tiarqUserInApplicationRole = 1, tiarqApplicationRole, tiarqComponent, tiarqDomain, tiarqName };
17
18LPCWSTR vcsApplicationRolePropertyQuery =
19 L"SELECT `Name`, `Value` FROM `ComPlusApplicationRoleProperty` WHERE `ApplicationRole_` = ?";
20
21
22// property definitions
23
24CPI_PROPERTY_DEFINITION pdlApplicationRoleProperties[] =
25{
26 {L"Description", cpptString, 500},
27 {NULL, cpptNone, 0}
28};
29
30
31// prototypes for private helper functions
32
33static HRESULT TrusteesInApplicationRolesRead(
34 LPCWSTR pwzQuery,
35 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
36 CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList
37 );
38static void FreeApplicationRole(
39 CPI_APPLICATION_ROLE* pItm
40 );
41static void FreeUserInApplicationRole(
42 CPI_USER_IN_APPLICATION_ROLE* pItm
43 );
44//static HRESULT GetUsersCollForApplicationRole(
45// CPI_APPLICATION_ROLE* pAppRole,
46// ICatalogCollection** ppiUsersColl
47// );
48static HRESULT FindObjectForApplicationRole(
49 CPI_APPLICATION_ROLE* pItm,
50 ICatalogObject** ppiRoleObj
51 );
52static HRESULT AddApplicationRoleToActionData(
53 CPI_APPLICATION_ROLE* pItm,
54 int iActionType,
55 int iActionCost,
56 LPWSTR* ppwzActionData
57 );
58static HRESULT AddUserInApplicationRoleToActionData(
59 CPI_USER_IN_APPLICATION_ROLE* pItm,
60 int iActionType,
61 int iActionCost,
62 LPWSTR* ppwzActionData
63 );
64
65
66// function definitions
67
68void CpiApplicationRoleListFree(
69 CPI_APPLICATION_ROLE_LIST* pList
70 )
71{
72 CPI_APPLICATION_ROLE* pItm = pList->pFirst;
73
74 while (pItm)
75 {
76 CPI_APPLICATION_ROLE* pDelete = pItm;
77 pItm = pItm->pNext;
78 FreeApplicationRole(pDelete);
79 }
80}
81
82HRESULT CpiApplicationRolesRead(
83 CPI_APPLICATION_LIST* pAppList,
84 CPI_APPLICATION_ROLE_LIST* pAppRoleList
85 )
86{
87 HRESULT hr = S_OK;
88 UINT er = ERROR_SUCCESS;
89
90 PMSIHANDLE hView, hRec;
91
92 CPI_APPLICATION_ROLE* pItm = NULL;
93 LPWSTR pwzData = NULL;
94 BOOL fMatchingArchitecture = FALSE;
95
96 // loop through all application roles
97 hr = WcaOpenExecuteView(vcsApplicationRoleQuery, &hView);
98 ExitOnFailure(hr, "Failed to execute view on ComPlusApplicationRole table");
99
100 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
101 {
102 // get component
103 hr = WcaGetRecordString(hRec, arqComponent, &pwzData);
104 ExitOnFailure(hr, "Failed to get component");
105
106 // check if the component is our processor architecture
107 if (pwzData && *pwzData)
108 {
109 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
110 ExitOnFailure(hr, "Failed to get component architecture.");
111
112 if (!fMatchingArchitecture)
113 {
114 continue; // not the same architecture, ignore
115 }
116 }
117
118 // create entry
119 pItm = (CPI_APPLICATION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_APPLICATION_ROLE));
120 if (!pItm)
121 ExitFunction1(hr = E_OUTOFMEMORY);
122
123 // get component install state
124 if (pwzData && *pwzData)
125 {
126 pItm->fHasComponent = TRUE;
127
128 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
129 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
130 }
131
132 // get key
133 hr = WcaGetRecordString(hRec, arqApplicationRole, &pwzData);
134 ExitOnFailure(hr, "Failed to get key");
135 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
136
137 // get application
138 hr = WcaGetRecordString(hRec, arqApplication, &pwzData);
139 ExitOnFailure(hr, "Failed to get application");
140
141 hr = CpiApplicationFindByKey(pAppList, pwzData, &pItm->pApplication);
142 if (S_FALSE == hr)
143 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
144 ExitOnFailure(hr, "Failed to find application, key: %S", pwzData);
145
146 // get name
147 hr = WcaGetRecordFormattedString(hRec, arqName, &pwzData);
148 ExitOnFailure(hr, "Failed to get name");
149 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
150
151 // get properties
152 if (CpiTableExists(cptComPlusApplicationRoleProperty))
153 {
154 hr = CpiPropertiesRead(vcsApplicationRolePropertyQuery, pItm->wzKey, pdlApplicationRoleProperties, &pItm->pProperties, &pItm->iPropertyCount);
155 ExitOnFailure(hr, "Failed to get properties");
156 }
157
158 // set references & increment counters
159 if (pItm->fHasComponent)
160 {
161 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
162 {
163 CpiApplicationAddReferenceInstall(pItm->pApplication);
164 pAppRoleList->iInstallCount++;
165 }
166 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
167 {
168 CpiApplicationAddReferenceUninstall(pItm->pApplication);
169 pAppRoleList->iUninstallCount++;
170 }
171 }
172
173 // add entry
174 if (pAppRoleList->pFirst)
175 pItm->pNext = pAppRoleList->pFirst;
176 pAppRoleList->pFirst = pItm;
177 pItm = NULL;
178 }
179
180 if (E_NOMOREITEMS == hr)
181 hr = S_OK;
182
183LExit:
184 // clean up
185 if (pItm)
186 FreeApplicationRole(pItm);
187
188 ReleaseStr(pwzData);
189
190 return hr;
191}
192
193HRESULT CpiApplicationRolesVerifyInstall(
194 CPI_APPLICATION_ROLE_LIST* pList
195 )
196{
197 HRESULT hr = S_OK;
198 UINT er = ERROR_SUCCESS;
199
200 ICatalogObject* piRoleObj = NULL;
201
202 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
203 {
204 // referenced locaters or roles that are being installed
205 if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)))
206 continue;
207
208 // if the role is referensed and is not a locater, it must be installed
209 if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
210 MessageExitOnFailure(hr = E_FAIL, msierrComPlusApplicationRoleDependency, "An application role is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
211
212 // role is a locater
213 if (!pItm->fHasComponent)
214 {
215 // get collection object for role
216 hr = FindObjectForApplicationRole(pItm, &piRoleObj);
217 ExitOnFailure(hr, "Failed to find collection object for role");
218
219 // if the role was not found
220 if (S_FALSE == hr)
221 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationRoleNotFound, "An application role required by this installation was not found, key: %S", pItm->wzKey);
222 }
223
224 // role is supposed to be created
225 else if (!CpiIsInstalled(pItm->isInstalled))
226 {
227 do {
228 // find roles with conflicting name or id
229 hr = FindObjectForApplicationRole(pItm, NULL);
230 ExitOnFailure(hr, "Failed to find collection object for role");
231
232 if (S_OK == hr)
233 {
234 er = WcaErrorMessage(msierrComPlusApplicationRoleConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
235 switch (er)
236 {
237 case IDABORT:
238 ExitOnFailure(hr = E_FAIL, "An application with a conflictiong name exists, key: %S", pItm->wzKey);
239 break;
240 case IDRETRY:
241 break;
242 case IDIGNORE:
243 default:
244 hr = S_FALSE; // indicate that this is not a conflict
245 }
246 }
247 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
248 }
249
250 // clean up
251 ReleaseNullObject(piRoleObj);
252 }
253
254 hr = S_OK;
255
256LExit:
257 // clean up
258 ReleaseObject(piRoleObj);
259
260 return hr;
261}
262
263HRESULT CpiApplicationRolesVerifyUninstall(
264 CPI_APPLICATION_ROLE_LIST* pList
265 )
266{
267 HRESULT hr = S_OK;
268
269 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
270 {
271 // referenced locaters or roles that are being installed
272 if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction)))
273 continue;
274
275 // get collection object for role
276 hr = FindObjectForApplicationRole(pItm, NULL);
277 ExitOnFailure(hr, "Failed to find collection object for role");
278
279 // if the role was not found
280 if (S_FALSE == hr)
281 {
282 pItm->fObjectNotFound = TRUE;
283 if (pItm->fHasComponent)
284 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
285 }
286 }
287
288 hr = S_OK;
289
290LExit:
291 return hr;
292}
293
294void CpiApplicationRoleAddReferenceInstall(
295 CPI_APPLICATION_ROLE* pItm
296 )
297{
298 pItm->fReferencedForInstall = TRUE;
299 CpiApplicationAddReferenceInstall(pItm->pApplication);
300}
301
302void CpiApplicationRoleAddReferenceUninstall(
303 CPI_APPLICATION_ROLE* pItm
304 )
305{
306 pItm->fReferencedForUninstall = TRUE;
307 CpiApplicationAddReferenceUninstall(pItm->pApplication);
308}
309
310HRESULT CpiApplicationRolesInstall(
311 CPI_APPLICATION_ROLE_LIST* pList,
312 int iRunMode,
313 LPWSTR* ppwzActionData,
314 int* piProgress
315 )
316{
317 HRESULT hr = S_OK;
318
319 int iActionType;
320
321 // add action text
322 hr = CpiAddActionTextToActionData(L"CreateComPlusApplicationRoles", ppwzActionData);
323 ExitOnFailure(hr, "Failed to add action text to custom action data");
324
325 // add count to action data
326 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
327 ExitOnFailure(hr, "Failed to add count to custom action data");
328
329 // add roles to custom action data
330 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
331 {
332 // roles that are being installed only
333 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
334 continue;
335
336 // action type
337 if (rmRollback == iRunMode)
338 {
339 if (CpiIsInstalled(pItm->isInstalled))
340 iActionType = atNoOp;
341 else
342 iActionType = atRemove;
343 }
344 else
345 iActionType = atCreate;
346
347 // add to action data
348 hr = AddApplicationRoleToActionData(pItm, iActionType, COST_APPLICATION_ROLE_CREATE, ppwzActionData);
349 ExitOnFailure(hr, "Failed to add application role to custom action data, key: %S", pItm->wzKey);
350 }
351
352 // add progress tics
353 if (piProgress)
354 *piProgress += COST_APPLICATION_ROLE_CREATE * pList->iInstallCount;
355
356 hr = S_OK;
357
358LExit:
359 return hr;
360}
361
362HRESULT CpiApplicationRolesUninstall(
363 CPI_APPLICATION_ROLE_LIST* pList,
364 int iRunMode,
365 LPWSTR* ppwzActionData,
366 int* piProgress
367 )
368{
369 HRESULT hr = S_OK;
370
371 int iActionType;
372
373 // add action text
374 hr = CpiAddActionTextToActionData(L"RemoveComPlusApplicationRoles", ppwzActionData);
375 ExitOnFailure(hr, "Failed to add action text to custom action data");
376
377 // add count to action data
378 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
379 ExitOnFailure(hr, "Failed to add count to custom action data");
380
381 // add roles to custom action data
382 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
383 {
384 // roles that are being uninstalled only
385 if (pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
386 continue;
387
388 // action type
389 if (rmRollback == iRunMode)
390 iActionType = atCreate;
391 else
392 iActionType = atRemove;
393
394 // add to action data
395 hr = AddApplicationRoleToActionData(pItm, iActionType, COST_APPLICATION_ROLE_DELETE, ppwzActionData);
396 ExitOnFailure(hr, "Failed to add application role to custom action data, key: %S", pItm->wzKey);
397 }
398
399 // add progress tics
400 if (piProgress)
401 *piProgress += COST_APPLICATION_ROLE_DELETE * pList->iUninstallCount;
402
403 hr = S_OK;
404
405LExit:
406 return hr;
407}
408
409HRESULT CpiApplicationRoleFindByKey(
410 CPI_APPLICATION_ROLE_LIST* pList,
411 LPCWSTR pwzKey,
412 CPI_APPLICATION_ROLE** ppAppRole
413 )
414{
415 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
416 {
417 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
418 {
419 *ppAppRole = pItm;
420 return S_OK;
421 }
422 }
423
424 return S_FALSE;
425}
426
427void CpiUserInApplicationRoleListFree(
428 CPI_USER_IN_APPLICATION_ROLE_LIST* pList
429 )
430{
431 CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst;
432
433 while (pItm)
434 {
435 CPI_USER_IN_APPLICATION_ROLE* pDelete = pItm;
436 pItm = pItm->pNext;
437 FreeUserInApplicationRole(pDelete);
438 }
439}
440
441HRESULT CpiUsersInApplicationRolesRead(
442 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
443 CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList
444 )
445{
446 HRESULT hr = S_OK;
447
448 // read users in application roles
449 if (CpiTableExists(cptComPlusUserInApplicationRole))
450 {
451 hr = TrusteesInApplicationRolesRead(vcsUserInApplicationRoleQuery, pAppRoleList, pUsrInAppRoleList);
452 ExitOnFailure(hr, "Failed to read users in application roles");
453 }
454
455 // read groups in application roles
456 if (CpiTableExists(cptComPlusGroupInApplicationRole))
457 {
458 hr = TrusteesInApplicationRolesRead(vcsGroupInApplicationRoleQuery, pAppRoleList, pUsrInAppRoleList);
459 ExitOnFailure(hr, "Failed to read groups in application roles");
460 }
461
462 hr = S_OK;
463
464LExit:
465 return hr;
466}
467
468HRESULT CpiUsersInApplicationRolesInstall(
469 CPI_USER_IN_APPLICATION_ROLE_LIST* pList,
470 int iRunMode,
471 LPWSTR* ppwzActionData,
472 int* piProgress
473 )
474{
475 HRESULT hr = S_OK;
476
477 int iActionType;
478
479 // add action text
480 hr = CpiAddActionTextToActionData(L"AddUsersToComPlusApplicationRoles", ppwzActionData);
481 ExitOnFailure(hr, "Failed to add action text to custom action data");
482
483 // add count to action data
484 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
485 ExitOnFailure(hr, "Failed to add count to custom action data");
486
487 // add roles to custom action data
488 for (CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
489 {
490 // roles that are being installed only
491 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
492 continue;
493
494 // action type
495 if (rmRollback == iRunMode)
496 {
497 if (CpiIsInstalled(pItm->isInstalled))
498 iActionType = atNoOp;
499 else
500 iActionType = atRemove;
501 }
502 else
503 iActionType = atCreate;
504
505 // add to action data
506 hr = AddUserInApplicationRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_CREATE, ppwzActionData);
507 ExitOnFailure(hr, "Failed to add user in application role to custom action data, key: %S", pItm->wzKey);
508 }
509
510 // add progress tics
511 if (piProgress)
512 *piProgress += COST_USER_IN_APPLICATION_ROLE_CREATE * pList->iInstallCount;
513
514 hr = S_OK;
515
516LExit:
517 return hr;
518}
519
520HRESULT CpiUsersInApplicationRolesUninstall(
521 CPI_USER_IN_APPLICATION_ROLE_LIST* pList,
522 int iRunMode,
523 LPWSTR* ppwzActionData,
524 int* piProgress
525 )
526{
527 HRESULT hr = S_OK;
528
529 int iActionType;
530
531 // add action text
532 hr = CpiAddActionTextToActionData(L"RemoveUsersFromComPlusAppRoles", ppwzActionData);
533 ExitOnFailure(hr, "Failed to add action text to custom action data");
534
535 // add count to action data
536 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
537 ExitOnFailure(hr, "Failed to add count to custom action data");
538
539 // add roles to custom action data
540 for (CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
541 {
542 // roles that are being uninstalled only
543 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
544 continue;
545
546 // action type
547 if (rmRollback == iRunMode)
548 iActionType = atCreate;
549 else
550 iActionType = atRemove;
551
552 // add to action data
553 hr = AddUserInApplicationRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_DELETE, ppwzActionData);
554 ExitOnFailure(hr, "Failed to add user in application role to custom action data, key: %S", pItm->wzKey);
555 }
556
557 // add progress tics
558 if (piProgress)
559 *piProgress += COST_USER_IN_APPLICATION_ROLE_DELETE * pList->iUninstallCount;
560
561 hr = S_OK;
562
563LExit:
564 return hr;
565}
566
567
568// helper function definitions
569
570static HRESULT TrusteesInApplicationRolesRead(
571 LPCWSTR pwzQuery,
572 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
573 CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList
574 )
575{
576 HRESULT hr = S_OK;
577 UINT er = ERROR_SUCCESS;
578
579 PMSIHANDLE hView, hRec;
580
581 CPI_USER_IN_APPLICATION_ROLE* pItm = NULL;
582 LPWSTR pwzData = NULL;
583 LPWSTR pwzDomain = NULL;
584 LPWSTR pwzName = NULL;
585 BOOL fMatchingArchitecture = FALSE;
586
587 // loop through all application roles
588 hr = WcaOpenExecuteView(pwzQuery, &hView);
589 ExitOnFailure(hr, "Failed to execute view on table");
590
591 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
592 {
593 // get component
594 hr = WcaGetRecordString(hRec, tiarqComponent, &pwzData);
595 ExitOnFailure(hr, "Failed to get component");
596
597 // check if the component is our processor architecture
598 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
599 ExitOnFailure(hr, "Failed to get component architecture.");
600
601 if (!fMatchingArchitecture)
602 {
603 continue; // not the same architecture, ignore
604 }
605
606 // create entry
607 pItm = (CPI_USER_IN_APPLICATION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_USER_IN_APPLICATION_ROLE));
608 if (!pItm)
609 ExitFunction1(hr = E_OUTOFMEMORY);
610
611 // get component install state
612 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
613 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
614
615 // get key
616 hr = WcaGetRecordString(hRec, tiarqUserInApplicationRole, &pwzData);
617 ExitOnFailure(hr, "Failed to get key");
618 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
619
620 // get application role
621 hr = WcaGetRecordString(hRec, tiarqApplicationRole, &pwzData);
622 ExitOnFailure(hr, "Failed to get application role");
623
624 hr = CpiApplicationRoleFindByKey(pAppRoleList, pwzData, &pItm->pApplicationRole);
625 if (S_FALSE == hr)
626 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
627 ExitOnFailure(hr, "Failed to find application role, key: %S", pwzData);
628
629 // get user domain
630 hr = WcaGetRecordFormattedString(hRec, tiarqDomain, &pwzDomain);
631 ExitOnFailure(hr, "Failed to get domain");
632
633 // get user name
634 hr = WcaGetRecordFormattedString(hRec, tiarqName, &pwzName);
635 ExitOnFailure(hr, "Failed to get name");
636
637 // build account name
638 hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount);
639 ExitOnFailure(hr, "Failed to build account name");
640
641 // set references & increment counters
642 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
643 {
644 CpiApplicationRoleAddReferenceInstall(pItm->pApplicationRole);
645 pUsrInAppRoleList->iInstallCount++;
646 }
647 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
648 {
649 CpiApplicationRoleAddReferenceUninstall(pItm->pApplicationRole);
650 pUsrInAppRoleList->iUninstallCount++;
651 }
652
653 // add entry
654 if (pUsrInAppRoleList->pFirst)
655 pItm->pNext = pUsrInAppRoleList->pFirst;
656 pUsrInAppRoleList->pFirst = pItm;
657 pItm = NULL;
658 }
659
660 if (E_NOMOREITEMS == hr)
661 hr = S_OK;
662
663LExit:
664 // clean up
665 if (pItm)
666 FreeUserInApplicationRole(pItm);
667
668 ReleaseStr(pwzData);
669 ReleaseStr(pwzDomain);
670 ReleaseStr(pwzName);
671
672 return hr;
673}
674
675static void FreeApplicationRole(
676 CPI_APPLICATION_ROLE* pItm
677 )
678{
679 if (pItm->pProperties)
680 CpiPropertiesFreeList(pItm->pProperties);
681
682 ReleaseObject(pItm->piUsersColl);
683
684 ::HeapFree(::GetProcessHeap(), 0, pItm);
685}
686
687static void FreeUserInApplicationRole(
688 CPI_USER_IN_APPLICATION_ROLE* pItm
689 )
690{
691 ReleaseStr(pItm->pwzAccount);
692
693 ::HeapFree(::GetProcessHeap(), 0, pItm);
694}
695
696//static HRESULT GetUsersCollForApplicationRole(
697// CPI_APPLICATION_ROLE* pAppRole,
698// ICatalogCollection** ppiUsersColl
699// )
700//{
701// HRESULT hr = S_OK;
702//
703// ICatalogCollection* piRoleColl = NULL;
704// ICatalogObject* piRoleObj = NULL;
705//
706// // if a previous attempt to locate the collection object failed
707// if (pAppRole->fObjectNotFound)
708// ExitFunction1(hr = S_FALSE);
709//
710// // get applications collection
711// if (!pAppRole->piUsersColl)
712// {
713// // get collection object for role
714// hr = FindObjectForApplicationRole(pAppRole, &piRoleObj);
715// ExitOnFailure(hr, "Failed to find collection object for role");
716//
717// if (S_FALSE == hr)
718// ExitFunction(); // exit with hr = S_FALSE
719//
720// // get users collection
721// hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", &pAppRole->piUsersColl);
722// ExitOnFailure(hr, "Failed to get users in role collection");
723// }
724//
725// // return value
726// *ppiUsersColl = pAppRole->piUsersColl;
727// (*ppiUsersColl)->AddRef();
728//
729// hr = S_OK;
730//
731//LExit:
732// // clean up
733// ReleaseObject(piRoleColl);
734// ReleaseObject(piRoleObj);
735//
736// return hr;
737//}
738
739static HRESULT FindObjectForApplicationRole(
740 CPI_APPLICATION_ROLE* pItm,
741 ICatalogObject** ppiRoleObj
742 )
743{
744 HRESULT hr = S_OK;
745
746 ICatalogCollection* piRoleColl = NULL;
747
748 // get roles collection
749 hr = CpiGetRolesCollForApplication(pItm->pApplication, &piRoleColl);
750 ExitOnFailure(hr, "Failed to get collection");
751
752 if (S_FALSE == hr)
753 ExitFunction(); // exit with hr = S_FALSE
754
755 // find role object
756 hr = CpiFindCollectionObject(piRoleColl, NULL, pItm->wzName, ppiRoleObj);
757 ExitOnFailure(hr, "Failed to find object");
758
759 // exit with hr from CpiFindCollectionObject()
760
761LExit:
762 // clean up
763 ReleaseObject(piRoleColl);
764
765 return hr;
766}
767
768static HRESULT AddApplicationRoleToActionData(
769 CPI_APPLICATION_ROLE* pItm,
770 int iActionType,
771 int iActionCost,
772 LPWSTR* ppwzActionData
773 )
774{
775 HRESULT hr = S_OK;
776
777 // add action information to custom action data
778 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
779 ExitOnFailure(hr, "Failed to add action type to custom action data");
780 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
781 ExitOnFailure(hr, "Failed to add action cost to custom action data");
782
783 // add application role information to custom action data
784 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
785 ExitOnFailure(hr, "Failed to add application role key to custom action data");
786 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
787 ExitOnFailure(hr, "Failed to add application role name to custom action data");
788
789 // add application information to custom action data
790 hr = WcaWriteStringToCaData(pItm->pApplication->wzID, ppwzActionData);
791 ExitOnFailure(hr, "Failed to add application id to custom action data");
792
793 // add partition information to custom action data
794 hr = WcaWriteStringToCaData(pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"", ppwzActionData);
795 ExitOnFailure(hr, "Failed to add partition id to custom action data");
796
797 // add properties to custom action data
798 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
799 ExitOnFailure(hr, "Failed to add properties to custom action data");
800
801 hr = S_OK;
802
803LExit:
804 return hr;
805}
806
807static HRESULT AddUserInApplicationRoleToActionData(
808 CPI_USER_IN_APPLICATION_ROLE* pItm,
809 int iActionType,
810 int iActionCost,
811 LPWSTR* ppwzActionData
812 )
813{
814 HRESULT hr = S_OK;
815
816 // add action information to custom action data
817 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
818 ExitOnFailure(hr, "Failed to add action type to custom action data");
819 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
820 ExitOnFailure(hr, "Failed to add action cost to custom action data");
821
822 // add application role information to custom action data
823 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
824 ExitOnFailure(hr, "Failed to add key to custom action data");
825 hr = WcaWriteStringToCaData(pItm->pApplicationRole->wzName, ppwzActionData);
826 ExitOnFailure(hr, "Failed to add role name to custom action data");
827 hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData);
828 ExitOnFailure(hr, "Failed to add user account to custom action data");
829
830 // add application information to custom action data
831 CPI_APPLICATION* pApplication = pItm->pApplicationRole->pApplication;
832 hr = WcaWriteStringToCaData(pApplication->wzID, ppwzActionData);
833 ExitOnFailure(hr, "Failed to add application id to custom action data");
834
835 // add partition information to custom action data
836 hr = WcaWriteStringToCaData(pApplication->pPartition ? pApplication->pPartition->wzID : L"", ppwzActionData);
837 ExitOnFailure(hr, "Failed to add partition id to custom action data");
838
839 hr = S_OK;
840
841LExit:
842 return hr;
843}
diff --git a/src/ca/cpapprolesched.h b/src/ca/cpapprolesched.h
new file mode 100644
index 00000000..02852eef
--- /dev/null
+++ b/src/ca/cpapprolesched.h
@@ -0,0 +1,112 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_APPLICATION_ROLE
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
9
10 int iPropertyCount;
11 CPI_PROPERTY* pProperties;
12
13 BOOL fHasComponent;
14 BOOL fReferencedForInstall;
15 BOOL fReferencedForUninstall;
16 BOOL fObjectNotFound;
17
18 INSTALLSTATE isInstalled, isAction;
19
20 CPI_APPLICATION* pApplication;
21
22 ICatalogCollection* piUsersColl;
23
24 CPI_APPLICATION_ROLE* pNext;
25};
26
27struct CPI_APPLICATION_ROLE_LIST
28{
29 CPI_APPLICATION_ROLE* pFirst;
30
31 int iInstallCount;
32 int iUninstallCount;
33};
34
35struct CPI_USER_IN_APPLICATION_ROLE
36{
37 WCHAR wzKey[MAX_DARWIN_KEY + 1];
38 LPWSTR pwzAccount;
39
40 INSTALLSTATE isInstalled, isAction;
41
42 CPI_APPLICATION_ROLE* pApplicationRole;
43
44 CPI_USER_IN_APPLICATION_ROLE* pNext;
45};
46
47struct CPI_USER_IN_APPLICATION_ROLE_LIST
48{
49 CPI_USER_IN_APPLICATION_ROLE* pFirst;
50
51 int iInstallCount;
52 int iUninstallCount;
53};
54
55
56// function prototypes
57
58void CpiApplicationRoleListFree(
59 CPI_APPLICATION_ROLE_LIST* pList
60 );
61HRESULT CpiApplicationRolesRead(
62 CPI_APPLICATION_LIST* pAppList,
63 CPI_APPLICATION_ROLE_LIST* pAppRoleList
64 );
65HRESULT CpiApplicationRolesVerifyInstall(
66 CPI_APPLICATION_ROLE_LIST* pList
67 );
68HRESULT CpiApplicationRolesVerifyUninstall(
69 CPI_APPLICATION_ROLE_LIST* pList
70 );
71void CpiApplicationRoleAddReferenceInstall(
72 CPI_APPLICATION_ROLE* pItm
73 );
74void CpiApplicationRoleAddReferenceUninstall(
75 CPI_APPLICATION_ROLE* pItm
76 );
77HRESULT CpiApplicationRolesInstall(
78 CPI_APPLICATION_ROLE_LIST* pList,
79 int iRunMode,
80 LPWSTR* ppwzActionData,
81 int* piProgress
82 );
83HRESULT CpiApplicationRolesUninstall(
84 CPI_APPLICATION_ROLE_LIST* pList,
85 int iRunMode,
86 LPWSTR* ppwzActionData,
87 int* piProgress
88 );
89HRESULT CpiApplicationRoleFindByKey(
90 CPI_APPLICATION_ROLE_LIST* pList,
91 LPCWSTR pwzKey,
92 CPI_APPLICATION_ROLE** ppAppRole
93 );
94void CpiUserInApplicationRoleListFree(
95 CPI_USER_IN_APPLICATION_ROLE_LIST* pList
96 );
97HRESULT CpiUsersInApplicationRolesRead(
98 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
99 CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList
100 );
101HRESULT CpiUsersInApplicationRolesInstall(
102 CPI_USER_IN_APPLICATION_ROLE_LIST* pList,
103 int iRunMode,
104 LPWSTR* ppwzActionData,
105 int* piProgress
106 );
107HRESULT CpiUsersInApplicationRolesUninstall(
108 CPI_USER_IN_APPLICATION_ROLE_LIST* pList,
109 int iRunMode,
110 LPWSTR* ppwzActionData,
111 int* piProgress
112 );
diff --git a/src/ca/cpappsched.cpp b/src/ca/cpappsched.cpp
new file mode 100644
index 00000000..cec99794
--- /dev/null
+++ b/src/ca/cpappsched.cpp
@@ -0,0 +1,752 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsApplicationQuery =
9 L"SELECT `Application`, `Component_`, `Partition_`, `Id`, `Name` FROM `ComPlusApplication`";
10enum eApplicationQuery { aqApplication = 1, aqComponent, aqPartition, aqID, aqName };
11
12LPCWSTR vcsApplicationPropertyQuery =
13 L"SELECT `Name`, `Value` FROM `ComPlusApplicationProperty` WHERE `Application_` = ?";
14
15
16// property definitions
17
18CPI_PROPERTY_DEFINITION pdlApplicationProperties[] =
19{
20 {L"3GigSupportEnabled", cpptBoolean, 500},
21 {L"AccessChecksLevel", cpptInteger, 500},
22 {L"Activation", cpptInteger, 500},
23 {L"ApplicationAccessChecksEnabled", cpptBoolean, 500},
24 {L"ApplicationDirectory", cpptString, 501},
25 {L"Authentication", cpptInteger, 500},
26 {L"AuthenticationCapability", cpptInteger, 500},
27 {L"Changeable", cpptBoolean, 500},
28 {L"CommandLine", cpptString, 500},
29 {L"ConcurrentApps", cpptInteger, 501},
30 {L"CreatedBy", cpptString, 500},
31 {L"CRMEnabled", cpptBoolean, 500},
32 {L"CRMLogFile", cpptString, 500},
33 {L"Deleteable", cpptBoolean, 500},
34 {L"Description", cpptString, 500},
35 {L"DumpEnabled", cpptBoolean, 501},
36 {L"DumpOnException", cpptBoolean, 501},
37 {L"DumpOnFailfast", cpptBoolean, 501},
38 {L"DumpPath", cpptString, 501},
39 {L"EventsEnabled", cpptBoolean, 500},
40 {L"Identity", cpptString, 500},
41 {L"ImpersonationLevel", cpptInteger, 500},
42 {L"IsEnabled", cpptBoolean, 501},
43 {L"MaxDumpCount", cpptInteger, 501},
44 {L"Password", cpptString, 500},
45 {L"QCAuthenticateMsgs", cpptInteger, 501},
46 {L"QCListenerMaxThreads", cpptInteger, 501},
47 {L"QueueListenerEnabled", cpptBoolean, 500},
48 {L"QueuingEnabled", cpptBoolean, 500},
49 {L"RecycleActivationLimit", cpptInteger, 501},
50 {L"RecycleCallLimit", cpptInteger, 501},
51 {L"RecycleExpirationTimeout", cpptInteger, 501},
52 {L"RecycleLifetimeLimit", cpptInteger, 501},
53 {L"RecycleMemoryLimit", cpptInteger, 501},
54 {L"Replicable", cpptBoolean, 501},
55 {L"RunForever", cpptBoolean, 500},
56 {L"ShutdownAfter", cpptInteger, 500},
57 {L"SoapActivated", cpptBoolean, 502},
58 {L"SoapBaseUrl", cpptString, 502},
59 {L"SoapMailTo", cpptString, 502},
60 {L"SoapVRoot", cpptString, 502},
61 {L"SRPEnabled", cpptBoolean, 501},
62 {L"SRPTrustLevel", cpptInteger, 501},
63 {NULL, cpptNone, 0}
64};
65
66
67// prototypes for private helper functions
68
69static void FreeApplication(
70 CPI_APPLICATION* pItm
71 );
72static HRESULT FindObjectForApplication(
73 CPI_APPLICATION* pItm,
74 BOOL fFindId,
75 BOOL fFindName,
76 ICatalogObject** ppiAppObj
77 );
78static HRESULT AddApplicationToActionData(
79 CPI_APPLICATION* pItm,
80 int iActionType,
81 int iActionCost,
82 LPWSTR* ppwzActionData
83 );
84
85
86// function definitions
87
88void CpiApplicationListFree(
89 CPI_APPLICATION_LIST* pList
90 )
91{
92 CPI_APPLICATION* pItm = pList->pFirst;
93
94 while (pItm)
95 {
96 CPI_APPLICATION* pDelete = pItm;
97 pItm = pItm->pNext;
98 FreeApplication(pDelete);
99 }
100}
101
102HRESULT CpiApplicationsRead(
103 CPI_PARTITION_LIST* pPartList,
104 CPI_APPLICATION_LIST* pAppList
105 )
106{
107 HRESULT hr = S_OK;
108 UINT er = ERROR_SUCCESS;
109
110 int iVersionNT = 0;
111
112 PMSIHANDLE hView, hRec;
113
114 CPI_APPLICATION* pItm = NULL;
115 LPWSTR pwzData = NULL;
116 BOOL fMatchingArchitecture = FALSE;
117
118 // get NT version
119 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
120 ExitOnFailure(hr, "Failed to get VersionNT property");
121
122 // loop through all applications
123 hr = WcaOpenExecuteView(vcsApplicationQuery, &hView);
124 ExitOnFailure(hr, "Failed to execute view on ComPlusApplication table");
125
126 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
127 {
128 // get component
129 hr = WcaGetRecordString(hRec, aqComponent, &pwzData);
130 ExitOnFailure(hr, "Failed to get component");
131
132 // check if the component is our processor architecture
133 if (pwzData && *pwzData)
134 {
135 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
136 ExitOnFailure(hr, "Failed to get component architecture.");
137
138 if (!fMatchingArchitecture)
139 {
140 continue; // not the same architecture, ignore
141 }
142 }
143
144 // create entry
145 pItm = (CPI_APPLICATION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_APPLICATION));
146 if (!pItm)
147 ExitFunction1(hr = E_OUTOFMEMORY);
148
149 // get component install state
150 if (pwzData && *pwzData)
151 {
152 pItm->fHasComponent = TRUE;
153
154 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
155 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
156 }
157
158 // get key
159 hr = WcaGetRecordString(hRec, aqApplication, &pwzData);
160 ExitOnFailure(hr, "Failed to get key");
161 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
162
163 // get partition
164 if (502 <= iVersionNT)
165 {
166 hr = WcaGetRecordString(hRec, aqPartition, &pwzData);
167 ExitOnFailure(hr, "Failed to get partition");
168
169 if (pwzData && *pwzData)
170 {
171 hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition);
172 ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData);
173 }
174 }
175
176 // get id
177 hr = WcaGetRecordFormattedString(hRec, aqID, &pwzData);
178 ExitOnFailure(hr, "Failed to get id");
179
180 if (pwzData && *pwzData)
181 {
182 hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID));
183 ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData);
184 }
185
186 // get name
187 hr = WcaGetRecordFormattedString(hRec, aqName, &pwzData);
188 ExitOnFailure(hr, "Failed to get name");
189 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
190
191 // if application is a locater, either an id or a name must be provided
192 if (!pItm->fHasComponent && !*pItm->wzID && !*pItm->wzName)
193 ExitOnFailure(hr = E_FAIL, "An application locater must have either an id or a name associated, key: %S", pItm->wzKey);
194
195 // if application is not a locater, an name must be provided
196 if (pItm->fHasComponent && !*pItm->wzName)
197 ExitOnFailure(hr = E_FAIL, "An application must have a name associated, key: %S", pItm->wzKey);
198
199 // get properties
200 if (CpiTableExists(cptComPlusApplicationProperty) && pItm->fHasComponent)
201 {
202 hr = CpiPropertiesRead(vcsApplicationPropertyQuery, pItm->wzKey, pdlApplicationProperties, &pItm->pProperties, &pItm->iPropertyCount);
203 ExitOnFailure(hr, "Failed to get properties");
204 }
205
206 // set references & increment counters
207 if (pItm->fHasComponent)
208 {
209 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
210 {
211 if (pItm->pPartition)
212 CpiPartitionAddReferenceInstall(pItm->pPartition);
213 pAppList->iInstallCount++;
214 }
215 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
216 {
217 if (pItm->pPartition)
218 CpiPartitionAddReferenceUninstall(pItm->pPartition);
219 pAppList->iUninstallCount++;
220 }
221 }
222
223 // add entry
224 if (pAppList->pFirst)
225 pItm->pNext = pAppList->pFirst;
226 pAppList->pFirst = pItm;
227 pItm = NULL;
228 }
229
230 if (E_NOMOREITEMS == hr)
231 hr = S_OK;
232
233LExit:
234 // clean up
235 if (pItm)
236 FreeApplication(pItm);
237
238 ReleaseStr(pwzData);
239
240 return hr;
241}
242
243HRESULT CpiApplicationsVerifyInstall(
244 CPI_APPLICATION_LIST* pList
245 )
246{
247 HRESULT hr = S_OK;
248 UINT er = ERROR_SUCCESS;
249
250 ICatalogObject* piAppObj = NULL;
251
252 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
253 {
254 // referenced locaters or applications that are being installed
255 if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)))
256 continue;
257
258 // if the application is referensed and is not a locater, it must be installed
259 if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
260 MessageExitOnFailure(hr = E_FAIL, msierrComPlusApplicationDependency, "An application is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
261
262 // application is supposed to exist
263 if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled))
264 {
265 // get collection object for application
266 hr = FindObjectForApplication(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piAppObj);
267 ExitOnFailure(hr, "Failed to find collection object for application");
268
269 // if the application was found
270 if (S_OK == hr)
271 {
272 // if we don't have an id, copy id from object
273 if (!*pItm->wzID)
274 {
275 hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID));
276 ExitOnFailure(hr, "Failed to get id");
277 }
278 }
279
280 // if the application was not found
281 else
282 {
283 // if the application is a locater, this is an error
284 if (!pItm->fHasComponent)
285 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationNotFound, "An application required by this installation was not found, key: %S", pItm->wzKey);
286
287 // create a new id if one is missing
288 if (!*pItm->wzID)
289 {
290 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
291 ExitOnFailure(hr, "Failed to create id");
292 }
293 }
294 }
295
296 // application is supposed to be created
297 else
298 {
299 // check for conflicts
300 do {
301 if (*pItm->wzID)
302 {
303 // find applications with conflicting id
304 hr = FindObjectForApplication(pItm, TRUE, FALSE, &piAppObj);
305 ExitOnFailure(hr, "Failed to find collection object for application");
306
307 if (S_FALSE == hr)
308 {
309 // find applications with conflicting name
310 hr = FindObjectForApplication(pItm, FALSE, TRUE, &piAppObj);
311 ExitOnFailure(hr, "Failed to find collection object for application");
312
313 if (S_OK == hr)
314 // "A application with a conflictiong name exists. retry cancel"
315 er = WcaErrorMessage(msierrComPlusApplicationNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
316 else
317 break; // no conflicting entry found, break loop
318 }
319 else
320 // "A application with a conflicting id exists. abort retry ignore"
321 er = WcaErrorMessage(msierrComPlusApplicationIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
322 }
323 else
324 {
325 // find applications with conflicting name
326 hr = FindObjectForApplication(pItm, FALSE, TRUE, &piAppObj);
327 ExitOnFailure(hr, "Failed to find collection object for application");
328
329 if (S_OK == hr)
330 // "A subscription with a conflictiong name exists. abort retry ignore"
331 er = WcaErrorMessage(msierrComPlusApplicationNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
332 else
333 break; // no conflicting entry found, break loop
334 }
335
336 switch (er)
337 {
338 case IDCANCEL:
339 case IDABORT:
340 ExitOnFailure(hr = E_FAIL, "An application with a conflictiong name or id exists, key: %S", pItm->wzKey);
341 break;
342 case IDRETRY:
343 break;
344 case IDIGNORE:
345 default:
346 // if we don't have an id, copy id from object
347 if (!*pItm->wzID)
348 {
349 hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID));
350 ExitOnFailure(hr, "Failed to get id");
351 }
352 hr = S_FALSE; // indicate that this is not a conflict
353 }
354 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
355
356 // create a new id if one is missing
357 if (!*pItm->wzID)
358 {
359 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
360 ExitOnFailure(hr, "Failed to create id");
361 }
362 }
363
364 // clean up
365 ReleaseNullObject(piAppObj);
366 }
367
368 hr = S_OK;
369
370LExit:
371 // clean up
372 ReleaseObject(piAppObj);
373
374 return hr;
375}
376
377HRESULT CpiApplicationsVerifyUninstall(
378 CPI_APPLICATION_LIST* pList
379 )
380{
381 HRESULT hr = S_OK;
382 ICatalogObject* piAppObj = NULL;
383
384 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
385 {
386 // referenced locaters or applications that are being installed
387 if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction)))
388 continue;
389
390 // get collection object for application
391 hr = FindObjectForApplication(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piAppObj);
392 ExitOnFailure(hr, "Failed to find collection object for application");
393
394 // if the application was found
395 if (S_OK == hr)
396 {
397 // if we don't have an id, copy id from object
398 if (!*pItm->wzID)
399 {
400 hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID));
401 ExitOnFailure(hr, "Failed to get id");
402 }
403 }
404
405 // if the application was not found
406 else
407 {
408 pItm->fObjectNotFound = TRUE;
409 if (pItm->fHasComponent)
410 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
411 }
412
413 // clean up
414 ReleaseNullObject(piAppObj);
415 }
416
417 hr = S_OK;
418
419LExit:
420 // clean up
421 ReleaseObject(piAppObj);
422
423 return hr;
424}
425
426void CpiApplicationAddReferenceInstall(
427 CPI_APPLICATION* pItm
428 )
429{
430 pItm->fReferencedForInstall = TRUE;
431 if (pItm->pPartition)
432 CpiPartitionAddReferenceInstall(pItm->pPartition);
433}
434
435void CpiApplicationAddReferenceUninstall(
436 CPI_APPLICATION* pItm
437 )
438{
439 pItm->fReferencedForUninstall = TRUE;
440 if (pItm->pPartition)
441 CpiPartitionAddReferenceUninstall(pItm->pPartition);
442}
443
444HRESULT CpiApplicationsInstall(
445 CPI_APPLICATION_LIST* pList,
446 int iRunMode,
447 LPWSTR* ppwzActionData,
448 int* piProgress
449 )
450{
451 HRESULT hr = S_OK;
452
453 int iActionType;
454
455 // add action text
456 hr = CpiAddActionTextToActionData(L"CreateComPlusApplications", ppwzActionData);
457 ExitOnFailure(hr, "Failed to add action text to custom action data");
458
459 // add applicaton count to action data
460 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
461 ExitOnFailure(hr, "Failed to add count to custom action data");
462
463 // add applications to custom action data
464 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
465 {
466 // applications that are being installed only
467 if (!pItm->fHasComponent || !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
468 continue;
469
470 // action type
471 if (rmRollback == iRunMode)
472 {
473 if (CpiIsInstalled(pItm->isInstalled))
474 iActionType = atNoOp;
475 else
476 iActionType = atRemove;
477 }
478 else
479 iActionType = atCreate;
480
481 // add to action data
482 hr = AddApplicationToActionData(pItm, iActionType, COST_APPLICATION_CREATE, ppwzActionData);
483 ExitOnFailure(hr, "Failed to add applicaton to custom action data, key: %S", pItm->wzKey);
484 }
485
486 // add progress tics
487 if (piProgress)
488 *piProgress += COST_APPLICATION_CREATE * pList->iInstallCount;
489
490 hr = S_OK;
491
492LExit:
493 return hr;
494}
495
496HRESULT CpiApplicationsUninstall(
497 CPI_APPLICATION_LIST* pList,
498 int iRunMode,
499 LPWSTR* ppwzActionData,
500 int* piProgress
501 )
502{
503 HRESULT hr = S_OK;
504
505 int iActionType;
506
507 // add action text
508 hr = CpiAddActionTextToActionData(L"RemoveComPlusApplications", ppwzActionData);
509 ExitOnFailure(hr, "Failed to add action text to custom action data");
510
511 // add applicaton count to action data
512 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
513 ExitOnFailure(hr, "Failed to add count to custom action data");
514
515 // add applications to custom action data
516 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
517 {
518 // applications that are being uninstalled only
519 if (!pItm->fHasComponent || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
520 continue;
521
522 // action type
523 if (rmRollback == iRunMode)
524 iActionType = atCreate;
525 else
526 iActionType = atRemove;
527
528 // add to action data
529 hr = AddApplicationToActionData(pItm, iActionType, COST_APPLICATION_DELETE, ppwzActionData);
530 ExitOnFailure(hr, "Failed to add applicaton to custom action data, key: %S", pItm->wzKey);
531 }
532
533 // add progress tics
534 if (piProgress)
535 *piProgress += COST_APPLICATION_DELETE * pList->iUninstallCount;
536
537 hr = S_OK;
538
539LExit:
540 return hr;
541}
542
543HRESULT CpiApplicationFindByKey(
544 CPI_APPLICATION_LIST* pList,
545 LPCWSTR pwzKey,
546 CPI_APPLICATION** ppApp
547 )
548{
549 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
550 {
551 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
552 {
553 *ppApp = pItm;
554 return S_OK;
555 }
556 }
557
558 return S_FALSE;
559}
560
561HRESULT CpiGetRolesCollForApplication(
562 CPI_APPLICATION* pApp,
563 ICatalogCollection** ppiRolesColl
564 )
565{
566 HRESULT hr = S_OK;
567
568 ICatalogCollection* piAppColl = NULL;
569 ICatalogObject* piAppObj = NULL;
570
571 // if a previous attempt to locate the collection object failed
572 if (pApp->fObjectNotFound)
573 ExitFunction1(hr = S_FALSE);
574
575 // get applications collection
576 if (!pApp->piRolesColl)
577 {
578 // get applications collection
579 if (pApp->pPartition)
580 hr = CpiGetApplicationsCollForPartition(pApp->pPartition, &piAppColl);
581 else
582 hr = CpiGetApplicationsCollection(&piAppColl);
583 ExitOnFailure(hr, "Failed to get applications collection");
584
585 if (S_FALSE == hr)
586 ExitFunction(); // exit with hr = S_FALSE
587
588 // find application object
589 hr = CpiFindCollectionObject(piAppColl, pApp->wzID, *pApp->wzID ? NULL : pApp->wzName, &piAppObj);
590 ExitOnFailure(hr, "Failed to find application object");
591
592 if (S_FALSE == hr)
593 ExitFunction(); // exit with hr = S_FALSE
594
595 // get roles collection
596 hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Roles", &pApp->piRolesColl);
597 ExitOnFailure(hr, "Failed to get roles collection");
598 }
599
600 // return value
601 *ppiRolesColl = pApp->piRolesColl;
602 (*ppiRolesColl)->AddRef();
603
604 hr = S_OK;
605
606LExit:
607 // clean up
608 ReleaseObject(piAppColl);
609 ReleaseObject(piAppObj);
610
611 return hr;
612}
613
614HRESULT CpiGetComponentsCollForApplication(
615 CPI_APPLICATION* pApp,
616 ICatalogCollection** ppiCompsColl
617 )
618{
619 HRESULT hr = S_OK;
620
621 ICatalogCollection* piAppColl = NULL;
622 ICatalogObject* piAppObj = NULL;
623
624 // if a previous attempt to locate the collection object failed
625 if (pApp->fObjectNotFound)
626 ExitFunction1(hr = S_FALSE);
627
628 // get applications collection
629 if (!pApp->piCompsColl)
630 {
631 // get applications collection
632 if (pApp->pPartition)
633 hr = CpiGetApplicationsCollForPartition(pApp->pPartition, &piAppColl);
634 else
635 hr = CpiGetApplicationsCollection(&piAppColl);
636 ExitOnFailure(hr, "Failed to get applications collection");
637
638 if (S_FALSE == hr)
639 ExitFunction(); // exit with hr = S_FALSE
640
641 // find application object
642 hr = CpiFindCollectionObject(piAppColl, pApp->wzID, *pApp->wzID ? NULL : pApp->wzName, &piAppObj);
643 ExitOnFailure(hr, "Failed to find application object");
644
645 if (S_FALSE == hr)
646 ExitFunction(); // exit with hr = S_FALSE
647
648 // get roles collection
649 hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Components", &pApp->piCompsColl);
650 ExitOnFailure(hr, "Failed to get components collection");
651 }
652
653 // return value
654 *ppiCompsColl = pApp->piCompsColl;
655 (*ppiCompsColl)->AddRef();
656
657 hr = S_OK;
658
659LExit:
660 // clean up
661 ReleaseObject(piAppColl);
662 ReleaseObject(piAppObj);
663
664 return hr;
665}
666
667
668// helper function definitions
669
670static void FreeApplication(
671 CPI_APPLICATION* pItm
672 )
673{
674 if (pItm->pProperties)
675 CpiPropertiesFreeList(pItm->pProperties);
676
677 ReleaseObject(pItm->piRolesColl);
678 ReleaseObject(pItm->piCompsColl);
679
680 ::HeapFree(::GetProcessHeap(), 0, pItm);
681}
682
683static HRESULT FindObjectForApplication(
684 CPI_APPLICATION* pItm,
685 BOOL fFindId,
686 BOOL fFindName,
687 ICatalogObject** ppiAppObj
688 )
689{
690 HRESULT hr = S_OK;
691
692 ICatalogCollection* piAppColl = NULL;
693
694 // get applications collection
695 if (pItm->pPartition)
696 hr = CpiGetApplicationsCollForPartition(pItm->pPartition, &piAppColl);
697 else
698 hr = CpiGetApplicationsCollection(&piAppColl);
699 ExitOnFailure(hr, "Failed to get applications collection");
700
701 if (S_FALSE == hr)
702 ExitFunction(); // exit with hr = S_FALSE
703
704 // find application object
705 hr = CpiFindCollectionObject(piAppColl, fFindId ? pItm->wzID : NULL, fFindName ? pItm->wzName : NULL, ppiAppObj);
706 ExitOnFailure(hr, "Failed to find application object");
707
708 // exit with hr from CpiFindCollectionObject()
709
710LExit:
711 // clean up
712 ReleaseObject(piAppColl);
713
714 return hr;
715}
716
717static HRESULT AddApplicationToActionData(
718 CPI_APPLICATION* pItm,
719 int iActionType,
720 int iActionCost,
721 LPWSTR* ppwzActionData
722 )
723{
724 HRESULT hr = S_OK;
725
726 // add action information to custom action data
727 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
728 ExitOnFailure(hr, "Failed to add action type to custom action data");
729 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
730 ExitOnFailure(hr, "Failed to add action cost to custom action data");
731
732 // add application information to custom action data
733 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
734 ExitOnFailure(hr, "Failed to add application key to custom action data");
735 hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
736 ExitOnFailure(hr, "Failed to add application id to custom action data");
737 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
738 ExitOnFailure(hr, "Failed to add application name to custom action data");
739
740 // add partition information to custom action data
741 hr = WcaWriteStringToCaData(pItm->pPartition ? pItm->pPartition->wzID : L"", ppwzActionData);
742 ExitOnFailure(hr, "Failed to add partition id to custom action data");
743
744 // add properties to custom action data
745 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
746 ExitOnFailure(hr, "Failed to add properties to custom action data");
747
748 hr = S_OK;
749
750LExit:
751 return hr;
752}
diff --git a/src/ca/cpappsched.h b/src/ca/cpappsched.h
new file mode 100644
index 00000000..2cd6a0ee
--- /dev/null
+++ b/src/ca/cpappsched.h
@@ -0,0 +1,83 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_APPLICATION
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzID[CPI_MAX_GUID + 1];
9 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
10
11 int iPropertyCount;
12 CPI_PROPERTY* pProperties;
13
14 BOOL fHasComponent;
15 BOOL fReferencedForInstall;
16 BOOL fReferencedForUninstall;
17 BOOL fObjectNotFound;
18
19 INSTALLSTATE isInstalled, isAction;
20
21 CPI_PARTITION* pPartition;
22
23 ICatalogCollection* piRolesColl;
24 ICatalogCollection* piCompsColl;
25
26 CPI_APPLICATION* pNext;
27};
28
29struct CPI_APPLICATION_LIST
30{
31 CPI_APPLICATION* pFirst;
32
33 int iInstallCount;
34 int iUninstallCount;
35};
36
37
38// function prototypes
39
40void CpiApplicationListFree(
41 CPI_APPLICATION_LIST* pList
42 );
43HRESULT CpiApplicationsRead(
44 CPI_PARTITION_LIST* pPartList,
45 CPI_APPLICATION_LIST* pAppList
46 );
47HRESULT CpiApplicationsVerifyInstall(
48 CPI_APPLICATION_LIST* pList
49 );
50HRESULT CpiApplicationsVerifyUninstall(
51 CPI_APPLICATION_LIST* pList
52 );
53void CpiApplicationAddReferenceInstall(
54 CPI_APPLICATION* pItm
55 );
56void CpiApplicationAddReferenceUninstall(
57 CPI_APPLICATION* pItm
58 );
59HRESULT CpiApplicationsInstall(
60 CPI_APPLICATION_LIST* pList,
61 int iRunMode,
62 LPWSTR* ppwzActionData,
63 int* piProgress
64 );
65HRESULT CpiApplicationsUninstall(
66 CPI_APPLICATION_LIST* pList,
67 int iRunMode,
68 LPWSTR* ppwzActionData,
69 int* piProgress
70 );
71HRESULT CpiApplicationFindByKey(
72 CPI_APPLICATION_LIST* pList,
73 LPCWSTR pwzKey,
74 CPI_APPLICATION** ppApp
75 );
76HRESULT CpiGetRolesCollForApplication(
77 CPI_APPLICATION* pApp,
78 ICatalogCollection** ppiRolesColl
79 );
80HRESULT CpiGetComponentsCollForApplication(
81 CPI_APPLICATION* pApp,
82 ICatalogCollection** ppiCompsColl
83 );
diff --git a/src/ca/cpasmexec.cpp b/src/ca/cpasmexec.cpp
new file mode 100644
index 00000000..339c08e1
--- /dev/null
+++ b/src/ca/cpasmexec.cpp
@@ -0,0 +1,1888 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// GAC related declarations
7
8typedef struct _FUSION_INSTALL_REFERENCE_
9{
10 DWORD cbSize;
11 DWORD dwFlags;
12 GUID guidScheme;
13 LPCWSTR szIdentifier;
14 LPCWSTR szNonCannonicalData;
15} FUSION_INSTALL_REFERENCE;
16
17typedef struct _FUSION_INSTALL_REFERENCE_ *LPFUSION_INSTALL_REFERENCE;
18
19typedef const FUSION_INSTALL_REFERENCE *LPCFUSION_INSTALL_REFERENCE;
20
21typedef struct _ASSEMBLY_INFO
22{
23 ULONG cbAssemblyInfo;
24 DWORD dwAssemblyFlags;
25 ULARGE_INTEGER uliAssemblySizeInKB;
26 LPWSTR pszCurrentAssemblyPathBuf;
27 ULONG cchBuf;
28} ASSEMBLY_INFO;
29
30typedef interface IAssemblyCacheItem IAssemblyCacheItem;
31
32MIDL_INTERFACE("e707dcde-d1cd-11d2-bab9-00c04f8eceae")
33IAssemblyCache : public IUnknown
34{
35public:
36 virtual HRESULT STDMETHODCALLTYPE UninstallAssembly(
37 /* [in] */ DWORD dwFlags,
38 /* [in] */ LPCWSTR pszAssemblyName,
39 /* [in] */ LPCFUSION_INSTALL_REFERENCE pRefData,
40 /* [optional][out] */ ULONG *pulDisposition) = 0;
41
42 virtual HRESULT STDMETHODCALLTYPE QueryAssemblyInfo(
43 /* [in] */ DWORD dwFlags,
44 /* [in] */ LPCWSTR pszAssemblyName,
45 /* [out][in] */ ASSEMBLY_INFO *pAsmInfo) = 0;
46
47 virtual HRESULT STDMETHODCALLTYPE CreateAssemblyCacheItem(
48 /* [in] */ DWORD dwFlags,
49 /* [in] */ PVOID pvReserved,
50 /* [out] */ IAssemblyCacheItem **ppAsmItem,
51 /* [optional][in] */ LPCWSTR pszAssemblyName) = 0;
52
53 virtual HRESULT STDMETHODCALLTYPE CreateAssemblyScavenger(
54 /* [out] */ IUnknown **ppUnkReserved) = 0;
55
56 virtual HRESULT STDMETHODCALLTYPE InstallAssembly(
57 /* [in] */ DWORD dwFlags,
58 /* [in] */ LPCWSTR pszManifestFilePath,
59 /* [in] */ LPCFUSION_INSTALL_REFERENCE pRefData) = 0;
60};
61
62typedef HRESULT (__stdcall *LoadLibraryShimFunc)(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll);
63typedef HRESULT (__stdcall *CreateAssemblyCacheFunc)(IAssemblyCache **ppAsmCache, DWORD dwReserved);
64
65
66// RegistrationHelper related declarations
67
68static const GUID CLSID_RegistrationHelper =
69 { 0x89a86e7b, 0xc229, 0x4008, { 0x9b, 0xaa, 0x2f, 0x5c, 0x84, 0x11, 0xd7, 0xe0 } };
70
71enum eInstallationFlags {
72 ifConfigureComponentsOnly = 16,
73 ifFindOrCreateTargetApplication = 4,
74 ifExpectExistingTypeLib = 1
75};
76
77
78// private constants
79
80enum eAssemblyAttributes
81{
82 aaEventClass = (1 << 0),
83 aaDotNetAssembly = (1 << 1),
84 aaPathFromGAC = (1 << 2),
85 aaRunInCommit = (1 << 3)
86};
87
88
89// private structs
90
91struct CPI_ROLE_ASSIGNMENT
92{
93 WCHAR wzKey[MAX_DARWIN_KEY + 1];
94 WCHAR wzRoleName[MAX_DARWIN_COLUMN + 1];
95
96 CPI_ROLE_ASSIGNMENT* pNext;
97};
98
99struct CPI_METHOD
100{
101 WCHAR wzIndex[11 + 1];
102 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
103
104 CPI_PROPERTY* pPropertyList;
105 CPI_ROLE_ASSIGNMENT* pRoleAssignmentList;
106
107 CPI_METHOD* pNext;
108};
109
110struct CPI_INTERFACE
111{
112 WCHAR wzIID[CPI_MAX_GUID + 1];
113
114 CPI_PROPERTY* pPropertyList;
115 CPI_ROLE_ASSIGNMENT* pRoleAssignmentList;
116 CPI_METHOD* pMethodList;
117
118 CPI_INTERFACE* pNext;
119};
120
121struct CPI_COMPONENT
122{
123 WCHAR wzCLSID[CPI_MAX_GUID + 1];
124
125 CPI_PROPERTY* pPropertyList;
126 CPI_ROLE_ASSIGNMENT* pRoleAssignmentList;
127 CPI_INTERFACE* pInterfaceList;
128
129 CPI_COMPONENT* pNext;
130};
131
132struct CPI_ASSEMBLY_ATTRIBUTES
133{
134 int iActionType;
135 int iActionCost;
136 LPWSTR pwzKey;
137 LPWSTR pwzAssemblyName;
138 LPWSTR pwzDllPath;
139 LPWSTR pwzTlbPath;
140 LPWSTR pwzPSDllPath;
141 LPWSTR pwzAppID;
142 LPWSTR pwzPartID;
143 int iAttributes;
144 CPI_COMPONENT* pCompList;
145};
146
147struct CPI_ROLE_ASSIGNMENTS_ATTRIBUTES
148{
149 int iActionType;
150 int iActionCost;
151 LPWSTR pwzKey;
152 LPWSTR pwzAppID;
153 LPWSTR pwzPartID;
154 int iRoleCount;
155 CPI_COMPONENT* pCompList;
156};
157
158
159// prototypes for private helper functions
160
161static HRESULT RegisterAssembly(
162 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
163 );
164static HRESULT UnregisterAssembly(
165 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
166 );
167static void InitAssemblyExec();
168static void UninitAssemblyExec();
169static HRESULT GetRegistrationHelper(
170 IDispatch** ppiRegHlp
171 );
172static HRESULT GetAssemblyCacheObject(
173 IAssemblyCache** ppAssemblyCache
174 );
175static HRESULT GetAssemblyPathFromGAC(
176 LPCWSTR pwzAssemblyName,
177 LPWSTR* ppwzAssemblyPath
178 );
179static HRESULT RegisterDotNetAssembly(
180 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
181 );
182static HRESULT RegisterNativeAssembly(
183 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
184 );
185static HRESULT UnregisterDotNetAssembly(
186 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
187 );
188static HRESULT RemoveComponents(
189 ICatalogCollection* piCompColl,
190 CPI_COMPONENT* pCompList
191 );
192static HRESULT ReadAssemblyAttributes(
193 LPWSTR* ppwzData,
194 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
195 );
196static void FreeAssemblyAttributes(
197 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
198 );
199static HRESULT ReadRoleAssignmentsAttributes(
200 LPWSTR* ppwzData,
201 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
202 );
203static void FreeRoleAssignmentsAttributes(
204 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
205 );
206static HRESULT ConfigureComponents(
207 LPCWSTR pwzPartID,
208 LPCWSTR pwzAppID,
209 CPI_COMPONENT* pCompList,
210 BOOL fCreate,
211 BOOL fProgress
212 );
213static HRESULT ConfigureInterfaces(
214 ICatalogCollection* piCompColl,
215 ICatalogObject* piCompObj,
216 CPI_INTERFACE* pIntfList,
217 BOOL fCreate
218 );
219static HRESULT ConfigureMethods(
220 ICatalogCollection* piIntfColl,
221 ICatalogObject* piIntfObj,
222 CPI_METHOD* pMethList,
223 BOOL fCreate
224 );
225static HRESULT ConfigureRoleAssignments(
226 LPCWSTR pwzCollName,
227 ICatalogCollection* piCompColl,
228 ICatalogObject* piCompObj,
229 CPI_ROLE_ASSIGNMENT* pRoleList,
230 BOOL fCreate
231 );
232static HRESULT ReadComponentList(
233 LPWSTR* ppwzData,
234 CPI_COMPONENT** ppCompList
235 );
236static HRESULT ReadInterfaceList(
237 LPWSTR* ppwzData,
238 CPI_INTERFACE** ppIntfList
239 );
240static HRESULT ReadMethodList(
241 LPWSTR* ppwzData,
242 CPI_METHOD** ppMethList
243 );
244static HRESULT ReadRoleAssignmentList(
245 LPWSTR* ppwzData,
246 CPI_ROLE_ASSIGNMENT** ppRoleList
247 );
248static void FreeComponentList(
249 CPI_COMPONENT* pList
250 );
251static void FreeInterfaceList(
252 CPI_INTERFACE* pList
253 );
254static void FreeMethodList(
255 CPI_METHOD* pList
256 );
257static void FreeRoleAssignmentList(
258 CPI_ROLE_ASSIGNMENT* pList
259 );
260
261
262// variables
263
264static IDispatch* gpiRegHlp;
265static IAssemblyCache* gpAssemblyCache;
266static HMODULE ghMscoree;
267static HMODULE ghFusion;
268
269
270// function definitions
271
272HRESULT CpiConfigureAssemblies(
273 LPWSTR* ppwzData,
274 HANDLE hRollbackFile
275 )
276{
277 HRESULT hr = S_OK;
278
279 CPI_ASSEMBLY_ATTRIBUTES attrs;
280 ::ZeroMemory(&attrs, sizeof(attrs));
281
282 // initialize
283 InitAssemblyExec();
284
285 // read action text
286 hr = CpiActionStartMessage(ppwzData, FALSE);
287 ExitOnFailure(hr, "Failed to send action start message");
288
289 // get count
290 int iCnt = 0;
291 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
292 ExitOnFailure(hr, "Failed to read count");
293
294 // write count to rollback file
295 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
296 ExitOnFailure(hr, "Failed to write count to rollback file");
297
298 for (int i = 0; i < iCnt; i++)
299 {
300 // read attributes from CustomActionData
301 hr = ReadAssemblyAttributes(ppwzData, &attrs);
302 ExitOnFailure(hr, "Failed to read assembly attributes");
303
304 // write key to rollback file
305 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
306 ExitOnFailure(hr, "Failed to write key to rollback file");
307
308 // action
309 switch (attrs.iActionType)
310 {
311 case atCreate:
312 hr = RegisterAssembly(&attrs);
313 ExitOnFailure(hr, "Failed to register assembly, key: %S", attrs.pwzKey);
314 break;
315 case atRemove:
316 hr = UnregisterAssembly(&attrs);
317 ExitOnFailure(hr, "Failed to unregister assembly, key: %S", attrs.pwzKey);
318 break;
319 default:
320 hr = S_OK;
321 break;
322 }
323
324 if (S_FALSE == hr)
325 ExitFunction(); // aborted by user
326
327 // write completion status to rollback file
328 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
329 ExitOnFailure(hr, "Failed to write completion status to rollback file");
330
331 // progress
332 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
333 ExitOnFailure(hr, "Failed to update progress");
334 }
335
336 hr = S_OK;
337
338LExit:
339 // clean up
340 FreeAssemblyAttributes(&attrs);
341
342 // uninitialize
343 UninitAssemblyExec();
344
345 return hr;
346}
347
348HRESULT CpiRollbackConfigureAssemblies(
349 LPWSTR* ppwzData,
350 CPI_ROLLBACK_DATA* pRollbackDataList
351 )
352{
353 HRESULT hr = S_OK;
354
355 int iRollbackStatus;
356
357 CPI_ASSEMBLY_ATTRIBUTES attrs;
358 ::ZeroMemory(&attrs, sizeof(attrs));
359
360 // initialize
361 InitAssemblyExec();
362
363 // read action text
364 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
365 ExitOnFailure(hr, "Failed to send action start message");
366
367 // get count
368 int iCnt = 0;
369 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
370 ExitOnFailure(hr, "Failed to read count");
371
372 for (int i = 0; i < iCnt; i++)
373 {
374 // read attributes from CustomActionData
375 hr = ReadAssemblyAttributes(ppwzData, &attrs);
376 ExitOnFailure(hr, "Failed to read assembly attributes");
377
378 // rollback status
379 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
380
381 if (S_FALSE == hr)
382 continue; // not found, nothing to rollback
383
384 // action
385 switch (attrs.iActionType)
386 {
387 case atCreate:
388 hr = RegisterAssembly(&attrs);
389 if (FAILED(hr))
390 WcaLog(LOGMSG_STANDARD, "Failed to register assembly, hr: 0x%x, key: %S", hr, attrs.pwzKey);
391 break;
392 case atRemove:
393 hr = UnregisterAssembly(&attrs);
394 if (FAILED(hr))
395 WcaLog(LOGMSG_STANDARD, "Failed to unregister assembly, hr: 0x%x, key: %S", hr, attrs.pwzKey);
396 break;
397 }
398
399 // check rollback status
400 if (0 == iRollbackStatus)
401 continue; // operation did not complete, skip progress
402
403 // progress
404 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
405 ExitOnFailure(hr, "Failed to update progress");
406 }
407
408 hr = S_OK;
409
410LExit:
411 // clean up
412 FreeAssemblyAttributes(&attrs);
413
414 // uninitialize
415 UninitAssemblyExec();
416
417 return hr;
418}
419
420HRESULT CpiConfigureRoleAssignments(
421 LPWSTR* ppwzData,
422 HANDLE hRollbackFile
423 )
424{
425 HRESULT hr = S_OK;
426
427 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES attrs;
428 ::ZeroMemory(&attrs, sizeof(attrs));
429
430 // read action text
431 hr = CpiActionStartMessage(ppwzData, FALSE);
432 ExitOnFailure(hr, "Failed to send action start message");
433
434 // get count
435 int iCnt = 0;
436 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
437 ExitOnFailure(hr, "Failed to read count");
438
439 // write count to rollback file
440 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
441 ExitOnFailure(hr, "Failed to write count to rollback file");
442
443 for (int i = 0; i < iCnt; i++)
444 {
445 // read attributes from CustomActionData
446 hr = ReadRoleAssignmentsAttributes(ppwzData, &attrs);
447 ExitOnFailure(hr, "Failed to read role assignments attributes");
448
449 // write key to rollback file
450 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
451 ExitOnFailure(hr, "Failed to write key to rollback file");
452
453 // action
454 if (atNoOp != attrs.iActionType)
455 {
456 hr = ConfigureComponents(attrs.pwzPartID, attrs.pwzAppID, attrs.pCompList, atCreate == attrs.iActionType, TRUE);
457 ExitOnFailure(hr, "Failed to configure components");
458
459 if (S_FALSE == hr)
460 ExitFunction(); // aborted by user
461 }
462
463 // write completion status to rollback file
464 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
465 ExitOnFailure(hr, "Failed to write completion status to rollback file");
466
467 // progress
468 hr = WcaProgressMessage(attrs.iActionCost * attrs.iRoleCount, FALSE);
469 ExitOnFailure(hr, "Failed to update progress");
470 }
471
472 hr = S_OK;
473
474LExit:
475 // clean up
476 FreeRoleAssignmentsAttributes(&attrs);
477
478 return hr;
479}
480
481HRESULT CpiRollbackConfigureRoleAssignments(
482 LPWSTR* ppwzData,
483 CPI_ROLLBACK_DATA* pRollbackDataList
484 )
485{
486 HRESULT hr = S_OK;
487
488 int iRollbackStatus;
489
490 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES attrs;
491 ::ZeroMemory(&attrs, sizeof(attrs));
492
493 // read action text
494 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
495 ExitOnFailure(hr, "Failed to send action start message");
496
497 // get count
498 int iCnt = 0;
499 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
500 ExitOnFailure(hr, "Failed to read count");
501
502 for (int i = 0; i < iCnt; i++)
503 {
504 // read attributes from CustomActionData
505 hr = ReadRoleAssignmentsAttributes(ppwzData, &attrs);
506 ExitOnFailure(hr, "Failed to read role assignments attributes");
507
508 // rollback status
509 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
510
511 if (S_FALSE == hr)
512 continue; // not found, nothing to rollback
513
514 // action
515 if (atNoOp != attrs.iActionType)
516 {
517 hr = ConfigureComponents(attrs.pwzPartID, attrs.pwzAppID, attrs.pCompList, atCreate == attrs.iActionType, TRUE);
518 ExitOnFailure(hr, "Failed to configure components");
519
520 if (S_FALSE == hr)
521 ExitFunction(); // aborted by user
522 }
523
524 // check rollback status
525 if (0 == iRollbackStatus)
526 continue; // operation did not complete, skip progress
527
528 // progress
529 hr = WcaProgressMessage(attrs.iActionCost * attrs.iRoleCount, FALSE);
530 ExitOnFailure(hr, "Failed to update progress");
531 }
532
533 hr = S_OK;
534
535LExit:
536 // clean up
537 FreeRoleAssignmentsAttributes(&attrs);
538
539 return hr;
540}
541
542
543// helper function definitions
544
545static HRESULT RegisterAssembly(
546 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
547 )
548{
549 HRESULT hr = S_OK;
550
551 // progress message
552 hr = CpiActionDataMessage(1, (pAttrs->iAttributes & aaPathFromGAC) ? pAttrs->pwzAssemblyName : pAttrs->pwzDllPath);
553 ExitOnFailure(hr, "Failed to send progress messages");
554
555 if (S_FALSE == hr)
556 ExitFunction(); // aborted by user
557
558 // log
559 WcaLog(LOGMSG_VERBOSE, "Registering assembly, key: %S", pAttrs->pwzKey);
560
561 // extract path from GAC
562 if (pAttrs->iAttributes & aaPathFromGAC)
563 {
564 hr = GetAssemblyPathFromGAC(pAttrs->pwzAssemblyName, &pAttrs->pwzDllPath);
565 if (S_FALSE == hr)
566 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
567 ExitOnFailure(hr, "Failed to get path for assembly from GAC");
568
569 // log
570 WcaLog(LOGMSG_VERBOSE, "Assembly path extracted from GAC, key: %S, path: '%S'", pAttrs->pwzKey, pAttrs->pwzDllPath);
571 }
572
573 // .net assembly
574 if (pAttrs->iAttributes & aaDotNetAssembly)
575 {
576 hr = RegisterDotNetAssembly(pAttrs);
577 ExitOnFailure(hr, "Failed to register .NET assembly");
578 }
579
580 // native assembly
581 else
582 {
583 hr = RegisterNativeAssembly(pAttrs);
584 ExitOnFailure(hr, "Failed to register native assembly");
585 }
586
587 // configure components
588 if (pAttrs->pCompList)
589 {
590 hr = ConfigureComponents(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pCompList, TRUE, FALSE);
591 ExitOnFailure(hr, "Failed to configure components");
592 }
593
594 hr = S_OK;
595
596LExit:
597 return hr;
598}
599
600static HRESULT UnregisterAssembly(
601 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
602 )
603{
604 HRESULT hr = S_OK;
605
606 long lChanges = 0;
607
608 ICatalogCollection* piColl = NULL;
609 ICatalogObject* piObj = NULL;
610
611 // progress message
612 hr = CpiActionDataMessage(1, (pAttrs->iAttributes & aaPathFromGAC) ? pAttrs->pwzAssemblyName : pAttrs->pwzDllPath);
613 ExitOnFailure(hr, "Failed to send progress messages");
614
615 if (S_FALSE == hr)
616 ExitFunction(); // aborted by user
617
618 // log
619 WcaLog(LOGMSG_VERBOSE, "Unregistering assembly, key: %S", pAttrs->pwzKey);
620
621 // extract path from GAC
622 if (pAttrs->iAttributes & aaPathFromGAC)
623 {
624 hr = GetAssemblyPathFromGAC(pAttrs->pwzAssemblyName, &pAttrs->pwzDllPath);
625 ExitOnFailure(hr, "Failed to get path for assembly from GAC");
626
627 if (S_FALSE == hr)
628 {
629 WcaLog(LOGMSG_VERBOSE, "Unable to locate assembly in GAC, assembly will not be unregistered from COM+, key: %S", pAttrs->pwzKey);
630 ExitFunction1(hr = S_OK);
631 }
632
633 // log
634 WcaLog(LOGMSG_VERBOSE, "Assembly path extracted from GAC, key: %S, path: '%S'", pAttrs->pwzKey, pAttrs->pwzDllPath);
635 }
636
637 // .NET assembly
638 if (pAttrs->iAttributes & aaDotNetAssembly)
639 {
640 if (pAttrs->pwzAppID && *pAttrs->pwzAppID)
641 {
642 // When unregistering a .net assembly using the RegistrationHelper class, and the application is
643 // left empty after all components in the assembly are removed, the RegistrationHelper class also
644 // attempts to remove the application for some reason. However, it does not handle the situation
645 // when the application has its deleteable property set to false, and will simply fail if this is
646 // the case. This is the reason we are clearing the deleatable property of the application here.
647 //
648 // TODO: handle rollbacks
649
650 // get applications collection
651 hr = CpiGetApplicationsCollection(pAttrs->pwzPartID, &piColl);
652 ExitOnFailure(hr, "Failed to get applications collection");
653
654 if (S_FALSE == hr)
655 {
656 // applications collection not found
657 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve applications collection, nothing to delete, key: %S", pAttrs->pwzKey);
658 ExitFunction1(hr = S_OK);
659 }
660
661 // find application object
662 hr = CpiFindCollectionObjectByStringKey(piColl, pAttrs->pwzAppID, &piObj);
663 ExitOnFailure(hr, "Failed to find application object");
664
665 if (S_FALSE == hr)
666 {
667 // application not found
668 WcaLog(LOGMSG_VERBOSE, "Unable to find application object, nothing to delete, key: %S", pAttrs->pwzKey);
669 ExitFunction1(hr = S_OK);
670 }
671
672 // reset deleteable property
673 hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable");
674 ExitOnFailure(hr, "Failed to reset deleteable property");
675 }
676
677 // unregister assembly
678 hr = UnregisterDotNetAssembly(pAttrs);
679 ExitOnFailure(hr, "Failed to unregister .NET assembly");
680 }
681
682 // native assembly
683 else
684 {
685 // get components collection
686 hr = CpiGetComponentsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piColl);
687 ExitOnFailure(hr, "Failed to get components collection");
688
689 if (S_FALSE == hr)
690 {
691 // components collection not found
692 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve components collection, nothing to delete, key: %S", pAttrs->pwzKey);
693 ExitFunction1(hr = S_OK);
694 }
695
696 // remove components
697 hr = RemoveComponents(piColl, pAttrs->pCompList);
698 ExitOnFailure(hr, "Failed to get remove components");
699
700 // save changes
701 hr = piColl->SaveChanges(&lChanges);
702 if (COMADMIN_E_OBJECTERRORS == hr)
703 CpiLogCatalogErrorInfo();
704 ExitOnFailure(hr, "Failed to save changes");
705 }
706
707 hr = S_OK;
708
709LExit:
710 // clean up
711 ReleaseObject(piColl);
712 ReleaseObject(piObj);
713
714 return hr;
715}
716
717static void InitAssemblyExec()
718{
719 gpiRegHlp = NULL;
720 gpAssemblyCache = NULL;
721 ghMscoree = NULL;
722 ghFusion = NULL;
723}
724
725static void UninitAssemblyExec()
726{
727 ReleaseObject(gpiRegHlp);
728 ReleaseObject(gpAssemblyCache);
729 if (ghFusion)
730 ::FreeLibrary(ghFusion);
731 if (ghMscoree)
732 ::FreeLibrary(ghMscoree);
733}
734
735static HRESULT GetRegistrationHelper(
736 IDispatch** ppiRegHlp
737 )
738{
739 HRESULT hr = S_OK;
740
741 if (!gpiRegHlp)
742 {
743 // create registration helper object
744 hr = ::CoCreateInstance(CLSID_RegistrationHelper, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&gpiRegHlp);
745 ExitOnFailure(hr, "Failed to create registration helper object");
746 }
747
748 gpiRegHlp->AddRef();
749 *ppiRegHlp = gpiRegHlp;
750
751 hr = S_OK;
752
753LExit:
754 return hr;
755}
756
757static HRESULT GetAssemblyCacheObject(
758 IAssemblyCache** ppAssemblyCache
759 )
760{
761 HRESULT hr = S_OK;
762
763 if (!gpAssemblyCache)
764 {
765 // mscoree.dll
766 if (!ghMscoree)
767 {
768 // load mscoree.dll
769 ghMscoree = ::LoadLibraryW(L"mscoree.dll");
770 ExitOnNull(ghMscoree, hr, E_FAIL, "Failed to load mscoree.dll");
771 }
772
773 // fusion.dll
774 if (!ghFusion)
775 {
776 // get LoadLibraryShim function address
777 LoadLibraryShimFunc pfnLoadLibraryShim = (LoadLibraryShimFunc)::GetProcAddress(ghMscoree, "LoadLibraryShim");
778 ExitOnNull(pfnLoadLibraryShim, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for LoadLibraryShim() function");
779
780 // load fusion.dll
781 hr = pfnLoadLibraryShim(L"fusion.dll", NULL, NULL, &ghFusion);
782 ExitOnFailure(hr, "Failed to load fusion.dll");
783 }
784
785 // get CreateAssemblyCache function address
786 CreateAssemblyCacheFunc pfnCreateAssemblyCache = (CreateAssemblyCacheFunc)::GetProcAddress(ghFusion, "CreateAssemblyCache");
787 ExitOnNull(pfnCreateAssemblyCache, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for CreateAssemblyCache() function");
788
789 // create AssemblyCache object
790 hr = pfnCreateAssemblyCache(&gpAssemblyCache, 0);
791 ExitOnFailure(hr, "Failed to create AssemblyCache object");
792 }
793
794 gpAssemblyCache->AddRef();
795 *ppAssemblyCache = gpAssemblyCache;
796
797 hr = S_OK;
798
799LExit:
800 return hr;
801}
802
803static HRESULT GetAssemblyPathFromGAC(
804 LPCWSTR pwzAssemblyName,
805 LPWSTR* ppwzAssemblyPath
806 )
807{
808 HRESULT hr = S_OK;
809
810 IAssemblyCache* pAssemblyCache = NULL;
811
812 ASSEMBLY_INFO assemblyInfo;
813 WCHAR wzPathBuf[MAX_PATH];
814
815 ::ZeroMemory(&assemblyInfo, sizeof(ASSEMBLY_INFO));
816 ::ZeroMemory(wzPathBuf, countof(wzPathBuf));
817
818 // get AssemblyCache object
819 hr = GetAssemblyCacheObject(&pAssemblyCache);
820 ExitOnFailure(hr, "Failed to get AssemblyCache object");
821
822 // get assembly info
823 assemblyInfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
824 assemblyInfo.pszCurrentAssemblyPathBuf = wzPathBuf;
825 assemblyInfo.cchBuf = countof(wzPathBuf);
826
827 hr = pAssemblyCache->QueryAssemblyInfo(0, pwzAssemblyName, &assemblyInfo);
828 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
829 ExitFunction1(hr = S_FALSE);
830 ExitOnFailure(hr, "Failed to get assembly info");
831
832 // copy assembly path
833 hr = StrAllocString(ppwzAssemblyPath, wzPathBuf, 0);
834 ExitOnFailure(hr, "Failed to copy assembly path");
835
836 hr = S_OK;
837
838LExit:
839 // clean up
840 ReleaseObject(pAssemblyCache);
841
842 return hr;
843}
844
845static HRESULT RegisterDotNetAssembly(
846 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
847 )
848{
849 HRESULT hr = S_OK;
850
851 IDispatch* piRegHlp = NULL;
852
853 DISPID dispid;
854 BSTR bstrMember = NULL;
855
856 long lInstallationFlags = 0;
857
858 VARIANTARG rgvarg[5];
859 DISPPARAMS dispparams;
860 EXCEPINFO excepInfo;
861
862 BSTR bstrPartName = NULL;
863 BSTR bstrAppName = NULL;
864 BSTR bstrDllPath = NULL;
865 BSTR bstrTlbPath = NULL;
866
867 ::ZeroMemory(rgvarg, sizeof(rgvarg));
868 ::ZeroMemory(&dispparams, sizeof(dispparams));
869 ::ZeroMemory(&excepInfo, sizeof(excepInfo));
870
871 bstrMember = ::SysAllocString(L"InstallAssembly_2");
872 ExitOnNull(bstrMember, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for method name");
873
874 // create BSTRs for parameters
875 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
876 {
877 bstrPartName = ::SysAllocString(pAttrs->pwzPartID);
878 ExitOnNull(bstrPartName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
879 }
880
881 if (pAttrs->pwzAppID && *pAttrs->pwzAppID)
882 {
883 bstrAppName = ::SysAllocString(pAttrs->pwzAppID);
884 ExitOnNull(bstrAppName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
885 }
886
887 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
888 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
889
890 if (pAttrs->pwzTlbPath && *pAttrs->pwzTlbPath)
891 {
892 bstrTlbPath = ::SysAllocString(pAttrs->pwzTlbPath);
893 ExitOnNull(bstrTlbPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path");
894 }
895
896 // get registration helper object
897 hr = GetRegistrationHelper(&piRegHlp);
898 ExitOnFailure(hr, "Failed to get registration helper object");
899
900 // get dispatch id of InstallAssembly() method
901 hr = piRegHlp->GetIDsOfNames(IID_NULL, &bstrMember, 1, LOCALE_USER_DEFAULT, &dispid);
902 ExitOnFailure(hr, "Failed to get dispatch id of InstallAssembly() method");
903
904 // set installation flags
905 lInstallationFlags = ifExpectExistingTypeLib;
906
907 if (!bstrAppName)
908 lInstallationFlags |= ifFindOrCreateTargetApplication;
909
910 // invoke InstallAssembly() method
911 rgvarg[0].vt = VT_I4;
912 rgvarg[0].lVal = lInstallationFlags;
913 rgvarg[1].vt = VT_BYREF|VT_BSTR;
914 rgvarg[1].pbstrVal = &bstrTlbPath;
915 rgvarg[2].vt = VT_BSTR;
916 rgvarg[2].bstrVal = bstrPartName;
917 rgvarg[3].vt = VT_BYREF|VT_BSTR;
918 rgvarg[3].pbstrVal = &bstrAppName;
919 rgvarg[4].vt = VT_BSTR;
920 rgvarg[4].bstrVal = bstrDllPath;
921 dispparams.rgvarg = rgvarg;
922 dispparams.cArgs = 5;
923 dispparams.cNamedArgs = 0;
924
925 hr = piRegHlp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL);
926 if (DISP_E_EXCEPTION == hr)
927 {
928 // log exception information
929 if (!excepInfo.pfnDeferredFillIn || (excepInfo.pfnDeferredFillIn && SUCCEEDED(excepInfo.pfnDeferredFillIn(&excepInfo))))
930 {
931 WcaLog(LOGMSG_STANDARD, "ExceptionInfo: Code='%hu', Source='%S', Description='%S', HelpFile='%S', HelpContext='%u'",
932 excepInfo.wCode, excepInfo.bstrSource,
933 excepInfo.bstrDescription ? excepInfo.bstrDescription : L"",
934 excepInfo.bstrHelpFile ? excepInfo.bstrHelpFile : L"",
935 excepInfo.dwHelpContext);
936 }
937 }
938 ExitOnFailure(hr, "Failed to invoke RegistrationHelper.InstallAssembly() method");
939
940 hr = S_OK;
941
942LExit:
943 // clean up
944 ReleaseObject(piRegHlp);
945
946 ReleaseBSTR(bstrMember);
947
948 ReleaseBSTR(excepInfo.bstrSource);
949 ReleaseBSTR(excepInfo.bstrDescription);
950 ReleaseBSTR(excepInfo.bstrHelpFile);
951
952 ReleaseBSTR(bstrPartName);
953 ReleaseBSTR(bstrAppName);
954 ReleaseBSTR(bstrDllPath);
955 ReleaseBSTR(bstrTlbPath);
956
957 return hr;
958}
959
960static HRESULT RegisterNativeAssembly(
961 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
962 )
963{
964 HRESULT hr = S_OK;
965
966 ICOMAdminCatalog* piCatalog = NULL;
967 ICOMAdminCatalog2* piCatalog2 = NULL;
968 BSTR bstrGlobPartID = NULL;
969
970 BSTR bstrPartID = NULL;
971 BSTR bstrAppID = NULL;
972 BSTR bstrDllPath = NULL;
973 BSTR bstrTlbPath = NULL;
974 BSTR bstrPSDllPath = NULL;
975
976 // create BSTRs for parameters
977 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
978 {
979 bstrPartID = ::SysAllocString(pAttrs->pwzPartID);
980 ExitOnNull(bstrPartID, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
981 }
982
983 bstrAppID = ::SysAllocString(pAttrs->pwzAppID);
984 ExitOnNull(bstrAppID, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
985
986 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
987 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
988
989 bstrTlbPath = ::SysAllocString(pAttrs->pwzTlbPath ? pAttrs->pwzTlbPath : L"");
990 ExitOnNull(bstrTlbPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path");
991
992 bstrPSDllPath = ::SysAllocString(pAttrs->pwzPSDllPath ? pAttrs->pwzPSDllPath : L"");
993 ExitOnNull(bstrPSDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path");
994
995 // get catalog
996 hr = CpiGetAdminCatalog(&piCatalog);
997 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
998
999 // get ICOMAdminCatalog2 interface
1000 hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2);
1001
1002 // COM+ 1.5 or later
1003 if (E_NOINTERFACE != hr)
1004 {
1005 ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface");
1006
1007 // partition id
1008 if (!bstrPartID)
1009 {
1010 // get global partition id
1011 hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID);
1012 ExitOnFailure(hr, "Failed to get global partition id");
1013 }
1014
1015 // set current partition
1016 hr = piCatalog2->put_CurrentPartition(bstrPartID ? bstrPartID : bstrGlobPartID);
1017 ExitOnFailure(hr, "Failed to set current partition");
1018 }
1019
1020 // COM+ pre 1.5
1021 else
1022 {
1023 // this version of COM+ does not support partitions, make sure a partition was not specified
1024 if (bstrPartID)
1025 ExitOnFailure(hr = E_FAIL, "Partitions are not supported by this version of COM+");
1026 }
1027
1028 // install event classes
1029 if (pAttrs->iAttributes & aaEventClass)
1030 {
1031 hr = piCatalog->InstallEventClass(bstrAppID, bstrDllPath, bstrTlbPath, bstrPSDllPath);
1032 if (COMADMIN_E_OBJECTERRORS == hr)
1033 CpiLogCatalogErrorInfo();
1034 ExitOnFailure(hr, "Failed to install event classes");
1035 }
1036
1037 // install components
1038 else
1039 {
1040 hr = piCatalog->InstallComponent(bstrAppID, bstrDllPath, bstrTlbPath, bstrPSDllPath);
1041 if (COMADMIN_E_OBJECTERRORS == hr)
1042 CpiLogCatalogErrorInfo();
1043 ExitOnFailure(hr, "Failed to install components");
1044 }
1045
1046 hr = S_OK;
1047
1048LExit:
1049 // clean up
1050 ReleaseObject(piCatalog);
1051 ReleaseObject(piCatalog2);
1052 ReleaseBSTR(bstrGlobPartID);
1053
1054 ReleaseBSTR(bstrPartID);
1055 ReleaseBSTR(bstrAppID);
1056 ReleaseBSTR(bstrDllPath);
1057 ReleaseBSTR(bstrTlbPath);
1058 ReleaseBSTR(bstrPSDllPath);
1059
1060 return hr;
1061}
1062
1063static HRESULT UnregisterDotNetAssembly(
1064 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1065 )
1066{
1067 HRESULT hr = S_OK;
1068
1069 IDispatch* piRegHlp = NULL;
1070
1071 DISPID dispid;
1072 BSTR bstrMember = NULL;
1073
1074 VARIANTARG rgvarg[3];
1075 DISPPARAMS dispparams;
1076 EXCEPINFO excepInfo;
1077
1078 BSTR bstrPartName = NULL;
1079 BSTR bstrAppName = NULL;
1080 BSTR bstrDllPath = NULL;
1081
1082 ::ZeroMemory(rgvarg, sizeof(rgvarg));
1083 ::ZeroMemory(&dispparams, sizeof(dispparams));
1084 ::ZeroMemory(&excepInfo, sizeof(excepInfo));
1085
1086 bstrMember = ::SysAllocString(L"UninstallAssembly_2");
1087 ExitOnNull(bstrMember, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for method name");
1088
1089 // create BSTRs for parameters
1090 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
1091 {
1092 bstrPartName = ::SysAllocString(pAttrs->pwzPartID);
1093 ExitOnNull(bstrPartName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
1094 }
1095
1096 bstrAppName = ::SysAllocString(pAttrs->pwzAppID);
1097 ExitOnNull(bstrAppName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
1098
1099 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
1100 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
1101
1102 // get registration helper object
1103 hr = GetRegistrationHelper(&piRegHlp);
1104 ExitOnFailure(hr, "Failed to get registration helper object");
1105
1106 // get dispatch id of UninstallAssembly() method
1107 hr = piRegHlp->GetIDsOfNames(IID_NULL, &bstrMember, 1, LOCALE_USER_DEFAULT, &dispid);
1108 ExitOnFailure(hr, "Failed to get dispatch id of UninstallAssembly() method");
1109
1110 // invoke UninstallAssembly() method
1111 rgvarg[0].vt = VT_BSTR;
1112 rgvarg[0].bstrVal = bstrPartName;
1113 rgvarg[1].vt = VT_BSTR;
1114 rgvarg[1].bstrVal = bstrAppName;
1115 rgvarg[2].vt = VT_BSTR;
1116 rgvarg[2].bstrVal = bstrDllPath;
1117 dispparams.rgvarg = rgvarg;
1118 dispparams.cArgs = 3;
1119 dispparams.cNamedArgs = 0;
1120
1121 hr = piRegHlp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL);
1122 if (DISP_E_EXCEPTION == hr)
1123 {
1124 // log exception information
1125 if (!excepInfo.pfnDeferredFillIn || (excepInfo.pfnDeferredFillIn && SUCCEEDED(excepInfo.pfnDeferredFillIn(&excepInfo))))
1126 {
1127 WcaLog(LOGMSG_STANDARD, "ExceptionInfo: Code='%hu', Source='%S', Description='%S', HelpFile='%S', HelpContext='%u'",
1128 excepInfo.wCode, excepInfo.bstrSource,
1129 excepInfo.bstrDescription ? excepInfo.bstrDescription : L"",
1130 excepInfo.bstrHelpFile ? excepInfo.bstrHelpFile : L"",
1131 excepInfo.dwHelpContext);
1132 }
1133 }
1134 ExitOnFailure(hr, "Failed to invoke RegistrationHelper.UninstallAssembly() method");
1135
1136 hr = S_OK;
1137
1138LExit:
1139 // clean up
1140 ReleaseObject(piRegHlp);
1141
1142 ReleaseBSTR(bstrMember);
1143
1144 ReleaseBSTR(excepInfo.bstrSource);
1145 ReleaseBSTR(excepInfo.bstrDescription);
1146 ReleaseBSTR(excepInfo.bstrHelpFile);
1147
1148 ReleaseBSTR(bstrPartName);
1149 ReleaseBSTR(bstrAppName);
1150 ReleaseBSTR(bstrDllPath);
1151
1152 return hr;
1153}
1154
1155static HRESULT RemoveComponents(
1156 ICatalogCollection* piCompColl,
1157 CPI_COMPONENT* pCompList
1158 )
1159{
1160 HRESULT hr = S_OK;
1161
1162 for (CPI_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext)
1163 {
1164 // remove
1165 hr = CpiRemoveCollectionObject(piCompColl, pItm->wzCLSID, NULL, FALSE);
1166 ExitOnFailure(hr, "Failed to remove component");
1167
1168 if (S_FALSE == hr)
1169 WcaLog(LOGMSG_VERBOSE, "Component not found, nothing to delete, key: %S", pItm->wzCLSID);
1170 }
1171
1172 hr = S_OK;
1173
1174LExit:
1175 return hr;
1176}
1177
1178static HRESULT ReadAssemblyAttributes(
1179 LPWSTR* ppwzData,
1180 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1181 )
1182{
1183 HRESULT hr = S_OK;
1184
1185 // read attributes
1186 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
1187 ExitOnFailure(hr, "Failed to read action type");
1188 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
1189 ExitOnFailure(hr, "Failed to read action cost");
1190 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
1191 ExitOnFailure(hr, "Failed to read key");
1192 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAssemblyName);
1193 ExitOnFailure(hr, "Failed to read assembly name");
1194 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzDllPath);
1195 ExitOnFailure(hr, "Failed to read dll path");
1196 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzTlbPath);
1197 ExitOnFailure(hr, "Failed to read tlb path");
1198 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPSDllPath);
1199 ExitOnFailure(hr, "Failed to read proxy-stub dll path");
1200 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iAttributes);
1201 ExitOnFailure(hr, "Failed to read attributes");
1202 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
1203 ExitOnFailure(hr, "Failed to read application id");
1204 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
1205 ExitOnFailure(hr, "Failed to read partition id");
1206
1207 // free existing component list
1208 if (pAttrs->pCompList)
1209 {
1210 FreeComponentList(pAttrs->pCompList);
1211 pAttrs->pCompList = NULL;
1212 }
1213
1214 // read components
1215 hr = ReadComponentList(ppwzData, &pAttrs->pCompList);
1216 ExitOnFailure(hr, "Failed to read components");
1217
1218 hr = S_OK;
1219
1220LExit:
1221 return hr;
1222}
1223
1224static void FreeAssemblyAttributes(
1225 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1226 )
1227{
1228 ReleaseStr(pAttrs->pwzKey);
1229 ReleaseStr(pAttrs->pwzAssemblyName);
1230 ReleaseStr(pAttrs->pwzDllPath);
1231 ReleaseStr(pAttrs->pwzTlbPath);
1232 ReleaseStr(pAttrs->pwzPSDllPath);
1233 ReleaseStr(pAttrs->pwzAppID);
1234 ReleaseStr(pAttrs->pwzPartID);
1235
1236 if (pAttrs->pCompList)
1237 FreeComponentList(pAttrs->pCompList);
1238}
1239
1240static HRESULT ReadRoleAssignmentsAttributes(
1241 LPWSTR* ppwzData,
1242 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
1243 )
1244{
1245 HRESULT hr = S_OK;
1246
1247 // read attributes
1248 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
1249 ExitOnFailure(hr, "Failed to read action type");
1250 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
1251 ExitOnFailure(hr, "Failed to read action cost");
1252 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
1253 ExitOnFailure(hr, "Failed to read key");
1254 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iRoleCount);
1255 ExitOnFailure(hr, "Failed to read role assignments count");
1256 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
1257 ExitOnFailure(hr, "Failed to read application id");
1258 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
1259 ExitOnFailure(hr, "Failed to read partition id");
1260
1261 // free existing component list
1262 if (pAttrs->pCompList)
1263 {
1264 FreeComponentList(pAttrs->pCompList);
1265 pAttrs->pCompList = NULL;
1266 }
1267
1268 // read components
1269 hr = ReadComponentList(ppwzData, &pAttrs->pCompList);
1270 ExitOnFailure(hr, "Failed to read components");
1271
1272 hr = S_OK;
1273
1274LExit:
1275 return hr;
1276}
1277
1278static void FreeRoleAssignmentsAttributes(
1279 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
1280 )
1281{
1282 ReleaseStr(pAttrs->pwzKey);
1283 ReleaseStr(pAttrs->pwzAppID);
1284 ReleaseStr(pAttrs->pwzPartID);
1285
1286 if (pAttrs->pCompList)
1287 FreeComponentList(pAttrs->pCompList);
1288}
1289
1290
1291static HRESULT ConfigureComponents(
1292 LPCWSTR pwzPartID,
1293 LPCWSTR pwzAppID,
1294 CPI_COMPONENT* pCompList,
1295 BOOL fCreate,
1296 BOOL fProgress
1297 )
1298{
1299 HRESULT hr = S_OK;
1300
1301 ICatalogCollection* piCompColl = NULL;
1302 ICatalogObject* piCompObj = NULL;
1303
1304 long lChanges = 0;
1305
1306 // get components collection
1307 hr = CpiGetComponentsCollection(pwzPartID, pwzAppID, &piCompColl);
1308 if (S_FALSE == hr)
1309 if (fCreate)
1310 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1311 else
1312 ExitFunction1(hr = S_OK);
1313 ExitOnFailure(hr, "Failed to get components collection");
1314
1315 // read components
1316 for (CPI_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext)
1317 {
1318 // progress message
1319 if (fProgress)
1320 {
1321 hr = CpiActionDataMessage(1, pItm->wzCLSID);
1322 ExitOnFailure(hr, "Failed to send progress messages");
1323
1324 if (S_FALSE == hr)
1325 ExitFunction(); // aborted by user
1326 }
1327
1328 // find component
1329 hr = CpiFindCollectionObjectByStringKey(piCompColl, pItm->wzCLSID, &piCompObj);
1330 if (S_FALSE == hr)
1331 if (fCreate)
1332 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1333 else
1334 continue;
1335 ExitOnFailure(hr, "Failed to find component object");
1336
1337 // properties
1338 hr = CpiPutCollectionObjectValues(piCompObj, pItm->pPropertyList);
1339 ExitOnFailure(hr, "Failed to write properties");
1340
1341 // read roles
1342 if (pItm->pRoleAssignmentList)
1343 {
1344 hr = ConfigureRoleAssignments(L"RolesForComponent", piCompColl, piCompObj, pItm->pRoleAssignmentList, fCreate);
1345 ExitOnFailure(hr, "Failed to read roles");
1346 }
1347
1348 // read interfaces
1349 if (pItm->pInterfaceList)
1350 {
1351 hr = ConfigureInterfaces(piCompColl, piCompObj, pItm->pInterfaceList, fCreate);
1352 ExitOnFailure(hr, "Failed to read interfaces");
1353 }
1354
1355 // clean up
1356 ReleaseNullObject(piCompObj);
1357 }
1358
1359 // save changes
1360 hr = piCompColl->SaveChanges(&lChanges);
1361 if (COMADMIN_E_OBJECTERRORS == hr)
1362 CpiLogCatalogErrorInfo();
1363 ExitOnFailure(hr, "Failed to save changes");
1364
1365 hr = S_OK;
1366
1367LExit:
1368 // clean up
1369 ReleaseObject(piCompColl);
1370 ReleaseObject(piCompObj);
1371
1372 return hr;
1373}
1374
1375static HRESULT ConfigureInterfaces(
1376 ICatalogCollection* piCompColl,
1377 ICatalogObject* piCompObj,
1378 CPI_INTERFACE* pIntfList,
1379 BOOL fCreate
1380 )
1381{
1382 HRESULT hr = S_OK;
1383
1384 ICatalogCollection* piIntfColl = NULL;
1385 ICatalogObject* piIntfObj = NULL;
1386
1387 long lChanges = 0;
1388
1389 // get interfaces collection
1390 hr = CpiGetInterfacesCollection(piCompColl, piCompObj, &piIntfColl);
1391 if (S_FALSE == hr)
1392 if (fCreate)
1393 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1394 else
1395 ExitFunction1(hr = S_OK);
1396 ExitOnFailure(hr, "Failed to get interfaces collection");
1397
1398 // read interfaces
1399 for (CPI_INTERFACE* pItm = pIntfList; pItm; pItm = pItm->pNext)
1400 {
1401 // find interface
1402 hr = CpiFindCollectionObjectByStringKey(piIntfColl, pItm->wzIID, &piIntfObj);
1403 if (S_FALSE == hr)
1404 if (fCreate)
1405 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1406 else
1407 continue;
1408 ExitOnFailure(hr, "Failed to find interface object");
1409
1410 // properties
1411 hr = CpiPutCollectionObjectValues(piIntfObj, pItm->pPropertyList);
1412 ExitOnFailure(hr, "Failed to write properties");
1413
1414 // read roles
1415 if (pItm->pRoleAssignmentList)
1416 {
1417 hr = ConfigureRoleAssignments(L"RolesForInterface", piIntfColl, piIntfObj, pItm->pRoleAssignmentList, fCreate);
1418 ExitOnFailure(hr, "Failed to read roles");
1419 }
1420
1421 // read methods
1422 if (pItm->pMethodList)
1423 {
1424 hr = ConfigureMethods(piIntfColl, piIntfObj, pItm->pMethodList, fCreate);
1425 ExitOnFailure(hr, "Failed to read methods");
1426 }
1427
1428 // clean up
1429 ReleaseNullObject(piIntfObj);
1430 }
1431
1432 // save changes
1433 hr = piIntfColl->SaveChanges(&lChanges);
1434 if (COMADMIN_E_OBJECTERRORS == hr)
1435 CpiLogCatalogErrorInfo();
1436 ExitOnFailure(hr, "Failed to save changes");
1437
1438 hr = S_OK;
1439
1440LExit:
1441 // clean up
1442 ReleaseObject(piIntfColl);
1443 ReleaseObject(piIntfObj);
1444
1445 return hr;
1446}
1447
1448static HRESULT ConfigureMethods(
1449 ICatalogCollection* piIntfColl,
1450 ICatalogObject* piIntfObj,
1451 CPI_METHOD* pMethList,
1452 BOOL fCreate
1453 )
1454{
1455 HRESULT hr = S_OK;
1456
1457 ICatalogCollection* piMethColl = NULL;
1458 ICatalogObject* piMethObj = NULL;
1459
1460 long lChanges = 0;
1461
1462 // get methods collection
1463 hr = CpiGetMethodsCollection(piIntfColl, piIntfObj, &piMethColl);
1464 if (S_FALSE == hr)
1465 if (fCreate)
1466 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1467 else
1468 ExitFunction1(hr = S_OK);
1469 ExitOnFailure(hr, "Failed to get methods collection");
1470
1471 // read methods
1472 for (CPI_METHOD* pItm = pMethList; pItm; pItm = pItm->pNext)
1473 {
1474 // find method
1475 if (*pItm->wzIndex)
1476 hr = CpiFindCollectionObjectByIntegerKey(piMethColl, _wtol(pItm->wzIndex), &piMethObj);
1477 else
1478 hr = CpiFindCollectionObjectByName(piMethColl, pItm->wzName, &piMethObj);
1479
1480 if (S_FALSE == hr)
1481 if (fCreate)
1482 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1483 else
1484 continue;
1485 ExitOnFailure(hr, "Failed to find method object");
1486
1487 // properties
1488 hr = CpiPutCollectionObjectValues(piMethObj, pItm->pPropertyList);
1489 ExitOnFailure(hr, "Failed to write properties");
1490
1491 // read roles
1492 if (pItm->pRoleAssignmentList)
1493 {
1494 hr = ConfigureRoleAssignments(L"RolesForMethod", piMethColl, piMethObj, pItm->pRoleAssignmentList, fCreate);
1495 ExitOnFailure(hr, "Failed to read roles");
1496 }
1497
1498 // clean up
1499 ReleaseNullObject(piMethObj);
1500 }
1501
1502 // save changes
1503 hr = piMethColl->SaveChanges(&lChanges);
1504 if (COMADMIN_E_OBJECTERRORS == hr)
1505 CpiLogCatalogErrorInfo();
1506 ExitOnFailure(hr, "Failed to save changes");
1507
1508 hr = S_OK;
1509
1510LExit:
1511 // clean up
1512 ReleaseObject(piMethColl);
1513 ReleaseObject(piMethObj);
1514
1515 return hr;
1516}
1517
1518static HRESULT ConfigureRoleAssignments(
1519 LPCWSTR pwzCollName,
1520 ICatalogCollection* piCompColl,
1521 ICatalogObject* piCompObj,
1522 CPI_ROLE_ASSIGNMENT* pRoleList,
1523 BOOL fCreate
1524 )
1525{
1526 HRESULT hr = S_OK;
1527
1528 ICatalogCollection* piRoleColl = NULL;
1529 ICatalogObject* piRoleObj = NULL;
1530
1531 long lChanges = 0;
1532
1533 // get roles collection
1534 hr = CpiGetCatalogCollection(piCompColl, piCompObj, pwzCollName, &piRoleColl);
1535 if (S_FALSE == hr)
1536 if (fCreate)
1537 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1538 else
1539 ExitFunction1(hr = S_OK);
1540 ExitOnFailure(hr, "Failed to get role assignments collection");
1541
1542 // read roles
1543 for (CPI_ROLE_ASSIGNMENT* pItm = pRoleList; pItm; pItm = pItm->pNext)
1544 {
1545 if (fCreate)
1546 {
1547 // find existing role
1548 hr = CpiFindCollectionObjectByName(piRoleColl, pItm->wzRoleName, NULL);
1549 ExitOnFailure(hr, "Failed to find role, key: %S", pItm->wzKey);
1550
1551 if (S_OK == hr)
1552 continue; // role already exists
1553
1554 // add object
1555 hr = CpiAddCollectionObject(piRoleColl, &piRoleObj);
1556 ExitOnFailure(hr, "Failed to add role assignment to collection");
1557
1558 // role name
1559 hr = CpiPutCollectionObjectValue(piRoleObj, L"Name", pItm->wzRoleName);
1560 ExitOnFailure(hr, "Failed to set role name property, key: %S", pItm->wzKey);
1561
1562 // clean up
1563 ReleaseNullObject(piRoleObj);
1564 }
1565 else
1566 {
1567 // remove role
1568 hr = CpiRemoveCollectionObject(piRoleColl, NULL, pItm->wzRoleName, FALSE);
1569 ExitOnFailure(hr, "Failed to remove role, key: %S", pItm->wzKey);
1570 }
1571 }
1572
1573 // save changes
1574 hr = piRoleColl->SaveChanges(&lChanges);
1575 if (COMADMIN_E_OBJECTERRORS == hr)
1576 CpiLogCatalogErrorInfo();
1577 ExitOnFailure(hr, "Failed to save changes");
1578
1579 hr = S_OK;
1580
1581LExit:
1582 // clean up
1583 ReleaseObject(piRoleColl);
1584 ReleaseObject(piRoleObj);
1585
1586 return hr;
1587}
1588
1589static HRESULT ReadComponentList(
1590 LPWSTR* ppwzData,
1591 CPI_COMPONENT** ppCompList
1592 )
1593{
1594 HRESULT hr = S_OK;
1595
1596 LPWSTR pwzData = NULL;
1597
1598 CPI_COMPONENT* pItm = NULL;
1599
1600 int iCnt = 0;
1601
1602 // read count
1603 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1604 ExitOnFailure(hr, "Failed to read count");
1605
1606 // read components
1607 for (int i = 0; i < iCnt; i++)
1608 {
1609 pItm = (CPI_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_COMPONENT));
1610 if (!pItm)
1611 ExitFunction1(hr = E_OUTOFMEMORY);
1612
1613 // read clsid
1614 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1615 ExitOnFailure(hr, "Failed to read clsid");
1616 StringCchCopyW(pItm->wzCLSID, countof(pItm->wzCLSID), pwzData);
1617
1618 // read properties
1619 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1620 ExitOnFailure(hr, "Failed to read properties");
1621
1622 // read role assignments
1623 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1624 ExitOnFailure(hr, "Failed to read role assignments");
1625
1626 // read interfaces
1627 hr = ReadInterfaceList(ppwzData, &pItm->pInterfaceList);
1628 ExitOnFailure(hr, "Failed to read interfaces");
1629
1630 // add to list
1631 if (*ppCompList)
1632 pItm->pNext = *ppCompList;
1633 *ppCompList = pItm;
1634 pItm = NULL;
1635 }
1636
1637 hr = S_OK;
1638
1639LExit:
1640 // clean up
1641 ReleaseStr(pwzData);
1642
1643 if (pItm)
1644 FreeComponentList(pItm);
1645
1646 return hr;
1647}
1648
1649static HRESULT ReadInterfaceList(
1650 LPWSTR* ppwzData,
1651 CPI_INTERFACE** ppIntfList
1652 )
1653{
1654 HRESULT hr = S_OK;
1655
1656 LPWSTR pwzData = NULL;
1657
1658 CPI_INTERFACE* pItm = NULL;
1659
1660 int iCnt = 0;
1661
1662 // read count
1663 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1664 ExitOnFailure(hr, "Failed to read count");
1665
1666 // read interfaces
1667 for (int i = 0; i < iCnt; i++)
1668 {
1669 pItm = (CPI_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_INTERFACE));
1670 if (!pItm)
1671 ExitFunction1(hr = E_OUTOFMEMORY);
1672
1673 // read iid
1674 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1675 ExitOnFailure(hr, "Failed to read iid");
1676 StringCchCopyW(pItm->wzIID, countof(pItm->wzIID), pwzData);
1677
1678 // read properties
1679 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1680 ExitOnFailure(hr, "Failed to read properties");
1681
1682 // read role assignments
1683 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1684 ExitOnFailure(hr, "Failed to read role assignments");
1685
1686 // read methods
1687 hr = ReadMethodList(ppwzData, &pItm->pMethodList);
1688 ExitOnFailure(hr, "Failed to read methods");
1689
1690 // add to list
1691 if (*ppIntfList)
1692 pItm->pNext = *ppIntfList;
1693 *ppIntfList = pItm;
1694 pItm = NULL;
1695 }
1696
1697 hr = S_OK;
1698
1699LExit:
1700 // clean up
1701 ReleaseStr(pwzData);
1702
1703 if (pItm)
1704 FreeInterfaceList(pItm);
1705
1706 return hr;
1707}
1708
1709static HRESULT ReadMethodList(
1710 LPWSTR* ppwzData,
1711 CPI_METHOD** ppMethList
1712 )
1713{
1714 HRESULT hr = S_OK;
1715
1716 LPWSTR pwzData = NULL;
1717
1718 CPI_METHOD* pItm = NULL;
1719
1720 int iCnt = 0;
1721
1722 // read count
1723 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1724 ExitOnFailure(hr, "Failed to read count");
1725
1726 // read methods
1727 for (int i = 0; i < iCnt; i++)
1728 {
1729 pItm = (CPI_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_METHOD));
1730 if (!pItm)
1731 ExitFunction1(hr = E_OUTOFMEMORY);
1732
1733 // read index
1734 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1735 ExitOnFailure(hr, "Failed to read index");
1736 StringCchCopyW(pItm->wzIndex, countof(pItm->wzIndex), pwzData);
1737
1738 // read name
1739 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1740 ExitOnFailure(hr, "Failed to read name");
1741 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
1742
1743 // read properties
1744 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1745 ExitOnFailure(hr, "Failed to read properties");
1746
1747 // read role assignments
1748 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1749 ExitOnFailure(hr, "Failed to read role assignments");
1750
1751 // add to list
1752 if (*ppMethList)
1753 pItm->pNext = *ppMethList;
1754 *ppMethList = pItm;
1755 pItm = NULL;
1756 }
1757
1758 hr = S_OK;
1759
1760LExit:
1761 // clean up
1762 ReleaseStr(pwzData);
1763
1764 if (pItm)
1765 FreeMethodList(pItm);
1766
1767 return hr;
1768}
1769
1770static HRESULT ReadRoleAssignmentList(
1771 LPWSTR* ppwzData,
1772 CPI_ROLE_ASSIGNMENT** ppRoleList
1773 )
1774{
1775 HRESULT hr = S_OK;
1776
1777 LPWSTR pwzData = NULL;
1778
1779 CPI_ROLE_ASSIGNMENT* pItm = NULL;
1780
1781 int iCnt = 0;
1782
1783 // read role count
1784 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1785 ExitOnFailure(hr, "Failed to read role assignments count");
1786
1787 // read roles
1788 for (int i = 0; i < iCnt; i++)
1789 {
1790 pItm = (CPI_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLE_ASSIGNMENT));
1791 if (!pItm)
1792 ExitFunction1(hr = E_OUTOFMEMORY);
1793
1794 // read key
1795 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1796 ExitOnFailure(hr, "Failed to read key");
1797 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1798
1799 // read role name
1800 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1801 ExitOnFailure(hr, "Failed to read role name");
1802 StringCchCopyW(pItm->wzRoleName, countof(pItm->wzRoleName), pwzData);
1803
1804 // add to list
1805 if (*ppRoleList)
1806 pItm->pNext = *ppRoleList;
1807 *ppRoleList = pItm;
1808 pItm = NULL;
1809 }
1810
1811 hr = S_OK;
1812
1813LExit:
1814 // clean up
1815 ReleaseStr(pwzData);
1816
1817 if (pItm)
1818 FreeRoleAssignmentList(pItm);
1819
1820 return hr;
1821}
1822
1823static void FreeComponentList(
1824 CPI_COMPONENT* pList
1825 )
1826{
1827 while (pList)
1828 {
1829 if (pList->pPropertyList)
1830 CpiFreePropertyList(pList->pPropertyList);
1831 if (pList->pRoleAssignmentList)
1832 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1833 if (pList->pInterfaceList)
1834 FreeInterfaceList(pList->pInterfaceList);
1835
1836 CPI_COMPONENT* pDelete = pList;
1837 pList = pList->pNext;
1838 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1839 }
1840}
1841
1842static void FreeInterfaceList(
1843 CPI_INTERFACE* pList
1844 )
1845{
1846 while (pList)
1847 {
1848 if (pList->pPropertyList)
1849 CpiFreePropertyList(pList->pPropertyList);
1850 if (pList->pRoleAssignmentList)
1851 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1852 if (pList->pMethodList)
1853 FreeMethodList(pList->pMethodList);
1854
1855 CPI_INTERFACE* pDelete = pList;
1856 pList = pList->pNext;
1857 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1858 }
1859}
1860
1861static void FreeMethodList(
1862 CPI_METHOD* pList
1863 )
1864{
1865 while (pList)
1866 {
1867 if (pList->pPropertyList)
1868 CpiFreePropertyList(pList->pPropertyList);
1869 if (pList->pRoleAssignmentList)
1870 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1871
1872 CPI_METHOD* pDelete = pList;
1873 pList = pList->pNext;
1874 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1875 }
1876}
1877
1878static void FreeRoleAssignmentList(
1879 CPI_ROLE_ASSIGNMENT* pList
1880 )
1881{
1882 while (pList)
1883 {
1884 CPI_ROLE_ASSIGNMENT* pDelete = pList;
1885 pList = pList->pNext;
1886 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1887 }
1888}
diff --git a/src/ca/cpasmexec.h b/src/ca/cpasmexec.h
new file mode 100644
index 00000000..56184c01
--- /dev/null
+++ b/src/ca/cpasmexec.h
@@ -0,0 +1,20 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureAssemblies(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureAssemblies(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
13HRESULT CpiConfigureRoleAssignments(
14 LPWSTR* ppwzData,
15 HANDLE hRollbackFile
16 );
17HRESULT CpiRollbackConfigureRoleAssignments(
18 LPWSTR* ppwzData,
19 CPI_ROLLBACK_DATA* pRollbackDataList
20 );
diff --git a/src/ca/cpasmsched.cpp b/src/ca/cpasmsched.cpp
new file mode 100644
index 00000000..97ecff61
--- /dev/null
+++ b/src/ca/cpasmsched.cpp
@@ -0,0 +1,2135 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsMsiAssemblyNameQuery =
9 L"SELECT `Name`, `Value` FROM `MsiAssemblyName` WHERE `Component_` = ?";
10enum eMsiAssemblyNameQuery { manqName = 1, manqValue };
11
12LPCWSTR vcsModuleQuery =
13 L"SELECT `ModuleID` FROM `ModuleSignature`";
14enum eModuleQuery { mqModule = 1 };
15
16LPCWSTR vcsAssemblyQuery =
17 L"SELECT `Assembly`, `Component_`, `Application_`, `AssemblyName`, `DllPath`, `TlbPath`, `PSDllPath`, `Attributes` FROM `ComPlusAssembly`";
18enum eAssemblyQuery { aqAssembly = 1, aqComponent, aqApplication, aqAssemblyName, aqDllPath, aqTlbPath, aqPSDllPath, aqAttributes };
19
20LPCWSTR vcsComponentQuery =
21 L"SELECT `ComPlusComponent`, `CLSID` FROM `ComPlusComponent` WHERE `Assembly_` = ?";
22enum eComponentQuery { cqComponent = 1, cqCLSID };
23
24LPCWSTR vcsComponentPropertyQuery =
25 L"SELECT `Name`, `Value` FROM `ComPlusComponentProperty` WHERE `ComPlusComponent_` = ?";
26
27LPCWSTR vcsInterfaceQuery =
28 L"SELECT `Interface`, `IID` FROM `ComPlusInterface` WHERE `ComPlusComponent_` = ?";
29enum eInterfaceQuery { iqInterface = 1, iqIID };
30
31LPCWSTR vcsInterfacePropertyQuery =
32 L"SELECT `Name`, `Value` FROM `ComPlusInterfaceProperty` WHERE `Interface_` = ?";
33
34LPCWSTR vcsMethodQuery =
35 L"SELECT `Method`, `Index`, `Name` FROM `ComPlusMethod` WHERE `Interface_` = ?";
36enum eMethodQuery { mqMethod = 1, mqIndex, mqName };
37
38LPCWSTR vcsMethodPropertyQuery =
39 L"SELECT `Name`, `Value` FROM `ComPlusMethodProperty` WHERE `Method_` = ?";
40
41LPCWSTR vcsRoleForComponentQuery =
42 L"SELECT `RoleForComponent`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForComponent` WHERE `ComPlusComponent_` = ?";
43LPCWSTR vcsRoleForInterfaceQuery =
44 L"SELECT `RoleForInterface`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForInterface` WHERE `Interface_` = ?";
45LPCWSTR vcsRoleForMethodQuery =
46 L"SELECT `RoleForMethod`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForMethod` WHERE `Method_` = ?";
47
48enum eRoleAssignmentQuery { raqKey = 1, raqApplicationRole, raqComponent };
49
50LPCWSTR vcsModuleComponentsQuery =
51 L"SELECT `Component`, `ModuleID` FROM `ModuleComponents`";
52LPCWSTR vcsModuleDependencyQuery =
53 L"SELECT `ModuleID`, `RequiredID` FROM `ModuleDependency`";
54LPCWSTR vcsAssemblyDependencyQuery =
55 L"SELECT `Assembly_`, `RequiredAssembly_` FROM `ComPlusAssemblyDependency`";
56
57enum eKeyPairQuery { kpqFirstKey = 1, kpqSecondKey };
58
59
60// private structs
61
62struct CPI_KEY_PAIR
63{
64 WCHAR wzFirstKey[MAX_DARWIN_KEY + 1];
65 WCHAR wzSecondKey[MAX_DARWIN_KEY + 1];
66
67 CPI_KEY_PAIR* pNext;
68};
69
70struct CPI_DEPENDENCY_CHAIN
71{
72 LPCWSTR pwzKey;
73
74 CPI_DEPENDENCY_CHAIN* pPrev;
75};
76
77struct CPI_MODULE
78{
79 WCHAR wzKey[MAX_DARWIN_KEY + 1];
80
81 CPI_MODULE* pPrev;
82 CPI_MODULE* pNext;
83};
84
85struct CPI_MODULE_LIST
86{
87 CPI_MODULE* pFirst;
88 CPI_MODULE* pLast;
89};
90
91
92// property definitions
93
94CPI_PROPERTY_DEFINITION pdlComponentProperties[] =
95{
96 {L"AllowInprocSubscribers", cpptBoolean, 500},
97 {L"ComponentAccessChecksEnabled", cpptBoolean, 500},
98 {L"ComponentTransactionTimeout", cpptInteger, 500},
99 {L"ComponentTransactionTimeoutEnabled", cpptBoolean, 500},
100 {L"COMTIIntrinsics", cpptBoolean, 500},
101 {L"ConstructionEnabled", cpptBoolean, 500},
102 {L"ConstructorString", cpptString, 500},
103 {L"CreationTimeout", cpptInteger, 500},
104 {L"Description", cpptString, 500},
105 {L"EventTrackingEnabled", cpptBoolean, 500},
106 {L"ExceptionClass", cpptString, 500},
107 {L"FireInParallel", cpptBoolean, 500},
108 {L"IISIntrinsics", cpptBoolean, 500},
109 {L"InitializesServerApplication", cpptBoolean, 500},
110 {L"IsEnabled", cpptBoolean, 501},
111 {L"IsPrivateComponent", cpptBoolean, 501},
112 {L"JustInTimeActivation", cpptBoolean, 500},
113 {L"LoadBalancingSupported", cpptBoolean, 500},
114 {L"MaxPoolSize", cpptInteger, 500},
115 {L"MinPoolSize", cpptInteger, 500},
116 {L"MultiInterfacePublisherFilterCLSID", cpptString, 500},
117 {L"MustRunInClientContext", cpptBoolean, 500},
118 {L"MustRunInDefaultContext", cpptBoolean, 501},
119 {L"ObjectPoolingEnabled", cpptBoolean, 500},
120 {L"PublisherID", cpptString, 500},
121 {L"SoapAssemblyName", cpptString, 502},
122 {L"SoapTypeName", cpptString, 502},
123 {L"Synchronization", cpptInteger, 500},
124 {L"Transaction", cpptInteger, 500},
125 {L"TxIsolationLevel", cpptInteger, 501},
126 {NULL, cpptNone, 0}
127};
128
129CPI_PROPERTY_DEFINITION pdlInterfaceProperties[] =
130{
131 {L"Description", cpptString, 500},
132 {L"QueuingEnabled", cpptBoolean, 500},
133 {NULL, cpptNone, 0}
134};
135
136CPI_PROPERTY_DEFINITION pdlMethodProperties[] =
137{
138 {L"AutoComplete", cpptBoolean, 500},
139 {L"Description", cpptString, 500},
140 {NULL, cpptNone, 0}
141};
142
143
144// prototypes for private helper functions
145
146static HRESULT GetAssemblyName(
147 LPCWSTR pwzComponent,
148 LPWSTR* ppwzAssemblyName
149 );
150static HRESULT KeyPairsRead(
151 LPCWSTR pwzQuery,
152 CPI_KEY_PAIR** ppKeyPairList
153 );
154static HRESULT ModulesRead(
155 CPI_MODULE_LIST* pModList
156 );
157static HRESULT AssembliesRead(
158 CPI_KEY_PAIR* pModCompList,
159 CPI_APPLICATION_LIST* pAppList,
160 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
161 CPI_ASSEMBLY_LIST* pAsmList
162 );
163static HRESULT ComponentsRead(
164 LPCWSTR pwzAsmKey,
165 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
166 CPI_ASSEMBLY* pAsm
167 );
168static HRESULT InterfacesRead(
169 LPCWSTR pwzCompKey,
170 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
171 CPI_ASSEMBLY* pAsm,
172 CPI_COMPONENT* pComp
173 );
174static HRESULT MethodsRead(
175 LPCWSTR pwzIntfKey,
176 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
177 CPI_ASSEMBLY* pAsm,
178 CPI_INTERFACE* pIntf
179 );
180static HRESULT RoleAssignmentsRead(
181 LPCWSTR pwzQuery,
182 LPCWSTR pwzKey,
183 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
184 CPI_ROLE_ASSIGNMENT** ppRoleList,
185 int* piInstallCount,
186 int* piUninstallCount
187 );
188static HRESULT TopSortModuleList(
189 CPI_KEY_PAIR* pDepList,
190 CPI_MODULE_LIST* pList
191 );
192static HRESULT SwapDependentModules(
193 CPI_DEPENDENCY_CHAIN* pdcPrev,
194 CPI_KEY_PAIR* pDepList,
195 CPI_MODULE_LIST* pList,
196 CPI_MODULE* pRoot,
197 CPI_MODULE* pItm
198 );
199static HRESULT ModuleFindByKey(
200 CPI_MODULE* pItm,
201 LPCWSTR pwzKey,
202 BOOL fReverse,
203 CPI_MODULE** ppItm
204 );
205static void SortAssemblyListByModule(
206 CPI_MODULE_LIST* pModList,
207 CPI_ASSEMBLY_LIST* pAsmList
208 );
209static HRESULT TopSortAssemblyList(
210 CPI_KEY_PAIR* pDepList,
211 CPI_ASSEMBLY_LIST* pList
212 );
213static HRESULT SwapDependentAssemblies(
214 CPI_DEPENDENCY_CHAIN* pdcPrev,
215 CPI_KEY_PAIR* pDepList,
216 CPI_ASSEMBLY_LIST* pList,
217 CPI_ASSEMBLY* pRoot,
218 CPI_ASSEMBLY* pItm
219 );
220static HRESULT AssemblyFindByKey(
221 CPI_ASSEMBLY* pItm,
222 LPCWSTR pwzKey,
223 BOOL fReverse,
224 CPI_ASSEMBLY** ppItm
225 );
226static HRESULT AddAssemblyToActionData(
227 CPI_ASSEMBLY* pItm,
228 BOOL fInstall,
229 int iActionType,
230 int iActionCost,
231 LPWSTR* ppwzActionData
232 );
233static HRESULT AddRoleAssignmentsToActionData(
234 CPI_ASSEMBLY* pItm,
235 BOOL fInstall,
236 int iActionType,
237 int iActionCost,
238 LPWSTR* ppwzActionData
239 );
240static HRESULT AddComponentToActionData(
241 CPI_COMPONENT* pItm,
242 BOOL fInstall,
243 BOOL fProps,
244 BOOL fRoles,
245 LPWSTR* ppwzActionData
246 );
247static HRESULT AddInterfaceToActionData(
248 CPI_INTERFACE* pItm,
249 BOOL fInstall,
250 BOOL fProps,
251 BOOL fRoles,
252 LPWSTR* ppwzActionData
253 );
254static HRESULT AddMethodToActionData(
255 CPI_METHOD* pItm,
256 BOOL fInstall,
257 BOOL fProps,
258 BOOL fRoles,
259 LPWSTR* ppwzActionData
260 );
261static HRESULT AddRolesToActionData(
262 int iRoleInstallCount,
263 int iRoleUninstallCount,
264 CPI_ROLE_ASSIGNMENT* pRoleList,
265 BOOL fInstall,
266 BOOL fRoles,
267 LPWSTR* ppwzActionData
268 );
269static HRESULT KeyPairFindByFirstKey(
270 CPI_KEY_PAIR* pList,
271 LPCWSTR pwzKey,
272 CPI_KEY_PAIR** ppItm
273 );
274static void AssemblyFree(
275 CPI_ASSEMBLY* pItm
276 );
277static void KeyPairsFreeList(
278 CPI_KEY_PAIR* pList
279 );
280void ModuleListFree(
281 CPI_MODULE_LIST* pList
282 );
283static void ModuleFree(
284 CPI_MODULE* pItm
285 );
286static void ComponentsFreeList(
287 CPI_COMPONENT* pList
288 );
289static void InterfacesFreeList(
290 CPI_INTERFACE* pList
291 );
292static void MethodsFreeList(
293 CPI_METHOD* pList
294 );
295static void RoleAssignmentsFreeList(
296 CPI_ROLE_ASSIGNMENT* pList
297 );
298
299
300// function definitions
301
302void CpiAssemblyListFree(
303 CPI_ASSEMBLY_LIST* pList
304 )
305{
306 CPI_ASSEMBLY* pItm = pList->pFirst;
307
308 while (pItm)
309 {
310 CPI_ASSEMBLY* pDelete = pItm;
311 pItm = pItm->pNext;
312 AssemblyFree(pDelete);
313 }
314}
315
316HRESULT CpiAssembliesRead(
317 CPI_APPLICATION_LIST* pAppList,
318 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
319 CPI_ASSEMBLY_LIST* pAsmList
320 )
321{
322 HRESULT hr = S_OK;
323 CPI_MODULE_LIST modList;
324 CPI_KEY_PAIR* pModCompList = NULL;
325 CPI_KEY_PAIR* pModDepList = NULL;
326 CPI_KEY_PAIR* pAsmDepList = NULL;
327
328 ::ZeroMemory(&modList, sizeof(CPI_MODULE_LIST));
329
330 BOOL fModuleSignatureTable = (S_OK == WcaTableExists(L"ModuleSignature"));
331 BOOL fModuleComponentsTable = (S_OK == WcaTableExists(L"ModuleComponents"));
332 BOOL fModuleDependencyTable = (S_OK == WcaTableExists(L"ModuleDependency"));
333
334 // read modules
335 if (fModuleSignatureTable)
336 {
337 hr = ModulesRead(&modList);
338 ExitOnFailure(hr, "Failed to read ModuleSignature table");
339 }
340
341 // read module components
342 if (fModuleComponentsTable)
343 {
344 hr = KeyPairsRead(vcsModuleComponentsQuery, &pModCompList);
345 ExitOnFailure(hr, "Failed to read ModuleComponents table");
346 }
347
348 // read module dependencies
349 if (fModuleDependencyTable)
350 {
351 hr = KeyPairsRead(vcsModuleDependencyQuery, &pModDepList);
352 ExitOnFailure(hr, "Failed to read ModuleDependency table");
353 }
354
355 // read assemblies
356 hr = AssembliesRead(pModCompList, pAppList, pAppRoleList, pAsmList);
357 ExitOnFailure(hr, "Failed to read ComPlusAssembly table");
358
359 // read assembly dependencies
360 if (CpiTableExists(cptComPlusAssemblyDependency))
361 {
362 hr = KeyPairsRead(vcsAssemblyDependencyQuery, &pAsmDepList);
363 ExitOnFailure(hr, "Failed to read ComPlusAssemblyDependency table");
364 }
365
366 // sort modules
367 if (modList.pFirst && pModDepList)
368 {
369 hr = TopSortModuleList(pModDepList, &modList);
370 ExitOnFailure(hr, "Failed to sort modules");
371 }
372
373 // sort assemblies by module
374 if (pAsmList->pFirst && modList.pFirst && pModDepList)
375 SortAssemblyListByModule(&modList, pAsmList);
376
377 // sort assemblies by dependency
378 if (pAsmList->pFirst && pAsmDepList)
379 {
380 hr = TopSortAssemblyList(pAsmDepList, pAsmList);
381 ExitOnFailure(hr, "Failed to sort assemblies");
382 }
383
384 hr = S_OK;
385
386LExit:
387 // clean up
388 ModuleListFree(&modList);
389 if (pModCompList)
390 KeyPairsFreeList(pModCompList);
391 if (pModDepList)
392 KeyPairsFreeList(pModDepList);
393 if (pAsmDepList)
394 KeyPairsFreeList(pAsmDepList);
395
396 return hr;
397}
398
399HRESULT CpiAssembliesVerifyInstall(
400 CPI_ASSEMBLY_LIST* pList
401 )
402{
403 HRESULT hr = S_OK;
404
405 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
406 {
407 // assemblies that are being installed
408 if (!pItm->fReferencedForInstall && !pItm->iRoleAssignmentsInstallCount && !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
409 continue;
410
411 // if the assembly is referensed, it must be installed
412 if ((pItm->fReferencedForInstall || pItm->iRoleAssignmentsInstallCount) && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
413 MessageExitOnFailure(hr = E_FAIL, msierrComPlusAssemblyDependency, "An assembly is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
414 }
415
416 hr = S_OK;
417
418LExit:
419 return hr;
420}
421
422HRESULT CpiAssembliesVerifyUninstall(
423 CPI_ASSEMBLY_LIST* pList
424 )
425{
426 HRESULT hr = S_OK;
427
428 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
429 {
430 // assemblies that are being uninstalled
431 if (!pItm->fReferencedForUninstall && !pItm->iRoleAssignmentsUninstallCount && (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction) && !WcaIsReInstalling(pItm->isInstalled, pItm->isAction)))
432 continue;
433
434 // if the application is not present, there is no need to remove the components
435 if (pItm->pApplication && pItm->pApplication->fObjectNotFound)
436 {
437 pItm->fIgnore = TRUE;
438 pList->iUninstallCount--; // elements with the fIgnore flag set will not be scheduled for uninstall
439 pList->iRoleUninstallCount--;
440 }
441 }
442
443 hr = S_OK;
444
445//LExit:
446 return hr;
447}
448
449HRESULT CpiAssembliesInstall(
450 CPI_ASSEMBLY_LIST* pList,
451 int iRunMode,
452 LPWSTR* ppwzActionData,
453 int* piProgress
454 )
455{
456 HRESULT hr = S_OK;
457
458 int iActionType;
459 int iCount = 0;
460
461 // add action text
462 hr = CpiAddActionTextToActionData(L"RegisterComPlusAssemblies", ppwzActionData);
463 ExitOnFailure(hr, "Failed to add action text to custom action data");
464
465 // assembly count
466 switch (iRunMode)
467 {
468 case rmDeferred:
469 iCount = pList->iInstallCount - pList->iCommitCount;
470 break;
471 case rmCommit:
472 iCount = pList->iCommitCount;
473 break;
474 case rmRollback:
475 iCount = pList->iInstallCount;
476 break;
477 }
478
479 // add assembly count to action data
480 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
481 ExitOnFailure(hr, "Failed to add count to custom action data");
482
483 // add assemblies to custom action data in forward order
484 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
485 {
486 // assemblies that are being installed, or contains roll assignments to install
487 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
488 continue;
489
490 // assemblies that are being installed must be scheduled during the right type of action
491 BOOL fRunInCommit = 0 != (pItm->iAttributes & aaRunInCommit);
492 if (((rmCommit == iRunMode && !fRunInCommit) || (rmDeferred == iRunMode && fRunInCommit)))
493 continue;
494
495 // action type
496 if (rmRollback == iRunMode)
497 {
498 if (CpiIsInstalled(pItm->isInstalled))
499 iActionType = atNoOp;
500 else
501 iActionType = atRemove;
502 }
503 else
504 iActionType = atCreate;
505
506 // add to action data
507 hr = AddAssemblyToActionData(pItm, TRUE, iActionType, COST_ASSEMBLY_REGISTER, ppwzActionData);
508 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
509 }
510
511 // add progress tics
512 if (piProgress)
513 *piProgress += COST_ASSEMBLY_REGISTER * iCount;
514
515 hr = S_OK;
516
517LExit:
518 return hr;
519}
520
521HRESULT CpiAssembliesUninstall(
522 CPI_ASSEMBLY_LIST* pList,
523 int iRunMode,
524 LPWSTR* ppwzActionData,
525 int* piProgress
526 )
527{
528 HRESULT hr = S_OK;
529
530 int iActionType;
531
532 // add action text
533 hr = CpiAddActionTextToActionData(L"UnregisterComPlusAssemblies", ppwzActionData);
534 ExitOnFailure(hr, "Failed to add action text to custom action data");
535
536 // add assembly count to action data
537 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
538 ExitOnFailure(hr, "Failed to add count to custom action data");
539
540 // add assemblies to custom action data in reverse order
541 for (CPI_ASSEMBLY* pItm = pList->pLast; pItm; pItm = pItm->pPrev)
542 {
543 // assemblies that are being uninstalled
544 if (pItm->fIgnore || (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction) && !WcaIsReInstalling(pItm->isInstalled, pItm->isAction)))
545 continue;
546
547 // action type
548 if (rmRollback == iRunMode)
549 iActionType = atCreate;
550 else
551 iActionType = atRemove;
552
553 // add to action data
554 hr = AddAssemblyToActionData(pItm, FALSE, iActionType, COST_ASSEMBLY_UNREGISTER, ppwzActionData);
555 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
556 }
557
558 // add progress tics
559 if (piProgress)
560 *piProgress += COST_ASSEMBLY_UNREGISTER * pList->iUninstallCount;
561
562 hr = S_OK;
563
564LExit:
565 return hr;
566}
567
568HRESULT CpiRoleAssignmentsInstall(
569 CPI_ASSEMBLY_LIST* pList,
570 int iRunMode,
571 LPWSTR* ppwzActionData,
572 int* piProgress
573 )
574{
575 HRESULT hr = S_OK;
576
577 int iActionType;
578 int iCount = 0;
579
580 // add action text
581 hr = CpiAddActionTextToActionData(L"AddComPlusRoleAssignments", ppwzActionData);
582 ExitOnFailure(hr, "Failed to add action text to custom action data");
583
584 // assembly count
585 switch (iRunMode)
586 {
587 case rmDeferred:
588 iCount = pList->iRoleInstallCount - pList->iRoleCommitCount;
589 break;
590 case rmCommit:
591 iCount = pList->iRoleCommitCount;
592 break;
593 case rmRollback:
594 iCount = pList->iRoleInstallCount;
595 break;
596 }
597
598 // add assembly count to action data
599 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
600 ExitOnFailure(hr, "Failed to add count to custom action data");
601
602 // add assemblies to custom action data in forward order
603 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
604 {
605 // assemblies that are being installed, or contains roll assignments to install
606 if (!pItm->iRoleAssignmentsInstallCount)
607 continue;
608
609 // assemblies that are being installed must be scheduled during the right type of action
610 BOOL fRunInCommit = 0 != (pItm->iAttributes & aaRunInCommit);
611 if (((rmCommit == iRunMode && !fRunInCommit) || (rmDeferred == iRunMode && fRunInCommit)))
612 continue;
613
614 // action type
615 if (rmRollback == iRunMode)
616 {
617 if (CpiIsInstalled(pItm->isInstalled))
618 iActionType = atNoOp;
619 else
620 iActionType = atRemove;
621 }
622 else
623 iActionType = atCreate;
624
625 // add to action data
626 hr = AddRoleAssignmentsToActionData(pItm, TRUE, iActionType, COST_ROLLASSIGNMENT_CREATE, ppwzActionData);
627 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
628
629 // add progress tics
630 if (piProgress)
631 *piProgress += COST_ROLLASSIGNMENT_CREATE * pItm->iRoleAssignmentsInstallCount;
632 }
633
634 hr = S_OK;
635
636LExit:
637 return hr;
638}
639
640HRESULT CpiRoleAssignmentsUninstall(
641 CPI_ASSEMBLY_LIST* pList,
642 int iRunMode,
643 LPWSTR* ppwzActionData,
644 int* piProgress
645 )
646{
647 HRESULT hr = S_OK;
648
649 int iActionType;
650
651 // add action text
652 hr = CpiAddActionTextToActionData(L"RemoveComPlusRoleAssignments", ppwzActionData);
653 ExitOnFailure(hr, "Failed to add action text to custom action data");
654
655 // add assembly count to action data
656 hr = WcaWriteIntegerToCaData(pList->iRoleUninstallCount, ppwzActionData);
657 ExitOnFailure(hr, "Failed to add count to custom action data");
658
659 // add assemblies to custom action data in reverse order
660 for (CPI_ASSEMBLY* pItm = pList->pLast; pItm; pItm = pItm->pPrev)
661 {
662 // assemblies that are being uninstalled
663 if (pItm->fIgnore || !pItm->iRoleAssignmentsUninstallCount)
664 continue;
665
666 // action type
667 if (rmRollback == iRunMode)
668 iActionType = atCreate;
669 else
670 iActionType = atRemove;
671
672 // add to action data
673 hr = AddRoleAssignmentsToActionData(pItm, FALSE, iActionType, COST_ROLLASSIGNMENT_DELETE, ppwzActionData);
674 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
675
676 // add progress tics
677 if (piProgress)
678 *piProgress += COST_ROLLASSIGNMENT_DELETE * pItm->iRoleAssignmentsUninstallCount;
679 }
680
681 hr = S_OK;
682
683LExit:
684 return hr;
685}
686
687HRESULT CpiGetSubscriptionsCollForComponent(
688 CPI_ASSEMBLY* pAsm,
689 CPI_COMPONENT* pComp,
690 ICatalogCollection** ppiSubsColl
691 )
692{
693 HRESULT hr = S_OK;
694
695 ICatalogCollection* piCompColl = NULL;
696 ICatalogObject* piCompObj = NULL;
697
698 // get applications collection
699 if (!pComp->piSubsColl)
700 {
701 // get components collection for application
702 hr = CpiGetComponentsCollForApplication(pAsm->pApplication, &piCompColl);
703 ExitOnFailure(hr, "Failed to get components collection for application");
704
705 if (S_FALSE == hr)
706 ExitFunction(); // exit with hr = S_FALSE
707
708 // find component object
709 hr = CpiFindCollectionObject(piCompColl, pComp->wzCLSID, NULL, &piCompObj);
710 ExitOnFailure(hr, "Failed to find component object");
711
712 if (S_FALSE == hr)
713 ExitFunction(); // exit with hr = S_FALSE
714
715 // get roles collection
716 hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", &pComp->piSubsColl);
717 ExitOnFailure(hr, "Failed to get subscriptions collection");
718 }
719
720 // return value
721 *ppiSubsColl = pComp->piSubsColl;
722 (*ppiSubsColl)->AddRef();
723
724 hr = S_OK;
725
726LExit:
727 // clean up
728 ReleaseObject(piCompColl);
729 ReleaseObject(piCompObj);
730
731 return hr;
732}
733
734
735// helper function definitions
736
737static HRESULT GetAssemblyName(
738 LPCWSTR pwzComponent,
739 LPWSTR* ppwzAssemblyName
740 )
741{
742 HRESULT hr = S_OK;
743
744 PMSIHANDLE hView, hRecKey, hRec;
745
746 LPWSTR pwzKey = NULL;
747
748 LPWSTR pwzName = NULL;
749 LPWSTR pwzVersion = NULL;
750 LPWSTR pwzCulture = NULL;
751 LPWSTR pwzPublicKeyToken = NULL;
752
753 // create parameter record
754 hRecKey = ::MsiCreateRecord(1);
755 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
756 hr = WcaSetRecordString(hRecKey, 1, pwzComponent);
757 ExitOnFailure(hr, "Failed to set record string");
758
759 // open view
760 hr = WcaOpenView(vcsMsiAssemblyNameQuery, &hView);
761 ExitOnFailure(hr, "Failed to open view on MsiAssemblyName table");
762 hr = WcaExecuteView(hView, hRecKey);
763 ExitOnFailure(hr, "Failed to execute view on MsiAssemblyName table");
764
765 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
766 {
767 // read key
768 hr = WcaGetRecordString(hRec, manqName, &pwzKey);
769 ExitOnFailure(hr, "Failed to get name");
770
771 // read value
772 if (0 == lstrcmpiW(L"name", pwzKey))
773 hr = WcaGetRecordString(hRec, manqValue, &pwzName);
774 else if (0 == lstrcmpiW(L"version", pwzKey))
775 hr = WcaGetRecordString(hRec, manqValue, &pwzVersion);
776 else if (0 == lstrcmpiW(L"culture", pwzKey))
777 hr = WcaGetRecordString(hRec, manqValue, &pwzCulture);
778 else if (0 == lstrcmpiW(L"publicKeyToken", pwzKey))
779 hr = WcaGetRecordString(hRec, manqValue, &pwzPublicKeyToken);
780 else
781 {
782 WcaLog(LOGMSG_VERBOSE, "Unknown name in MsiAssemblyName table: %S, %S", pwzComponent, pwzKey);
783 hr = S_OK;
784 }
785
786 ExitOnFailure(hr, "Failed to get value");
787 }
788
789 if (E_NOMOREITEMS != hr)
790 ExitOnFailure(hr, "Failed to fetch record");
791
792 // verify
793 if (!(pwzName && *pwzName) || !(pwzVersion && *pwzVersion))
794 ExitOnFailure(hr = E_FAIL, "Incomplete assembly name");
795
796 // build name string
797 hr = StrAllocFormatted(ppwzAssemblyName, L"%s, Version=%s, Culture=%s, PublicKeyToken=%s",
798 pwzName, pwzVersion,
799 pwzCulture && *pwzCulture ? pwzCulture : L"Neutral",
800 pwzPublicKeyToken && *pwzPublicKeyToken ? pwzPublicKeyToken : L"null");
801 ExitOnFailure(hr, "Failed to build assembly name string");
802
803 hr = S_OK;
804
805LExit:
806 // clean up
807 ReleaseStr(pwzKey);
808 ReleaseStr(pwzName);
809 ReleaseStr(pwzVersion);
810 ReleaseStr(pwzCulture);
811 ReleaseStr(pwzPublicKeyToken);
812
813 return hr;
814}
815
816static HRESULT KeyPairsRead(
817 LPCWSTR pwzQuery,
818 CPI_KEY_PAIR** ppKeyPairList
819 )
820{
821 HRESULT hr = S_OK;
822
823 PMSIHANDLE hView, hRec;
824
825 CPI_KEY_PAIR* pItm = NULL;
826 LPWSTR pwzData = NULL;
827
828 // loop through all dependencies
829 hr = WcaOpenExecuteView(pwzQuery, &hView);
830 ExitOnFailure(hr, "Failed to execute view on table");
831
832 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
833 {
834 // create entry
835 pItm = (CPI_KEY_PAIR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_KEY_PAIR));
836 if (!pItm)
837 ExitFunction1(hr = E_OUTOFMEMORY);
838
839 // get key
840 hr = WcaGetRecordString(hRec, kpqFirstKey, &pwzData);
841 ExitOnFailure(hr, "Failed to get first key");
842 StringCchCopyW(pItm->wzFirstKey, countof(pItm->wzFirstKey), pwzData);
843
844 // get key
845 hr = WcaGetRecordString(hRec, kpqSecondKey, &pwzData);
846 ExitOnFailure(hr, "Failed to get second key");
847 StringCchCopyW(pItm->wzSecondKey, countof(pItm->wzSecondKey), pwzData);
848
849 // add entry
850 if (*ppKeyPairList)
851 pItm->pNext = *ppKeyPairList;
852 *ppKeyPairList = pItm;
853 pItm = NULL;
854 }
855
856 if (E_NOMOREITEMS == hr)
857 hr = S_OK;
858
859LExit:
860 // clean up
861 if (pItm)
862 KeyPairsFreeList(pItm);
863
864 ReleaseStr(pwzData);
865
866 return hr;
867}
868
869static HRESULT ModulesRead(
870 CPI_MODULE_LIST* pModList
871 )
872{
873 HRESULT hr = S_OK;
874
875 PMSIHANDLE hView, hRec;
876
877 CPI_MODULE* pItm = NULL;
878 LPWSTR pwzData = NULL;
879
880 // loop through all modules
881 hr = WcaOpenExecuteView(vcsModuleQuery, &hView);
882 ExitOnFailure(hr, "Failed to execute view on ModuleSignature table");
883
884 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
885 {
886 // create entry
887 pItm = (CPI_MODULE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_MODULE));
888 if (!pItm)
889 ExitFunction1(hr = E_OUTOFMEMORY);
890
891 // get key
892 hr = WcaGetRecordString(hRec, mqModule, &pwzData);
893 ExitOnFailure(hr, "Failed to get key");
894 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
895
896 // add entry
897 if (pModList->pLast)
898 {
899 pModList->pLast->pNext = pItm;
900 pItm->pPrev = pModList->pLast;
901 }
902 else
903 pModList->pFirst = pItm;
904 pModList->pLast = pItm;
905 pItm = NULL;
906 }
907
908 if (E_NOMOREITEMS == hr)
909 hr = S_OK;
910
911LExit:
912 // clean up
913 if (pItm)
914 ModuleFree(pItm);
915
916 ReleaseStr(pwzData);
917
918 return hr;
919}
920
921static HRESULT AssembliesRead(
922 CPI_KEY_PAIR* pModCompList,
923 CPI_APPLICATION_LIST* pAppList,
924 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
925 CPI_ASSEMBLY_LIST* pAsmList
926 )
927{
928 HRESULT hr = S_OK;
929 UINT er = ERROR_SUCCESS;
930
931 PMSIHANDLE hView, hRec;
932
933 CPI_ASSEMBLY* pItm = NULL;
934 CPI_KEY_PAIR* pModComp;
935 LPWSTR pwzData = NULL;
936 LPWSTR pwzComponent = NULL;
937 BOOL fMatchingArchitecture = FALSE;
938
939 // loop through all assemblies
940 hr = WcaOpenExecuteView(vcsAssemblyQuery, &hView);
941 ExitOnFailure(hr, "Failed to execute view on ComPlusAssembly table");
942
943 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
944 {
945 // get component
946 hr = WcaGetRecordString(hRec, aqComponent, &pwzComponent);
947 ExitOnFailure(hr, "Failed to get component");
948
949 // check if the component is our processor architecture
950 hr = CpiVerifyComponentArchitecure(pwzComponent, &fMatchingArchitecture);
951 ExitOnFailure(hr, "Failed to get component architecture.");
952
953 if (!fMatchingArchitecture)
954 {
955 continue; // not the same architecture, ignore
956 }
957
958 // create entry
959 pItm = (CPI_ASSEMBLY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ASSEMBLY));
960 if (!pItm)
961 ExitFunction1(hr = E_OUTOFMEMORY);
962
963 // get component install state
964 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &pItm->isInstalled, &pItm->isAction);
965 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
966
967 // get key
968 hr = WcaGetRecordString(hRec, aqAssembly, &pwzData);
969 ExitOnFailure(hr, "Failed to get key");
970 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
971
972 // get attributes
973 hr = WcaGetRecordInteger(hRec, aqAttributes, &pItm->iAttributes);
974 ExitOnFailure(hr, "Failed to get attributes");
975
976 // get assembly name
977 hr = WcaGetRecordFormattedString(hRec, aqAssemblyName, &pItm->pwzAssemblyName);
978 ExitOnFailure(hr, "Failed to get assembly name");
979
980 if (!*pItm->pwzAssemblyName && (pItm->iAttributes & aaPathFromGAC))
981 {
982 // get assembly name for component
983 hr = GetAssemblyName(pwzComponent, &pItm->pwzAssemblyName);
984 ExitOnFailure(hr, "Failed to get assembly name for component");
985 }
986
987 // get dll path
988 hr = WcaGetRecordFormattedString(hRec, aqDllPath, &pItm->pwzDllPath);
989 ExitOnFailure(hr, "Failed to get assembly dll path");
990
991 // get module
992 // TODO: if there is a very large number of components belonging to modules, this search might be slow
993 hr = KeyPairFindByFirstKey(pModCompList, pwzData, &pModComp);
994
995 if (S_OK == hr)
996 StringCchCopyW(pItm->wzModule, countof(pItm->wzModule), pModComp->wzSecondKey);
997
998 // get application
999 hr = WcaGetRecordString(hRec, aqApplication, &pwzData);
1000 ExitOnFailure(hr, "Failed to get application");
1001
1002 if (pwzData && *pwzData)
1003 {
1004 hr = CpiApplicationFindByKey(pAppList, pwzData, &pItm->pApplication);
1005 if (S_FALSE == hr)
1006 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1007 ExitOnFailure(hr, "Failed to find application, key: %S", pwzData);
1008 }
1009
1010 // get tlb path
1011 hr = WcaGetRecordFormattedString(hRec, aqTlbPath, &pItm->pwzTlbPath);
1012 ExitOnFailure(hr, "Failed to get assembly tlb path");
1013
1014 // get proxy-stub dll path
1015 hr = WcaGetRecordFormattedString(hRec, aqPSDllPath, &pItm->pwzPSDllPath);
1016 ExitOnFailure(hr, "Failed to get assembly proxy-stub DLL path");
1017
1018 // read components
1019 if (CpiTableExists(cptComPlusComponent))
1020 {
1021 hr = ComponentsRead(pItm->wzKey, pAppRoleList, pItm);
1022 ExitOnFailure(hr, "Failed to read components for assembly");
1023 }
1024
1025 // set references & increment counters
1026 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1027 {
1028 pAsmList->iInstallCount++;
1029 if (pItm->iAttributes & aaRunInCommit)
1030 pAsmList->iCommitCount++;
1031 }
1032 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction) || WcaIsReInstalling(pItm->isInstalled, pItm->isAction))
1033 pAsmList->iUninstallCount++;
1034
1035 if (pItm->iRoleAssignmentsInstallCount)
1036 {
1037 pAsmList->iRoleInstallCount++;
1038 if (pItm->iAttributes & aaRunInCommit)
1039 pAsmList->iRoleCommitCount++;
1040 }
1041 if (pItm->iRoleAssignmentsUninstallCount)
1042 pAsmList->iRoleUninstallCount++;
1043
1044 if (pItm->pApplication)
1045 {
1046 if (pItm->iRoleAssignmentsInstallCount || WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1047 CpiApplicationAddReferenceInstall(pItm->pApplication);
1048 if (pItm->iRoleAssignmentsUninstallCount || WcaIsUninstalling(pItm->isInstalled, pItm->isAction) || WcaIsReInstalling(pItm->isInstalled, pItm->isAction))
1049 CpiApplicationAddReferenceUninstall(pItm->pApplication);
1050 }
1051
1052 // add entry
1053 if (pAsmList->pLast)
1054 {
1055 pAsmList->pLast->pNext = pItm;
1056 pItm->pPrev = pAsmList->pLast;
1057 }
1058 else
1059 pAsmList->pFirst = pItm;
1060 pAsmList->pLast = pItm;
1061 pItm = NULL;
1062 }
1063
1064 if (E_NOMOREITEMS == hr)
1065 hr = S_OK;
1066
1067LExit:
1068 // clean up
1069 if (pItm)
1070 AssemblyFree(pItm);
1071
1072 ReleaseStr(pwzData);
1073 ReleaseStr(pwzComponent);
1074
1075 return hr;
1076}
1077
1078static HRESULT TopSortModuleList(
1079 CPI_KEY_PAIR* pDepList,
1080 CPI_MODULE_LIST* pList
1081 )
1082{
1083 HRESULT hr = S_OK;
1084
1085 // top sort list
1086 for (CPI_MODULE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
1087 {
1088 // append module
1089 hr = SwapDependentModules(NULL, pDepList, pList, pItm, pItm);
1090 ExitOnFailure(hr, "Failed to swap dependent modules");
1091 }
1092
1093 hr = S_OK;
1094
1095LExit:
1096 return hr;
1097}
1098
1099static HRESULT SwapDependentModules(
1100 CPI_DEPENDENCY_CHAIN* pdcPrev, // list containing the entire dependency chain
1101 CPI_KEY_PAIR* pDepList, // module dependency list
1102 CPI_MODULE_LIST* pList, // module list being sorted
1103 CPI_MODULE* pRoot, // first module in the chain
1104 CPI_MODULE* pItm // current module to test for dependencies
1105 )
1106{
1107 HRESULT hr = S_OK;
1108
1109 CPI_MODULE* pDepItm;
1110
1111 // find dependencies
1112 for (CPI_KEY_PAIR* pDep = pDepList; pDep; pDep = pDep->pNext)
1113 {
1114 if (0 == lstrcmpW(pItm->wzKey, pDep->wzFirstKey))
1115 {
1116 CPI_DEPENDENCY_CHAIN dcItm;
1117 dcItm.pwzKey = pItm->wzKey;
1118 dcItm.pPrev = pdcPrev;
1119
1120 // check for circular dependencies
1121 for (CPI_DEPENDENCY_CHAIN* pdcItm = &dcItm; pdcItm; pdcItm = pdcItm->pPrev)
1122 {
1123 if (0 == lstrcmpW(pdcItm->pwzKey, pDep->wzSecondKey))
1124 {
1125 // circular dependency found
1126 ExitOnFailure(hr = E_FAIL, "Circular module dependency found, key: %S", pDep->wzSecondKey);
1127 }
1128 }
1129
1130 // make sure the item is not already in the list
1131 hr = ModuleFindByKey(pRoot->pPrev, pDep->wzSecondKey, TRUE, &pDepItm); // find in reverse order
1132
1133 if (S_OK == hr)
1134 continue; // item found, move on
1135
1136 // find item in the list
1137 hr = ModuleFindByKey(pRoot->pNext, pDep->wzSecondKey, FALSE, &pDepItm); // find in forward order
1138
1139 if (S_FALSE == hr)
1140 {
1141 // not found
1142 ExitOnFailure(hr = E_FAIL, "Module dependency not found, key: %S", pDep->wzSecondKey);
1143 }
1144
1145 // if this item in turn has dependencies, they have to be swaped first
1146 hr = SwapDependentModules(&dcItm, pDepList, pList, pRoot, pDepItm);
1147 ExitOnFailure(hr, "Failed to swap dependent module");
1148
1149 // remove item from its current position
1150 pDepItm->pPrev->pNext = pDepItm->pNext; // pDepItm can never be the first item, no need to check pPrev
1151 if (pDepItm->pNext)
1152 pDepItm->pNext->pPrev = pDepItm->pPrev;
1153 else
1154 {
1155 pList->pLast = pDepItm->pPrev;
1156 pList->pLast->pNext = NULL;
1157 }
1158
1159 // insert before the current item
1160 if (pRoot->pPrev)
1161 pRoot->pPrev->pNext = pDepItm;
1162 else
1163 pList->pFirst = pDepItm;
1164 pDepItm->pPrev = pRoot->pPrev;
1165 pRoot->pPrev = pDepItm;
1166 pDepItm->pNext = pRoot;
1167 }
1168 }
1169
1170 hr = S_OK;
1171
1172LExit:
1173 return hr;
1174}
1175
1176static HRESULT ModuleFindByKey(
1177 CPI_MODULE* pItm,
1178 LPCWSTR pwzKey,
1179 BOOL fReverse,
1180 CPI_MODULE** ppItm
1181 )
1182{
1183 for (; pItm; pItm = fReverse ? pItm->pPrev : pItm->pNext)
1184 {
1185 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
1186 {
1187 *ppItm = pItm;
1188 return S_OK;
1189 }
1190 }
1191
1192 return S_FALSE;
1193}
1194
1195static void SortAssemblyListByModule(
1196 CPI_MODULE_LIST* pModList,
1197 CPI_ASSEMBLY_LIST* pAsmList
1198 )
1199{
1200 CPI_ASSEMBLY* pMoved = NULL; // first moved item
1201
1202 // loop modules in reverse order
1203 for (CPI_MODULE* pMod = pModList->pLast; pMod; pMod = pMod->pPrev)
1204 {
1205 // loop assemblies in forward order, starting with the first unmoved item
1206 CPI_ASSEMBLY* pAsm = pMoved ? pMoved->pNext : pAsmList->pFirst;
1207 while (pAsm)
1208 {
1209 CPI_ASSEMBLY* pNext = pAsm->pNext;
1210
1211 // check if assembly belongs to the current module
1212 if (0 == lstrcmpW(pMod->wzKey, pAsm->wzModule))
1213 {
1214 // if the item is not already first in the list
1215 if (pAsm->pPrev)
1216 {
1217 // remove item from it's current position
1218 pAsm->pPrev->pNext = pAsm->pNext;
1219 if (pAsm->pNext)
1220 pAsm->pNext->pPrev = pAsm->pPrev;
1221 else
1222 pAsmList->pLast = pAsm->pPrev;
1223
1224 // insert item first in the list
1225 pAsmList->pFirst->pPrev = pAsm;
1226 pAsm->pNext = pAsmList->pFirst;
1227 pAsm->pPrev = NULL;
1228 pAsmList->pFirst = pAsm;
1229 }
1230
1231 // if we haven't moved any items yet, this is the first moved item
1232 if (!pMoved)
1233 pMoved = pAsm;
1234 }
1235
1236 pAsm = pNext;
1237 }
1238 }
1239}
1240
1241static HRESULT TopSortAssemblyList(
1242 CPI_KEY_PAIR* pDepList,
1243 CPI_ASSEMBLY_LIST* pList
1244 )
1245{
1246 HRESULT hr = S_OK;
1247
1248 // top sort list
1249 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
1250 {
1251 // append module
1252 hr = SwapDependentAssemblies(NULL, pDepList, pList, pItm, pItm);
1253 ExitOnFailure(hr, "Failed to swap dependent assemblies");
1254 }
1255
1256 hr = S_OK;
1257
1258LExit:
1259 return hr;
1260}
1261
1262static HRESULT SwapDependentAssemblies(
1263 CPI_DEPENDENCY_CHAIN* pdcPrev, // list containing the entire dependency chain
1264 CPI_KEY_PAIR* pDepList, // assembly dependency list
1265 CPI_ASSEMBLY_LIST* pList, // assembly list being sorted
1266 CPI_ASSEMBLY* pRoot, // first assembly in the chain
1267 CPI_ASSEMBLY* pItm // current assembly to test for dependencies
1268 )
1269{
1270 HRESULT hr = S_OK;
1271
1272 CPI_ASSEMBLY* pDepItm;
1273
1274 // find dependencies
1275 for (CPI_KEY_PAIR* pDep = pDepList; pDep; pDep = pDep->pNext)
1276 {
1277 if (0 == lstrcmpW(pItm->wzKey, pDep->wzFirstKey))
1278 {
1279 CPI_DEPENDENCY_CHAIN dcItm;
1280 dcItm.pwzKey = pItm->wzKey;
1281 dcItm.pPrev = pdcPrev;
1282
1283 // check for circular dependencies
1284 for (CPI_DEPENDENCY_CHAIN* pdcItm = &dcItm; pdcItm; pdcItm = pdcItm->pPrev)
1285 {
1286 if (0 == lstrcmpW(pdcItm->pwzKey, pDep->wzSecondKey))
1287 {
1288 // circular dependency found
1289 ExitOnFailure(hr = E_FAIL, "Circular assembly dependency found, key: %S", pDep->wzSecondKey);
1290 }
1291 }
1292
1293 // make sure the item is not already in the list
1294 hr = AssemblyFindByKey(pRoot->pPrev, pDep->wzSecondKey, TRUE, &pDepItm); // find in reverse order
1295
1296 if (S_OK == hr)
1297 continue; // item found, move on
1298
1299 // find item in the list
1300 hr = AssemblyFindByKey(pRoot->pNext, pDep->wzSecondKey, FALSE, &pDepItm); // find in forward order
1301
1302 if (S_FALSE == hr)
1303 {
1304 // not found
1305 ExitOnFailure(hr = E_FAIL, "Assembly dependency not found, key: %S", pDep->wzSecondKey);
1306 }
1307
1308 // if the root item belongs to a module, this item must also belong to the same module
1309 if (*pItm->wzModule)
1310 {
1311 if (0 != lstrcmpW(pDepItm->wzModule, pItm->wzModule))
1312 ExitOnFailure(hr = E_FAIL, "An assembly dependency can only exist between two assemblies not belonging to modules, or belonging to the same module. assembly: %S, required assembly: %S", pItm->wzKey, pDepItm->wzKey);
1313 }
1314
1315 // if this item in turn has dependencies, they have to be swaped first
1316 hr = SwapDependentAssemblies(&dcItm, pDepList, pList, pRoot, pDepItm);
1317 ExitOnFailure(hr, "Failed to swap dependent assemblies");
1318
1319 // remove item from its current position
1320 pDepItm->pPrev->pNext = pDepItm->pNext; // pDepItm can never be the first item, no need to check pPrev
1321 if (pDepItm->pNext)
1322 pDepItm->pNext->pPrev = pDepItm->pPrev;
1323 else
1324 {
1325 pList->pLast = pDepItm->pPrev;
1326 pList->pLast->pNext = NULL;
1327 }
1328
1329 // insert before the current item
1330 if (pRoot->pPrev)
1331 pRoot->pPrev->pNext = pDepItm;
1332 else
1333 pList->pFirst = pDepItm;
1334 pDepItm->pPrev = pRoot->pPrev;
1335 pRoot->pPrev = pDepItm;
1336 pDepItm->pNext = pRoot;
1337 }
1338 }
1339
1340 hr = S_OK;
1341
1342LExit:
1343 return hr;
1344}
1345
1346static HRESULT AssemblyFindByKey(
1347 CPI_ASSEMBLY* pItm,
1348 LPCWSTR pwzKey,
1349 BOOL fReverse,
1350 CPI_ASSEMBLY** ppItm
1351 )
1352{
1353 for (; pItm; pItm = fReverse ? pItm->pPrev : pItm->pNext)
1354 {
1355 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
1356 {
1357 *ppItm = pItm;
1358 return S_OK;
1359 }
1360 }
1361
1362 return S_FALSE;
1363}
1364
1365static HRESULT ComponentsRead(
1366 LPCWSTR pwzAsmKey,
1367 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1368 CPI_ASSEMBLY* pAsm
1369 )
1370{
1371 HRESULT hr = S_OK;
1372 PMSIHANDLE hView;
1373 PMSIHANDLE hRec;
1374 PMSIHANDLE hRecKey;
1375 CPI_COMPONENT* pItm = NULL;
1376 LPWSTR pwzData = NULL;
1377
1378 // create parameter record
1379 hRecKey = ::MsiCreateRecord(1);
1380 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
1381 hr = WcaSetRecordString(hRecKey, 1, pwzAsmKey);
1382 ExitOnFailure(hr, "Failed to set record string");
1383
1384 // open view
1385 hr = WcaOpenView(vcsComponentQuery, &hView);
1386 ExitOnFailure(hr, "Failed to open view on ComPlusComponent table");
1387 hr = WcaExecuteView(hView, hRecKey);
1388 ExitOnFailure(hr, "Failed to execute view on ComPlusComponent table");
1389
1390 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1391 {
1392 // create entry
1393 pItm = (CPI_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_COMPONENT));
1394 if (!pItm)
1395 ExitFunction1(hr = E_OUTOFMEMORY);
1396
1397 // get key
1398 hr = WcaGetRecordString(hRec, cqComponent, &pwzData);
1399 ExitOnFailure(hr, "Failed to get key");
1400 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1401
1402 // get clsid
1403 hr = WcaGetRecordFormattedString(hRec, cqCLSID, &pwzData);
1404 ExitOnFailure(hr, "Failed to get clsid");
1405 StringCchCopyW(pItm->wzCLSID, countof(pItm->wzCLSID), pwzData);
1406
1407 // read properties
1408 if (CpiTableExists(cptComPlusComponentProperty))
1409 {
1410 hr = CpiPropertiesRead(vcsComponentPropertyQuery, pItm->wzKey, pdlComponentProperties, &pItm->pProperties, &pItm->iPropertyCount);
1411 ExitOnFailure(hr, "Failed to get component properties");
1412 }
1413
1414 // read roles
1415 if (CpiTableExists(cptComPlusRoleForComponent))
1416 {
1417 hr = RoleAssignmentsRead(vcsRoleForComponentQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1418 ExitOnFailure(hr, "Failed to get roles for component");
1419 }
1420
1421 if (pItm->iRoleInstallCount)
1422 pAsm->iRoleAssignmentsInstallCount++;
1423 if (pItm->iRoleUninstallCount)
1424 pAsm->iRoleAssignmentsUninstallCount++;
1425
1426 // read interfaces
1427 if (CpiTableExists(cptComPlusInterface))
1428 {
1429 hr = InterfacesRead(pItm->wzKey, pAppRoleList, pAsm, pItm);
1430 ExitOnFailure(hr, "Failed to get interfaces for component");
1431 }
1432
1433 // add entry
1434 pAsm->iComponentCount++;
1435 if (pAsm->pComponents)
1436 pItm->pNext = pAsm->pComponents;
1437 pAsm->pComponents = pItm;
1438 pItm = NULL;
1439 }
1440
1441 if (E_NOMOREITEMS == hr)
1442 hr = S_OK;
1443
1444LExit:
1445 // clean up
1446 if (pItm)
1447 ComponentsFreeList(pItm);
1448
1449 ReleaseStr(pwzData);
1450
1451 return hr;
1452}
1453
1454static HRESULT InterfacesRead(
1455 LPCWSTR pwzCompKey,
1456 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1457 CPI_ASSEMBLY* pAsm,
1458 CPI_COMPONENT* pComp
1459 )
1460{
1461 HRESULT hr = S_OK;
1462 PMSIHANDLE hView;
1463 PMSIHANDLE hRec;
1464 PMSIHANDLE hRecKey;
1465 CPI_INTERFACE* pItm = NULL;
1466 LPWSTR pwzData = NULL;
1467
1468 // create parameter record
1469 hRecKey = ::MsiCreateRecord(1);
1470 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
1471 hr = WcaSetRecordString(hRecKey, 1, pwzCompKey);
1472 ExitOnFailure(hr, "Failed to set record string");
1473
1474 // open view
1475 hr = WcaOpenView(vcsInterfaceQuery, &hView);
1476 ExitOnFailure(hr, "Failed to open view on ComPlusInterface table");
1477 hr = WcaExecuteView(hView, hRecKey);
1478 ExitOnFailure(hr, "Failed to execute view on ComPlusInterface table");
1479
1480 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1481 {
1482 // create entry
1483 pItm = (CPI_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_INTERFACE));
1484 if (!pItm)
1485 ExitFunction1(hr = E_OUTOFMEMORY);
1486
1487 // get key
1488 hr = WcaGetRecordString(hRec, iqInterface, &pwzData);
1489 ExitOnFailure(hr, "Failed to get key");
1490 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1491
1492 // get iid
1493 hr = WcaGetRecordFormattedString(hRec, iqIID, &pwzData);
1494 ExitOnFailure(hr, "Failed to get iid");
1495 StringCchCopyW(pItm->wzIID, countof(pItm->wzIID), pwzData);
1496
1497 // read properties
1498 if (CpiTableExists(cptComPlusInterfaceProperty))
1499 {
1500 hr = CpiPropertiesRead(vcsInterfacePropertyQuery, pItm->wzKey, pdlInterfaceProperties, &pItm->pProperties, &pItm->iPropertyCount);
1501 ExitOnFailure(hr, "Failed to get interface properties");
1502 }
1503
1504 // read roles
1505 if (CpiTableExists(cptComPlusRoleForInterface))
1506 {
1507 hr = RoleAssignmentsRead(vcsRoleForInterfaceQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1508 ExitOnFailure(hr, "Failed to get roles for interface");
1509 }
1510
1511 if (pItm->iRoleInstallCount)
1512 pAsm->iRoleAssignmentsInstallCount++;
1513 if (pItm->iRoleUninstallCount)
1514 pAsm->iRoleAssignmentsUninstallCount++;
1515
1516 // read methods
1517 if (CpiTableExists(cptComPlusMethod))
1518 {
1519 hr = MethodsRead(pItm->wzKey, pAppRoleList, pAsm, pItm);
1520 ExitOnFailure(hr, "Failed to get methods for interface");
1521 }
1522
1523 // add entry
1524 pComp->iInterfaceCount++;
1525 if (pComp->pInterfaces)
1526 pItm->pNext = pComp->pInterfaces;
1527 pComp->pInterfaces = pItm;
1528 pItm = NULL;
1529 }
1530
1531 if (E_NOMOREITEMS == hr)
1532 hr = S_OK;
1533
1534LExit:
1535 // clean up
1536 if (pItm)
1537 InterfacesFreeList(pItm);
1538
1539 ReleaseStr(pwzData);
1540
1541 return hr;
1542}
1543
1544static HRESULT MethodsRead(
1545 LPCWSTR pwzIntfKey,
1546 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1547 CPI_ASSEMBLY* pAsm,
1548 CPI_INTERFACE* pIntf
1549 )
1550{
1551 HRESULT hr = S_OK;
1552 PMSIHANDLE hView, hRec, hRecKey;
1553 CPI_METHOD* pItm = NULL;
1554 LPWSTR pwzData = NULL;
1555
1556 // create parameter record
1557 hRecKey = ::MsiCreateRecord(1);
1558 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
1559 hr = WcaSetRecordString(hRecKey, 1, pwzIntfKey);
1560 ExitOnFailure(hr, "Failed to set record string");
1561
1562 // open view
1563 hr = WcaOpenView(vcsMethodQuery, &hView);
1564 ExitOnFailure(hr, "Failed to open view on ComPlusMethod table");
1565 hr = WcaExecuteView(hView, hRecKey);
1566 ExitOnFailure(hr, "Failed to execute view on ComPlusMethod table");
1567
1568 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1569 {
1570 // create entry
1571 pItm = (CPI_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_METHOD));
1572 if (!pItm)
1573 ExitFunction1(hr = E_OUTOFMEMORY);
1574
1575 // get key
1576 hr = WcaGetRecordString(hRec, iqInterface, &pwzData);
1577 ExitOnFailure(hr, "Failed to get key");
1578 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1579
1580 // get index
1581 hr = WcaGetRecordFormattedString(hRec, mqIndex, &pwzData);
1582 ExitOnFailure(hr, "Failed to get index");
1583 StringCchCopyW(pItm->wzIndex, countof(pItm->wzIndex), pwzData);
1584
1585 // get name
1586 hr = WcaGetRecordFormattedString(hRec, mqName, &pwzData);
1587 ExitOnFailure(hr, "Failed to get name");
1588 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
1589
1590 // either an index or a name must be provided
1591 if (!*pItm->wzIndex && !*pItm->wzName)
1592 ExitOnFailure(hr = E_FAIL, "A method must have either an index or a name associated, key: %S", pItm->wzKey);
1593
1594 // read properties
1595 if (CpiTableExists(cptComPlusMethodProperty))
1596 {
1597 hr = CpiPropertiesRead(vcsMethodPropertyQuery, pItm->wzKey, pdlMethodProperties, &pItm->pProperties, &pItm->iPropertyCount);
1598 ExitOnFailure(hr, "Failed to get method properties");
1599 }
1600
1601 // read roles
1602 if (CpiTableExists(cptComPlusRoleForMethod))
1603 {
1604 hr = RoleAssignmentsRead(vcsRoleForMethodQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1605 ExitOnFailure(hr, "Failed to get roles for method");
1606 }
1607
1608 if (pItm->iRoleInstallCount)
1609 pAsm->iRoleAssignmentsInstallCount++;
1610 if (pItm->iRoleUninstallCount)
1611 pAsm->iRoleAssignmentsUninstallCount++;
1612
1613 // add entry
1614 pIntf->iMethodCount++;
1615 if (pIntf->pMethods)
1616 pItm->pNext = pIntf->pMethods;
1617 pIntf->pMethods = pItm;
1618 pItm = NULL;
1619 }
1620
1621 if (E_NOMOREITEMS == hr)
1622 hr = S_OK;
1623
1624LExit:
1625 // clean up
1626 if (pItm)
1627 MethodsFreeList(pItm);
1628
1629 ReleaseStr(pwzData);
1630
1631 return hr;
1632}
1633
1634static HRESULT RoleAssignmentsRead(
1635 LPCWSTR pwzQuery,
1636 LPCWSTR pwzKey,
1637 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1638 CPI_ROLE_ASSIGNMENT** ppRoleList,
1639 int* piInstallCount,
1640 int* piUninstallCount
1641 )
1642{
1643 HRESULT hr = S_OK;
1644 UINT er = ERROR_SUCCESS;
1645
1646 PMSIHANDLE hView, hRec, hRecKey;
1647
1648 CPI_ROLE_ASSIGNMENT* pItm = NULL;
1649 LPWSTR pwzData = NULL;
1650 BOOL fMatchingArchitecture = FALSE;
1651
1652 // create parameter record
1653 hRecKey = ::MsiCreateRecord(1);
1654 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
1655 hr = WcaSetRecordString(hRecKey, 1, pwzKey);
1656 ExitOnFailure(hr, "Failed to set record string");
1657
1658 // open view
1659 hr = WcaOpenView(pwzQuery, &hView);
1660 ExitOnFailure(hr, "Failed to open view on role assignment table");
1661 hr = WcaExecuteView(hView, hRecKey);
1662 ExitOnFailure(hr, "Failed to execute view on role assignment table");
1663
1664 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1665 {
1666 // get component
1667 hr = WcaGetRecordString(hRec, raqComponent, &pwzData);
1668 ExitOnFailure(hr, "Failed to get assembly component");
1669
1670 // check if the component is our processor architecture
1671 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
1672 ExitOnFailure(hr, "Failed to get component architecture.");
1673
1674 if (!fMatchingArchitecture)
1675 {
1676 continue; // not the same architecture, ignore
1677 }
1678
1679 // create entry
1680 pItm = (CPI_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLE_ASSIGNMENT));
1681 if (!pItm)
1682 ExitFunction1(hr = E_OUTOFMEMORY);
1683
1684 // get component install state
1685 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
1686 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
1687
1688 // get key
1689 hr = WcaGetRecordString(hRec, raqKey, &pwzData);
1690 ExitOnFailure(hr, "Failed to get key");
1691 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1692
1693 // get application role
1694 hr = WcaGetRecordString(hRec, raqApplicationRole, &pwzData);
1695 ExitOnFailure(hr, "Failed to get application role");
1696
1697 hr = CpiApplicationRoleFindByKey(pAppRoleList, pwzData, &pItm->pApplicationRole);
1698 if (S_FALSE == hr)
1699 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1700 ExitOnFailure(hr, "Failed to find application, key: %S", pwzData);
1701
1702 // set references & increment counters
1703 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1704 {
1705 CpiApplicationRoleAddReferenceInstall(pItm->pApplicationRole);
1706 ++*piInstallCount;
1707 }
1708 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
1709 {
1710 CpiApplicationRoleAddReferenceUninstall(pItm->pApplicationRole);
1711 ++*piUninstallCount;
1712 }
1713
1714 // add entry
1715 if (*ppRoleList)
1716 pItm->pNext = *ppRoleList;
1717 *ppRoleList = pItm;
1718 pItm = NULL;
1719 }
1720
1721 if (E_NOMOREITEMS == hr)
1722 hr = S_OK;
1723
1724LExit:
1725 // clean up
1726 if (pItm)
1727 RoleAssignmentsFreeList(pItm);
1728
1729 ReleaseStr(pwzData);
1730
1731 return hr;
1732}
1733
1734static HRESULT AddAssemblyToActionData(
1735 CPI_ASSEMBLY* pItm,
1736 BOOL fInstall,
1737 int iActionType,
1738 int iActionCost,
1739 LPWSTR* ppwzActionData
1740 )
1741{
1742 HRESULT hr = S_OK;
1743
1744 // add action information to custom action data
1745 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
1746 ExitOnFailure(hr, "Failed to add action type to custom action data");
1747 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
1748 ExitOnFailure(hr, "Failed to add action cost to custom action data");
1749
1750 // add assembly information to custom action data
1751 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
1752 ExitOnFailure(hr, "Failed to add assembly key to custom action data");
1753 hr = WcaWriteStringToCaData(pItm->pwzAssemblyName, ppwzActionData);
1754 ExitOnFailure(hr, "Failed to add assembly name to custom action data");
1755 hr = WcaWriteStringToCaData(pItm->pwzDllPath, ppwzActionData);
1756 ExitOnFailure(hr, "Failed to add assembly dll path to custom action data");
1757 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pwzTlbPath : L"", ppwzActionData);
1758 ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data");
1759 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pwzPSDllPath : L"", ppwzActionData);
1760 ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data");
1761 hr = WcaWriteIntegerToCaData(pItm->iAttributes, ppwzActionData);
1762 ExitOnFailure(hr, "Failed to add assembly attributes to custom action data");
1763
1764 // add application information to custom action data
1765 hr = WcaWriteStringToCaData(pItm->pApplication ? pItm->pApplication->wzID : L"", ppwzActionData);
1766 ExitOnFailure(hr, "Failed to add application id to custom action data");
1767
1768 // add partition information to custom action data
1769 LPCWSTR pwzPartID = pItm->pApplication && pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"";
1770 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
1771 ExitOnFailure(hr, "Failed to add partition id to custom action data");
1772
1773 // add components to custom action data
1774 //
1775 // components are needed acording to the following table:
1776 //
1777 // Native .NET
1778 // --------------------------------------------
1779 // NoOp | No | No
1780 // Create | Yes | Yes
1781 // Remove | Yes | No
1782 //
1783 int iCompCount = (atCreate == iActionType || (atRemove == iActionType && 0 == (pItm->iAttributes & aaDotNetAssembly))) ? pItm->iComponentCount : 0;
1784 hr = WcaWriteIntegerToCaData(iCompCount, ppwzActionData);
1785 ExitOnFailure(hr, "Failed to add component count to custom action data, key: %S", pItm->wzKey);
1786
1787 if (iCompCount)
1788 {
1789 for (CPI_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext)
1790 {
1791 hr = AddComponentToActionData(pComp, fInstall, atCreate == iActionType, FALSE, ppwzActionData);
1792 ExitOnFailure(hr, "Failed to add component to custom action data, component: %S", pComp->wzKey);
1793 }
1794 }
1795
1796 hr = S_OK;
1797
1798LExit:
1799 return hr;
1800}
1801
1802static HRESULT AddRoleAssignmentsToActionData(
1803 CPI_ASSEMBLY* pItm,
1804 BOOL fInstall,
1805 int iActionType,
1806 int iActionCost,
1807 LPWSTR* ppwzActionData
1808 )
1809{
1810 HRESULT hr = S_OK;
1811
1812 // add action information to custom action data
1813 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
1814 ExitOnFailure(hr, "Failed to add action type to custom action data");
1815 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
1816 ExitOnFailure(hr, "Failed to add action cost to custom action data");
1817
1818 // add assembly information to custom action data
1819 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
1820 ExitOnFailure(hr, "Failed to add assembly key to custom action data");
1821 hr = WcaWriteIntegerToCaData(fInstall ? pItm->iRoleAssignmentsInstallCount : pItm->iRoleAssignmentsUninstallCount, ppwzActionData);
1822 ExitOnFailure(hr, "Failed to add role assignments count to custom action data");
1823
1824 // add application information to custom action data
1825 hr = WcaWriteStringToCaData(pItm->pApplication ? pItm->pApplication->wzID : L"", ppwzActionData);
1826 ExitOnFailure(hr, "Failed to add application id to custom action data");
1827
1828 // add partition information to custom action data
1829 LPCWSTR pwzPartID = pItm->pApplication && pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"";
1830 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
1831 ExitOnFailure(hr, "Failed to add partition id to custom action data");
1832
1833 // add components to custom action data
1834 hr = WcaWriteIntegerToCaData(pItm->iComponentCount, ppwzActionData);
1835 ExitOnFailure(hr, "Failed to add component count to custom action data");
1836
1837 for (CPI_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext)
1838 {
1839 hr = AddComponentToActionData(pComp, fInstall, FALSE, TRUE, ppwzActionData);
1840 ExitOnFailure(hr, "Failed to add component to custom action data, component: %S", pComp->wzKey);
1841 }
1842
1843 hr = S_OK;
1844
1845LExit:
1846 return hr;
1847}
1848
1849static HRESULT AddComponentToActionData(
1850 CPI_COMPONENT* pItm,
1851 BOOL fInstall,
1852 BOOL fProps,
1853 BOOL fRoles,
1854 LPWSTR* ppwzActionData
1855 )
1856{
1857 HRESULT hr = S_OK;
1858
1859 // add component information to custom action data
1860 hr = WcaWriteStringToCaData(pItm->wzCLSID, ppwzActionData);
1861 ExitOnFailure(hr, "Failed to add component CLSID to custom action data");
1862
1863 // add properties to custom action data
1864 hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
1865 ExitOnFailure(hr, "Failed to add properties to custom action data");
1866
1867 // add roles to custom action data
1868 hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData);
1869 ExitOnFailure(hr, "Failed to add roles to custom action data");
1870
1871 // add interfaces to custom action data
1872 int iIntfCount = (fProps || fRoles) ? pItm->iInterfaceCount : 0;
1873 hr = WcaWriteIntegerToCaData(iIntfCount, ppwzActionData);
1874 ExitOnFailure(hr, "Failed to add interface count to custom action data");
1875
1876 if (iIntfCount)
1877 {
1878 for (CPI_INTERFACE* pIntf = pItm->pInterfaces; pIntf; pIntf = pIntf->pNext)
1879 {
1880 hr = AddInterfaceToActionData(pIntf, fInstall, fProps, fRoles, ppwzActionData);
1881 ExitOnFailure(hr, "Failed to add interface custom action data, interface: %S", pIntf->wzKey);
1882 }
1883 }
1884
1885 hr = S_OK;
1886
1887LExit:
1888 return hr;
1889}
1890
1891static HRESULT AddInterfaceToActionData(
1892 CPI_INTERFACE* pItm,
1893 BOOL fInstall,
1894 BOOL fProps,
1895 BOOL fRoles,
1896 LPWSTR* ppwzActionData
1897 )
1898{
1899 HRESULT hr = S_OK;
1900
1901 // add interface information to custom action data
1902 hr = WcaWriteStringToCaData(pItm->wzIID, ppwzActionData);
1903 ExitOnFailure(hr, "Failed to add interface IID to custom action data");
1904
1905 // add properties to custom action data
1906 hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
1907 ExitOnFailure(hr, "Failed to add properties to custom action data");
1908
1909 // add roles to custom action data
1910 hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData);
1911 ExitOnFailure(hr, "Failed to add roles to custom action data");
1912
1913 // add methods to custom action data
1914 hr = WcaWriteIntegerToCaData(pItm->iMethodCount, ppwzActionData);
1915 ExitOnFailure(hr, "Failed to add method count to custom action data");
1916
1917 for (CPI_METHOD* pMeth = pItm->pMethods; pMeth; pMeth = pMeth->pNext)
1918 {
1919 hr = AddMethodToActionData(pMeth, fInstall, fProps, fRoles, ppwzActionData);
1920 ExitOnFailure(hr, "Failed to add method custom action data, method: %S", pMeth->wzKey);
1921 }
1922
1923 hr = S_OK;
1924
1925LExit:
1926 return hr;
1927}
1928
1929static HRESULT AddMethodToActionData(
1930 CPI_METHOD* pItm,
1931 BOOL fInstall,
1932 BOOL fProps,
1933 BOOL fRoles,
1934 LPWSTR* ppwzActionData
1935 )
1936{
1937 HRESULT hr = S_OK;
1938
1939 // add interface information to custom action data
1940 hr = WcaWriteStringToCaData(pItm->wzIndex, ppwzActionData);
1941 ExitOnFailure(hr, "Failed to add method index to custom action data");
1942
1943 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
1944 ExitOnFailure(hr, "Failed to add method name to custom action data");
1945
1946 // add properties to custom action data
1947 hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
1948 ExitOnFailure(hr, "Failed to add properties to custom action data");
1949
1950 // add roles to custom action data
1951 hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData);
1952 ExitOnFailure(hr, "Failed to add roles to custom action data");
1953
1954 hr = S_OK;
1955
1956LExit:
1957 return hr;
1958}
1959
1960static HRESULT AddRolesToActionData(
1961 int iRoleInstallCount,
1962 int iRoleUninstallCount,
1963 CPI_ROLE_ASSIGNMENT* pRoleList,
1964 BOOL fInstall,
1965 BOOL fRoles,
1966 LPWSTR* ppwzActionData
1967 )
1968{
1969 HRESULT hr = S_OK;
1970
1971 int iRoleCount = fRoles ? (fInstall ? iRoleInstallCount : iRoleUninstallCount) : 0;
1972 hr = WcaWriteIntegerToCaData(iRoleCount, ppwzActionData);
1973 ExitOnFailure(hr, "Failed to add role count to custom action data");
1974
1975 if (iRoleCount)
1976 {
1977 for (CPI_ROLE_ASSIGNMENT* pRole = pRoleList; pRole; pRole = pRole->pNext)
1978 {
1979 // make sure the install state matches the create flag
1980 if (fInstall ? !WcaIsInstalling(pRole->isInstalled, pRole->isAction) : !WcaIsUninstalling(pRole->isInstalled, pRole->isAction))
1981 continue;
1982
1983 hr = WcaWriteStringToCaData(pRole->pApplicationRole->wzKey, ppwzActionData);
1984 ExitOnFailure(hr, "Failed to add key to custom action data, role: %S", pRole->wzKey);
1985
1986 hr = WcaWriteStringToCaData(pRole->pApplicationRole->wzName, ppwzActionData);
1987 ExitOnFailure(hr, "Failed to add role name to custom action data, role: %S", pRole->wzKey);
1988 }
1989 }
1990
1991 hr = S_OK;
1992
1993LExit:
1994 return hr;
1995}
1996
1997static HRESULT KeyPairFindByFirstKey(
1998 CPI_KEY_PAIR* pList,
1999 LPCWSTR pwzKey,
2000 CPI_KEY_PAIR** ppItm
2001 )
2002{
2003 for (; pList; pList = pList->pNext)
2004 {
2005 if (0 == lstrcmpW(pList->wzFirstKey, pwzKey))
2006 {
2007 *ppItm = pList;
2008 return S_OK;
2009 }
2010 }
2011
2012 return S_FALSE;
2013}
2014
2015static void AssemblyFree(
2016 CPI_ASSEMBLY* pItm
2017 )
2018{
2019 ReleaseStr(pItm->pwzAssemblyName);
2020 ReleaseStr(pItm->pwzDllPath);
2021 ReleaseStr(pItm->pwzTlbPath);
2022 ReleaseStr(pItm->pwzPSDllPath);
2023
2024 if (pItm->pComponents)
2025 ComponentsFreeList(pItm->pComponents);
2026
2027 ::HeapFree(::GetProcessHeap(), 0, pItm);
2028}
2029
2030static void KeyPairsFreeList(
2031 CPI_KEY_PAIR* pList
2032 )
2033{
2034 while (pList)
2035 {
2036 CPI_KEY_PAIR* pDelete = pList;
2037 pList = pList->pNext;
2038 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2039 }
2040}
2041
2042void ModuleListFree(
2043 CPI_MODULE_LIST* pList
2044 )
2045{
2046 CPI_MODULE* pItm = pList->pFirst;
2047
2048 while (pItm)
2049 {
2050 CPI_MODULE* pDelete = pItm;
2051 pItm = pItm->pNext;
2052 ModuleFree(pDelete);
2053 }
2054}
2055
2056static void ModuleFree(
2057 CPI_MODULE* pItm
2058 )
2059{
2060 ::HeapFree(::GetProcessHeap(), 0, pItm);
2061}
2062
2063static void ComponentsFreeList(
2064 CPI_COMPONENT* pList
2065 )
2066{
2067 while (pList)
2068 {
2069 if (pList->pProperties)
2070 CpiPropertiesFreeList(pList->pProperties);
2071
2072 if (pList->pRoles)
2073 RoleAssignmentsFreeList(pList->pRoles);
2074
2075 if (pList->pInterfaces)
2076 InterfacesFreeList(pList->pInterfaces);
2077
2078 ReleaseObject(pList->piSubsColl);
2079
2080 CPI_COMPONENT* pDelete = pList;
2081 pList = pList->pNext;
2082 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2083 }
2084}
2085
2086static void InterfacesFreeList(
2087 CPI_INTERFACE* pList
2088 )
2089{
2090 while (pList)
2091 {
2092 if (pList->pProperties)
2093 CpiPropertiesFreeList(pList->pProperties);
2094
2095 if (pList->pRoles)
2096 RoleAssignmentsFreeList(pList->pRoles);
2097
2098 if (pList->pMethods)
2099 MethodsFreeList(pList->pMethods);
2100
2101 CPI_INTERFACE* pDelete = pList;
2102 pList = pList->pNext;
2103 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2104 }
2105}
2106
2107static void MethodsFreeList(
2108 CPI_METHOD* pList
2109 )
2110{
2111 while (pList)
2112 {
2113 if (pList->pProperties)
2114 CpiPropertiesFreeList(pList->pProperties);
2115
2116 if (pList->pRoles)
2117 RoleAssignmentsFreeList(pList->pRoles);
2118
2119 CPI_METHOD* pDelete = pList;
2120 pList = pList->pNext;
2121 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2122 }
2123}
2124
2125static void RoleAssignmentsFreeList(
2126 CPI_ROLE_ASSIGNMENT* pList
2127 )
2128{
2129 while (pList)
2130 {
2131 CPI_ROLE_ASSIGNMENT* pDelete = pList;
2132 pList = pList->pNext;
2133 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2134 }
2135}
diff --git a/src/ca/cpasmsched.h b/src/ca/cpasmsched.h
new file mode 100644
index 00000000..b5a68d7e
--- /dev/null
+++ b/src/ca/cpasmsched.h
@@ -0,0 +1,168 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5enum eAssemblyAttributes
6{
7 aaEventClass = (1 << 0),
8 aaDotNetAssembly = (1 << 1),
9 aaPathFromGAC = (1 << 2),
10 aaRunInCommit = (1 << 3)
11};
12
13
14// structs
15
16struct CPI_ROLE_ASSIGNMENT
17{
18 WCHAR wzKey[MAX_DARWIN_KEY + 1];
19
20 INSTALLSTATE isInstalled, isAction;
21
22 CPI_APPLICATION_ROLE* pApplicationRole;
23
24 CPI_ROLE_ASSIGNMENT* pNext;
25};
26
27struct CPI_METHOD
28{
29 WCHAR wzKey[MAX_DARWIN_KEY + 1];
30 WCHAR wzIndex[11 + 1];
31 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
32
33 int iPropertyCount;
34 CPI_PROPERTY* pProperties;
35
36 int iRoleInstallCount;
37 int iRoleUninstallCount;
38 CPI_ROLE_ASSIGNMENT* pRoles;
39
40 CPI_METHOD* pNext;
41};
42
43struct CPI_INTERFACE
44{
45 WCHAR wzKey[MAX_DARWIN_KEY + 1];
46 WCHAR wzIID[CPI_MAX_GUID + 1];
47
48 int iPropertyCount;
49 CPI_PROPERTY* pProperties;
50
51 int iRoleInstallCount;
52 int iRoleUninstallCount;
53 CPI_ROLE_ASSIGNMENT* pRoles;
54
55 int iMethodCount;
56 CPI_METHOD* pMethods;
57
58 CPI_INTERFACE* pNext;
59};
60
61struct CPI_COMPONENT
62{
63 WCHAR wzKey[MAX_DARWIN_KEY + 1];
64 WCHAR wzCLSID[CPI_MAX_GUID + 1];
65
66 int iPropertyCount;
67 CPI_PROPERTY* pProperties;
68
69 int iRoleInstallCount;
70 int iRoleUninstallCount;
71 CPI_ROLE_ASSIGNMENT* pRoles;
72
73 int iInterfaceCount;
74 CPI_INTERFACE* pInterfaces;
75
76 ICatalogCollection* piSubsColl;
77
78 CPI_COMPONENT* pNext;
79};
80
81struct CPI_ASSEMBLY
82{
83 WCHAR wzKey[MAX_DARWIN_KEY + 1];
84 WCHAR wzModule[MAX_DARWIN_KEY + 1];
85 LPWSTR pwzAssemblyName;
86 LPWSTR pwzDllPath;
87 LPWSTR pwzTlbPath;
88 LPWSTR pwzPSDllPath;
89 int iAttributes;
90
91 int iComponentCount;
92 CPI_COMPONENT* pComponents;
93
94 BOOL fReferencedForInstall;
95 BOOL fReferencedForUninstall;
96 BOOL fIgnore;
97
98 int iRoleAssignmentsInstallCount;
99 int iRoleAssignmentsUninstallCount;
100
101 INSTALLSTATE isInstalled, isAction;
102
103 CPI_APPLICATION* pApplication;
104
105 CPI_ASSEMBLY* pPrev;
106 CPI_ASSEMBLY* pNext;
107};
108
109struct CPI_ASSEMBLY_LIST
110{
111 CPI_ASSEMBLY* pFirst;
112 CPI_ASSEMBLY* pLast;
113
114 int iInstallCount;
115 int iCommitCount;
116 int iUninstallCount;
117
118 int iRoleInstallCount;
119 int iRoleCommitCount;
120 int iRoleUninstallCount;
121};
122
123
124// function prototypes
125
126void CpiAssemblyListFree(
127 CPI_ASSEMBLY_LIST* pList
128 );
129HRESULT CpiAssembliesRead(
130 CPI_APPLICATION_LIST* pAppList,
131 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
132 CPI_ASSEMBLY_LIST* pAsmList
133 );
134HRESULT CpiAssembliesVerifyInstall(
135 CPI_ASSEMBLY_LIST* pList
136 );
137HRESULT CpiAssembliesVerifyUninstall(
138 CPI_ASSEMBLY_LIST* pList
139 );
140HRESULT CpiAssembliesInstall(
141 CPI_ASSEMBLY_LIST* pList,
142 int iRunMode,
143 LPWSTR* ppwzActionData,
144 int* piProgress
145 );
146HRESULT CpiAssembliesUninstall(
147 CPI_ASSEMBLY_LIST* pList,
148 int iRunMode,
149 LPWSTR* ppwzActionData,
150 int* piProgress
151 );
152HRESULT CpiRoleAssignmentsInstall(
153 CPI_ASSEMBLY_LIST* pList,
154 int iRunMode,
155 LPWSTR* ppwzActionData,
156 int* piProgress
157 );
158HRESULT CpiRoleAssignmentsUninstall(
159 CPI_ASSEMBLY_LIST* pList,
160 int iRunMode,
161 LPWSTR* ppwzActionData,
162 int* piProgress
163 );
164HRESULT CpiGetSubscriptionsCollForComponent(
165 CPI_ASSEMBLY* pAsm,
166 CPI_COMPONENT* pComp,
167 ICatalogCollection** ppiSubsColl
168 );
diff --git a/src/ca/cpcost.h b/src/ca/cpcost.h
new file mode 100644
index 00000000..7a23e03b
--- /dev/null
+++ b/src/ca/cpcost.h
@@ -0,0 +1,30 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#define COST_PARTITION_CREATE 10000
6#define COST_PARTITION_DELETE 10000
7
8#define COST_PARTITION_USER_CREATE 10000
9#define COST_PARTITION_USER_DELETE 10000
10
11#define COST_USER_IN_PARTITION_ROLE_CREATE 10000
12#define COST_USER_IN_PARTITION_ROLE_DELETE 10000
13
14#define COST_APPLICATION_CREATE 10000
15#define COST_APPLICATION_DELETE 10000
16
17#define COST_APPLICATION_ROLE_CREATE 10000
18#define COST_APPLICATION_ROLE_DELETE 10000
19
20#define COST_USER_IN_APPLICATION_ROLE_CREATE 10000
21#define COST_USER_IN_APPLICATION_ROLE_DELETE 10000
22
23#define COST_ASSEMBLY_REGISTER 50000
24#define COST_ASSEMBLY_UNREGISTER 10000
25
26#define COST_ROLLASSIGNMENT_CREATE 10000
27#define COST_ROLLASSIGNMENT_DELETE 10000
28
29#define COST_SUBSCRIPTION_CREATE 10000
30#define COST_SUBSCRIPTION_DELETE 10000
diff --git a/src/ca/cpexec.cpp b/src/ca/cpexec.cpp
new file mode 100644
index 00000000..fa2446d8
--- /dev/null
+++ b/src/ca/cpexec.cpp
@@ -0,0 +1,704 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5/********************************************************************
6 DllMain - standard entry point for all WiX CustomActions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInst,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInst);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
27
28/********************************************************************
29 ComPlusPrepare - CUSTOM ACTION ENTRY POINT
30
31 Input: deferred CustomActionData - ComPlusPrepare
32********************************************************************/
33extern "C" UINT __stdcall ComPlusPrepare(MSIHANDLE hInstall)
34{
35 HRESULT hr = S_OK;
36 UINT er = ERROR_SUCCESS;
37
38 LPWSTR pwzCustomActionData = NULL;
39 LPWSTR pwzData = NULL;
40
41 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
42
43 // initialize
44 hr = WcaInitialize(hInstall, "ComPlusPrepare");
45 ExitOnFailure(hr, "Failed to initialize ComPlusPrepare");
46
47 // get custom action data
48 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
49 ExitOnFailure(hr, "Failed to get CustomActionData");
50 pwzData = pwzCustomActionData;
51
52 // create rollback file
53 hRollbackFile = ::CreateFileW(pwzData, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
54 if (INVALID_HANDLE_VALUE == hRollbackFile)
55 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to create rollback file, name: %S", pwzData);
56
57 hr = S_OK;
58
59LExit:
60 // clean up
61 ReleaseStr(pwzCustomActionData);
62
63 if (INVALID_HANDLE_VALUE != hRollbackFile)
64 ::CloseHandle(hRollbackFile);
65
66 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
67 return WcaFinalize(er);
68}
69
70/********************************************************************
71 ComPlusCleanup - CUSTOM ACTION ENTRY POINT
72
73 Input: deferred CustomActionData - ComPlusCleanup
74********************************************************************/
75extern "C" UINT __stdcall ComPlusCleanup(MSIHANDLE hInstall)
76{
77 HRESULT hr = S_OK;
78 UINT er = ERROR_SUCCESS;
79
80 LPWSTR pwzCustomActionData = NULL;
81 LPWSTR pwzData = NULL;
82
83 // initialize
84 hr = WcaInitialize(hInstall, "ComPlusCleanup");
85 ExitOnFailure(hr, "Failed to initialize ComPlusCleanup");
86
87 // get custom action data
88 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
89 ExitOnFailure(hr, "Failed to get CustomActionData");
90 pwzData = pwzCustomActionData;
91
92 // delete rollback file
93 if (!::DeleteFileW(pwzData))
94 {
95 // error, but not a showstopper
96 hr = HRESULT_FROM_WIN32(::GetLastError());
97 WcaLog(LOGMSG_STANDARD, "Failed to delete rollback file, hr: 0x%x, name: %S", hr, pwzData);
98 }
99
100 hr = S_OK;
101
102LExit:
103 // clean up
104 ReleaseStr(pwzCustomActionData);
105
106 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
107 return WcaFinalize(er);
108}
109
110/********************************************************************
111 ComPlusInstallExecute - CUSTOM ACTION ENTRY POINT
112
113 Input: deferred CustomActionData - ComPlusInstallExecute
114********************************************************************/
115extern "C" UINT __stdcall ComPlusInstallExecute(MSIHANDLE hInstall)
116{
117 HRESULT hr = S_OK;
118 UINT er = ERROR_SUCCESS;
119
120 LPWSTR pwzCustomActionData = NULL;
121 LPWSTR pwzData = NULL;
122 LPWSTR pwzRollbackFileName = NULL;
123
124 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
125
126 BOOL fInitializedCom = FALSE;
127
128 // initialize
129 hr = WcaInitialize(hInstall, "ComPlusInstallExecute");
130 ExitOnFailure(hr, "Failed to initialize ComPlusInstallExecute");
131
132 hr = ::CoInitialize(NULL);
133 ExitOnFailure(hr, "Failed to initialize COM");
134 fInitializedCom = TRUE;
135
136 CpiInitialize();
137
138 // get custom action data
139 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
140 ExitOnFailure(hr, "Failed to get CustomActionData");
141 pwzData = pwzCustomActionData;
142
143 // open rollback file
144 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
145 ExitOnFailure(hr, "Failed to read rollback file name");
146
147 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
148 if (INVALID_HANDLE_VALUE == hRollbackFile)
149 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
150
151 // create partitions
152 hr = CpiConfigurePartitions(&pwzData, hRollbackFile);
153 ExitOnFailure(hr, "Failed to create partitions");
154 if (S_FALSE == hr) ExitFunction();
155
156 // create users in partition roles
157 hr = CpiConfigureUsersInPartitionRoles(&pwzData, hRollbackFile);
158 ExitOnFailure(hr, "Failed to create users in partition roles");
159 if (S_FALSE == hr) ExitFunction();
160
161 // create partition users
162 hr = CpiConfigurePartitionUsers(&pwzData, hRollbackFile);
163 ExitOnFailure(hr, "Failed to add partition users");
164 if (S_FALSE == hr) ExitFunction();
165
166 // create applications
167 hr = CpiConfigureApplications(&pwzData, hRollbackFile);
168 ExitOnFailure(hr, "Failed to create applications");
169 if (S_FALSE == hr) ExitFunction();
170
171 // create application roles
172 hr = CpiConfigureApplicationRoles(&pwzData, hRollbackFile);
173 ExitOnFailure(hr, "Failed to create application roles");
174 if (S_FALSE == hr) ExitFunction();
175
176 // create users in application roles
177 hr = CpiConfigureUsersInApplicationRoles(&pwzData, hRollbackFile);
178 ExitOnFailure(hr, "Failed to create users in application roles");
179 if (S_FALSE == hr) ExitFunction();
180
181 // register assemblies
182 hr = CpiConfigureAssemblies(&pwzData, hRollbackFile);
183 ExitOnFailure(hr, "Failed to register assemblies");
184 if (S_FALSE == hr) ExitFunction();
185
186 // create role assignments
187 hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile);
188 ExitOnFailure(hr, "Failed to create role assignments");
189 if (S_FALSE == hr) ExitFunction();
190
191 // create subscriptions
192 hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile);
193 ExitOnFailure(hr, "Failed to create subscriptions");
194 if (S_FALSE == hr) ExitFunction();
195
196 hr = S_OK;
197
198LExit:
199 // clean up
200 ReleaseStr(pwzCustomActionData);
201 ReleaseStr(pwzRollbackFileName);
202
203 if (INVALID_HANDLE_VALUE != hRollbackFile)
204 ::CloseHandle(hRollbackFile);
205
206 // unitialize
207 CpiFinalize();
208
209 if (fInitializedCom)
210 ::CoUninitialize();
211
212 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
213 return WcaFinalize(er);
214}
215
216/********************************************************************
217 ComPlusInstallExecuteCommit - CUSTOM ACTION ENTRY POINT
218
219 Input: deferred CustomActionData - ComPlusInstallExecuteCommit
220********************************************************************/
221extern "C" UINT __stdcall ComPlusInstallExecuteCommit(MSIHANDLE hInstall)
222{
223 HRESULT hr = S_OK;
224 UINT er = ERROR_SUCCESS;
225
226 LPWSTR pwzCustomActionData = NULL;
227 LPWSTR pwzData = NULL;
228 LPWSTR pwzRollbackFileName = NULL;
229
230 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
231
232 BOOL fInitializedCom = FALSE;
233
234 // initialize
235 hr = WcaInitialize(hInstall, "ComPlusInstallExecuteCommit");
236 ExitOnFailure(hr, "Failed to initialize ComPlusInstallExecuteCommit");
237
238 hr = ::CoInitialize(NULL);
239 ExitOnFailure(hr, "Failed to initialize COM");
240 fInitializedCom = TRUE;
241
242 CpiInitialize();
243
244 // get custom action data
245 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
246 ExitOnFailure(hr, "Failed to get CustomActionData");
247 pwzData = pwzCustomActionData;
248
249 // open rollback file
250 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
251 ExitOnFailure(hr, "Failed to read rollback file name");
252
253 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
254 if (INVALID_HANDLE_VALUE == hRollbackFile)
255 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
256
257 if (INVALID_SET_FILE_POINTER == ::SetFilePointer(hRollbackFile, 0, NULL, FILE_END))
258 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set file pointer");
259
260 // register assemblies
261 hr = CpiConfigureAssemblies(&pwzData, hRollbackFile);
262 ExitOnFailure(hr, "Failed to register assemblies");
263 if (S_FALSE == hr) ExitFunction();
264
265 // create role assignments
266 hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile);
267 ExitOnFailure(hr, "Failed to create role assignments");
268 if (S_FALSE == hr) ExitFunction();
269
270 // create subscriptions
271 hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile);
272 ExitOnFailure(hr, "Failed to create subscriptions");
273 if (S_FALSE == hr) ExitFunction();
274
275 hr = S_OK;
276
277LExit:
278 // clean up
279 ReleaseStr(pwzCustomActionData);
280
281 if (INVALID_HANDLE_VALUE != hRollbackFile)
282 ::CloseHandle(hRollbackFile);
283
284 // unitialize
285 CpiFinalize();
286
287 if (fInitializedCom)
288 ::CoUninitialize();
289
290 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
291 return WcaFinalize(er);
292}
293
294/********************************************************************
295 ComPlusRollbackInstallExecute - CUSTOM ACTION ENTRY POINT
296
297 Input: deferred CustomActionData - ComPlusRollbackInstallExecute
298********************************************************************/
299extern "C" UINT __stdcall ComPlusRollbackInstallExecute(MSIHANDLE hInstall)
300{
301 HRESULT hr = S_OK;
302 UINT er = ERROR_SUCCESS;
303
304 LPWSTR pwzCustomActionData = NULL;
305 LPWSTR pwzData = NULL;
306 LPWSTR pwzRollbackFileName = NULL;
307
308 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
309
310 CPI_ROLLBACK_DATA* prdPartitions = NULL;
311 CPI_ROLLBACK_DATA* prdUsersInPartitionRoles = NULL;
312 CPI_ROLLBACK_DATA* prdPartitionUsers = NULL;
313 CPI_ROLLBACK_DATA* prdApplications = NULL;
314 CPI_ROLLBACK_DATA* prdApplicationRoles = NULL;
315 CPI_ROLLBACK_DATA* prdUsersApplicationRoles = NULL;
316 CPI_ROLLBACK_DATA* prdAssemblies = NULL;
317 CPI_ROLLBACK_DATA* prdRoleAssignments = NULL;
318 CPI_ROLLBACK_DATA* prdSubscriptions = NULL;
319
320 BOOL fInitializedCom = FALSE;
321
322 // initialize
323 hr = WcaInitialize(hInstall, "ComPlusRollbackInstallExecute");
324 ExitOnFailure(hr, "Failed to initialize ComPlusRollbackInstallExecute");
325
326 hr = ::CoInitialize(NULL);
327 ExitOnFailure(hr, "Failed to initialize COM");
328 fInitializedCom = TRUE;
329
330 CpiInitialize();
331
332 // get custom action data
333 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
334 ExitOnFailure(hr, "Failed to get CustomActionData");
335 pwzData = pwzCustomActionData;
336
337 // open rollback file
338 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
339 ExitOnFailure(hr, "Failed to read rollback file name");
340
341 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
342 if (INVALID_HANDLE_VALUE == hRollbackFile)
343 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
344
345 // read rollback data (execute)
346 hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitions);
347 ExitOnFailure(hr, "Failed to read partitions rollback data");
348 hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersInPartitionRoles);
349 ExitOnFailure(hr, "Failed to read users in partition roles rollback data");
350 hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitionUsers);
351 ExitOnFailure(hr, "Failed to read partition users rollback data");
352 hr = CpiReadRollbackDataList(hRollbackFile, &prdApplications);
353 ExitOnFailure(hr, "Failed to read applications rollback data");
354 hr = CpiReadRollbackDataList(hRollbackFile, &prdApplicationRoles);
355 ExitOnFailure(hr, "Failed to read application roles rollback data");
356 hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersApplicationRoles);
357 ExitOnFailure(hr, "Failed to read users in application roles rollback data");
358 hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies);
359 ExitOnFailure(hr, "Failed to read assemblies rollback data");
360 hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments);
361 ExitOnFailure(hr, "Failed to read role assignments rollback data");
362 hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions);
363 ExitOnFailure(hr, "Failed to read subscription rollback data");
364
365 // read rollback data (commit)
366 hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies);
367 ExitOnFailure(hr, "Failed to read assemblies rollback data (commit)");
368 hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments);
369 ExitOnFailure(hr, "Failed to read role assignments rollback data");
370 hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions);
371 ExitOnFailure(hr, "Failed to read subscription rollback data (commit)");
372
373 ::CloseHandle(hRollbackFile);
374 hRollbackFile = INVALID_HANDLE_VALUE;
375
376 // rollback create subscriptions
377 hr = CpiRollbackConfigureSubscriptions(&pwzData, prdSubscriptions);
378 ExitOnFailure(hr, "Failed to rollback create subscriptions");
379
380 // rollback create role assignments
381 hr = CpiRollbackConfigureRoleAssignments(&pwzData, prdRoleAssignments);
382 ExitOnFailure(hr, "Failed to rollback create role assignments");
383
384 // rollback register assemblies
385 hr = CpiRollbackConfigureAssemblies(&pwzData, prdAssemblies);
386 ExitOnFailure(hr, "Failed to rollback register assemblies");
387
388 // rollback create users in application roles
389 hr = CpiRollbackConfigureUsersInApplicationRoles(&pwzData, prdUsersApplicationRoles);
390 ExitOnFailure(hr, "Failed to rollback create users in application roles");
391
392 // rollback create application roles
393 hr = CpiRollbackConfigureApplicationRoles(&pwzData, prdApplicationRoles);
394 ExitOnFailure(hr, "Failed to rollback create application roles");
395
396 // rollback create applications
397 hr = CpiRollbackConfigureApplications(&pwzData, prdApplications);
398 ExitOnFailure(hr, "Failed to rollback create applications");
399
400 // rollback create partition users
401 hr = CpiRollbackConfigurePartitionUsers(&pwzData, prdPartitionUsers);
402 ExitOnFailure(hr, "Failed to rollback create partition users");
403
404 // rollback create users in partition roles
405 hr = CpiRollbackConfigureUsersInPartitionRoles(&pwzData, prdUsersInPartitionRoles);
406 ExitOnFailure(hr, "Failed to rollback create users in partition roles");
407
408 // rollback create partitions
409 hr = CpiRollbackConfigurePartitions(&pwzData, prdPartitions);
410 ExitOnFailure(hr, "Failed to rollback create partitions");
411
412 hr = S_OK;
413
414LExit:
415 // clean up
416 ReleaseStr(pwzCustomActionData);
417 ReleaseStr(pwzRollbackFileName);
418
419 if (INVALID_HANDLE_VALUE != hRollbackFile)
420 ::CloseHandle(hRollbackFile);
421
422 if (prdPartitions)
423 CpiFreeRollbackDataList(prdPartitions);
424 if (prdUsersInPartitionRoles)
425 CpiFreeRollbackDataList(prdUsersInPartitionRoles);
426 if (prdPartitionUsers)
427 CpiFreeRollbackDataList(prdPartitionUsers);
428 if (prdApplications)
429 CpiFreeRollbackDataList(prdApplications);
430 if (prdApplicationRoles)
431 CpiFreeRollbackDataList(prdApplicationRoles);
432 if (prdUsersApplicationRoles)
433 CpiFreeRollbackDataList(prdUsersApplicationRoles);
434 if (prdAssemblies)
435 CpiFreeRollbackDataList(prdAssemblies);
436 if (prdRoleAssignments)
437 CpiFreeRollbackDataList(prdRoleAssignments);
438 if (prdSubscriptions)
439 CpiFreeRollbackDataList(prdSubscriptions);
440
441 // unitialize
442 CpiFinalize();
443
444 if (fInitializedCom)
445 ::CoUninitialize();
446
447 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
448 return WcaFinalize(er);
449}
450
451/********************************************************************
452 ComPlusUninstallExecute - CUSTOM ACTION ENTRY POINT
453
454 Input: deferred CustomActionData - ComPlusUninstallExecute
455********************************************************************/
456extern "C" UINT __stdcall ComPlusUninstallExecute(MSIHANDLE hInstall)
457{
458 HRESULT hr = S_OK;
459 UINT er = ERROR_SUCCESS;
460
461 LPWSTR pwzCustomActionData = NULL;
462 LPWSTR pwzData = NULL;
463 LPWSTR pwzRollbackFileName = NULL;
464
465 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
466
467 BOOL fInitializedCom = FALSE;
468
469 // initialize
470 hr = WcaInitialize(hInstall, "ComPlusUninstallExecute");
471 ExitOnFailure(hr, "Failed to initialize ComPlusUninstallExecute");
472
473 hr = ::CoInitialize(NULL);
474 ExitOnFailure(hr, "Failed to initialize COM");
475 fInitializedCom = TRUE;
476
477 CpiInitialize();
478
479 // get custom action data
480 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
481 ExitOnFailure(hr, "Failed to get CustomActionData");
482 pwzData = pwzCustomActionData;
483
484 // open rollback file
485 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
486 ExitOnFailure(hr, "Failed to read rollback file name");
487
488 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
489 if (INVALID_HANDLE_VALUE == hRollbackFile)
490 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
491
492 // delete subscriptions
493 hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile);
494 ExitOnFailure(hr, "Failed to delete subscriptions");
495 if (S_FALSE == hr) ExitFunction();
496
497 // delete role assignments
498 hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile);
499 ExitOnFailure(hr, "Failed to delete role assignments");
500 if (S_FALSE == hr) ExitFunction();
501
502 // unregister assemblies
503 hr = CpiConfigureAssemblies(&pwzData, hRollbackFile);
504 ExitOnFailure(hr, "Failed to unregister assemblies");
505 if (S_FALSE == hr) ExitFunction();
506
507 // remove users in application roles
508 hr = CpiConfigureUsersInApplicationRoles(&pwzData, hRollbackFile);
509 ExitOnFailure(hr, "Failed to delete users in application roles");
510 if (S_FALSE == hr) ExitFunction();
511
512 // remove application roles
513 hr = CpiConfigureApplicationRoles(&pwzData, hRollbackFile);
514 ExitOnFailure(hr, "Failed to delete application roles");
515 if (S_FALSE == hr) ExitFunction();
516
517 // remove applications
518 hr = CpiConfigureApplications(&pwzData, hRollbackFile);
519 ExitOnFailure(hr, "Failed to remove applications");
520 if (S_FALSE == hr) ExitFunction();
521
522 // remove partition users
523 hr = CpiConfigurePartitionUsers(&pwzData, hRollbackFile);
524 ExitOnFailure(hr, "Failed to remove partition users");
525 if (S_FALSE == hr) ExitFunction();
526
527 // remove users in partition roles
528 hr = CpiConfigureUsersInPartitionRoles(&pwzData, hRollbackFile);
529 ExitOnFailure(hr, "Failed to delete users in partition roles");
530 if (S_FALSE == hr) ExitFunction();
531
532 // remove partitions
533 hr = CpiConfigurePartitions(&pwzData, hRollbackFile);
534 ExitOnFailure(hr, "Failed to delete partitions");
535 if (S_FALSE == hr) ExitFunction();
536
537 hr = S_OK;
538
539LExit:
540 // clean up
541 ReleaseStr(pwzCustomActionData);
542 ReleaseStr(pwzRollbackFileName);
543
544 if (INVALID_HANDLE_VALUE != hRollbackFile)
545 ::CloseHandle(hRollbackFile);
546
547 // unitialize
548 CpiFinalize();
549
550 if (fInitializedCom)
551 ::CoUninitialize();
552
553 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
554 return WcaFinalize(er);
555}
556
557/********************************************************************
558 ComPlusRollbackUninstallExecute - CUSTOM ACTION ENTRY POINT
559
560 Input: deferred CustomActionData - ComPlusRollbackUninstallExecute
561********************************************************************/
562extern "C" UINT __stdcall ComPlusRollbackUninstallExecute(MSIHANDLE hInstall)
563{
564 HRESULT hr = S_OK;
565 UINT er = ERROR_SUCCESS;
566
567 LPWSTR pwzCustomActionData = NULL;
568 LPWSTR pwzData = NULL;
569 LPWSTR pwzRollbackFileName = NULL;
570
571 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
572
573 CPI_ROLLBACK_DATA* prdPartitions = NULL;
574 CPI_ROLLBACK_DATA* prdUsersInPartitionRoles = NULL;
575 CPI_ROLLBACK_DATA* prdPartitionUsers = NULL;
576 CPI_ROLLBACK_DATA* prdApplications = NULL;
577 CPI_ROLLBACK_DATA* prdApplicationRoles = NULL;
578 CPI_ROLLBACK_DATA* prdUsersApplicationRoles = NULL;
579 CPI_ROLLBACK_DATA* prdAssemblies = NULL;
580 CPI_ROLLBACK_DATA* prdRoleAssignments = NULL;
581 CPI_ROLLBACK_DATA* prdSubscriptions = NULL;
582
583 BOOL fInitializedCom = FALSE;
584
585 // initialize
586 hr = WcaInitialize(hInstall, "ComPlusRollbackUninstallExecute");
587 ExitOnFailure(hr, "Failed to initialize ComPlusRollbackUninstallExecute");
588
589 hr = ::CoInitialize(NULL);
590 ExitOnFailure(hr, "Failed to initialize COM");
591 fInitializedCom = TRUE;
592
593 CpiInitialize();
594
595 // get custom action data
596 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
597 ExitOnFailure(hr, "Failed to get CustomActionData");
598 pwzData = pwzCustomActionData;
599
600 // open rollback file
601 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
602 ExitOnFailure(hr, "Failed to read rollback file name");
603
604 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
605 if (INVALID_HANDLE_VALUE == hRollbackFile)
606 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
607
608 // read rollback data
609 hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions);
610 ExitOnFailure(hr, "Failed to read subscription rollback data");
611 hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments);
612 ExitOnFailure(hr, "Failed to read role assignments rollback data");
613 hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies);
614 ExitOnFailure(hr, "Failed to read assemblies rollback data");
615 hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersApplicationRoles);
616 ExitOnFailure(hr, "Failed to read users in application roles rollback data");
617 hr = CpiReadRollbackDataList(hRollbackFile, &prdApplicationRoles);
618 ExitOnFailure(hr, "Failed to read application roles rollback data");
619 hr = CpiReadRollbackDataList(hRollbackFile, &prdApplications);
620 ExitOnFailure(hr, "Failed to read applications rollback data");
621 hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitionUsers);
622 ExitOnFailure(hr, "Failed to read partition users rollback data");
623 hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersInPartitionRoles);
624 ExitOnFailure(hr, "Failed to read users in partition roles rollback data");
625 hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitions);
626 ExitOnFailure(hr, "Failed to read partitions rollback data");
627
628 ::CloseHandle(hRollbackFile);
629 hRollbackFile = INVALID_HANDLE_VALUE;
630
631 // rollback remove partitions
632 hr = CpiRollbackConfigurePartitions(&pwzData, prdPartitions);
633 ExitOnFailure(hr, "Failed to rollback delete partitions");
634
635 // rollback remove users in partition roles
636 hr = CpiRollbackConfigureUsersInPartitionRoles(&pwzData, prdUsersInPartitionRoles);
637 ExitOnFailure(hr, "Failed to rollback delete users in partition roles");
638
639 // rollback remove partition users
640 hr = CpiRollbackConfigurePartitionUsers(&pwzData, prdPartitionUsers);
641 ExitOnFailure(hr, "Failed to rollback delete partition users");
642
643 // rollback remove applications
644 hr = CpiRollbackConfigureApplications(&pwzData, prdApplications);
645 ExitOnFailure(hr, "Failed to rollback delete applications");
646
647 // rollback remove application roles
648 hr = CpiRollbackConfigureApplicationRoles(&pwzData, prdApplicationRoles);
649 ExitOnFailure(hr, "Failed to rollback delete application roles");
650
651 // rollback remove users in application roles
652 hr = CpiRollbackConfigureUsersInApplicationRoles(&pwzData, prdUsersApplicationRoles);
653 ExitOnFailure(hr, "Failed to rollback delete users in application roles");
654
655 // rollback unregister assemblies
656 hr = CpiRollbackConfigureAssemblies(&pwzData, prdAssemblies);
657 ExitOnFailure(hr, "Failed to rollback unregister assemblies");
658
659 // rollback delete role assignments
660 hr = CpiRollbackConfigureRoleAssignments(&pwzData, prdAssemblies);
661 ExitOnFailure(hr, "Failed to rollback delete role assignments");
662
663 // rollback delete subscriptions
664 hr = CpiRollbackConfigureSubscriptions(&pwzData, prdSubscriptions);
665 ExitOnFailure(hr, "Failed to rollback delete subscriptions");
666
667 hr = S_OK;
668
669LExit:
670 // clean up
671 ReleaseStr(pwzCustomActionData);
672 ReleaseStr(pwzRollbackFileName);
673
674 if (INVALID_HANDLE_VALUE != hRollbackFile)
675 ::CloseHandle(hRollbackFile);
676
677 if (prdPartitions)
678 CpiFreeRollbackDataList(prdPartitions);
679 if (prdUsersInPartitionRoles)
680 CpiFreeRollbackDataList(prdUsersInPartitionRoles);
681 if (prdPartitionUsers)
682 CpiFreeRollbackDataList(prdPartitionUsers);
683 if (prdApplications)
684 CpiFreeRollbackDataList(prdApplications);
685 if (prdApplicationRoles)
686 CpiFreeRollbackDataList(prdApplicationRoles);
687 if (prdUsersApplicationRoles)
688 CpiFreeRollbackDataList(prdUsersApplicationRoles);
689 if (prdAssemblies)
690 CpiFreeRollbackDataList(prdAssemblies);
691 if (prdRoleAssignments)
692 CpiFreeRollbackDataList(prdRoleAssignments);
693 if (prdSubscriptions)
694 CpiFreeRollbackDataList(prdSubscriptions);
695
696 // unitialize
697 CpiFinalize();
698
699 if (fInitializedCom)
700 ::CoUninitialize();
701
702 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
703 return WcaFinalize(er);
704}
diff --git a/src/ca/cpexec.def b/src/ca/cpexec.def
new file mode 100644
index 00000000..1dad15c2
--- /dev/null
+++ b/src/ca/cpexec.def
@@ -0,0 +1,11 @@
1; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3
4EXPORTS
5 ComPlusPrepare
6 ComPlusCleanup
7 ComPlusInstallExecute
8 ComPlusInstallExecuteCommit
9 ComPlusRollbackInstallExecute
10 ComPlusUninstallExecute
11 ComPlusRollbackUninstallExecute
diff --git a/src/ca/cppartexec.cpp b/src/ca/cppartexec.cpp
new file mode 100644
index 00000000..d8c30c6a
--- /dev/null
+++ b/src/ca/cppartexec.cpp
@@ -0,0 +1,690 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_PARTITION_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzID;
14 LPWSTR pwzName;
15 CPI_PROPERTY* pPropList;
16};
17
18struct CPI_PARTITION_USER_ATTRIBUTES
19{
20 int iActionType;
21 int iActionCost;
22 LPWSTR pwzKey;
23 LPWSTR pwzAccount;
24 LPWSTR pwzPartID;
25};
26
27
28// prototypes for private helper functions
29
30static HRESULT ReadPartitionAttributes(
31 LPWSTR* ppwzData,
32 CPI_PARTITION_ATTRIBUTES* pAttrs
33 );
34static void FreePartitionAttributes(
35 CPI_PARTITION_ATTRIBUTES* pAttrs
36 );
37static HRESULT CreatePartition(
38 CPI_PARTITION_ATTRIBUTES* pAttrs
39 );
40static HRESULT RemovePartition(
41 CPI_PARTITION_ATTRIBUTES* pAttrs
42 );
43static HRESULT ReadPartitionUserAttributes(
44 LPWSTR* ppwzData,
45 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
46 );
47static void FreePartitionUserAttributes(
48 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
49 );
50static HRESULT CreatePartitionUser(
51 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
52 );
53static HRESULT RemovePartitionUser(
54 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
55 );
56
57
58// function definitions
59
60HRESULT CpiConfigurePartitions(
61 LPWSTR* ppwzData,
62 HANDLE hRollbackFile
63 )
64{
65 HRESULT hr = S_OK;
66
67 CPI_PARTITION_ATTRIBUTES attrs;
68 ::ZeroMemory(&attrs, sizeof(attrs));
69
70 // read action text
71 hr = CpiActionStartMessage(ppwzData, FALSE);
72 ExitOnFailure(hr, "Failed to send action start message");
73
74 // ger partition count
75 int iCnt = 0;
76 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
77 ExitOnFailure(hr, "Failed to read count");
78
79 // write count to rollback file
80 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
81 ExitOnFailure(hr, "Failed to write count to rollback file");
82
83 for (int i = 0; i < iCnt; i++)
84 {
85 // read partition attributes from CustomActionData
86 hr = ReadPartitionAttributes(ppwzData, &attrs);
87 ExitOnFailure(hr, "Failed to read attributes");
88
89 // progress message
90 hr = CpiActionDataMessage(1, attrs.pwzName);
91 ExitOnFailure(hr, "Failed to send progress messages");
92
93 if (S_FALSE == hr)
94 ExitFunction();
95
96 // write key to rollback file
97 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
98 ExitOnFailure(hr, "Failed to write key to rollback file");
99
100 // action
101 switch (attrs.iActionType)
102 {
103 case atCreate:
104 hr = CreatePartition(&attrs);
105 ExitOnFailure(hr, "Failed to create partition, key: %S", attrs.pwzKey);
106 break;
107 case atRemove:
108 hr = RemovePartition(&attrs);
109 ExitOnFailure(hr, "Failed to remove partition, key: %S", attrs.pwzKey);
110 break;
111 }
112
113 // write completion status to rollback file
114 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
115 ExitOnFailure(hr, "Failed to write completion status to rollback file");
116
117 // progress
118 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
119 ExitOnFailure(hr, "Failed to update progress");
120 }
121
122 hr = S_OK;
123
124LExit:
125 // clean up
126 FreePartitionAttributes(&attrs);
127
128 return hr;
129}
130
131HRESULT CpiRollbackConfigurePartitions(
132 LPWSTR* ppwzData,
133 CPI_ROLLBACK_DATA* pRollbackDataList
134 )
135{
136 HRESULT hr = S_OK;
137
138 int iRollbackStatus;
139
140 CPI_PARTITION_ATTRIBUTES attrs;
141 ::ZeroMemory(&attrs, sizeof(attrs));
142
143 // read action text
144 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
145 ExitOnFailure(hr, "Failed to send action start message");
146
147 // get count
148 int iCnt = 0;
149 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
150 ExitOnFailure(hr, "Failed to read count");
151
152 for (int i = 0; i < iCnt; i++)
153 {
154 // read partition attributes from CustomActionData
155 hr = ReadPartitionAttributes(ppwzData, &attrs);
156 ExitOnFailure(hr, "Failed to read attributes");
157
158 // rollback status
159 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
160
161 if (S_FALSE == hr)
162 continue; // not found, nothing to rollback
163
164 // progress message
165 hr = CpiActionDataMessage(1, attrs.pwzName);
166 ExitOnFailure(hr, "Failed to send progress messages");
167
168 if (S_FALSE == hr)
169 ExitFunction();
170
171 // action
172 switch (attrs.iActionType)
173 {
174 case atCreate:
175 hr = CreatePartition(&attrs);
176 if (FAILED(hr))
177 WcaLog(LOGMSG_STANDARD, "Failed to create partition, hr: 0x%x, key: %S", hr, attrs.pwzKey);
178 break;
179 case atRemove:
180 hr = RemovePartition(&attrs);
181 if (FAILED(hr))
182 WcaLog(LOGMSG_STANDARD, "Failed to remove partition, hr: 0x%x, key: %S", hr, attrs.pwzKey);
183 break;
184 }
185
186 // check rollback status
187 if (0 == iRollbackStatus)
188 continue; // operation did not complete, skip progress
189
190 // progress
191 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
192 ExitOnFailure(hr, "Failed to update progress");
193 }
194
195 hr = S_OK;
196
197LExit:
198 // clean up
199 FreePartitionAttributes(&attrs);
200
201 return hr;
202}
203
204HRESULT CpiConfigurePartitionUsers(
205 LPWSTR* ppwzData,
206 HANDLE hRollbackFile
207 )
208{
209 HRESULT hr = S_OK;
210
211 CPI_PARTITION_USER_ATTRIBUTES attrs;
212 ::ZeroMemory(&attrs, sizeof(attrs));
213
214 // read action text
215 hr = CpiActionStartMessage(ppwzData, FALSE);
216 ExitOnFailure(hr, "Failed to send action start message");
217
218 // ger partition count
219 int iCnt = 0;
220 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
221 ExitOnFailure(hr, "Failed to read count");
222
223 // write count to rollback file
224 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
225 ExitOnFailure(hr, "Failed to write count to rollback file");
226
227 for (int i = 0; i < iCnt; i++)
228 {
229 // read partition attributes from CustomActionData
230 hr = ReadPartitionUserAttributes(ppwzData, &attrs);
231 ExitOnFailure(hr, "Failed to read attributes");
232
233 // progress message
234 hr = CpiActionDataMessage(1, attrs.pwzAccount);
235 ExitOnFailure(hr, "Failed to send progress messages");
236
237 if (S_FALSE == hr)
238 ExitFunction();
239
240 // write key to rollback file
241 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
242 ExitOnFailure(hr, "Failed to write key to rollback file");
243
244 // action
245 switch (attrs.iActionType)
246 {
247 case atCreate:
248 hr = CreatePartitionUser(&attrs);
249 ExitOnFailure(hr, "Failed to create partition user, key: %S", attrs.pwzKey);
250 break;
251 case atRemove:
252 hr = RemovePartitionUser(&attrs);
253 ExitOnFailure(hr, "Failed to remove partition user, key: %S", attrs.pwzKey);
254 break;
255 }
256
257 // write completion status to rollback file
258 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
259 ExitOnFailure(hr, "Failed to write completion status to rollback file");
260
261 // progress
262 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
263 ExitOnFailure(hr, "Failed to update progress");
264 }
265
266 hr = S_OK;
267
268LExit:
269 // clean up
270 FreePartitionUserAttributes(&attrs);
271
272 return hr;
273}
274
275HRESULT CpiRollbackConfigurePartitionUsers(
276 LPWSTR* ppwzData,
277 CPI_ROLLBACK_DATA* pRollbackDataList
278 )
279{
280 HRESULT hr = S_OK;
281
282 int iRollbackStatus;
283
284 CPI_PARTITION_USER_ATTRIBUTES attrs;
285 ::ZeroMemory(&attrs, sizeof(attrs));
286
287 // read action text
288 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
289 ExitOnFailure(hr, "Failed to send action start message");
290
291 // get count
292 int iCnt = 0;
293 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
294 ExitOnFailure(hr, "Failed to read count");
295
296 for (int i = 0; i < iCnt; i++)
297 {
298 // read partition attributes from CustomActionData
299 hr = ReadPartitionUserAttributes(ppwzData, &attrs);
300 ExitOnFailure(hr, "Failed to read attributes");
301
302 // rollback status
303 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
304
305 if (S_FALSE == hr)
306 continue; // not found, nothing to rollback
307
308 // progress message
309 hr = CpiActionDataMessage(1, attrs.pwzAccount);
310 ExitOnFailure(hr, "Failed to send progress messages");
311
312 if (S_FALSE == hr)
313 ExitFunction();
314
315 // action
316 switch (attrs.iActionType)
317 {
318 case atCreate:
319 hr = CreatePartitionUser(&attrs);
320 ExitOnFailure(hr, "Failed to create partition user, key: %S", attrs.pwzKey);
321 break;
322 case atRemove:
323 hr = RemovePartitionUser(&attrs);
324 ExitOnFailure(hr, "Failed to remove partition user, key: %S", attrs.pwzKey);
325 break;
326 }
327
328 // check rollback status
329 if (0 == iRollbackStatus)
330 continue; // operation did not complete, skip progress
331
332 // progress
333 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
334 ExitOnFailure(hr, "Failed to update progress");
335 }
336
337 hr = S_OK;
338
339LExit:
340 // clean up
341 FreePartitionUserAttributes(&attrs);
342
343 return hr;
344}
345
346
347// helper function definitions
348
349static HRESULT ReadPartitionAttributes(
350 LPWSTR* ppwzData,
351 CPI_PARTITION_ATTRIBUTES* pAttrs
352 )
353{
354 HRESULT hr = S_OK;
355
356 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
357 ExitOnFailure(hr, "Failed to read action type");
358 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
359 ExitOnFailure(hr, "Failed to read action cost");
360 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
361 ExitOnFailure(hr, "Failed to read key");
362 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID);
363 ExitOnFailure(hr, "Failed to read id");
364 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
365 ExitOnFailure(hr, "Failed to read name");
366 hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList);
367 ExitOnFailure(hr, "Failed to read properties");
368
369 hr = S_OK;
370
371LExit:
372 return hr;
373}
374
375static void FreePartitionAttributes(
376 CPI_PARTITION_ATTRIBUTES* pAttrs
377 )
378{
379 ReleaseStr(pAttrs->pwzKey);
380 ReleaseStr(pAttrs->pwzID);
381 ReleaseStr(pAttrs->pwzName);
382
383 if (pAttrs->pPropList)
384 CpiFreePropertyList(pAttrs->pPropList);
385}
386
387static HRESULT CreatePartition(
388 CPI_PARTITION_ATTRIBUTES* pAttrs
389 )
390{
391 HRESULT hr = S_OK;
392
393 ICatalogCollection* piPartColl = NULL;
394 ICatalogObject* piPartObj = NULL;
395
396 long lChanges = 0;
397
398 // log
399 WcaLog(LOGMSG_VERBOSE, "Creating partition, key: %S", pAttrs->pwzKey);
400
401 // get partitions collection
402 hr = CpiGetPartitionsCollection(&piPartColl);
403 ExitOnFailure(hr, "Failed to get partitions collection");
404
405 // check if partition exists
406 hr = CpiFindCollectionObjectByStringKey(piPartColl, pAttrs->pwzID, &piPartObj);
407 ExitOnFailure(hr, "Failed to find partition");
408
409 if (S_FALSE == hr)
410 {
411 // create partition
412 hr = CpiAddCollectionObject(piPartColl, &piPartObj);
413 ExitOnFailure(hr, "Failed to add partition to collection");
414
415 hr = CpiPutCollectionObjectValue(piPartObj, L"ID", pAttrs->pwzID);
416 ExitOnFailure(hr, "Failed to set partition id property");
417
418 hr = CpiPutCollectionObjectValue(piPartObj, L"Name", pAttrs->pwzName);
419 ExitOnFailure(hr, "Failed to set partition name property");
420 }
421
422 // properties
423 hr = CpiPutCollectionObjectValues(piPartObj, pAttrs->pPropList);
424 ExitOnFailure(hr, "Failed to write properties");
425
426 // save changes
427 hr = piPartColl->SaveChanges(&lChanges);
428 if (COMADMIN_E_OBJECTERRORS == hr)
429 CpiLogCatalogErrorInfo();
430 ExitOnFailure(hr, "Failed to save changes");
431
432 // log
433 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
434
435 hr = S_OK;
436
437LExit:
438 // clean up
439 ReleaseObject(piPartColl);
440 ReleaseObject(piPartObj);
441
442 return hr;
443}
444
445static HRESULT RemovePartition(
446 CPI_PARTITION_ATTRIBUTES* pAttrs
447 )
448{
449 HRESULT hr = S_OK;
450
451 ICatalogCollection* piPartColl = NULL;
452
453 long lChanges = 0;
454
455 // log
456 WcaLog(LOGMSG_VERBOSE, "Removing partition, key: %S", pAttrs->pwzKey);
457
458 // get partitions collection
459 hr = CpiGetPartitionsCollection(&piPartColl);
460 ExitOnFailure(hr, "Failed to get partitions collection");
461
462 // remove
463 hr = CpiRemoveCollectionObject(piPartColl, pAttrs->pwzID, NULL, TRUE);
464 ExitOnFailure(hr, "Failed to remove partition");
465
466 if (S_FALSE == hr)
467 {
468 // partition not found
469 WcaLog(LOGMSG_VERBOSE, "Partition not found, nothing to delete, key: %S", pAttrs->pwzKey);
470 ExitFunction1(hr = S_OK);
471 }
472
473 // save changes
474 hr = piPartColl->SaveChanges(&lChanges);
475 if (COMADMIN_E_OBJECTERRORS == hr)
476 CpiLogCatalogErrorInfo();
477 ExitOnFailure(hr, "Failed to save changes");
478
479 // log
480 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
481
482 hr = S_OK;
483
484LExit:
485 // clean up
486 ReleaseObject(piPartColl);
487
488 return hr;
489}
490
491static HRESULT ReadPartitionUserAttributes(
492 LPWSTR* ppwzData,
493 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
494 )
495{
496 HRESULT hr = S_OK;
497
498 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
499 ExitOnFailure(hr, "Failed to read action type");
500 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
501 ExitOnFailure(hr, "Failed to read action cost");
502 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
503 ExitOnFailure(hr, "Failed to read key");
504 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount);
505 ExitOnFailure(hr, "Failed to read account name");
506 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
507 ExitOnFailure(hr, "Failed to read partition id");
508
509 hr = S_OK;
510
511LExit:
512 return hr;
513}
514
515static void FreePartitionUserAttributes(
516 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
517 )
518{
519 ReleaseStr(pAttrs->pwzKey);
520 ReleaseStr(pAttrs->pwzAccount);
521 ReleaseStr(pAttrs->pwzPartID);
522}
523
524static HRESULT CreatePartitionUser(
525 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
526 )
527{
528 HRESULT hr = S_OK;
529 UINT er = ERROR_SUCCESS;
530
531 ICatalogCollection* piUserColl = NULL;
532 ICatalogObject* piUserObj = NULL;
533
534 PSID pSid = NULL;
535 long lChanges = 0;
536
537 // log
538 WcaLog(LOGMSG_VERBOSE, "Setting default partition for user, key: %S", pAttrs->pwzKey);
539
540 // get partition users collection
541 hr = CpiGetPartitionUsersCollection(&piUserColl);
542 ExitOnFailure(hr, "Failed to get partition users collection");
543
544 // get SID for account
545 do {
546 er = ERROR_SUCCESS;
547 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
548 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
549 {
550 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
551 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
552 switch (er)
553 {
554 case IDABORT:
555 ExitFunction(); // exit with error code from CpiAccountNameToSid()
556 case IDRETRY:
557 break;
558 case IDIGNORE:
559 default:
560 ExitFunction1(hr = S_OK);
561 }
562 }
563 else
564 ExitOnFailure(hr, "Failed to get SID for account");
565 } while (IDRETRY == er);
566
567 // remove any existing entry
568 hr = CpiRemoveUserCollectionObject(piUserColl, pSid);
569 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
570 {
571 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
572 hr = S_FALSE;
573 }
574 else
575 ExitOnFailure(hr, "Failed to remove user");
576
577 if (S_OK == hr)
578 WcaLog(LOGMSG_VERBOSE, "Existing default partition for user was removed, key: %S", pAttrs->pwzKey);
579
580 // add partition user
581 hr = CpiAddCollectionObject(piUserColl, &piUserObj);
582 ExitOnFailure(hr, "Failed to add partition to collection");
583
584 hr = CpiPutCollectionObjectValue(piUserObj, L"AccountName", pAttrs->pwzAccount);
585 ExitOnFailure(hr, "Failed to set account name property");
586
587 hr = CpiPutCollectionObjectValue(piUserObj, L"DefaultPartitionID", pAttrs->pwzPartID);
588 ExitOnFailure(hr, "Failed to set default partition id property");
589
590 // save changes
591 hr = piUserColl->SaveChanges(&lChanges);
592 if (COMADMIN_E_OBJECTERRORS == hr)
593 CpiLogCatalogErrorInfo();
594 ExitOnFailure(hr, "Failed to save changes");
595
596 // log
597 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
598
599 hr = S_OK;
600
601LExit:
602 // clean up
603 ReleaseObject(piUserColl);
604 ReleaseObject(piUserObj);
605
606 if (pSid)
607 ::HeapFree(::GetProcessHeap(), 0, pSid);
608
609 return hr;
610}
611
612static HRESULT RemovePartitionUser(
613 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
614 )
615{
616 HRESULT hr = S_OK;
617 UINT er = ERROR_SUCCESS;
618
619 ICatalogCollection* piUserColl = NULL;
620
621 PSID pSid = NULL;
622 long lChanges = 0;
623
624 // log
625 WcaLog(LOGMSG_VERBOSE, "Removing default partition for user, key: %S", pAttrs->pwzKey);
626
627 // get partition users collection
628 hr = CpiGetPartitionUsersCollection(&piUserColl);
629 ExitOnFailure(hr, "Failed to get partition users collection");
630
631 // get SID for account
632 do {
633 er = ERROR_SUCCESS;
634 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
635 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
636 {
637 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
638 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
639 switch (er)
640 {
641 case IDABORT:
642 ExitFunction(); // exit with error code from CpiAccountNameToSid()
643 case IDRETRY:
644 break;
645 case IDIGNORE:
646 default:
647 ExitFunction1(hr = S_OK);
648 }
649 }
650 else
651 ExitOnFailure(hr, "Failed to get SID for account");
652 } while (IDRETRY == er);
653
654 // remove
655 hr = CpiRemoveUserCollectionObject(piUserColl, pSid);
656 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
657 {
658 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
659 hr = S_FALSE;
660 }
661 else
662 ExitOnFailure(hr, "Failed to remove user");
663
664 if (S_FALSE == hr)
665 {
666 // user not found
667 WcaLog(LOGMSG_VERBOSE, "Default partition for user not found, nothing to delete, key: %S", pAttrs->pwzKey);
668 ExitFunction1(hr = S_OK);
669 }
670
671 // save changes
672 hr = piUserColl->SaveChanges(&lChanges);
673 if (COMADMIN_E_OBJECTERRORS == hr)
674 CpiLogCatalogErrorInfo();
675 ExitOnFailure(hr, "Failed to save changes");
676
677 // log
678 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
679
680 hr = S_OK;
681
682LExit:
683 // clean up
684 ReleaseObject(piUserColl);
685
686 if (pSid)
687 ::HeapFree(::GetProcessHeap(), 0, pSid);
688
689 return hr;
690}
diff --git a/src/ca/cppartexec.h b/src/ca/cppartexec.h
new file mode 100644
index 00000000..132a9f5a
--- /dev/null
+++ b/src/ca/cppartexec.h
@@ -0,0 +1,20 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigurePartitions(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigurePartitions(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
13HRESULT CpiConfigurePartitionUsers(
14 LPWSTR* ppwzData,
15 HANDLE hRollbackFile
16 );
17HRESULT CpiRollbackConfigurePartitionUsers(
18 LPWSTR* ppwzData,
19 CPI_ROLLBACK_DATA* pRollbackDataList
20 );
diff --git a/src/ca/cppartroleexec.cpp b/src/ca/cppartroleexec.cpp
new file mode 100644
index 00000000..4a503c79
--- /dev/null
+++ b/src/ca/cppartroleexec.cpp
@@ -0,0 +1,397 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzRoleName;
14 LPWSTR pwzAccount;
15 LPWSTR pwzPartID;
16};
17
18
19// prototypes for private helper functions
20
21static HRESULT ReadUserInPartitionRoleAttributes(
22 LPWSTR* ppwzData,
23 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
24 );
25static void FreeUserInPartitionRoleAttributes(
26 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
27 );
28static HRESULT CreateUserInPartitionRole(
29 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
30 );
31static HRESULT RemoveUserInPartitionRole(
32 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
33 );
34
35
36// function definitions
37
38HRESULT CpiConfigureUsersInPartitionRoles(
39 LPWSTR* ppwzData,
40 HANDLE hRollbackFile
41 )
42{
43 HRESULT hr = S_OK;
44
45 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES attrs;
46 ::ZeroMemory(&attrs, sizeof(attrs));
47
48 // read action text
49 hr = CpiActionStartMessage(ppwzData, FALSE);
50 ExitOnFailure(hr, "Failed to send action start message");
51
52 // ger count
53 int iCnt = 0;
54 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
55 ExitOnFailure(hr, "Failed to read count");
56
57 // write count to rollback file
58 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
59 ExitOnFailure(hr, "Failed to write count to rollback file");
60
61 for (int i = 0; i < iCnt; i++)
62 {
63 // read attributes from CustomActionData
64 hr = ReadUserInPartitionRoleAttributes(ppwzData, &attrs);
65 ExitOnFailure(hr, "Failed to read attributes");
66
67 // progress message
68 hr = CpiActionDataMessage(1, attrs.pwzRoleName);
69 ExitOnFailure(hr, "Failed to send progress messages");
70
71 if (S_FALSE == hr)
72 ExitFunction();
73
74 // write key to rollback file
75 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
76 ExitOnFailure(hr, "Failed to write key to rollback file");
77
78 // action
79 switch (attrs.iActionType)
80 {
81 case atCreate:
82 hr = CreateUserInPartitionRole(&attrs);
83 ExitOnFailure(hr, "Failed to add user to partition role, key: %S", attrs.pwzKey);
84 break;
85 case atRemove:
86 hr = RemoveUserInPartitionRole(&attrs);
87 ExitOnFailure(hr, "Failed to remove user from partition role, key: %S", attrs.pwzKey);
88 break;
89 }
90
91 // write completion status to rollback file
92 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
93 ExitOnFailure(hr, "Failed to write completion status to rollback file");
94
95 // progress
96 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
97 ExitOnFailure(hr, "Failed to update progress");
98 }
99
100 hr = S_OK;
101
102LExit:
103 // clean up
104 FreeUserInPartitionRoleAttributes(&attrs);
105
106 return hr;
107}
108
109HRESULT CpiRollbackConfigureUsersInPartitionRoles(
110 LPWSTR* ppwzData,
111 CPI_ROLLBACK_DATA* pRollbackDataList
112 )
113{
114 HRESULT hr = S_OK;
115
116 int iRollbackStatus;
117
118 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES attrs;
119 ::ZeroMemory(&attrs, sizeof(attrs));
120
121 // read action text
122 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
123 ExitOnFailure(hr, "Failed to send action start message");
124
125 // get count
126 int iCnt = 0;
127 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
128 ExitOnFailure(hr, "Failed to read count");
129
130 for (int i = 0; i < iCnt; i++)
131 {
132 // read attributes from CustomActionData
133 hr = ReadUserInPartitionRoleAttributes(ppwzData, &attrs);
134 ExitOnFailure(hr, "Failed to read attributes");
135
136 // rollback status
137 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
138
139 if (S_FALSE == hr)
140 continue; // not found, nothing to rollback
141
142 // progress message
143 hr = CpiActionDataMessage(1, attrs.pwzRoleName);
144 ExitOnFailure(hr, "Failed to send progress messages");
145
146 if (S_FALSE == hr)
147 ExitFunction();
148
149 // action
150 switch (attrs.iActionType)
151 {
152 case atCreate:
153 hr = CreateUserInPartitionRole(&attrs);
154 if (FAILED(hr))
155 WcaLog(LOGMSG_STANDARD, "Failed to add user to partition role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
156 break;
157 case atRemove:
158 hr = RemoveUserInPartitionRole(&attrs);
159 if (FAILED(hr))
160 WcaLog(LOGMSG_STANDARD, "Failed to remove user from partition role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
161 break;
162 }
163
164 // check rollback status
165 if (0 == iRollbackStatus)
166 continue; // operation did not complete, skip progress
167
168 // progress
169 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
170 ExitOnFailure(hr, "Failed to update progress");
171 }
172
173 hr = S_OK;
174
175LExit:
176 // clean up
177 FreeUserInPartitionRoleAttributes(&attrs);
178
179 return hr;
180}
181
182
183// helper function definitions
184
185static HRESULT ReadUserInPartitionRoleAttributes(
186 LPWSTR* ppwzData,
187 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
188 )
189{
190 HRESULT hr = S_OK;
191
192 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
193 ExitOnFailure(hr, "Failed to read action type");
194 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
195 ExitOnFailure(hr, "Failed to read action cost");
196 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
197 ExitOnFailure(hr, "Failed to read key");
198 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzRoleName);
199 ExitOnFailure(hr, "Failed to read role name");
200 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount);
201 ExitOnFailure(hr, "Failed to read account name");
202 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
203 ExitOnFailure(hr, "Failed to read partition id");
204
205 hr = S_OK;
206
207LExit:
208 return hr;
209}
210
211static void FreeUserInPartitionRoleAttributes(
212 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
213 )
214{
215 ReleaseStr(pAttrs->pwzKey);
216 ReleaseStr(pAttrs->pwzRoleName);
217 ReleaseStr(pAttrs->pwzAccount);
218 ReleaseStr(pAttrs->pwzPartID);
219}
220
221static HRESULT CreateUserInPartitionRole(
222 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
223 )
224{
225 HRESULT hr = S_OK;
226 UINT er = ERROR_SUCCESS;
227
228 ICatalogCollection* piUsrInRoleColl = NULL;
229 ICatalogObject* piUsrInRoleObj = NULL;
230
231 PSID pSid = NULL;
232 long lChanges = 0;
233
234 // log
235 WcaLog(LOGMSG_VERBOSE, "Adding user to partition role, key: %S", pAttrs->pwzKey);
236
237 // get users in partition role collection
238 hr = CpiGetUsersInPartitionRoleCollection(pAttrs->pwzPartID, pAttrs->pwzRoleName, &piUsrInRoleColl);
239 if (S_FALSE == hr)
240 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
241 ExitOnFailure(hr, "Failed to get users in partition role collection");
242
243 // get SID for account
244 do {
245 er = ERROR_SUCCESS;
246 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
247 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
248 {
249 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
250 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
251 switch (er)
252 {
253 case IDABORT:
254 ExitFunction(); // exit with error code from CpiAccountNameToSid()
255 case IDRETRY:
256 break;
257 case IDIGNORE:
258 default:
259 ExitFunction1(hr = S_OK);
260 }
261 }
262 else
263 ExitOnFailure(hr, "Failed to get SID for account");
264 } while (IDRETRY == er);
265
266 // find any existing entry
267 hr = CpiFindUserCollectionObject(piUsrInRoleColl, pSid, NULL);
268 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
269 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
270 else
271 ExitOnFailure(hr, "Failed to find user in partition role");
272
273 if (S_OK == hr)
274 {
275 WcaLog(LOGMSG_VERBOSE, "User already assigned to partition role, key: %S", pAttrs->pwzKey);
276 ExitFunction(); // exit with hr = S_OK
277 }
278
279 // convert SID back to account name
280 hr = CpiSidToAccountName(pSid, &pAttrs->pwzAccount);
281 ExitOnFailure(hr, "Failed to convert SID to account name");
282
283 // add user
284 hr = CpiAddCollectionObject(piUsrInRoleColl, &piUsrInRoleObj);
285 ExitOnFailure(hr, "Failed to add user in role to collection");
286
287 hr = CpiPutCollectionObjectValue(piUsrInRoleObj, L"User", pAttrs->pwzAccount);
288 ExitOnFailure(hr, "Failed to set role name property");
289
290 // save changes
291 hr = piUsrInRoleColl->SaveChanges(&lChanges);
292 if (COMADMIN_E_OBJECTERRORS == hr)
293 CpiLogCatalogErrorInfo();
294 ExitOnFailure(hr, "Failed to save changes");
295
296 // log
297 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
298
299 hr = S_OK;
300
301LExit:
302 // clean up
303 ReleaseObject(piUsrInRoleColl);
304 ReleaseObject(piUsrInRoleObj);
305
306 if (pSid)
307 ::HeapFree(::GetProcessHeap(), 0, pSid);
308
309 return hr;
310}
311
312static HRESULT RemoveUserInPartitionRole(
313 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
314 )
315{
316 HRESULT hr = S_OK;
317 UINT er = ERROR_SUCCESS;
318
319 ICatalogCollection* piUsrInRoleColl = NULL;
320
321 PSID pSid = NULL;
322 long lChanges = 0;
323
324 // log
325 WcaLog(LOGMSG_VERBOSE, "Removing user from partition role, key: %S", pAttrs->pwzKey);
326
327 // get users in partition role collection
328 hr = CpiGetUsersInPartitionRoleCollection(pAttrs->pwzPartID, pAttrs->pwzRoleName, &piUsrInRoleColl);
329 ExitOnFailure(hr, "Failed to get users in partition role collection");
330
331 if (S_FALSE == hr)
332 {
333 // users in role collection not found
334 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve users in partition role collection, nothing to delete, key: %S", pAttrs->pwzKey);
335 ExitFunction1(hr = S_OK);
336 }
337
338 // get SID for account
339 do {
340 er = ERROR_SUCCESS;
341 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
342 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
343 {
344 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
345 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
346 switch (er)
347 {
348 case IDABORT:
349 ExitFunction(); // exit with error code from CpiAccountNameToSid()
350 case IDRETRY:
351 break;
352 case IDIGNORE:
353 default:
354 ExitFunction1(hr = S_OK);
355 }
356 }
357 else
358 ExitOnFailure(hr, "Failed to get SID for account");
359 } while (IDRETRY == er);
360
361 // remove
362 hr = CpiRemoveUserCollectionObject(piUsrInRoleColl, pSid);
363 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
364 {
365 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
366 hr = S_FALSE;
367 }
368 else
369 ExitOnFailure(hr, "Failed to remove user");
370
371 if (S_FALSE == hr)
372 {
373 // role not found
374 WcaLog(LOGMSG_VERBOSE, "User not found for partition role, nothing to delete, key: %S", pAttrs->pwzKey);
375 ExitFunction1(hr = S_OK);
376 }
377
378 // save changes
379 hr = piUsrInRoleColl->SaveChanges(&lChanges);
380 if (COMADMIN_E_OBJECTERRORS == hr)
381 CpiLogCatalogErrorInfo();
382 ExitOnFailure(hr, "Failed to save changes");
383
384 // log
385 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
386
387 hr = S_OK;
388
389LExit:
390 // clean up
391 ReleaseObject(piUsrInRoleColl);
392
393 if (pSid)
394 ::HeapFree(::GetProcessHeap(), 0, pSid);
395
396 return hr;
397}
diff --git a/src/ca/cppartroleexec.h b/src/ca/cppartroleexec.h
new file mode 100644
index 00000000..0ec47dad
--- /dev/null
+++ b/src/ca/cppartroleexec.h
@@ -0,0 +1,12 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureUsersInPartitionRoles(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureUsersInPartitionRoles(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
diff --git a/src/ca/cppartrolesched.cpp b/src/ca/cppartrolesched.cpp
new file mode 100644
index 00000000..a988f8e3
--- /dev/null
+++ b/src/ca/cppartrolesched.cpp
@@ -0,0 +1,421 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsPartitionRoleQuery =
9 L"SELECT `PartitionRole`, `Partition_`, `Component_`, `Name` FROM `ComPlusPartitionRole`";
10enum ePartitionRoleQuery { prqPartitionRole = 1, prqPartition, prqComponent, prqName };
11
12LPCWSTR vcsUserInPartitionRoleQuery =
13 L"SELECT `UserInPartitionRole`, `PartitionRole_`, `ComPlusUserInPartitionRole`.`Component_`, `Domain`, `Name` FROM `ComPlusUserInPartitionRole`, `User` WHERE `User_` = `User`";
14LPCWSTR vcsGroupInPartitionRoleQuery =
15 L"SELECT `GroupInPartitionRole`, `PartitionRole_`, `ComPlusGroupInPartitionRole`.`Component_`, `Domain`, `Name` FROM `ComPlusGroupInPartitionRole`, `Group` WHERE `Group_` = `Group`";
16enum eTrusteeInPartitionRoleQuery { tiprqUserInPartitionRole = 1, tiprqPartitionRole, tiprqComponent, tiprqDomain, tiprqName };
17
18
19// prototypes for private helper functions
20
21static HRESULT TrusteesInPartitionRolesRead(
22 LPCWSTR pwzQuery,
23 CPI_PARTITION_ROLE_LIST* pPartRoleList,
24 CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList
25 );
26static void FreePartitionRole(
27 CPI_PARTITION_ROLE* pItm
28 );
29static void FreeUserInPartitionRole(
30 CPI_USER_IN_PARTITION_ROLE* pItm
31 );
32static HRESULT AddUserInPartitionRoleToActionData(
33 CPI_USER_IN_PARTITION_ROLE* pItm,
34 int iActionType,
35 int iActionCost,
36 LPWSTR* ppwzActionData
37 );
38
39
40// function definitions
41
42void CpiPartitionRoleListFree(
43 CPI_PARTITION_ROLE_LIST* pList
44 )
45{
46 CPI_PARTITION_ROLE* pItm = pList->pFirst;
47
48 while (pItm)
49 {
50 CPI_PARTITION_ROLE* pDelete = pItm;
51 pItm = pItm->pNext;
52 FreePartitionRole(pDelete);
53 }
54}
55
56HRESULT CpiPartitionRolesRead(
57 CPI_PARTITION_LIST* pPartList,
58 CPI_PARTITION_ROLE_LIST* pPartRoleList
59 )
60{
61 HRESULT hr = S_OK;
62 PMSIHANDLE hView, hRec;
63 CPI_PARTITION_ROLE* pItm = NULL;
64 LPWSTR pwzData = NULL;
65
66 // loop through all application roles
67 hr = WcaOpenExecuteView(vcsPartitionRoleQuery, &hView);
68 ExitOnFailure(hr, "Failed to execute view on ComPlusPartitionRole table");
69
70 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
71 {
72 // create entry
73 pItm = (CPI_PARTITION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION_ROLE));
74 if (!pItm)
75 ExitFunction1(hr = E_OUTOFMEMORY);
76
77 // get key
78 hr = WcaGetRecordString(hRec, prqPartitionRole, &pwzData);
79 ExitOnFailure(hr, "Failed to get key");
80 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
81
82 // get partition
83 hr = WcaGetRecordString(hRec, prqPartition, &pwzData);
84 ExitOnFailure(hr, "Failed to get application");
85
86 hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition);
87 if (S_FALSE == hr)
88 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
89 ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData);
90
91 // get name
92 hr = WcaGetRecordFormattedString(hRec, prqName, &pwzData);
93 ExitOnFailure(hr, "Failed to get name");
94 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
95
96 // add entry
97 if (pPartRoleList->pFirst)
98 pItm->pNext = pPartRoleList->pFirst;
99 pPartRoleList->pFirst = pItm;
100 pItm = NULL;
101 }
102
103 if (E_NOMOREITEMS == hr)
104 hr = S_OK;
105
106LExit:
107 // clean up
108 if (pItm)
109 FreePartitionRole(pItm);
110
111 ReleaseStr(pwzData);
112
113 return hr;
114}
115
116HRESULT CpiPartitionRoleFindByKey(
117 CPI_PARTITION_ROLE_LIST* pList,
118 LPCWSTR pwzKey,
119 CPI_PARTITION_ROLE** ppPartRole
120 )
121{
122 for (CPI_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
123 {
124 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
125 {
126 *ppPartRole = pItm;
127 return S_OK;
128 }
129 }
130
131 return E_FAIL;
132}
133
134void CpiUserInPartitionRoleListFree(
135 CPI_USER_IN_PARTITION_ROLE_LIST* pList
136 )
137{
138 CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst;
139
140 while (pItm)
141 {
142 CPI_USER_IN_PARTITION_ROLE* pDelete = pItm;
143 pItm = pItm->pNext;
144 FreeUserInPartitionRole(pDelete);
145 }
146}
147
148HRESULT CpiUsersInPartitionRolesRead(
149 CPI_PARTITION_ROLE_LIST* pPartRoleList,
150 CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList
151 )
152{
153 HRESULT hr = S_OK;
154
155 // read users in partition roles
156 if (CpiTableExists(cptComPlusUserInPartitionRole))
157 {
158 hr = TrusteesInPartitionRolesRead(vcsUserInPartitionRoleQuery, pPartRoleList, pUsrInPartRoleList);
159 ExitOnFailure(hr, "Failed to read users in partition roles");
160 }
161
162 // read groups in partition roles
163 if (CpiTableExists(cptComPlusGroupInPartitionRole))
164 {
165 hr = TrusteesInPartitionRolesRead(vcsGroupInPartitionRoleQuery, pPartRoleList, pUsrInPartRoleList);
166 ExitOnFailure(hr, "Failed to read groups in partition roles");
167 }
168
169 hr = S_OK;
170
171LExit:
172 return hr;
173}
174
175HRESULT CpiUsersInPartitionRolesInstall(
176 CPI_USER_IN_PARTITION_ROLE_LIST* pList,
177 int iRunMode,
178 LPWSTR* ppwzActionData,
179 int* piProgress
180 )
181{
182 HRESULT hr = S_OK;
183
184 int iActionType;
185
186 // add action text
187 hr = CpiAddActionTextToActionData(L"AddUsersToComPlusPartitionRoles", ppwzActionData);
188 ExitOnFailure(hr, "Failed to add action text to custom action data");
189
190 // add count to action data
191 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
192 ExitOnFailure(hr, "Failed to add count to custom action data");
193
194 // add roles to custom action data
195 for (CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
196 {
197 // roles that are being installed only
198 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
199 continue;
200
201 // action type
202 if (rmRollback == iRunMode)
203 {
204 if (CpiIsInstalled(pItm->isInstalled))
205 iActionType = atNoOp;
206 else
207 iActionType = atRemove;
208 }
209 else
210 iActionType = atCreate;
211
212 // add to action data
213 hr = AddUserInPartitionRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_CREATE, ppwzActionData);
214 ExitOnFailure(hr, "Failed to add user in partition role to custom action data, key: %S", pItm->wzKey);
215 }
216
217 // add progress tics
218 if (piProgress)
219 *piProgress += COST_USER_IN_APPLICATION_ROLE_CREATE * pList->iInstallCount;
220
221 hr = S_OK;
222
223LExit:
224 return hr;
225}
226
227HRESULT CpiUsersInPartitionRolesUninstall(
228 CPI_USER_IN_PARTITION_ROLE_LIST* pList,
229 int iRunMode,
230 LPWSTR* ppwzActionData,
231 int* piProgress
232 )
233{
234 HRESULT hr = S_OK;
235
236 int iActionType;
237
238 // add action text
239 hr = CpiAddActionTextToActionData(L"RemoveUsersFromComPlusPartRoles", ppwzActionData);
240 ExitOnFailure(hr, "Failed to add action text to custom action data");
241
242 // add count to action data
243 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
244 ExitOnFailure(hr, "Failed to add count to custom action data");
245
246 // add roles to custom action data
247 for (CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
248 {
249 // roles that are being uninstalled only
250 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
251 continue;
252
253 // action type
254 if (rmRollback == iRunMode)
255 iActionType = atCreate;
256 else
257 iActionType = atRemove;
258
259 // add to action data
260 hr = AddUserInPartitionRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_DELETE, ppwzActionData);
261 ExitOnFailure(hr, "Failed to add user in partition role to custom action data, key: %S", pItm->wzKey);
262 }
263
264 // add progress tics
265 if (piProgress)
266 *piProgress += COST_USER_IN_APPLICATION_ROLE_DELETE * pList->iUninstallCount;
267
268 hr = S_OK;
269
270LExit:
271 return hr;
272}
273
274
275// helper function definitions
276
277static HRESULT TrusteesInPartitionRolesRead(
278 LPCWSTR pwzQuery,
279 CPI_PARTITION_ROLE_LIST* pPartRoleList,
280 CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList
281 )
282{
283 HRESULT hr = S_OK;
284 UINT er = ERROR_SUCCESS;
285
286 PMSIHANDLE hView, hRec;
287
288 CPI_USER_IN_PARTITION_ROLE* pItm = NULL;
289 LPWSTR pwzData = NULL;
290 LPWSTR pwzDomain = NULL;
291 LPWSTR pwzName = NULL;
292 BOOL fMatchingArchitecture = FALSE;
293
294 // loop through all application roles
295 hr = WcaOpenExecuteView(pwzQuery, &hView);
296 ExitOnFailure(hr, "Failed to execute view on table");
297
298 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
299 {
300 // get component
301 hr = WcaGetRecordString(hRec, tiprqComponent, &pwzData);
302 ExitOnFailure(hr, "Failed to get component");
303
304 // check if the component is our processor architecture
305 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
306 ExitOnFailure(hr, "Failed to get component architecture.");
307
308 if (!fMatchingArchitecture)
309 {
310 continue; // not the same architecture, ignore
311 }
312
313 // create entry
314 pItm = (CPI_USER_IN_PARTITION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_USER_IN_PARTITION_ROLE));
315 if (!pItm)
316 ExitFunction1(hr = E_OUTOFMEMORY);
317
318 // get component install state
319 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
320 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
321
322 // get key
323 hr = WcaGetRecordString(hRec, tiprqUserInPartitionRole, &pwzData);
324 ExitOnFailure(hr, "Failed to get key");
325 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
326
327 // get partition role
328 hr = WcaGetRecordString(hRec, tiprqPartitionRole, &pwzData);
329 ExitOnFailure(hr, "Failed to get partition role");
330
331 hr = CpiPartitionRoleFindByKey(pPartRoleList, pwzData, &pItm->pPartitionRole);
332 ExitOnFailure(hr, "Failed to find partition role, key: %S", pwzData);
333
334 // get user domain
335 hr = WcaGetRecordFormattedString(hRec, tiprqDomain, &pwzDomain);
336 ExitOnFailure(hr, "Failed to get domain");
337
338 // get user name
339 hr = WcaGetRecordFormattedString(hRec, tiprqName, &pwzName);
340 ExitOnFailure(hr, "Failed to get name");
341
342 // build account name
343 hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount);
344 ExitOnFailure(hr, "Failed to build account name");
345
346 // increment counters
347 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
348 pUsrInPartRoleList->iInstallCount++;
349 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
350 pUsrInPartRoleList->iUninstallCount++;
351
352 // add entry
353 if (pUsrInPartRoleList->pFirst)
354 pItm->pNext = pUsrInPartRoleList->pFirst;
355 pUsrInPartRoleList->pFirst = pItm;
356 pItm = NULL;
357 }
358
359 if (E_NOMOREITEMS == hr)
360 hr = S_OK;
361
362LExit:
363 // clean up
364 if (pItm)
365 FreeUserInPartitionRole(pItm);
366
367 ReleaseStr(pwzData);
368 ReleaseStr(pwzDomain);
369 ReleaseStr(pwzName);
370
371 return hr;
372}
373
374static void FreePartitionRole(
375 CPI_PARTITION_ROLE* pItm
376 )
377{
378 ::HeapFree(::GetProcessHeap(), 0, pItm);
379}
380
381static void FreeUserInPartitionRole(
382 CPI_USER_IN_PARTITION_ROLE* pItm
383 )
384{
385 ReleaseStr(pItm->pwzAccount);
386
387 ::HeapFree(::GetProcessHeap(), 0, pItm);
388}
389
390static HRESULT AddUserInPartitionRoleToActionData(
391 CPI_USER_IN_PARTITION_ROLE* pItm,
392 int iActionType,
393 int iActionCost,
394 LPWSTR* ppwzActionData
395 )
396{
397 HRESULT hr = S_OK;
398
399 // add action information to custom action data
400 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
401 ExitOnFailure(hr, "Failed to add action type to custom action data");
402 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
403 ExitOnFailure(hr, "Failed to add action cost to custom action data");
404
405 // add application role information to custom action data
406 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
407 ExitOnFailure(hr, "Failed to add key to custom action data");
408 hr = WcaWriteStringToCaData(pItm->pPartitionRole->wzName, ppwzActionData);
409 ExitOnFailure(hr, "Failed to add role name to custom action data");
410 hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData);
411 ExitOnFailure(hr, "Failed to add user account to custom action data");
412
413 // add partition information to custom action data
414 hr = WcaWriteStringToCaData(pItm->pPartitionRole->pPartition->wzID, ppwzActionData);
415 ExitOnFailure(hr, "Failed to add partition id to custom action data");
416
417 hr = S_OK;
418
419LExit:
420 return hr;
421}
diff --git a/src/ca/cppartrolesched.h b/src/ca/cppartrolesched.h
new file mode 100644
index 00000000..ff1275d9
--- /dev/null
+++ b/src/ca/cppartrolesched.h
@@ -0,0 +1,76 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_PARTITION_ROLE
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
9
10 CPI_PARTITION* pPartition;
11
12 ICatalogCollection* piUsersColl;
13
14 CPI_PARTITION_ROLE* pNext;
15};
16
17struct CPI_PARTITION_ROLE_LIST
18{
19 CPI_PARTITION_ROLE* pFirst;
20};
21
22struct CPI_USER_IN_PARTITION_ROLE
23{
24 WCHAR wzKey[MAX_DARWIN_KEY + 1];
25 LPWSTR pwzAccount;
26
27 INSTALLSTATE isInstalled, isAction;
28
29 CPI_PARTITION_ROLE* pPartitionRole;
30
31 CPI_USER_IN_PARTITION_ROLE* pNext;
32};
33
34struct CPI_USER_IN_PARTITION_ROLE_LIST
35{
36 CPI_USER_IN_PARTITION_ROLE* pFirst;
37
38 int iInstallCount;
39 int iUninstallCount;
40};
41
42
43// function prototypes
44
45void CpiPartitionRoleListFree(
46 CPI_PARTITION_ROLE_LIST* pList
47 );
48HRESULT CpiPartitionRolesRead(
49 CPI_PARTITION_LIST* pPartList,
50 CPI_PARTITION_ROLE_LIST* pPartRoleList
51 );
52HRESULT CpiPartitionRoleFindByKey(
53 CPI_PARTITION_ROLE_LIST* pList,
54 LPCWSTR pwzKey,
55 CPI_PARTITION_ROLE** ppPartRole
56 );
57
58void CpiUserInPartitionRoleListFree(
59 CPI_USER_IN_PARTITION_ROLE_LIST* pList
60 );
61HRESULT CpiUsersInPartitionRolesRead(
62 CPI_PARTITION_ROLE_LIST* pPartRoleList,
63 CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList
64 );
65HRESULT CpiUsersInPartitionRolesInstall(
66 CPI_USER_IN_PARTITION_ROLE_LIST* pList,
67 int iRunMode,
68 LPWSTR* ppwzActionData,
69 int* piProgress
70 );
71HRESULT CpiUsersInPartitionRolesUninstall(
72 CPI_USER_IN_PARTITION_ROLE_LIST* pList,
73 int iRunMode,
74 LPWSTR* ppwzActionData,
75 int* piProgress
76 );
diff --git a/src/ca/cppartsched.cpp b/src/ca/cppartsched.cpp
new file mode 100644
index 00000000..6643a50b
--- /dev/null
+++ b/src/ca/cppartsched.cpp
@@ -0,0 +1,912 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsPartitionQuery =
9 L"SELECT `Partition`, `Component_`, `Id`, `Name` FROM `ComPlusPartition`";
10enum ePartitionQuery { pqPartition = 1, pqComponent, pqID, pqName };
11
12LPCWSTR vcsPartitionPropertyQuery =
13 L"SELECT `Name`, `Value` FROM `ComPlusPartitionProperty` WHERE `Partition_` = ?";
14
15LPCWSTR vcsPartitionUserQuery =
16 L"SELECT `PartitionUser`, `Partition_`, `ComPlusPartitionUser`.`Component_`, `Domain`, `Name` FROM `ComPlusPartitionUser`, `User` WHERE `User_` = `User`";
17enum ePartitionUserQuery { puqPartitionUser = 1, puqPartition, puqComponent, puqDomain, puqName };
18
19
20// property definitions
21
22CPI_PROPERTY_DEFINITION pdlPartitionProperties[] =
23{
24 {L"Changeable", cpptBoolean, 502},
25 {L"Deleteable", cpptBoolean, 502},
26 {L"Description", cpptString, 502},
27 {NULL, cpptNone, 0}
28};
29
30
31// prototypes for private helper functions
32
33static void FreePartition(
34 CPI_PARTITION* pItm
35 );
36static void FreePartitionUser(
37 CPI_PARTITION_USER* pItm
38 );
39static HRESULT AddPartitionToActionData(
40 CPI_PARTITION* pItm,
41 int iActionType,
42 int iActionCost,
43 LPWSTR* ppwzActionData
44 );
45static HRESULT AddPartitionUserToActionData(
46 CPI_PARTITION_USER* pItm,
47 int iActionType,
48 int iActionCost,
49 LPWSTR* ppwzActionData
50 );
51
52
53// function definitions
54
55void CpiPartitionListFree(
56 CPI_PARTITION_LIST* pList
57 )
58{
59 CPI_PARTITION* pItm = pList->pFirst;
60
61 while (pItm)
62 {
63 CPI_PARTITION* pDelete = pItm;
64 pItm = pItm->pNext;
65 FreePartition(pDelete);
66 }
67}
68
69HRESULT CpiPartitionsRead(
70 CPI_PARTITION_LIST* pPartList
71 )
72{
73 HRESULT hr = S_OK;
74 UINT er = ERROR_SUCCESS;
75
76 PMSIHANDLE hView, hRec;
77
78 CPI_PARTITION* pItm = NULL;
79 LPWSTR pwzData = NULL;
80 BOOL fMatchingArchitecture = FALSE;
81
82 // loop through all partitions
83 hr = WcaOpenExecuteView(vcsPartitionQuery, &hView);
84 ExitOnFailure(hr, "Failed to execute view on ComPlusPartition table");
85
86 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
87 {
88 // get component
89 hr = WcaGetRecordString(hRec, pqComponent, &pwzData);
90 ExitOnFailure(hr, "Failed to get component");
91
92 // check if the component is our processor architecture
93 if (pwzData && *pwzData)
94 {
95 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
96 ExitOnFailure(hr, "Failed to get component architecture.");
97
98 if (!fMatchingArchitecture)
99 {
100 continue; // not the same architecture, ignore
101 }
102 }
103
104 // create entry
105 pItm = (CPI_PARTITION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION));
106 if (!pItm)
107 ExitFunction1(hr = E_OUTOFMEMORY);
108
109 // get component install state
110 if (pwzData && *pwzData)
111 {
112 pItm->fHasComponent = TRUE;
113
114 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
115 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
116 }
117
118 // get key
119 hr = WcaGetRecordString(hRec, pqPartition, &pwzData);
120 ExitOnFailure(hr, "Failed to get key");
121 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
122
123 // get id
124 hr = WcaGetRecordFormattedString(hRec, pqID, &pwzData);
125 ExitOnFailure(hr, "Failed to get id");
126
127 if (pwzData && *pwzData)
128 {
129 hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID));
130 ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData);
131 }
132
133 // get name
134 hr = WcaGetRecordFormattedString(hRec, pqName, &pwzData);
135 ExitOnFailure(hr, "Failed to get name");
136 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
137
138 // if partition is a locater, either an id or a name must be provided
139 if (!pItm->fHasComponent && !*pItm->wzID && !*pItm->wzName)
140 ExitOnFailure(hr = E_FAIL, "A partition locater must have either an id or a name associated, key: %S", pItm->wzKey);
141
142 // if partition is not a locater, an name must be provided
143 if (pItm->fHasComponent && !*pItm->wzName)
144 ExitOnFailure(hr = E_FAIL, "A partition must have a name associated, key: %S", pItm->wzKey);
145
146 // get properties
147 if (CpiTableExists(cptComPlusPartitionProperty) && pItm->fHasComponent)
148 {
149 hr = CpiPropertiesRead(vcsPartitionPropertyQuery, pItm->wzKey, pdlPartitionProperties, &pItm->pProperties, &pItm->iPropertyCount);
150 ExitOnFailure(hr, "Failed to get properties");
151 }
152
153 // increment counters
154 if (pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))
155 pPartList->iInstallCount++;
156 if (pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
157 pPartList->iUninstallCount++;
158
159 // add entry
160 if (pPartList->pFirst)
161 pItm->pNext = pPartList->pFirst;
162 pPartList->pFirst = pItm;
163 pItm = NULL;
164 }
165
166 if (E_NOMOREITEMS == hr)
167 hr = S_OK;
168
169LExit:
170 // clean up
171 if (pItm)
172 FreePartition(pItm);
173
174 ReleaseStr(pwzData);
175
176 return hr;
177}
178
179HRESULT CpiPartitionsVerifyInstall(
180 CPI_PARTITION_LIST* pList
181 )
182{
183 HRESULT hr = S_OK;
184 UINT er = ERROR_SUCCESS;
185
186 ICatalogCollection* piPartColl = NULL;
187 ICatalogObject* piPartObj = NULL;
188
189 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
190 {
191 // referenced locaters or partitions that are being installed
192 if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)))
193 continue;
194
195 // if the partition is referensed and is not a locater, it must be installed
196 if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
197 MessageExitOnFailure(hr = E_FAIL, msierrComPlusPartitionDependency, "A partition is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
198
199 // get partitions collection
200 if (!piPartColl)
201 {
202 hr = CpiGetPartitionsCollection(&piPartColl);
203 ExitOnFailure(hr, "Failed to get partitions collection");
204 }
205
206 // partition is supposed to exist
207 if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled))
208 {
209 // get collection object for partition
210 hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj);
211 ExitOnFailure(hr, "Failed to find collection object for partition");
212
213 // if the partition was found
214 if (S_OK == hr)
215 {
216 // if we don't have an id, copy id from object
217 if (!*pItm->wzID)
218 {
219 hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID));
220 ExitOnFailure(hr, "Failed to get id");
221 }
222 }
223
224 // if the partition was not found
225 else
226 {
227 // if the application is a locater, this is an error
228 if (!pItm->fHasComponent)
229 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusPartitionNotFound, "A partition required by this installation was not found, key: %S", pItm->wzKey);
230
231 // create a new id if one is missing
232 if (!*pItm->wzID)
233 {
234 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
235 ExitOnFailure(hr, "Failed to create id");
236 }
237 }
238 }
239
240 // partition is supposed to be created
241 else
242 {
243 // check for conflicts
244 do {
245 if (*pItm->wzID)
246 {
247 // find partitions with conflicting id
248 hr = CpiFindCollectionObject(piPartColl, pItm->wzID, NULL, &piPartObj);
249 ExitOnFailure(hr, "Failed to find collection object for partition");
250
251 if (S_FALSE == hr)
252 {
253 // find partitions with conflicting name
254 hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj);
255 ExitOnFailure(hr, "Failed to find collection object for partition");
256
257 if (S_OK == hr)
258 // "A partition with a conflictiong name exists. retry cancel"
259 er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
260 else
261 break; // no conflicting entry found, break loop
262 }
263 else
264 // "A partition with a conflicting id exists. abort retry ignore"
265 er = WcaErrorMessage(msierrComPlusPartitionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
266 }
267 else
268 {
269 // find partitions with conflicting name
270 hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj);
271 ExitOnFailure(hr, "Failed to find collection object for partition");
272
273 if (S_OK == hr)
274 // "A partition with a conflictiong name exists. abort retry ignore"
275 er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
276 else
277 break; // no conflicting entry found, break loop
278 }
279
280 switch (er)
281 {
282 case IDCANCEL:
283 case IDABORT:
284 ExitOnFailure(hr = E_FAIL, "A partition with a conflictiong name or id exists, key: %S", pItm->wzKey);
285 break;
286 case IDRETRY:
287 break;
288 case IDIGNORE:
289 default:
290 // if we don't have an id, copy id from object
291 if (!*pItm->wzID)
292 {
293 hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID));
294 ExitOnFailure(hr, "Failed to get id");
295 }
296 hr = S_FALSE; // indicate that this is not a conflict
297 }
298 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
299
300 // create a new id if one is missing
301 if (!*pItm->wzID)
302 {
303 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
304 ExitOnFailure(hr, "Failed to create id");
305 }
306 }
307
308 // clean up
309 ReleaseNullObject(piPartObj);
310 }
311
312 hr = S_OK;
313
314LExit:
315 // clean up
316 ReleaseObject(piPartColl);
317 ReleaseObject(piPartObj);
318
319 return hr;
320}
321
322HRESULT CpiPartitionsVerifyUninstall(
323 CPI_PARTITION_LIST* pList
324 )
325{
326 HRESULT hr = S_OK;
327 ICatalogCollection* piPartColl = NULL;
328 ICatalogObject* piPartObj = NULL;
329
330 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
331 {
332 // referenced locaters or partitions that are being uninstalled
333 if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction)))
334 continue;
335
336 // get partitions collection
337 if (!piPartColl)
338 {
339 hr = CpiGetPartitionsCollection(&piPartColl);
340 ExitOnFailure(hr, "Failed to get partitions collection");
341 }
342
343 // get collection object for partition
344 hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj);
345 ExitOnFailure(hr, "Failed to find collection object for partition");
346
347 // if the partition was found
348 if (S_OK == hr)
349 {
350 // if we don't have an id, copy id from object
351 if (!*pItm->wzID)
352 {
353 hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID));
354 ExitOnFailure(hr, "Failed to get id");
355 }
356 }
357
358 // if the partition was not found
359 else
360 {
361 pItm->fObjectNotFound = TRUE;
362 if (pItm->fHasComponent)
363 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
364 }
365
366 // clean up
367 ReleaseNullObject(piPartObj);
368 }
369
370 hr = S_OK;
371
372LExit:
373 // clean up
374 ReleaseObject(piPartColl);
375 ReleaseObject(piPartObj);
376
377 return hr;
378}
379
380void CpiPartitionAddReferenceInstall(
381 CPI_PARTITION* pItm
382 )
383{
384 pItm->fReferencedForInstall = TRUE;
385}
386
387void CpiPartitionAddReferenceUninstall(
388 CPI_PARTITION* pItm
389 )
390{
391 pItm->fReferencedForUninstall = TRUE;
392}
393
394HRESULT CpiPartitionsInstall(
395 CPI_PARTITION_LIST* pList,
396 int iRunMode,
397 LPWSTR* ppwzActionData,
398 int* piProgress
399 )
400{
401 HRESULT hr = S_OK;
402
403 int iActionType;
404
405 // add action text
406 hr = CpiAddActionTextToActionData(L"CreateComPlusPartitions", ppwzActionData);
407 ExitOnFailure(hr, "Failed to add action text to custom action data");
408
409 // add partition count to action data
410 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
411 ExitOnFailure(hr, "Failed to add count to custom action data");
412
413 // add applications to custom action data
414 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
415 {
416 // partitions that are being installed only
417 if (!pItm->fHasComponent || !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
418 continue;
419
420 // action type
421 if (rmRollback == iRunMode)
422 {
423 if (CpiIsInstalled(pItm->isInstalled))
424 iActionType = atNoOp;
425 else
426 iActionType = atRemove;
427 }
428 else
429 iActionType = atCreate;
430
431 // add to action data
432 hr = AddPartitionToActionData(pItm, iActionType, COST_PARTITION_CREATE, ppwzActionData);
433 ExitOnFailure(hr, "Failed to add partition to custom action data, key: %S", pItm->wzKey);
434 }
435
436 // add progress tics
437 if (piProgress)
438 *piProgress += COST_PARTITION_CREATE * pList->iInstallCount;
439
440 hr = S_OK;
441
442LExit:
443 return hr;
444}
445
446HRESULT CpiPartitionsUninstall(
447 CPI_PARTITION_LIST* pList,
448 int iRunMode,
449 LPWSTR* ppwzActionData,
450 int* piProgress
451 )
452{
453 HRESULT hr = S_OK;
454
455 int iActionType;
456
457 // add action text
458 hr = CpiAddActionTextToActionData(L"RemoveComPlusPartitions", ppwzActionData);
459 ExitOnFailure(hr, "Failed to add action text to custom action data");
460
461 // add partition count to action data
462 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
463 ExitOnFailure(hr, "Failed to add count to custom action data");
464
465 // add partitions to custom action data
466 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
467 {
468 // partitions that are being uninstalled only
469 if (!pItm->fHasComponent || pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
470 continue;
471
472 // action type
473 if (rmRollback == iRunMode)
474 iActionType = atCreate;
475 else
476 iActionType = atRemove;
477
478 // add to action data
479 hr = AddPartitionToActionData(pItm, iActionType, COST_PARTITION_DELETE, ppwzActionData);
480 ExitOnFailure(hr, "Failed to add partition to custom action data, key:", pItm->wzKey);
481 }
482
483 // add progress tics
484 if (piProgress)
485 *piProgress += COST_PARTITION_DELETE * pList->iUninstallCount;
486
487 hr = S_OK;
488
489LExit:
490 return hr;
491}
492
493HRESULT CpiPartitionFindByKey(
494 CPI_PARTITION_LIST* pList,
495 LPCWSTR wzKey,
496 CPI_PARTITION** ppItm
497 )
498{
499 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
500 {
501 if (0 == lstrcmpW(pItm->wzKey, wzKey))
502 {
503 *ppItm = pItm;
504 return S_OK;
505 }
506 }
507
508 return S_FALSE;
509}
510
511HRESULT CpiGetApplicationsCollForPartition(
512 CPI_PARTITION* pPart,
513 ICatalogCollection** ppiAppColl
514 )
515{
516 HRESULT hr = S_OK;
517
518 ICatalogCollection* piPartColl = NULL;
519 ICatalogObject* piPartObj = NULL;
520
521 // if a previous attempt to locate the collection object failed
522 if (pPart->fObjectNotFound)
523 ExitFunction1(hr = S_FALSE);
524
525 // get applications collection
526 if (!pPart->piApplicationsColl)
527 {
528 // get partitions collection from catalog
529 hr = CpiGetPartitionsCollection(&piPartColl);
530 ExitOnFailure(hr, "Failed to get partitions collection");
531
532 // find application object
533 hr = CpiFindCollectionObject(piPartColl, pPart->wzID, *pPart->wzID ? NULL : pPart->wzName, &piPartObj);
534 ExitOnFailure(hr, "Failed to find partition object");
535
536 if (S_FALSE == hr)
537 {
538 pPart->fObjectNotFound = TRUE;
539 ExitFunction(); // exit with hr = S_FALSE
540 }
541
542 // get roles collection
543 hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", &pPart->piApplicationsColl);
544 ExitOnFailure(hr, "Failed to get applications collection");
545 }
546
547 // return value
548 *ppiAppColl = pPart->piApplicationsColl;
549 (*ppiAppColl)->AddRef();
550
551 hr = S_OK;
552
553LExit:
554 // clean up
555 ReleaseObject(piPartColl);
556 ReleaseObject(piPartObj);
557
558 return hr;
559}
560
561HRESULT CpiGetRolesCollForPartition(
562 CPI_PARTITION* pPart,
563 ICatalogCollection** ppiRolesColl
564 )
565{
566 HRESULT hr = S_OK;
567
568 ICatalogCollection* piPartColl = NULL;
569 ICatalogObject* piPartObj = NULL;
570
571 // if a previous attempt to locate the collection object failed
572 if (pPart->fObjectNotFound)
573 ExitFunction1(hr = S_FALSE);
574
575 // get applications collection
576 if (!pPart->piRolesColl)
577 {
578 // get partitions collection from catalog
579 hr = CpiGetPartitionsCollection(&piPartColl);
580 ExitOnFailure(hr, "Failed to get partitions collection");
581
582 // find partition object
583 hr = CpiFindCollectionObject(piPartColl, pPart->wzID, *pPart->wzID ? NULL : pPart->wzName, &piPartObj);
584 ExitOnFailure(hr, "Failed to find partition object");
585
586 if (S_FALSE == hr)
587 ExitFunction(); // exit with hr = S_FALSE
588
589 // get roles collection
590 hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", &pPart->piRolesColl);
591 ExitOnFailure(hr, "Failed to get roles collection");
592 }
593
594 // return value
595 *ppiRolesColl = pPart->piRolesColl;
596 (*ppiRolesColl)->AddRef();
597
598 hr = S_OK;
599
600LExit:
601 // clean up
602 ReleaseObject(piPartColl);
603 ReleaseObject(piPartObj);
604
605 return hr;
606}
607
608void CpiPartitionUserListFree(
609 CPI_PARTITION_USER_LIST* pList
610 )
611{
612 CPI_PARTITION_USER* pItm = pList->pFirst;
613
614 while (pItm)
615 {
616 CPI_PARTITION_USER* pDelete = pItm;
617 pItm = pItm->pNext;
618 FreePartitionUser(pDelete);
619 }
620}
621
622HRESULT CpiPartitionUsersRead(
623 CPI_PARTITION_LIST* pPartList,
624 CPI_PARTITION_USER_LIST* pPartUsrList
625 )
626{
627 HRESULT hr = S_OK;
628 UINT er = ERROR_SUCCESS;
629
630 PMSIHANDLE hView, hRec;
631
632 CPI_PARTITION_USER* pItm = NULL;
633 LPWSTR pwzData = NULL;
634 LPWSTR pwzDomain = NULL;
635 LPWSTR pwzName = NULL;
636 BOOL fMatchingArchitecture = FALSE;
637
638 // loop through all partition users
639 hr = WcaOpenExecuteView(vcsPartitionUserQuery, &hView);
640 ExitOnFailure(hr, "Failed to execute view on ComPlusPartitionUser table");
641
642 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
643 {
644 // get component
645 hr = WcaGetRecordString(hRec, puqComponent, &pwzData);
646 ExitOnFailure(hr, "Failed to get component");
647
648 // check if the component is our processor architecture
649 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
650 ExitOnFailure(hr, "Failed to get component architecture.");
651
652 if (!fMatchingArchitecture)
653 {
654 continue; // not the same architecture, ignore
655 }
656
657 // create entry
658 pItm = (CPI_PARTITION_USER*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION_USER));
659 if (!pItm)
660 ExitFunction1(hr = E_OUTOFMEMORY);
661
662 // get component install state
663 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
664 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
665
666 // get key
667 hr = WcaGetRecordString(hRec, puqPartitionUser, &pwzData);
668 ExitOnFailure(hr, "Failed to get key");
669 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
670
671 // get partition
672 hr = WcaGetRecordString(hRec, puqPartition, &pwzData);
673 ExitOnFailure(hr, "Failed to get partition");
674
675 hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition);
676 if (S_FALSE == hr)
677 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
678 ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData);
679
680 // get user domain
681 hr = WcaGetRecordFormattedString(hRec, puqDomain, &pwzDomain);
682 ExitOnFailure(hr, "Failed to get user domain");
683
684 // get user name
685 hr = WcaGetRecordFormattedString(hRec, puqName, &pwzName);
686 ExitOnFailure(hr, "Failed to get user name");
687
688 // build account name
689 hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount);
690 ExitOnFailure(hr, "Failed to build account name");
691
692 // set references & increment counters
693 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
694 {
695 pItm->pPartition->fReferencedForInstall = TRUE;
696 pPartUsrList->iInstallCount++;
697 }
698 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
699 {
700 pItm->pPartition->fReferencedForUninstall = TRUE;
701 pPartUsrList->iUninstallCount++;
702 }
703
704 // add entry
705 if (pPartUsrList->pFirst)
706 pItm->pNext = pPartUsrList->pFirst;
707 pPartUsrList->pFirst = pItm;
708 pItm = NULL;
709 }
710
711 if (E_NOMOREITEMS == hr)
712 hr = S_OK;
713
714LExit:
715 // clean up
716 if (pItm)
717 FreePartitionUser(pItm);
718
719 ReleaseStr(pwzData);
720 ReleaseStr(pwzDomain);
721 ReleaseStr(pwzName);
722
723 return hr;
724}
725
726HRESULT CpiPartitionUsersInstall(
727 CPI_PARTITION_USER_LIST* pList,
728 int iRunMode,
729 LPWSTR* ppwzActionData,
730 int* piProgress
731 )
732{
733 HRESULT hr = S_OK;
734
735 int iActionType;
736
737 // add action text
738 hr = CpiAddActionTextToActionData(L"AddComPlusPartitionUsers", ppwzActionData);
739 ExitOnFailure(hr, "Failed to add action text to custom action data");
740
741 // add partition count to action data
742 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
743 ExitOnFailure(hr, "Failed to add count to custom action data");
744
745 // add applications to custom action data
746 for (CPI_PARTITION_USER* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
747 {
748 // partitions that are being installed only
749 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
750 continue;
751
752 // action type
753 if (rmRollback == iRunMode)
754 {
755 if (CpiIsInstalled(pItm->isInstalled))
756 iActionType = atNoOp;
757 else
758 iActionType = atRemove;
759 }
760 else
761 iActionType = atCreate;
762
763 // add to action data
764 hr = AddPartitionUserToActionData(pItm, iActionType, COST_PARTITION_USER_CREATE, ppwzActionData);
765 ExitOnFailure(hr, "Failed to add partition user to custom action data, key: %S", pItm->wzKey);
766 }
767
768 // add progress tics
769 if (piProgress)
770 *piProgress += COST_PARTITION_USER_CREATE * pList->iInstallCount;
771
772 hr = S_OK;
773
774LExit:
775 return hr;
776}
777
778HRESULT CpiPartitionUsersUninstall(
779 CPI_PARTITION_USER_LIST* pList,
780 int iRunMode,
781 LPWSTR* ppwzActionData,
782 int* piProgress
783 )
784{
785 HRESULT hr = S_OK;
786
787 int iActionType;
788
789 // add action text
790 hr = CpiAddActionTextToActionData(L"RemoveComPlusPartitionUsers", ppwzActionData);
791 ExitOnFailure(hr, "Failed to add action text to custom action data");
792
793 // add partition count to action data
794 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
795 ExitOnFailure(hr, "Failed to add count to custom action data");
796
797 // add partitions to custom action data
798 for (CPI_PARTITION_USER* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
799 {
800 // partitions that are being uninstalled only
801 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
802 continue;
803
804 // action type
805 if (rmRollback == iRunMode)
806 iActionType = atCreate;
807 else
808 iActionType = atRemove;
809
810 // add to action data
811 hr = AddPartitionUserToActionData(pItm, iActionType, COST_PARTITION_USER_DELETE, ppwzActionData);
812 ExitOnFailure(hr, "Failed to add partition user to custom action data, key: %S", pItm->wzKey);
813 }
814
815 // add progress tics
816 if (piProgress)
817 *piProgress += COST_PARTITION_USER_DELETE * pList->iUninstallCount;
818
819 hr = S_OK;
820
821LExit:
822 return hr;
823}
824
825
826// helper function definitions
827
828static void FreePartition(
829 CPI_PARTITION* pItm
830 )
831{
832 if (pItm->pProperties)
833 CpiPropertiesFreeList(pItm->pProperties);
834
835 ReleaseObject(pItm->piApplicationsColl);
836 ReleaseObject(pItm->piRolesColl);
837
838 ::HeapFree(::GetProcessHeap(), 0, pItm);
839}
840
841static void FreePartitionUser(
842 CPI_PARTITION_USER* pItm
843 )
844{
845 ReleaseStr(pItm->pwzAccount);
846
847 ::HeapFree(::GetProcessHeap(), 0, pItm);
848}
849
850static HRESULT AddPartitionToActionData(
851 CPI_PARTITION* pItm,
852 int iActionType,
853 int iActionCost,
854 LPWSTR* ppwzActionData
855 )
856{
857 HRESULT hr = S_OK;
858
859 // add action information to custom action data
860 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
861 ExitOnFailure(hr, "Failed to add action type to custom action data");
862 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
863 ExitOnFailure(hr, "Failed to add action cost to custom action data");
864
865 // add partition information to custom action data
866 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
867 ExitOnFailure(hr, "Failed to add partition key to custom action data");
868 hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
869 ExitOnFailure(hr, "Failed to add partition id to custom action data");
870 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
871 ExitOnFailure(hr, "Failed to add partition name to custom action data");
872
873 // add properties to custom action data
874 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
875 ExitOnFailure(hr, "Failed to add properties to custom action data");
876
877 hr = S_OK;
878
879LExit:
880 return hr;
881}
882
883static HRESULT AddPartitionUserToActionData(
884 CPI_PARTITION_USER* pItm,
885 int iActionType,
886 int iActionCost,
887 LPWSTR* ppwzActionData
888 )
889{
890 HRESULT hr = S_OK;
891
892 // add action information to custom action data
893 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
894 ExitOnFailure(hr, "Failed to add action type to custom action data");
895 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
896 ExitOnFailure(hr, "Failed to add action cost to custom action data");
897
898 // add partition user information to custom action data
899 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
900 ExitOnFailure(hr, "Failed to add partition user key to custom action data");
901 hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData);
902 ExitOnFailure(hr, "Failed to add user account to custom action data");
903
904 // add partition information to custom action data
905 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pPartition->wzID : L"", ppwzActionData);
906 ExitOnFailure(hr, "Failed to add partition id to custom action data");
907
908 hr = S_OK;
909
910LExit:
911 return hr;
912}
diff --git a/src/ca/cppartsched.h b/src/ca/cppartsched.h
new file mode 100644
index 00000000..55085912
--- /dev/null
+++ b/src/ca/cppartsched.h
@@ -0,0 +1,125 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_PARTITION
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzID[CPI_MAX_GUID + 1];
9 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
10
11 int iPropertyCount;
12 CPI_PROPERTY* pProperties;
13
14 BOOL fHasComponent;
15 BOOL fReferencedForInstall;
16 BOOL fReferencedForUninstall;
17 BOOL fObjectNotFound;
18
19 INSTALLSTATE isInstalled, isAction;
20
21 ICatalogCollection* piApplicationsColl;
22 ICatalogCollection* piRolesColl;
23
24 CPI_PARTITION* pNext;
25};
26
27struct CPI_PARTITION_LIST
28{
29 CPI_PARTITION* pFirst;
30
31 int iInstallCount;
32 int iUninstallCount;
33};
34
35struct CPI_PARTITION_USER
36{
37 WCHAR wzKey[MAX_DARWIN_KEY + 1];
38 LPWSTR pwzAccount;
39
40 BOOL fNoFind;
41
42 INSTALLSTATE isInstalled, isAction;
43
44 CPI_PARTITION* pPartition;
45
46 CPI_PARTITION_USER* pNext;
47};
48
49struct CPI_PARTITION_USER_LIST
50{
51 CPI_PARTITION_USER* pFirst;
52
53 int iInstallCount;
54 int iUninstallCount;
55};
56
57
58// function prototypes
59
60void CpiPartitionListFree(
61 CPI_PARTITION_LIST* pList
62 );
63HRESULT CpiPartitionsRead(
64 CPI_PARTITION_LIST* pPartList
65 );
66HRESULT CpiPartitionsVerifyInstall(
67 CPI_PARTITION_LIST* pList
68 );
69HRESULT CpiPartitionsVerifyUninstall(
70 CPI_PARTITION_LIST* pList
71 );
72void CpiPartitionAddReferenceInstall(
73 CPI_PARTITION* pItm
74 );
75void CpiPartitionAddReferenceUninstall(
76 CPI_PARTITION* pItm
77 );
78HRESULT CpiPartitionsInstall(
79 CPI_PARTITION_LIST* pList,
80 int iRunMode,
81 LPWSTR* ppwzActionData,
82 int* piProgress
83 );
84HRESULT CpiPartitionsUninstall(
85 CPI_PARTITION_LIST* pList,
86 int iRunMode,
87 LPWSTR* ppwzActionData,
88 int* piProgress
89 );
90HRESULT CpiPartitionFindByKey(
91 CPI_PARTITION_LIST* pList,
92 LPCWSTR wzKey,
93 CPI_PARTITION** ppItm
94 );
95HRESULT CpiGetApplicationsCollForPartition(
96 CPI_PARTITION* pPart,
97 ICatalogCollection** ppiAppColl
98 );
99HRESULT CpiGetPartitionUsersCollection(
100 CPI_PARTITION* pPart,
101 ICatalogCollection** ppiPartUsrColl
102 );
103HRESULT CpiGetRolesCollForPartition(
104 CPI_PARTITION* pPart,
105 ICatalogCollection** ppiRolesColl
106 );
107void CpiPartitionUserListFree(
108 CPI_PARTITION_USER_LIST* pList
109 );
110HRESULT CpiPartitionUsersRead(
111 CPI_PARTITION_LIST* pPartList,
112 CPI_PARTITION_USER_LIST* pPartUsrList
113 );
114HRESULT CpiPartitionUsersInstall(
115 CPI_PARTITION_USER_LIST* pList,
116 int iRunMode,
117 LPWSTR* ppwzActionData,
118 int* piProgress
119 );
120HRESULT CpiPartitionUsersUninstall(
121 CPI_PARTITION_USER_LIST* pList,
122 int iRunMode,
123 LPWSTR* ppwzActionData,
124 int* piProgress
125 );
diff --git a/src/ca/cpsched.cpp b/src/ca/cpsched.cpp
new file mode 100644
index 00000000..ac0dda59
--- /dev/null
+++ b/src/ca/cpsched.cpp
@@ -0,0 +1,590 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6#ifdef _WIN64
7#define CP_COMPLUSROLLBACKINSTALLPREPARE L"ComPlusRollbackInstallPrepare_64"
8#define CP_COMPLUSINSTALLPREPARE L"ComPlusInstallPrepare_64"
9#define CP_COMPLUSROLLBACKINSTALLEXECUTE L"ComPlusRollbackInstallExecute_64"
10#define CP_COMPLUSINSTALLEXECUTE L"ComPlusInstallExecute_64"
11#define CP_COMPLUSINSTALLEXECUTECOMMIT L"ComPlusInstallExecuteCommit_64"
12#define CP_COMPLUSINSTALLCOMMIT L"ComPlusInstallCommit_64"
13#define CP_COMPLUSROLLBACKINSTALLPREPARE L"ComPlusRollbackInstallPrepare_64"
14#define CP_COMPLUSINSTALLPREPARE L"ComPlusInstallPrepare_64"
15#define CP_COMPLUSROLLBACKUNINSTALLEXECUTE L"ComPlusRollbackUninstallExecute_64"
16#define CP_COMPLUSUNINSTALLEXECUTE L"ComPlusUninstallExecute_64"
17#define CP_COMPLUSINSTALLCOMMIT L"ComPlusInstallCommit_64"
18#else
19#define CP_COMPLUSROLLBACKINSTALLPREPARE L"ComPlusRollbackInstallPrepare"
20#define CP_COMPLUSINSTALLPREPARE L"ComPlusInstallPrepare"
21#define CP_COMPLUSROLLBACKINSTALLEXECUTE L"ComPlusRollbackInstallExecute"
22#define CP_COMPLUSINSTALLEXECUTE L"ComPlusInstallExecute"
23#define CP_COMPLUSINSTALLEXECUTECOMMIT L"ComPlusInstallExecuteCommit"
24#define CP_COMPLUSINSTALLCOMMIT L"ComPlusInstallCommit"
25#define CP_COMPLUSROLLBACKINSTALLPREPARE L"ComPlusRollbackInstallPrepare"
26#define CP_COMPLUSINSTALLPREPARE L"ComPlusInstallPrepare"
27#define CP_COMPLUSROLLBACKUNINSTALLEXECUTE L"ComPlusRollbackUninstallExecute"
28#define CP_COMPLUSUNINSTALLEXECUTE L"ComPlusUninstallExecute"
29#define CP_COMPLUSINSTALLCOMMIT L"ComPlusInstallCommit"
30#endif
31
32
33/********************************************************************
34 DllMain - standard entry point for all WiX CustomActions
35
36********************************************************************/
37extern "C" BOOL WINAPI DllMain(
38 IN HINSTANCE hInst,
39 IN ULONG ulReason,
40 IN LPVOID)
41{
42 switch(ulReason)
43 {
44 case DLL_PROCESS_ATTACH:
45 WcaGlobalInitialize(hInst);
46 break;
47
48 case DLL_PROCESS_DETACH:
49 WcaGlobalFinalize();
50 break;
51 }
52
53 return TRUE;
54}
55
56/********************************************************************
57 ConfigureComPlusInstall - CUSTOM ACTION ENTRY POINT for installing COM+ components
58
59********************************************************************/
60extern "C" UINT __stdcall ConfigureComPlusInstall(MSIHANDLE hInstall)
61{
62 HRESULT hr = S_OK;
63 UINT er = ERROR_SUCCESS;
64
65 BOOL fInitializedCom = FALSE;
66
67 ICOMAdminCatalog* piCatalog = NULL;
68
69 CPI_PARTITION_LIST partList;
70 CPI_PARTITION_ROLE_LIST partRoleList;
71 CPI_USER_IN_PARTITION_ROLE_LIST usrInPartRoleList;
72 CPI_PARTITION_USER_LIST partUsrList;
73 CPI_APPLICATION_LIST appList;
74 CPI_APPLICATION_ROLE_LIST appRoleList;
75 CPI_USER_IN_APPLICATION_ROLE_LIST usrInAppRoleList;
76 CPI_ASSEMBLY_LIST asmList;
77 CPI_SUBSCRIPTION_LIST subList;
78
79 LPWSTR pwzRollbackFileName = NULL;
80 LPWSTR pwzActionData = NULL;
81 LPWSTR pwzRollbackActionData = NULL;
82 LPWSTR pwzCommitActionData = NULL;
83
84 int iVersionNT = 0;
85 int iProgress = 0;
86 int iCommitProgress = 0;
87
88 ::ZeroMemory(&partList, sizeof(CPI_PARTITION_LIST));
89 ::ZeroMemory(&partRoleList, sizeof(CPI_PARTITION_ROLE_LIST));
90 ::ZeroMemory(&usrInPartRoleList, sizeof(CPI_USER_IN_PARTITION_ROLE_LIST));
91 ::ZeroMemory(&partUsrList, sizeof(CPI_PARTITION_USER_LIST));
92 ::ZeroMemory(&appList, sizeof(CPI_APPLICATION_LIST));
93 ::ZeroMemory(&appRoleList, sizeof(CPI_APPLICATION_ROLE_LIST));
94 ::ZeroMemory(&usrInAppRoleList, sizeof(CPI_USER_IN_APPLICATION_ROLE_LIST));
95 ::ZeroMemory(&asmList, sizeof(CPI_ASSEMBLY_LIST));
96 ::ZeroMemory(&subList, sizeof(CPI_SUBSCRIPTION_LIST));
97
98 // initialize
99 hr = WcaInitialize(hInstall, "ConfigureComPlusInstall");
100 ExitOnFailure(hr, "Failed to initialize");
101
102 hr = ::CoInitialize(NULL);
103 ExitOnFailure(hr, "Failed to initialize COM");
104 fInitializedCom = TRUE;
105
106 CpiInitialize();
107
108 // check for the prerequsite tables
109 if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly))
110 {
111 WcaLog(LOGMSG_VERBOSE, "skipping install COM+ CustomAction, no ComPlusPartition, ComPlusApplication or ComPlusAssembly table present");
112 ExitFunction1(hr = S_FALSE);
113 }
114
115 // make sure we can access the COM+ admin catalog
116 do {
117 hr = CpiGetAdminCatalog(&piCatalog);
118 if (FAILED(hr))
119 {
120 WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog");
121 er = WcaErrorMessage(msierrComPlusCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
122 switch (er)
123 {
124 case IDABORT:
125 ExitFunction(); // exit with hr from CpiGetAdminCatalog() to kick off a rollback
126 case IDRETRY:
127 hr = S_FALSE;
128 break;
129 case IDIGNORE:
130 default:
131 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
132 }
133 }
134 } while (S_FALSE == hr);
135
136 // get NT version
137 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
138 ExitOnFailure(hr, "Failed to get VersionNT property");
139
140 // read elements
141 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartition))
142 {
143 hr = CpiPartitionsRead(&partList);
144 MessageExitOnFailure(hr, msierrComPlusPartitionReadFailed, "Failed to read ComPlusPartitions table");
145 }
146
147 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionRole))
148 {
149 hr = CpiPartitionRolesRead(&partList, &partRoleList);
150 MessageExitOnFailure(hr, msierrComPlusPartitionRoleReadFailed, "Failed to read ComPlusPartitionRole table");
151 }
152
153 if (502 <= iVersionNT && (CpiTableExists(cptComPlusUserInPartitionRole) || CpiTableExists(cptComPlusGroupInPartitionRole)))
154 {
155 hr = CpiUsersInPartitionRolesRead(&partRoleList, &usrInPartRoleList);
156 MessageExitOnFailure(hr, msierrComPlusUserInPartitionRoleReadFailed, "Failed to read ComPlusUserInPartitionRole table");
157 }
158
159 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionUser))
160 {
161 hr = CpiPartitionUsersRead(&partList, &partUsrList);
162 MessageExitOnFailure(hr, msierrComPlusPartitionUserReadFailed, "Failed to read ComPlusPartitionUser table");
163 }
164
165 if (CpiTableExists(cptComPlusApplication))
166 {
167 hr = CpiApplicationsRead(&partList, &appList);
168 MessageExitOnFailure(hr, msierrComPlusApplicationReadFailed, "Failed to read ComPlusApplication table");
169 }
170
171 if (CpiTableExists(cptComPlusApplicationRole))
172 {
173 hr = CpiApplicationRolesRead(&appList, &appRoleList);
174 MessageExitOnFailure(hr, msierrComPlusApplicationRoleReadFailed, "Failed to read ComPlusApplicationRole table");
175 }
176
177 if (CpiTableExists(cptComPlusUserInApplicationRole) || CpiTableExists(cptComPlusGroupInApplicationRole))
178 {
179 hr = CpiUsersInApplicationRolesRead(&appRoleList, &usrInAppRoleList);
180 MessageExitOnFailure(hr, msierrComPlusUserInApplicationRoleReadFailed, "Failed to read ComPlusUserInApplicationRole table");
181 }
182
183 if (CpiTableExists(cptComPlusAssembly))
184 {
185 hr = CpiAssembliesRead(&appList, &appRoleList, &asmList);
186 MessageExitOnFailure(hr, msierrComPlusAssembliesReadFailed, "Failed to read ComPlusAssembly table");
187 }
188
189 if (CpiTableExists(cptComPlusSubscription))
190 {
191 hr = CpiSubscriptionsRead(&asmList, &subList);
192 MessageExitOnFailure(hr, msierrComPlusSubscriptionReadFailed, "Failed to read ComPlusSubscription table");
193 }
194
195 // verify elements
196 hr = CpiPartitionsVerifyInstall(&partList);
197 ExitOnFailure(hr, "Failed to verify partitions");
198
199 hr = CpiApplicationsVerifyInstall(&appList);
200 ExitOnFailure(hr, "Failed to verify applications");
201
202 hr = CpiApplicationRolesVerifyInstall(&appRoleList);
203 ExitOnFailure(hr, "Failed to verify application roles");
204
205 hr = CpiAssembliesVerifyInstall(&asmList);
206 ExitOnFailure(hr, "Failed to verify assemblies");
207
208 if (subList.iInstallCount)
209 {
210 hr = CpiSubscriptionsVerifyInstall(&subList);
211 ExitOnFailure(hr, "Failed to verify subscriptions");
212 }
213
214 // schedule
215 if (partList.iInstallCount || appList.iInstallCount || usrInAppRoleList.iInstallCount ||
216 appRoleList.iInstallCount || asmList.iInstallCount || asmList.iRoleInstallCount || subList.iInstallCount)
217 {
218 // create rollback file name
219 hr = CpiGetTempFileName(&pwzRollbackFileName);
220 ExitOnFailure(hr, "Failed to get rollback file name");
221
222 // schedule rollback prepare custom action
223 hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLPREPARE, pwzRollbackFileName, 0);
224 ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallPrepare");
225
226 // schedule prepare custom action
227 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLPREPARE, pwzRollbackFileName, 0);
228 ExitOnFailure(hr, "Failed to schedule ComPlusInstallPrepare");
229
230 // schedule rollback custom action
231 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzRollbackActionData);
232 ExitOnFailure(hr, "Failed to add rollback file name to rollback custom action data");
233
234 hr = CpiSubscriptionsInstall(&subList, rmRollback, &pwzRollbackActionData, NULL);
235 ExitOnFailure(hr, "Failed to install subscriptions");
236 hr = CpiRoleAssignmentsInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
237 ExitOnFailure(hr, "Failed to install assemblies");
238 hr = CpiAssembliesInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
239 ExitOnFailure(hr, "Failed to install assemblies");
240 hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmRollback, &pwzRollbackActionData, NULL);
241 ExitOnFailure(hr, "Failed to install users in application roles");
242 hr = CpiApplicationRolesInstall(&appRoleList, rmRollback, &pwzRollbackActionData, NULL);
243 ExitOnFailure(hr, "Failed to install application roles");
244 hr = CpiApplicationsInstall(&appList, rmRollback, &pwzRollbackActionData, NULL);
245 ExitOnFailure(hr, "Failed to install applications");
246 hr = CpiPartitionUsersInstall(&partUsrList, rmRollback, &pwzRollbackActionData, NULL);
247 ExitOnFailure(hr, "Failed to install partition users");
248 hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmRollback, &pwzRollbackActionData, NULL);
249 ExitOnFailure(hr, "Failed to install users in partition roles");
250 hr = CpiPartitionsInstall(&partList, rmRollback, &pwzRollbackActionData, NULL);
251 ExitOnFailure(hr, "Failed to install partitions");
252
253 hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLEXECUTE, pwzRollbackActionData, 0);
254 ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallExecute");
255
256 // schedule install custom action
257 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzActionData);
258 ExitOnFailure(hr, "Failed to add rollback file name to custom action data");
259
260 hr = CpiPartitionsInstall(&partList, rmDeferred, &pwzActionData, &iProgress);
261 ExitOnFailure(hr, "Failed to install partitions");
262 hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmDeferred, &pwzActionData, &iProgress);
263 ExitOnFailure(hr, "Failed to install users in partition roles");
264 hr = CpiPartitionUsersInstall(&partUsrList, rmDeferred, &pwzActionData, &iProgress);
265 ExitOnFailure(hr, "Failed to install partition users");
266 hr = CpiApplicationsInstall(&appList, rmDeferred, &pwzActionData, &iProgress);
267 ExitOnFailure(hr, "Failed to install applications");
268 hr = CpiApplicationRolesInstall(&appRoleList, rmDeferred, &pwzActionData, &iProgress);
269 ExitOnFailure(hr, "Failed to install application roles");
270 hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmDeferred, &pwzActionData, &iProgress);
271 ExitOnFailure(hr, "Failed to install users in application roles");
272 hr = CpiAssembliesInstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
273 ExitOnFailure(hr, "Failed to install assemblies");
274 hr = CpiRoleAssignmentsInstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
275 ExitOnFailure(hr, "Failed to install assemblies");
276 hr = CpiSubscriptionsInstall(&subList, rmDeferred, &pwzActionData, &iProgress);
277 ExitOnFailure(hr, "Failed to install subscriptions");
278
279 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTE, pwzActionData, iProgress);
280 ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecute");
281
282 // schedule install commit custom action
283 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzCommitActionData);
284 ExitOnFailure(hr, "Failed to add rollback file name to commit custom action data");
285
286 hr = CpiAssembliesInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress);
287 ExitOnFailure(hr, "Failed to install assemblies");
288 hr = CpiRoleAssignmentsInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress);
289 ExitOnFailure(hr, "Failed to install assemblies");
290 hr = CpiSubscriptionsInstall(&subList, rmCommit, &pwzCommitActionData, &iCommitProgress);
291 ExitOnFailure(hr, "Failed to install subscriptions");
292
293 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTECOMMIT, pwzCommitActionData, iCommitProgress);
294 ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecuteCommit");
295
296 // schedule commit custom action
297 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLCOMMIT, pwzRollbackFileName, 0);
298 ExitOnFailure(hr, "Failed to schedule ComPlusInstallCommit");
299 }
300
301 hr = S_OK;
302
303LExit:
304 // clean up
305 ReleaseObject(piCatalog);
306
307 ReleaseStr(pwzRollbackFileName);
308 ReleaseStr(pwzActionData);
309 ReleaseStr(pwzRollbackActionData);
310 ReleaseStr(pwzCommitActionData);
311
312 CpiPartitionListFree(&partList);
313 CpiPartitionRoleListFree(&partRoleList);
314 CpiUserInPartitionRoleListFree(&usrInPartRoleList);
315 CpiPartitionUserListFree(&partUsrList);
316 CpiApplicationListFree(&appList);
317 CpiApplicationRoleListFree(&appRoleList);
318 CpiUserInApplicationRoleListFree(&usrInAppRoleList);
319 CpiAssemblyListFree(&asmList);
320 CpiSubscriptionListFree(&subList);
321
322 // unitialize
323 CpiFinalize();
324
325 if (fInitializedCom)
326 ::CoUninitialize();
327
328 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
329 return WcaFinalize(er);
330}
331
332
333/********************************************************************
334 ConfigureComPlusUninstall - CUSTOM ACTION ENTRY POINT for uninstalling COM+ components
335
336********************************************************************/
337extern "C" UINT __stdcall ConfigureComPlusUninstall(MSIHANDLE hInstall)
338{
339 HRESULT hr = S_OK;
340 UINT er = ERROR_SUCCESS;
341
342 BOOL fInitializedCom = FALSE;
343
344 ICOMAdminCatalog* piCatalog = NULL;
345
346 CPI_PARTITION_LIST partList;
347 CPI_PARTITION_ROLE_LIST partRoleList;
348 CPI_USER_IN_PARTITION_ROLE_LIST usrInPartRoleList;
349 CPI_PARTITION_USER_LIST partUsrList;
350 CPI_APPLICATION_LIST appList;
351 CPI_APPLICATION_ROLE_LIST appRoleList;
352 CPI_USER_IN_APPLICATION_ROLE_LIST usrInAppRoleList;
353 CPI_ASSEMBLY_LIST asmList;
354 CPI_SUBSCRIPTION_LIST subList;
355
356 LPWSTR pwzRollbackFileName = NULL;
357 LPWSTR pwzActionData = NULL;
358 LPWSTR pwzRollbackActionData = NULL;
359
360 int iVersionNT = 0;
361 int iProgress = 0;
362
363 ::ZeroMemory(&partList, sizeof(CPI_PARTITION_LIST));
364 ::ZeroMemory(&partRoleList, sizeof(CPI_PARTITION_ROLE_LIST));
365 ::ZeroMemory(&usrInPartRoleList, sizeof(CPI_USER_IN_PARTITION_ROLE_LIST));
366 ::ZeroMemory(&partUsrList, sizeof(CPI_PARTITION_USER_LIST));
367 ::ZeroMemory(&appList, sizeof(CPI_APPLICATION_LIST));
368 ::ZeroMemory(&appRoleList, sizeof(CPI_APPLICATION_ROLE_LIST));
369 ::ZeroMemory(&usrInAppRoleList, sizeof(CPI_USER_IN_APPLICATION_ROLE_LIST));
370 ::ZeroMemory(&asmList, sizeof(CPI_ASSEMBLY_LIST));
371 ::ZeroMemory(&subList, sizeof(CPI_SUBSCRIPTION_LIST));
372
373 // initialize
374 hr = WcaInitialize(hInstall, "ConfigureComPlusUninstall");
375 ExitOnFailure(hr, "Failed to initialize");
376
377 hr = ::CoInitialize(NULL);
378 ExitOnFailure(hr, "Failed to initialize COM");
379 fInitializedCom = TRUE;
380
381 CpiInitialize();
382
383 // check for the prerequsite tables
384 if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly))
385 {
386 WcaLog(LOGMSG_VERBOSE, "skipping uninstall COM+ CustomAction, no ComPlusPartition, ComPlusApplication or ComPlusAssembly table present");
387 ExitFunction1(hr = S_FALSE);
388 }
389
390 // make sure we can access the COM+ admin catalog
391 do {
392 hr = CpiGetAdminCatalog(&piCatalog);
393 if (FAILED(hr))
394 {
395 WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog");
396 er = WcaErrorMessage(msierrComPlusCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
397 switch (er)
398 {
399 case IDABORT:
400 ExitFunction(); // exit with hr from CpiGetAdminCatalog() to kick off a rollback
401 case IDRETRY:
402 hr = S_FALSE;
403 break;
404 case IDIGNORE:
405 default:
406 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
407 }
408 }
409 } while (S_FALSE == hr);
410
411 // get NT version
412 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
413 ExitOnFailure(hr, "Failed to get VersionNT property");
414
415 // read elements
416 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartition))
417 {
418 hr = CpiPartitionsRead(&partList);
419 MessageExitOnFailure(hr, msierrComPlusPartitionReadFailed, "Failed to read ComPlusPartitions table");
420 }
421
422 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionRole))
423 {
424 hr = CpiPartitionRolesRead(&partList, &partRoleList);
425 MessageExitOnFailure(hr, msierrComPlusPartitionRoleReadFailed, "Failed to read ComPlusPartitionRole table");
426 }
427
428 if (502 <= iVersionNT && (CpiTableExists(cptComPlusUserInPartitionRole) || CpiTableExists(cptComPlusGroupInPartitionRole)))
429 {
430 hr = CpiUsersInPartitionRolesRead(&partRoleList, &usrInPartRoleList);
431 MessageExitOnFailure(hr, msierrComPlusUserInPartitionRoleReadFailed, "Failed to read ComPlusUserInPartitionRole table");
432 }
433
434 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionUser))
435 {
436 hr = CpiPartitionUsersRead(&partList, &partUsrList);
437 MessageExitOnFailure(hr, msierrComPlusPartitionUserReadFailed, "Failed to read ComPlusPartitionUser table");
438 }
439
440 if (CpiTableExists(cptComPlusApplication))
441 {
442 hr = CpiApplicationsRead(&partList, &appList);
443 MessageExitOnFailure(hr, msierrComPlusApplicationReadFailed, "Failed to read ComPlusApplication table");
444 }
445
446 if (CpiTableExists(cptComPlusApplicationRole))
447 {
448 hr = CpiApplicationRolesRead(&appList, &appRoleList);
449 MessageExitOnFailure(hr, msierrComPlusApplicationRoleReadFailed, "Failed to read ComPlusApplicationRole table");
450 }
451
452 if (CpiTableExists(cptComPlusUserInApplicationRole) || CpiTableExists(cptComPlusGroupInApplicationRole))
453 {
454 hr = CpiUsersInApplicationRolesRead(&appRoleList, &usrInAppRoleList);
455 MessageExitOnFailure(hr, msierrComPlusUserInApplicationRoleReadFailed, "Failed to read ComPlusUserInApplicationRole table");
456 }
457
458 if (CpiTableExists(cptComPlusAssembly))
459 {
460 hr = CpiAssembliesRead(&appList, &appRoleList, &asmList);
461 MessageExitOnFailure(hr, msierrComPlusAssembliesReadFailed, "Failed to read ComPlusAssembly table");
462 }
463
464 if (CpiTableExists(cptComPlusSubscription))
465 {
466 hr = CpiSubscriptionsRead(&asmList, &subList);
467 MessageExitOnFailure(hr, msierrComPlusSubscriptionReadFailed, "Failed to read ComPlusSubscription table");
468 }
469
470 // verify elements
471 hr = CpiPartitionsVerifyUninstall(&partList);
472 ExitOnFailure(hr, "Failed to verify partitions");
473
474 hr = CpiApplicationsVerifyUninstall(&appList);
475 ExitOnFailure(hr, "Failed to verify applications");
476
477 hr = CpiApplicationRolesVerifyUninstall(&appRoleList);
478 ExitOnFailure(hr, "Failed to verify application roles");
479
480 hr = CpiAssembliesVerifyUninstall(&asmList);
481 ExitOnFailure(hr, "Failed to verify assemblies");
482
483 if (subList.iUninstallCount)
484 {
485 hr = CpiSubscriptionsVerifyUninstall(&subList);
486 ExitOnFailure(hr, "Failed to verify subscriptions");
487 }
488
489 // schedule
490 if (partList.iUninstallCount || appList.iUninstallCount || appRoleList.iUninstallCount ||
491 usrInAppRoleList.iUninstallCount || asmList.iUninstallCount || asmList.iRoleUninstallCount || subList.iUninstallCount)
492 {
493 // create rollback file name
494 hr = CpiGetTempFileName(&pwzRollbackFileName);
495 ExitOnFailure(hr, "Failed to get rollback file name");
496
497 // schedule rollback prepare custom action
498 hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLPREPARE, pwzRollbackFileName, 0);
499 ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallPrepare");
500
501 // schedule prepare custom action
502 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLPREPARE, pwzRollbackFileName, 0);
503 ExitOnFailure(hr, "Failed to schedule ComPlusInstallPrepare");
504
505 // schedule rollback custom action
506 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzRollbackActionData);
507 ExitOnFailure(hr, "Failed to add rollback file name to rollback custom action data");
508
509 hr = CpiPartitionsUninstall(&partList, rmRollback, &pwzRollbackActionData, NULL);
510 ExitOnFailure(hr, "Failed to uninstall partitions");
511 hr = CpiUsersInPartitionRolesUninstall(&usrInPartRoleList, rmRollback, &pwzRollbackActionData, NULL);
512 ExitOnFailure(hr, "Failed to uninstall users in partition roles");
513 hr = CpiPartitionUsersUninstall(&partUsrList, rmRollback, &pwzRollbackActionData, NULL);
514 ExitOnFailure(hr, "Failed to uninstall partition users");
515 hr = CpiApplicationsUninstall(&appList, rmRollback, &pwzRollbackActionData, NULL);
516 ExitOnFailure(hr, "Failed to uninstall applications");
517 hr = CpiApplicationRolesUninstall(&appRoleList, rmRollback, &pwzRollbackActionData, NULL);
518 ExitOnFailure(hr, "Failed to uninstall application roles");
519 hr = CpiUsersInApplicationRolesUninstall(&usrInAppRoleList, rmRollback, &pwzRollbackActionData, NULL);
520 ExitOnFailure(hr, "Failed to uninstall users in application roles");
521 hr = CpiAssembliesUninstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
522 ExitOnFailure(hr, "Failed to uninstall assemblies");
523 hr = CpiRoleAssignmentsUninstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
524 ExitOnFailure(hr, "Failed to uninstall assemblies");
525 hr = CpiSubscriptionsUninstall(&subList, rmRollback, &pwzRollbackActionData, NULL);
526 ExitOnFailure(hr, "Failed to uninstall subscriptions");
527
528 hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKUNINSTALLEXECUTE, pwzRollbackActionData, 0);
529 ExitOnFailure(hr, "Failed to schedule ComPlusRollbackUninstallExecute");
530
531 // schedule install custom action
532 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzActionData);
533 ExitOnFailure(hr, "Failed to add rollback file name to custom action data");
534
535 hr = CpiSubscriptionsUninstall(&subList, rmDeferred, &pwzActionData, &iProgress);
536 ExitOnFailure(hr, "Failed to uninstall subscriptions");
537 hr = CpiRoleAssignmentsUninstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
538 ExitOnFailure(hr, "Failed to uninstall assemblies");
539 hr = CpiAssembliesUninstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
540 ExitOnFailure(hr, "Failed to uninstall assemblies");
541 hr = CpiUsersInApplicationRolesUninstall(&usrInAppRoleList, rmDeferred, &pwzActionData, &iProgress);
542 ExitOnFailure(hr, "Failed to uninstall users in application roles");
543 hr = CpiApplicationRolesUninstall(&appRoleList, rmDeferred, &pwzActionData, &iProgress);
544 ExitOnFailure(hr, "Failed to uninstall application roles");
545 hr = CpiApplicationsUninstall(&appList, rmDeferred, &pwzActionData, &iProgress);
546 ExitOnFailure(hr, "Failed to uninstall applications");
547 hr = CpiPartitionUsersUninstall(&partUsrList, rmDeferred, &pwzActionData, &iProgress);
548 ExitOnFailure(hr, "Failed to uninstall partition users");
549 hr = CpiUsersInPartitionRolesUninstall(&usrInPartRoleList, rmDeferred, &pwzActionData, &iProgress);
550 ExitOnFailure(hr, "Failed to uninstall users in partition roles");
551 hr = CpiPartitionsUninstall(&partList, rmDeferred, &pwzActionData, &iProgress);
552 ExitOnFailure(hr, "Failed to uninstall partitions");
553
554 hr = WcaDoDeferredAction(CP_COMPLUSUNINSTALLEXECUTE, pwzActionData, iProgress);
555 ExitOnFailure(hr, "Failed to schedule ComPlusUninstallExecute");
556
557 // schedule commit custom action
558 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLCOMMIT, pwzRollbackFileName, 0);
559 ExitOnFailure(hr, "Failed to schedule ComPlusInstallCommit");
560 }
561
562 hr = S_OK;
563
564LExit:
565 // clean up
566 ReleaseObject(piCatalog);
567
568 ReleaseStr(pwzRollbackFileName);
569 ReleaseStr(pwzActionData);
570 ReleaseStr(pwzRollbackActionData);
571
572 CpiPartitionListFree(&partList);
573 CpiPartitionRoleListFree(&partRoleList);
574 CpiUserInPartitionRoleListFree(&usrInPartRoleList);
575 CpiPartitionUserListFree(&partUsrList);
576 CpiApplicationListFree(&appList);
577 CpiApplicationRoleListFree(&appRoleList);
578 CpiUserInApplicationRoleListFree(&usrInAppRoleList);
579 CpiAssemblyListFree(&asmList);
580 CpiSubscriptionListFree(&subList);
581
582 // unitialize
583 CpiFinalize();
584
585 if (fInitializedCom)
586 ::CoUninitialize();
587
588 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
589 return WcaFinalize(er);
590}
diff --git a/src/ca/cpsubsexec.cpp b/src/ca/cpsubsexec.cpp
new file mode 100644
index 00000000..bbcf9853
--- /dev/null
+++ b/src/ca/cpsubsexec.cpp
@@ -0,0 +1,411 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_SUBSCRIPTION_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzID;
14 LPWSTR pwzName;
15 LPWSTR pwzEventCLSID;
16 LPWSTR pwzPublisherID;
17 LPWSTR pwzCompCLSID;
18 LPWSTR pwzAppID;
19 LPWSTR pwzPartID;
20 CPI_PROPERTY* pPropList;
21};
22
23
24// prototypes for private helper functions
25
26static HRESULT ReadSubscriptionAttributes(
27 LPWSTR* ppwzData,
28 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
29 );
30static void FreeSubscriptionAttributes(
31 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
32 );
33static HRESULT CreateSubscription(
34 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
35 );
36static HRESULT RemoveSubscription(
37 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
38 );
39
40
41// function definitions
42
43HRESULT CpiConfigureSubscriptions(
44 LPWSTR* ppwzData,
45 HANDLE hRollbackFile
46 )
47{
48 HRESULT hr = S_OK;
49
50 CPI_SUBSCRIPTION_ATTRIBUTES attrs;
51 ::ZeroMemory(&attrs, sizeof(attrs));
52
53 // read action text
54 hr = CpiActionStartMessage(ppwzData, FALSE);
55 ExitOnFailure(hr, "Failed to send action start message");
56
57 // ger count
58 int iCnt = 0;
59 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
60 ExitOnFailure(hr, "Failed to read count");
61
62 // write count to rollback file
63 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
64 ExitOnFailure(hr, "Failed to write count to rollback file");
65
66 for (int i = 0; i < iCnt; i++)
67 {
68 // read attributes from CustomActionData
69 hr = ReadSubscriptionAttributes(ppwzData, &attrs);
70 ExitOnFailure(hr, "Failed to read attributes");
71
72 // progress message
73 hr = CpiActionDataMessage(1, attrs.pwzName);
74 ExitOnFailure(hr, "Failed to send progress messages");
75
76 if (S_FALSE == hr)
77 ExitFunction();
78
79 // write key to rollback file
80 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
81 ExitOnFailure(hr, "Failed to write key to rollback file");
82
83 // action
84 switch (attrs.iActionType)
85 {
86 case atCreate:
87 hr = CreateSubscription(&attrs);
88 ExitOnFailure(hr, "Failed to create subscription, key: %S", attrs.pwzKey);
89 break;
90 case atRemove:
91 hr = RemoveSubscription(&attrs);
92 ExitOnFailure(hr, "Failed to remove subscription, key: %S", attrs.pwzKey);
93 break;
94 }
95
96 // write completion status to rollback file
97 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
98 ExitOnFailure(hr, "Failed to write completion status to rollback file");
99
100 // progress
101 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
102 ExitOnFailure(hr, "Failed to update progress");
103 }
104
105 hr = S_OK;
106
107LExit:
108 // clean up
109 FreeSubscriptionAttributes(&attrs);
110
111 return hr;
112}
113
114HRESULT CpiRollbackConfigureSubscriptions(
115 LPWSTR* ppwzData,
116 CPI_ROLLBACK_DATA* pRollbackDataList
117 )
118{
119 HRESULT hr = S_OK;
120
121 int iRollbackStatus;
122
123 CPI_SUBSCRIPTION_ATTRIBUTES attrs;
124 ::ZeroMemory(&attrs, sizeof(attrs));
125
126 // read action text
127 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
128 ExitOnFailure(hr, "Failed to send action start message");
129
130 // ger count
131 int iCnt = 0;
132 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
133 ExitOnFailure(hr, "Failed to read count");
134
135 for (int i = 0; i < iCnt; i++)
136 {
137 // read attributes from CustomActionData
138 hr = ReadSubscriptionAttributes(ppwzData, &attrs);
139 ExitOnFailure(hr, "Failed to read attributes");
140
141 // rollback status
142 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
143
144 if (S_FALSE == hr)
145 continue; // not found, nothing to rollback
146
147 // progress message
148 hr = CpiActionDataMessage(1, attrs.pwzName);
149 ExitOnFailure(hr, "Failed to send progress messages");
150
151 if (S_FALSE == hr)
152 ExitFunction();
153
154 // action
155 switch (attrs.iActionType)
156 {
157 case atCreate:
158 hr = CreateSubscription(&attrs);
159 if (FAILED(hr))
160 WcaLog(LOGMSG_STANDARD, "Failed to create subscription, hr: 0x%x, key: %S", hr, attrs.pwzKey);
161 break;
162 case atRemove:
163 hr = RemoveSubscription(&attrs);
164 if (FAILED(hr))
165 WcaLog(LOGMSG_STANDARD, "Failed to remove subscription, hr: 0x%x, key: %S", hr, attrs.pwzKey);
166 break;
167 }
168
169 // check rollback status
170 if (0 == iRollbackStatus)
171 continue; // operation did not complete, skip progress
172
173 // progress
174 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
175 ExitOnFailure(hr, "Failed to update progress");
176 }
177
178 hr = S_OK;
179
180LExit:
181 // clean up
182 FreeSubscriptionAttributes(&attrs);
183
184 return hr;
185}
186
187
188// helper function definitions
189
190static HRESULT ReadSubscriptionAttributes(
191 LPWSTR* ppwzData,
192 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
193 )
194{
195 HRESULT hr = S_OK;
196
197 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
198 ExitOnFailure(hr, "Failed to read action type");
199 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
200 ExitOnFailure(hr, "Failed to read action cost");
201 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
202 ExitOnFailure(hr, "Failed to read key");
203 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID);
204 ExitOnFailure(hr, "Failed to read id");
205 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
206 ExitOnFailure(hr, "Failed to read name");
207 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzEventCLSID);
208 ExitOnFailure(hr, "Failed to read event clsid");
209 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPublisherID);
210 ExitOnFailure(hr, "Failed to read publisher id");
211 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzCompCLSID);
212 ExitOnFailure(hr, "Failed to read component clsid");
213 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
214 ExitOnFailure(hr, "Failed to read application id");
215 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
216 ExitOnFailure(hr, "Failed to read partition id");
217
218 hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList);
219 ExitOnFailure(hr, "Failed to read properties");
220
221 hr = S_OK;
222
223LExit:
224 return hr;
225}
226
227static void FreeSubscriptionAttributes(
228 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
229 )
230{
231 ReleaseStr(pAttrs->pwzKey);
232 ReleaseStr(pAttrs->pwzID);
233 ReleaseStr(pAttrs->pwzName);
234 ReleaseStr(pAttrs->pwzEventCLSID);
235 ReleaseStr(pAttrs->pwzPublisherID);
236 ReleaseStr(pAttrs->pwzCompCLSID);
237 ReleaseStr(pAttrs->pwzAppID);
238 ReleaseStr(pAttrs->pwzPartID);
239
240 if (pAttrs->pPropList)
241 CpiFreePropertyList(pAttrs->pPropList);
242}
243
244static HRESULT CreateSubscription(
245 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
246 )
247{
248 HRESULT hr = S_OK;
249 UINT er = ERROR_SUCCESS;
250
251 ICatalogCollection* piSubsColl = NULL;
252 ICatalogObject* piSubsObj = NULL;
253
254 PSID pSid = NULL;
255 long lChanges = 0;
256
257 // log
258 WcaLog(LOGMSG_VERBOSE, "Creating subscription, key: %S", pAttrs->pwzKey);
259
260 // get subscriptions collection
261 hr = CpiGetSubscriptionsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzCompCLSID, &piSubsColl);
262 if (S_FALSE == hr)
263 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
264 ExitOnFailure(hr, "Failed to get subscriptions collection");
265
266 // check if subscription exists
267 hr = CpiFindCollectionObjectByStringKey(piSubsColl, pAttrs->pwzID, &piSubsObj);
268 ExitOnFailure(hr, "Failed to find subscription");
269
270 if (S_FALSE == hr)
271 {
272 // create subscription
273 hr = CpiAddCollectionObject(piSubsColl, &piSubsObj);
274 ExitOnFailure(hr, "Failed to add subscription to collection");
275
276 hr = CpiPutCollectionObjectValue(piSubsObj, L"ID", pAttrs->pwzID);
277 ExitOnFailure(hr, "Failed to set subscription id property");
278
279 hr = CpiPutCollectionObjectValue(piSubsObj, L"Name", pAttrs->pwzName);
280 ExitOnFailure(hr, "Failed to set subscription name property");
281
282 if (pAttrs->pwzEventCLSID && *pAttrs->pwzEventCLSID)
283 {
284 hr = CpiPutCollectionObjectValue(piSubsObj, L"EventCLSID", pAttrs->pwzEventCLSID);
285 ExitOnFailure(hr, "Failed to set role event clsid property");
286 }
287
288 if (pAttrs->pwzPublisherID && *pAttrs->pwzPublisherID)
289 {
290 hr = CpiPutCollectionObjectValue(piSubsObj, L"PublisherID", pAttrs->pwzPublisherID);
291 ExitOnFailure(hr, "Failed to set role publisher id property");
292 }
293 }
294
295 // properties
296 for (CPI_PROPERTY* pItm = pAttrs->pPropList; pItm; pItm = pItm->pNext)
297 {
298 // UserName property
299 if (0 == lstrcmpW(pItm->wzName, L"UserName"))
300 {
301 // get SID for account
302 do {
303 er = ERROR_SUCCESS;
304 hr = CpiAccountNameToSid(pItm->pwzValue, &pSid);
305 if (!::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
306 {
307 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr)
308 {
309 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pItm->pwzValue);
310 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
311 switch (er)
312 {
313 case IDABORT:
314 ExitFunction(); // exit with error code from CpiAccountNameToSid()
315 case IDRETRY:
316 break;
317 case IDIGNORE:
318 default:
319 hr = S_FALSE;
320 }
321 }
322 else
323 ExitOnFailure(hr, "Failed to get SID for account, account: '%S'", pItm->pwzValue);
324 }
325 else if (FAILED(hr))
326 {
327 WcaLog(LOGMSG_STANDARD, "Failed to get SID for account, hr: 0x%x, account: '%S'", hr, pItm->pwzValue);
328 hr = S_FALSE;
329 }
330 } while (IDRETRY == er);
331
332 if (S_FALSE == hr)
333 continue;
334
335 // convert SID back to account name
336 hr = CpiSidToAccountName(pSid, &pItm->pwzValue);
337 ExitOnFailure(hr, "Failed to convert SID to account name");
338 }
339
340 // set property
341 hr = CpiPutCollectionObjectValue(piSubsObj, pItm->wzName, pItm->pwzValue);
342 ExitOnFailure(hr, "Failed to set object property value, name: %S", pItm->wzName);
343 }
344
345 // save changes
346 hr = piSubsColl->SaveChanges(&lChanges);
347 if (COMADMIN_E_OBJECTERRORS == hr)
348 CpiLogCatalogErrorInfo();
349 ExitOnFailure(hr, "Failed to save changes");
350
351 // log
352 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
353
354 hr = S_OK;
355
356LExit:
357 // clean up
358 ReleaseObject(piSubsColl);
359 ReleaseObject(piSubsObj);
360
361 if (pSid)
362 ::HeapFree(::GetProcessHeap(), 0, pSid);
363
364 return hr;
365}
366
367static HRESULT RemoveSubscription(
368 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
369 )
370{
371 HRESULT hr = S_OK;
372
373 ICatalogCollection* piSubsColl = NULL;
374
375 long lChanges = 0;
376
377 // log
378 WcaLog(LOGMSG_VERBOSE, "Removing subscription, key: %S", pAttrs->pwzKey);
379
380 // get subscriptions collection
381 hr = CpiGetSubscriptionsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzCompCLSID, &piSubsColl);
382 ExitOnFailure(hr, "Failed to get subscriptions collection");
383
384 if (S_FALSE == hr)
385 {
386 // subscription not found
387 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve subscriptions collection, nothing to delete, key: %S", pAttrs->pwzKey);
388 ExitFunction1(hr = S_OK);
389 }
390
391 // remove
392 hr = CpiRemoveCollectionObject(piSubsColl, pAttrs->pwzID, NULL, FALSE);
393 ExitOnFailure(hr, "Failed to remove subscriptions");
394
395 // save changes
396 hr = piSubsColl->SaveChanges(&lChanges);
397 if (COMADMIN_E_OBJECTERRORS == hr)
398 CpiLogCatalogErrorInfo();
399 ExitOnFailure(hr, "Failed to save changes");
400
401 // log
402 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
403
404 hr = S_OK;
405
406LExit:
407 // clean up
408 ReleaseObject(piSubsColl);
409
410 return hr;
411}
diff --git a/src/ca/cpsubsexec.h b/src/ca/cpsubsexec.h
new file mode 100644
index 00000000..2f4d3c75
--- /dev/null
+++ b/src/ca/cpsubsexec.h
@@ -0,0 +1,12 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureSubscriptions(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureSubscriptions(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
diff --git a/src/ca/cpsubssched.cpp b/src/ca/cpsubssched.cpp
new file mode 100644
index 00000000..73fd4f6d
--- /dev/null
+++ b/src/ca/cpsubssched.cpp
@@ -0,0 +1,606 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsSubscriptionQuery =
9 L"SELECT `Subscription`, `ComPlusComponent_`, `Component_`, `Id`, `Name`, `EventCLSID`, `PublisherID` FROM `ComPlusSubscription`";
10enum eSubscriptionQuery { sqSubscription = 1, sqComPlusComponent, sqComponent, sqID, sqName, sqEventCLSID, sqPublisherID };
11
12LPCWSTR vcsSubscriptionPropertyQuery =
13 L"SELECT `Name`, `Value` FROM `ComPlusSubscriptionProperty` WHERE `Subscription_` = ?";
14
15
16// property definitions
17
18CPI_PROPERTY_DEFINITION pdlSubscriptionProperties[] =
19{
20 {L"Description", cpptString, 500},
21 {L"Enabled", cpptBoolean, 500},
22 {L"EventClassPartitionID", cpptString, 502},
23 {L"FilterCriteria", cpptString, 500},
24 {L"InterfaceID", cpptString, 500},
25 {L"MachineName", cpptString, 500},
26 {L"MethodName", cpptString, 500},
27 {L"PerUser", cpptBoolean, 500},
28 {L"Queued", cpptBoolean, 500},
29 {L"SubscriberMoniker", cpptString, 500},
30 {L"UserName", cpptUser, 500},
31 {NULL, cpptNone, 0}
32};
33
34
35// prototypes for private helper functions
36
37static void FreeSubscription(
38 CPI_SUBSCRIPTION* pItm
39 );
40static HRESULT FindObjectForSubscription(
41 CPI_SUBSCRIPTION* pItm,
42 BOOL fFindId,
43 BOOL fFindName,
44 ICatalogObject** ppiSubsObj
45 );
46static HRESULT AddSubscriptionToActionData(
47 CPI_SUBSCRIPTION* pItm,
48 int iActionType,
49 int iActionCost,
50 LPWSTR* ppwzActionData
51 );
52static HRESULT ComponentFindByKey(
53 CPI_ASSEMBLY_LIST* pAsmList,
54 LPCWSTR pwzKey,
55 CPI_ASSEMBLY** ppAsmItm,
56 CPI_COMPONENT** ppCompItm
57 );
58
59
60// function definitions
61
62void CpiSubscriptionListFree(
63 CPI_SUBSCRIPTION_LIST* pList
64 )
65{
66 CPI_SUBSCRIPTION* pItm = pList->pFirst;
67
68 while (pItm)
69 {
70 CPI_SUBSCRIPTION* pDelete = pItm;
71 pItm = pItm->pNext;
72 FreeSubscription(pDelete);
73 }
74}
75
76HRESULT CpiSubscriptionsRead(
77 CPI_ASSEMBLY_LIST* pAsmList,
78 CPI_SUBSCRIPTION_LIST* pSubList
79 )
80{
81 HRESULT hr = S_OK;
82 UINT er = ERROR_SUCCESS;
83
84 PMSIHANDLE hView, hRec;
85
86 CPI_SUBSCRIPTION* pItm = NULL;
87 LPWSTR pwzData = NULL;
88 BOOL fMatchingArchitecture = FALSE;
89
90 // loop through all applications
91 hr = WcaOpenExecuteView(vcsSubscriptionQuery, &hView);
92 ExitOnFailure(hr, "Failed to execute view on ComPlusSubscription table");
93
94 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
95 {
96 // get component
97 hr = WcaGetRecordString(hRec, sqComponent, &pwzData);
98 ExitOnFailure(hr, "Failed to get component");
99
100 // check if the component is our processor architecture
101 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
102 ExitOnFailure(hr, "Failed to get component architecture.");
103
104 if (!fMatchingArchitecture)
105 {
106 continue; // not the same architecture, ignore
107 }
108
109 // create entry
110 pItm = (CPI_SUBSCRIPTION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_SUBSCRIPTION));
111 if (!pItm)
112 ExitFunction1(hr = E_OUTOFMEMORY);
113
114 // get component install state
115 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
116 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
117
118 // get key
119 hr = WcaGetRecordString(hRec, sqSubscription, &pwzData);
120 ExitOnFailure(hr, "Failed to get key");
121 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
122
123 // get com+ component
124 hr = WcaGetRecordString(hRec, sqComPlusComponent, &pwzData);
125 ExitOnFailure(hr, "Failed to get COM+ component");
126
127 hr = ComponentFindByKey(pAsmList, pwzData, &pItm->pAssembly, &pItm->pComponent);
128
129 if (S_FALSE == hr)
130 {
131 // component not found
132 ExitOnFailure(hr = E_FAIL, "Failed to find component, key: %S", pwzData);
133 }
134
135 // get id
136 hr = WcaGetRecordFormattedString(hRec, sqID, &pwzData);
137 ExitOnFailure(hr, "Failed to get id");
138
139 if (pwzData && *pwzData)
140 {
141 hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID));
142 ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData);
143 }
144
145 // get name
146 hr = WcaGetRecordFormattedString(hRec, sqName, &pwzData);
147 ExitOnFailure(hr, "Failed to get name");
148 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
149
150 // get event clsid
151 hr = WcaGetRecordFormattedString(hRec, sqEventCLSID, &pwzData);
152 ExitOnFailure(hr, "Failed to get event clsid");
153 StringCchCopyW(pItm->wzEventCLSID, countof(pItm->wzEventCLSID), pwzData);
154
155 // get publisher id
156 hr = WcaGetRecordFormattedString(hRec, sqPublisherID, &pwzData);
157 ExitOnFailure(hr, "Failed to get publisher id");
158 StringCchCopyW(pItm->wzPublisherID, countof(pItm->wzPublisherID), pwzData);
159
160 // get properties
161 if (CpiTableExists(cptComPlusSubscriptionProperty))
162 {
163 hr = CpiPropertiesRead(vcsSubscriptionPropertyQuery, pItm->wzKey, pdlSubscriptionProperties, &pItm->pProperties, &pItm->iPropertyCount);
164 ExitOnFailure(hr, "Failed to get subscription properties");
165 }
166
167 // set references & increment counters
168 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
169 {
170 CpiApplicationAddReferenceInstall(pItm->pAssembly->pApplication);
171 pItm->pAssembly->fReferencedForInstall = TRUE;
172 pSubList->iInstallCount++;
173 if (pItm->pAssembly->iAttributes & aaRunInCommit)
174 pSubList->iCommitCount++;
175 }
176 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
177 {
178 CpiApplicationAddReferenceUninstall(pItm->pAssembly->pApplication);
179 pItm->pAssembly->fReferencedForUninstall = TRUE;
180 pSubList->iUninstallCount++;
181 }
182
183 // add entry
184 if (pSubList->pFirst)
185 pItm->pNext = pSubList->pFirst;
186 pSubList->pFirst = pItm;
187 pItm = NULL;
188 }
189
190 if (E_NOMOREITEMS == hr)
191 hr = S_OK;
192
193LExit:
194 // clean up
195 if (pItm)
196 FreeSubscription(pItm);
197
198 ReleaseStr(pwzData);
199
200 return hr;
201}
202
203HRESULT CpiSubscriptionsVerifyInstall(
204 CPI_SUBSCRIPTION_LIST* pList
205 )
206{
207 HRESULT hr = S_OK;
208 UINT er = ERROR_SUCCESS;
209
210 ICatalogObject* piSubsObj = NULL;
211
212 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
213 {
214 // subscriptions that are being installed
215 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
216 continue;
217
218 // subscription is supposed to exist
219 if (CpiIsInstalled(pItm->isInstalled))
220 {
221 // if we don't have an id
222 if (!*pItm->wzID)
223 {
224 // find subscriptions with conflicting name
225 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
226 ExitOnFailure(hr, "Failed to find collection object for subscription");
227
228 // if the subscription was found
229 if (S_OK == hr)
230 {
231 // get id from subscription object
232 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
233 ExitOnFailure(hr, "Failed to get id");
234 }
235
236 // if the subscription was not found
237 else
238 {
239 // create a new id
240 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
241 ExitOnFailure(hr, "Failed to create id");
242 }
243 }
244 }
245
246 // subscription is supposed to be created
247 else
248 {
249 // check for conflicts
250 do {
251 if (*pItm->wzID)
252 {
253 // find subscriptions with conflicting id
254 hr = FindObjectForSubscription(pItm, TRUE, FALSE, &piSubsObj);
255 ExitOnFailure(hr, "Failed to find collection object for subscription");
256
257 if (S_FALSE == hr)
258 {
259 // find subscriptions with conflicting name
260 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
261 ExitOnFailure(hr, "Failed to find collection object for subscription");
262
263 if (S_OK == hr)
264 // "A subscription with a conflictiong name exists. retry cancel"
265 er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
266 else
267 break; // no conflicting entry found, break loop
268 }
269 else
270 // "A subscription with a conflicting id exists. abort retry ignore"
271 er = WcaErrorMessage(msierrComPlusSubscriptionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
272 }
273 else
274 {
275 // find subscriptions with conflicting name
276 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
277 ExitOnFailure(hr, "Failed to find collection object for subscription");
278
279 if (S_OK == hr)
280 // "A subscription with a conflictiong name exists. abort retry ignore"
281 er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
282 else
283 break; // no conflicting entry found, break loop
284 }
285
286 switch (er)
287 {
288 case IDCANCEL:
289 case IDABORT:
290 ExitOnFailure(hr = E_FAIL, "A subscription with a conflictiong name or id exists, key: %S", pItm->wzKey);
291 break;
292 case IDRETRY:
293 break;
294 case IDIGNORE:
295 default:
296 // if we don't have an id, copy id from object
297 if (!*pItm->wzID)
298 {
299 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
300 ExitOnFailure(hr, "Failed to get id");
301 }
302 hr = S_FALSE; // indicate that this is not a conflict
303 }
304 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
305
306 // create a new id if one is missing
307 if (!*pItm->wzID)
308 {
309 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
310 ExitOnFailure(hr, "Failed to create id");
311 }
312 }
313
314 // clean up
315 ReleaseNullObject(piSubsObj);
316 }
317
318 hr = S_OK;
319
320LExit:
321 // clean up
322 ReleaseObject(piSubsObj);
323
324 return hr;
325}
326
327HRESULT CpiSubscriptionsVerifyUninstall(
328 CPI_SUBSCRIPTION_LIST* pList
329 )
330{
331 HRESULT hr = S_OK;
332 ICatalogObject* piSubsObj = NULL;
333
334 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
335 {
336 // subscriptions that are being installed
337 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
338 continue;
339
340 // find subscriptions with conflicting name
341 hr = FindObjectForSubscription(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piSubsObj);
342 ExitOnFailure(hr, "Failed to find collection object for subscription");
343
344 // if the subscription was found
345 if (S_OK == hr)
346 {
347 // if we don't have an id, copy id from object
348 if (!*pItm->wzID)
349 {
350 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
351 ExitOnFailure(hr, "Failed to get id");
352 }
353 }
354
355 // if the subscription was not found
356 else
357 {
358 pItm->fObjectNotFound = TRUE;
359 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
360 }
361
362 // clean up
363 ReleaseNullObject(piSubsObj);
364 }
365
366 hr = S_OK;
367
368LExit:
369 // clean up
370 ReleaseObject(piSubsObj);
371
372 return hr;
373}
374
375HRESULT CpiSubscriptionsInstall(
376 CPI_SUBSCRIPTION_LIST* pList,
377 int iRunMode,
378 LPWSTR* ppwzActionData,
379 int* piProgress
380 )
381{
382 HRESULT hr = S_OK;
383
384 int iActionType;
385 int iCount = 0;
386
387 // add action text
388 hr = CpiAddActionTextToActionData(L"CreateSubscrComPlusComponents", ppwzActionData);
389 ExitOnFailure(hr, "Failed to add action text to custom action data");
390
391 // subscription count
392 switch (iRunMode)
393 {
394 case rmDeferred:
395 iCount = pList->iInstallCount - pList->iCommitCount;
396 break;
397 case rmCommit:
398 iCount = pList->iCommitCount;
399 break;
400 case rmRollback:
401 iCount = pList->iInstallCount;
402 break;
403 }
404
405 // add subscription count to action data
406 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
407 ExitOnFailure(hr, "Failed to add count to custom action data");
408
409 // add assemblies to custom action data in forward order
410 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
411 {
412 // roles that are being installed only
413 if ((rmCommit == iRunMode && !(pItm->pAssembly->iAttributes & aaRunInCommit)) ||
414 (rmDeferred == iRunMode && (pItm->pAssembly->iAttributes & aaRunInCommit)) ||
415 !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
416 continue;
417
418 // action type
419 if (rmRollback == iRunMode)
420 {
421 if (CpiIsInstalled(pItm->isInstalled))
422 iActionType = atNoOp;
423 else
424 iActionType = atRemove;
425 }
426 else
427 iActionType = atCreate;
428
429 // add to action data
430 hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_CREATE, ppwzActionData);
431 ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey);
432 }
433
434 // add progress tics
435 if (piProgress)
436 *piProgress += COST_SUBSCRIPTION_CREATE * pList->iInstallCount;
437
438 hr = S_OK;
439
440LExit:
441 return hr;
442}
443
444HRESULT CpiSubscriptionsUninstall(
445 CPI_SUBSCRIPTION_LIST* pList,
446 int iRunMode,
447 LPWSTR* ppwzActionData,
448 int* piProgress
449 )
450{
451 HRESULT hr = S_OK;
452
453 int iActionType;
454
455 // add action text
456 hr = CpiAddActionTextToActionData(L"RemoveSubscrComPlusComponents", ppwzActionData);
457 ExitOnFailure(hr, "Failed to add action text to custom action data");
458
459 // add subscription count to action data
460 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
461 ExitOnFailure(hr, "Failed to add count to custom action data");
462
463 // add assemblies to custom action data in reverse order
464 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
465 {
466 // roles that are being uninstalled only
467 if (pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
468 continue;
469
470 // action type
471 if (rmRollback == iRunMode)
472 iActionType = atCreate;
473 else
474 iActionType = atRemove;
475
476 // add to action data
477 hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_DELETE, ppwzActionData);
478 ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey);
479 }
480
481 // add progress tics
482 if (piProgress)
483 *piProgress += COST_SUBSCRIPTION_DELETE * pList->iUninstallCount;
484
485 hr = S_OK;
486
487LExit:
488 return hr;
489}
490
491
492// helper function definitions
493
494static void FreeSubscription(
495 CPI_SUBSCRIPTION* pItm
496 )
497{
498 if (pItm->pProperties)
499 CpiPropertiesFreeList(pItm->pProperties);
500
501 ::HeapFree(::GetProcessHeap(), 0, pItm);
502}
503
504static HRESULT FindObjectForSubscription(
505 CPI_SUBSCRIPTION* pItm,
506 BOOL fFindId,
507 BOOL fFindName,
508 ICatalogObject** ppiSubsObj
509 )
510{
511 HRESULT hr = S_OK;
512
513 ICatalogCollection* piSubsColl = NULL;
514
515 // get applications collection
516 hr = CpiGetSubscriptionsCollForComponent(pItm->pAssembly, pItm->pComponent, &piSubsColl);
517 ExitOnFailure(hr, "Failed to get collection");
518
519 if (S_FALSE == hr)
520 ExitFunction(); // exit with hr = S_FALSE
521
522 // find application object
523 hr = CpiFindCollectionObject(piSubsColl, fFindId ? pItm->wzID : NULL, fFindName ? pItm->wzName : NULL, ppiSubsObj);
524 ExitOnFailure(hr, "Failed to find object");
525
526 // exit with hr from CpiFindCollectionObject()
527
528LExit:
529 // clean up
530 ReleaseObject(piSubsColl);
531
532 return hr;
533}
534
535static HRESULT AddSubscriptionToActionData(
536 CPI_SUBSCRIPTION* pItm,
537 int iActionType,
538 int iActionCost,
539 LPWSTR* ppwzActionData
540 )
541{
542 HRESULT hr = S_OK;
543
544 // add action information to custom action data
545 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
546 ExitOnFailure(hr, "Failed to add action type to custom action data");
547 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
548 ExitOnFailure(hr, "Failed to add action cost to custom action data");
549
550 // add application role information to custom action data
551 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
552 ExitOnFailure(hr, "Failed to add subscription key to custom action data");
553 hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
554 ExitOnFailure(hr, "Failed to add subscription id to custom action data");
555 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
556 ExitOnFailure(hr, "Failed to add subscription name to custom action data");
557 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzEventCLSID : L"", ppwzActionData);
558 ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data");
559 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzPublisherID : L"", ppwzActionData);
560 ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data");
561
562 // add component information to custom action data
563 hr = WcaWriteStringToCaData(pItm->pComponent->wzCLSID, ppwzActionData);
564 ExitOnFailure(hr, "Failed to add application id to custom action data");
565
566 // add application information to custom action data
567 hr = WcaWriteStringToCaData(pItm->pAssembly->pApplication->wzID, ppwzActionData);
568 ExitOnFailure(hr, "Failed to add application id to custom action data");
569
570 // add partition information to custom action data
571 LPCWSTR pwzPartID = pItm->pAssembly->pApplication->pPartition ? pItm->pAssembly->pApplication->pPartition->wzID : L"";
572 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
573 ExitOnFailure(hr, "Failed to add partition id to custom action data");
574
575 // add properties to custom action data
576 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
577 ExitOnFailure(hr, "Failed to add properties to custom action data");
578
579 hr = S_OK;
580
581LExit:
582 return hr;
583}
584
585static HRESULT ComponentFindByKey(
586 CPI_ASSEMBLY_LIST* pAsmList,
587 LPCWSTR pwzKey,
588 CPI_ASSEMBLY** ppAsmItm,
589 CPI_COMPONENT** ppCompItm
590 )
591{
592 for (CPI_ASSEMBLY* pAsmItm = pAsmList->pFirst; pAsmItm; pAsmItm = pAsmItm->pNext)
593 {
594 for (CPI_COMPONENT* pCompItm = pAsmItm->pComponents; pCompItm; pCompItm = pCompItm->pNext)
595 {
596 if (0 == lstrcmpW(pCompItm->wzKey, pwzKey))
597 {
598 *ppAsmItm = pAsmItm;
599 *ppCompItm = pCompItm;
600 return S_OK;
601 }
602 }
603 }
604
605 return S_FALSE;
606}
diff --git a/src/ca/cpsubssched.h b/src/ca/cpsubssched.h
new file mode 100644
index 00000000..3fc18478
--- /dev/null
+++ b/src/ca/cpsubssched.h
@@ -0,0 +1,62 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_SUBSCRIPTION
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzID[CPI_MAX_GUID + 1];
9 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
10 WCHAR wzEventCLSID[CPI_MAX_GUID + 1];
11 WCHAR wzPublisherID[CPI_MAX_GUID + 1];
12
13 BOOL fObjectNotFound;
14
15 int iPropertyCount;
16 CPI_PROPERTY* pProperties;
17
18 INSTALLSTATE isInstalled, isAction;
19
20 CPI_ASSEMBLY* pAssembly;
21 CPI_COMPONENT* pComponent;
22
23 CPI_SUBSCRIPTION* pNext;
24};
25
26struct CPI_SUBSCRIPTION_LIST
27{
28 CPI_SUBSCRIPTION* pFirst;
29
30 int iInstallCount;
31 int iCommitCount;
32 int iUninstallCount;
33};
34
35
36// function prototypes
37
38void CpiSubscriptionListFree(
39 CPI_SUBSCRIPTION_LIST* pList
40 );
41HRESULT CpiSubscriptionsRead(
42 CPI_ASSEMBLY_LIST* pAsmList,
43 CPI_SUBSCRIPTION_LIST* pSubList
44 );
45HRESULT CpiSubscriptionsVerifyInstall(
46 CPI_SUBSCRIPTION_LIST* pList
47 );
48HRESULT CpiSubscriptionsVerifyUninstall(
49 CPI_SUBSCRIPTION_LIST* pList
50 );
51HRESULT CpiSubscriptionsInstall(
52 CPI_SUBSCRIPTION_LIST* pList,
53 int iRunMode,
54 LPWSTR* ppwzActionData,
55 int* piProgress
56 );
57HRESULT CpiSubscriptionsUninstall(
58 CPI_SUBSCRIPTION_LIST* pList,
59 int iRunMode,
60 LPWSTR* ppwzActionData,
61 int* piProgress
62 );
diff --git a/src/ca/cputilexec.cpp b/src/ca/cputilexec.cpp
new file mode 100644
index 00000000..e081678b
--- /dev/null
+++ b/src/ca/cputilexec.cpp
@@ -0,0 +1,1881 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_WELLKNOWN_SID
9{
10 LPCWSTR pwzName;
11 SID_IDENTIFIER_AUTHORITY iaIdentifierAuthority;
12 BYTE nSubAuthorityCount;
13 DWORD dwSubAuthority[8];
14};
15
16
17// well known SIDs
18
19CPI_WELLKNOWN_SID wsWellKnownSids[] = {
20 {L"\\Everyone", SECURITY_WORLD_SID_AUTHORITY, 1, {SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0}},
21 {L"\\Administrators", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0}},
22 {L"\\LocalSystem", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0}},
23 {L"\\LocalService", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}},
24 {L"\\NetworkService", SECURITY_NT_AUTHORITY, 1, {SECURITY_NETWORK_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}},
25 {L"\\AuthenticatedUser", SECURITY_NT_AUTHORITY, 1, {SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0}},
26 {L"\\Guests", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0, 0, 0, 0, 0, 0}},
27 {L"\\Users", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0}},
28 {L"\\CREATOR OWNER", SECURITY_NT_AUTHORITY, 1, {SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, 0}},
29 {NULL, SECURITY_NULL_SID_AUTHORITY, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
30};
31
32
33// prototypes for private helper functions
34
35static HRESULT FindUserCollectionObjectIndex(
36 ICatalogCollection* piColl,
37 PSID pSid,
38 int* pi
39 );
40static HRESULT CreateSidFromDomainRidPair(
41 PSID pDomainSid,
42 DWORD dwRid,
43 PSID* ppSid
44 );
45static HRESULT InitLsaUnicodeString(
46 PLSA_UNICODE_STRING plusStr,
47 LPCWSTR pwzStr,
48 DWORD dwLen
49 );
50static void FreeLsaUnicodeString(
51 PLSA_UNICODE_STRING plusStr
52 );
53static HRESULT WriteFileAll(
54 HANDLE hFile,
55 PBYTE pbBuffer,
56 DWORD dwBufferLength
57 );
58static HRESULT ReadFileAll(
59 HANDLE hFile,
60 PBYTE pbBuffer,
61 DWORD dwBufferLength
62 );
63
64
65// variables
66
67static ICOMAdminCatalog* gpiCatalog;
68
69
70// function definitions
71
72void CpiInitialize()
73{
74 // collections
75 gpiCatalog = NULL;
76}
77
78void CpiFinalize()
79{
80 // collections
81 ReleaseObject(gpiCatalog);
82}
83
84HRESULT CpiActionStartMessage(
85 LPWSTR* ppwzActionData,
86 BOOL fSuppress
87 )
88{
89 HRESULT hr = S_OK;
90 UINT er = ERROR_SUCCESS;
91
92 PMSIHANDLE hRec;
93
94 LPWSTR pwzData = NULL;
95
96 // create record
97 hRec = ::MsiCreateRecord(3);
98 ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record");
99
100 // action name
101 hr = WcaReadStringFromCaData(ppwzActionData, &pwzData);
102 ExitOnFailure(hr, "Failed to action name");
103
104 er = ::MsiRecordSetStringW(hRec, 1, pwzData);
105 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set action name");
106
107 // description
108 hr = WcaReadStringFromCaData(ppwzActionData, &pwzData);
109 ExitOnFailure(hr, "Failed to description");
110
111 er = ::MsiRecordSetStringW(hRec, 2, pwzData);
112 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set description");
113
114 // template
115 hr = WcaReadStringFromCaData(ppwzActionData, &pwzData);
116 ExitOnFailure(hr, "Failed to template");
117
118 er = ::MsiRecordSetStringW(hRec, 3, pwzData);
119 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set template");
120
121 // message
122 if (!fSuppress)
123 {
124 er = WcaProcessMessage(INSTALLMESSAGE_ACTIONSTART, hRec);
125 if (0 == er || IDOK == er || IDYES == er)
126 {
127 hr = S_OK;
128 }
129 else if (IDABORT == er || IDCANCEL == er)
130 {
131 WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit
132 hr = S_FALSE;
133 }
134 else
135 hr = E_UNEXPECTED;
136 }
137
138LExit:
139 // clean up
140 ReleaseStr(pwzData);
141
142 return hr;
143}
144
145HRESULT CpiActionDataMessage(
146 DWORD cArgs,
147 ...
148 )
149{
150 HRESULT hr = S_OK;
151 UINT er = ERROR_SUCCESS;
152
153 PMSIHANDLE hRec;
154 va_list args;
155
156 // record
157 hRec = ::MsiCreateRecord(cArgs);
158 ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record");
159
160 va_start(args, cArgs);
161 for (DWORD i = 1; i <= cArgs; i++)
162 {
163 LPCWSTR pwzArg = va_arg(args, WCHAR*);
164 if (pwzArg && *pwzArg)
165 {
166 er = ::MsiRecordSetStringW(hRec, i, pwzArg);
167 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set record field string");
168 }
169 }
170 va_end(args);
171
172 // message
173 er = WcaProcessMessage(INSTALLMESSAGE_ACTIONDATA, hRec);
174 if (0 == er || IDOK == er || IDYES == er)
175 {
176 hr = S_OK;
177 }
178 else if (IDABORT == er || IDCANCEL == er)
179 {
180 WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit
181 hr = S_FALSE;
182 }
183 else
184 hr = E_UNEXPECTED;
185
186LExit:
187 return hr;
188}
189
190HRESULT CpiGetAdminCatalog(
191 ICOMAdminCatalog** ppiCatalog
192 )
193{
194 HRESULT hr = S_OK;
195
196 if (!gpiCatalog)
197 {
198 // get collection
199 hr = ::CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_ALL, IID_ICOMAdminCatalog, (void**)&gpiCatalog);
200 ExitOnFailure(hr, "Failed to create COM+ admin catalog object");
201 }
202
203 // return value
204 gpiCatalog->AddRef();
205 *ppiCatalog = gpiCatalog;
206
207 hr = S_OK;
208
209LExit:
210 return hr;
211}
212
213HRESULT CpiLogCatalogErrorInfo()
214{
215 HRESULT hr = S_OK;
216
217 ICOMAdminCatalog* piCatalog = NULL;
218 ICatalogCollection* piErrColl = NULL;
219 IDispatch* piDisp = NULL;
220 ICatalogObject* piObj = NULL;
221
222 LPWSTR pwzName = NULL;
223 LPWSTR pwzErrorCode = NULL;
224 LPWSTR pwzMajorRef = NULL;
225 LPWSTR pwzMinorRef = NULL;
226
227 // get catalog
228 hr = CpiGetAdminCatalog(&piCatalog);
229 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
230
231 // get error info collection
232 hr = CpiGetCatalogCollection(L"ErrorInfo", &piErrColl);
233 ExitOnFailure(hr, "Failed to get error info collection");
234
235 // loop objects
236 long lCnt;
237 hr = piErrColl->get_Count(&lCnt);
238 ExitOnFailure(hr, "Failed to get to number of items in collection");
239
240 for (long i = 0; i < lCnt; i++)
241 {
242 // get ICatalogObject interface
243 hr = piErrColl->get_Item(i, &piDisp);
244 ExitOnFailure(hr, "Failed to get item from partitions collection");
245
246 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
247 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
248
249 // get properties
250 hr = CpiGetCollectionObjectValue(piObj, L"Name", &pwzName);
251 ExitOnFailure(hr, "Failed to get name");
252 hr = CpiGetCollectionObjectValue(piObj, L"ErrorCode", &pwzErrorCode);
253 ExitOnFailure(hr, "Failed to get error code");
254 hr = CpiGetCollectionObjectValue(piObj, L"MajorRef", &pwzMajorRef);
255 ExitOnFailure(hr, "Failed to get major ref");
256 hr = CpiGetCollectionObjectValue(piObj, L"MinorRef", &pwzMinorRef);
257 ExitOnFailure(hr, "Failed to get minor ref");
258
259 // write to log
260 WcaLog(LOGMSG_STANDARD, "ErrorInfo: Name='%S', ErrorCode='%S', MajorRef='%S', MinorRef='%S'",
261 pwzName, pwzErrorCode, pwzMajorRef, pwzMinorRef);
262
263 // clean up
264 ReleaseNullObject(piDisp);
265 ReleaseNullObject(piObj);
266 }
267
268 hr = S_OK;
269
270LExit:
271 // clean up
272 ReleaseObject(piCatalog);
273 ReleaseObject(piErrColl);
274 ReleaseObject(piDisp);
275 ReleaseObject(piObj);
276
277 ReleaseStr(pwzName);
278 ReleaseStr(pwzErrorCode);
279 ReleaseStr(pwzMajorRef);
280 ReleaseStr(pwzMinorRef);
281
282 return hr;
283}
284
285HRESULT CpiGetCatalogCollection(
286 LPCWSTR pwzName,
287 ICatalogCollection** ppiColl
288 )
289{
290 HRESULT hr = S_OK;
291
292 ICOMAdminCatalog* piCatalog = NULL;
293 IDispatch* piDisp = NULL;
294
295 BSTR bstrName = NULL;
296
297 // copy name string
298 bstrName = ::SysAllocString(pwzName);
299 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name");
300
301 // get catalog
302 hr = CpiGetAdminCatalog(&piCatalog);
303 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
304
305 // get collecton from catalog
306 hr = piCatalog->GetCollection(bstrName, &piDisp);
307 ExitOnFailure(hr, "Failed to get collection");
308
309 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
310 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
311
312 // populate collection
313 hr = (*ppiColl)->Populate();
314 if (COMADMIN_E_OBJECTERRORS == hr)
315 CpiLogCatalogErrorInfo();
316 ExitOnFailure(hr, "Failed to populate collection");
317
318 hr = S_OK;
319
320LExit:
321 // clean up
322 ReleaseObject(piCatalog);
323 ReleaseObject(piDisp);
324 ReleaseBSTR(bstrName);
325
326 return hr;
327}
328
329HRESULT CpiGetCatalogCollection(
330 ICatalogCollection* piColl,
331 ICatalogObject* piObj,
332 LPCWSTR pwzName,
333 ICatalogCollection** ppiColl
334 )
335{
336 HRESULT hr = S_OK;
337
338 ICOMAdminCatalog* piCatalog = NULL;
339 IDispatch* piDisp = NULL;
340
341 BSTR bstrName = NULL;
342
343 VARIANT vtKey;
344 ::VariantInit(&vtKey);
345
346 // copy name string
347 bstrName = ::SysAllocString(pwzName);
348 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name");
349
350 // get catalog
351 hr = CpiGetAdminCatalog(&piCatalog);
352 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
353
354 // get key
355 hr = piObj->get_Key(&vtKey);
356 ExitOnFailure(hr, "Failed to get object key");
357
358 // get collecton from catalog
359 hr = piColl->GetCollection(bstrName, vtKey, &piDisp);
360 ExitOnFailure(hr, "Failed to get collection");
361
362 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
363 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
364
365 // populate collection
366 hr = (*ppiColl)->Populate();
367 if (COMADMIN_E_OBJECTERRORS == hr)
368 CpiLogCatalogErrorInfo();
369 ExitOnFailure(hr, "Failed to populate collection");
370
371 hr = S_OK;
372
373LExit:
374 // clean up
375 ReleaseObject(piCatalog);
376 ReleaseObject(piDisp);
377 ReleaseBSTR(bstrName);
378 ::VariantClear(&vtKey);
379
380 return hr;
381}
382
383HRESULT CpiAddCollectionObject(
384 ICatalogCollection* piColl,
385 ICatalogObject** ppiObj
386 )
387{
388 HRESULT hr = S_OK;
389
390 IDispatch* piDisp = NULL;
391
392 hr = piColl->Add(&piDisp);
393 ExitOnFailure(hr, "Failed to add object to collection");
394
395 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)ppiObj);
396 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
397
398 hr = S_OK;
399
400LExit:
401 // clean up
402 ReleaseObject(piDisp);
403
404 return hr;
405}
406
407HRESULT CpiPutCollectionObjectValue(
408 ICatalogObject* piObj,
409 LPCWSTR pwzPropName,
410 LPCWSTR pwzValue
411 )
412{
413 HRESULT hr = S_OK;
414
415 BSTR bstrPropName = NULL;
416
417 VARIANT vtVal;
418 ::VariantInit(&vtVal);
419
420 // allocate property name string
421 bstrPropName = ::SysAllocString(pwzPropName);
422 ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate property name string");
423
424 // prepare value variant
425 vtVal.vt = VT_BSTR;
426 vtVal.bstrVal = ::SysAllocString(pwzValue);
427 ExitOnNull(vtVal.bstrVal, hr, E_OUTOFMEMORY, "Failed to allocate property value string");
428
429 // put value
430 hr = piObj->put_Value(bstrPropName, vtVal);
431 ExitOnFailure(hr, "Failed to put property value");
432
433 hr = S_OK;
434
435LExit:
436 // clean up
437 ReleaseBSTR(bstrPropName);
438 ::VariantClear(&vtVal);
439
440 return hr;
441}
442
443HRESULT CpiPutCollectionObjectValues(
444 ICatalogObject* piObj,
445 CPI_PROPERTY* pPropList
446 )
447{
448 HRESULT hr = S_OK;
449
450 for (CPI_PROPERTY* pItm = pPropList; pItm; pItm = pItm->pNext)
451 {
452 // set property
453 hr = CpiPutCollectionObjectValue(piObj, pItm->wzName, pItm->pwzValue);
454 ExitOnFailure(hr, "Failed to set object property value, name: %S", pItm->wzName);
455 }
456
457 hr = S_OK;
458
459LExit:
460 return hr;
461}
462
463HRESULT CpiGetCollectionObjectValue(
464 ICatalogObject* piObj,
465 LPCWSTR szPropName,
466 LPWSTR* ppwzValue
467 )
468{
469 HRESULT hr = S_OK;
470
471 BSTR bstrPropName = NULL;
472
473 VARIANT vtVal;
474 ::VariantInit(&vtVal);
475
476 // allocate property name string
477 bstrPropName = ::SysAllocString(szPropName);
478 ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate property name string");
479
480 // get value
481 hr = piObj->get_Value(bstrPropName, &vtVal);
482 ExitOnFailure(hr, "Failed to get property value");
483
484 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
485 ExitOnFailure(hr, "Failed to change variant type");
486
487 hr = StrAllocString(ppwzValue, vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal));
488 ExitOnFailure(hr, "Failed to allocate memory for value string");
489
490 hr = S_OK;
491
492LExit:
493 // clean up
494 ReleaseBSTR(bstrPropName);
495 ::VariantClear(&vtVal);
496
497 return hr;
498}
499
500HRESULT CpiResetObjectProperty(
501 ICatalogCollection* piColl,
502 ICatalogObject* piObj,
503 LPCWSTR pwzPropName
504 )
505{
506 HRESULT hr = S_OK;
507
508 BSTR bstrPropName = NULL;
509
510 long lChanges = 0;
511
512 VARIANT vtVal;
513 ::VariantInit(&vtVal);
514
515 // allocate property name string
516 bstrPropName = ::SysAllocString(pwzPropName);
517 ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate deleteable property name string");
518
519 // get value
520 hr = piObj->get_Value(bstrPropName, &vtVal);
521 ExitOnFailure(hr, "Failed to get deleteable property value");
522
523 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BOOL);
524 ExitOnFailure(hr, "Failed to change variant type");
525
526 // if the deleteable property is set
527 if (VARIANT_FALSE == vtVal.boolVal)
528 {
529 // clear property
530 vtVal.boolVal = VARIANT_TRUE;
531
532 hr = piObj->put_Value(bstrPropName, vtVal);
533 ExitOnFailure(hr, "Failed to get property value");
534
535 // save changes
536 hr = piColl->SaveChanges(&lChanges);
537 if (COMADMIN_E_OBJECTERRORS == hr)
538 CpiLogCatalogErrorInfo();
539 ExitOnFailure(hr, "Failed to save changes");
540 }
541
542 hr = S_OK;
543
544LExit:
545 // clean up
546 ReleaseBSTR(bstrPropName);
547 ::VariantClear(&vtVal);
548
549 return hr;
550}
551
552HRESULT CpiRemoveCollectionObject(
553 ICatalogCollection* piColl,
554 LPCWSTR pwzID,
555 LPCWSTR pwzName,
556 BOOL fResetDeleteable
557 )
558{
559 HRESULT hr = S_OK;
560
561 IDispatch* piDisp = NULL;
562 ICatalogObject* piObj = NULL;
563
564 BOOL fMatch = FALSE;
565
566 VARIANT vtVal;
567 ::VariantInit(&vtVal);
568
569 long lCnt;
570 hr = piColl->get_Count(&lCnt);
571 ExitOnFailure(hr, "Failed to get to number of items in collection");
572
573 for (long i = 0; i < lCnt; i++)
574 {
575 // get ICatalogObject interface
576 hr = piColl->get_Item(i, &piDisp);
577 ExitOnFailure(hr, "Failed to get object from collection");
578
579 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
580 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
581
582 // compare id
583 if (pwzID && *pwzID)
584 {
585 hr = piObj->get_Key(&vtVal);
586 ExitOnFailure(hr, "Failed to get key");
587
588 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
589 ExitOnFailure(hr, "Failed to change variant type");
590
591 if (0 == lstrcmpiW(vtVal.bstrVal, pwzID))
592 fMatch = TRUE;
593
594 ::VariantClear(&vtVal);
595 }
596
597 // compare name
598 if (pwzName && *pwzName)
599 {
600 hr = piObj->get_Name(&vtVal);
601 ExitOnFailure(hr, "Failed to get name");
602
603 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
604 ExitOnFailure(hr, "Failed to change variant type");
605
606 if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
607 fMatch = TRUE;
608
609 ::VariantClear(&vtVal);
610 }
611
612 // if it's a match, remove it
613 if (fMatch)
614 {
615 if (fResetDeleteable)
616 {
617 // reset deleteable property, if set
618 hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable");
619 ExitOnFailure(hr, "Failed to reset deleteable property");
620 }
621
622 hr = piColl->Remove(i);
623 ExitOnFailure(hr, "Failed to remove item from collection");
624 break;
625 }
626
627 // release interface pointers
628 ReleaseNullObject(piDisp);
629 ReleaseNullObject(piObj);
630 }
631
632 hr = S_OK;
633
634LExit:
635 // clean up
636 ReleaseObject(piDisp);
637 ReleaseObject(piObj);
638
639 ::VariantClear(&vtVal);
640
641 return hr;
642}
643
644HRESULT CpiRemoveUserCollectionObject(
645 ICatalogCollection* piColl,
646 PSID pSid
647 )
648{
649 HRESULT hr = S_OK;
650
651 int i = 0;
652
653 // find index
654 hr = FindUserCollectionObjectIndex(piColl, pSid, &i);
655 ExitOnFailure(hr, "Failed to find user collection index");
656
657 if (S_FALSE == hr)
658 ExitFunction(); // not found, exit with hr = S_FALSE
659
660 // remove object
661 hr = piColl->Remove(i);
662 ExitOnFailure(hr, "Failed to remove object from collection");
663
664 hr = S_OK;
665
666LExit:
667 return hr;
668}
669
670HRESULT CpiFindCollectionObjectByStringKey(
671 ICatalogCollection* piColl,
672 LPCWSTR pwzKey,
673 ICatalogObject** ppiObj
674 )
675{
676 HRESULT hr = S_OK;
677
678 IDispatch* piDisp = NULL;
679 ICatalogObject* piObj = NULL;
680
681 VARIANT vtVal;
682 ::VariantInit(&vtVal);
683
684 long lCnt;
685 hr = piColl->get_Count(&lCnt);
686 ExitOnFailure(hr, "Failed to get to number of items in collection");
687
688 for (long i = 0; i < lCnt; i++)
689 {
690 // get ICatalogObject interface
691 hr = piColl->get_Item(i, &piDisp);
692 ExitOnFailure(hr, "Failed to get object from collection");
693
694 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
695 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
696
697 // compare key
698 hr = piObj->get_Key(&vtVal);
699 ExitOnFailure(hr, "Failed to get key");
700
701 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
702 ExitOnFailure(hr, "Failed to change variant type");
703
704 if (0 == lstrcmpiW(vtVal.bstrVal, pwzKey))
705 {
706 if (ppiObj)
707 {
708 *ppiObj = piObj;
709 piObj = NULL;
710 }
711 ExitFunction1(hr = S_OK);
712 }
713
714 // clean up
715 ReleaseNullObject(piDisp);
716 ReleaseNullObject(piObj);
717
718 ::VariantClear(&vtVal);
719 }
720
721 hr = S_FALSE;
722
723LExit:
724 // clean up
725 ReleaseObject(piDisp);
726 ReleaseObject(piObj);
727
728 ::VariantClear(&vtVal);
729
730 return hr;
731}
732
733HRESULT CpiFindCollectionObjectByIntegerKey(
734 ICatalogCollection* piColl,
735 long lKey,
736 ICatalogObject** ppiObj
737 )
738{
739 HRESULT hr = S_OK;
740
741 IDispatch* piDisp = NULL;
742 ICatalogObject* piObj = NULL;
743
744 VARIANT vtVal;
745 ::VariantInit(&vtVal);
746
747 long lCnt;
748 hr = piColl->get_Count(&lCnt);
749 ExitOnFailure(hr, "Failed to get to number of items in collection");
750
751 for (long i = 0; i < lCnt; i++)
752 {
753 // get ICatalogObject interface
754 hr = piColl->get_Item(i, &piDisp);
755 ExitOnFailure(hr, "Failed to get object from collection");
756
757 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
758 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
759
760 // compare key
761 hr = piObj->get_Key(&vtVal);
762 ExitOnFailure(hr, "Failed to get key");
763
764 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_I4);
765 ExitOnFailure(hr, "Failed to change variant type");
766
767 if (vtVal.lVal == lKey)
768 {
769 if (ppiObj)
770 {
771 *ppiObj = piObj;
772 piObj = NULL;
773 }
774 ExitFunction1(hr = S_OK);
775 }
776
777 // clean up
778 ReleaseNullObject(piDisp);
779 ReleaseNullObject(piObj);
780
781 ::VariantClear(&vtVal);
782 }
783
784 hr = S_FALSE;
785
786LExit:
787 // clean up
788 ReleaseObject(piDisp);
789 ReleaseObject(piObj);
790
791 ::VariantClear(&vtVal);
792
793 return hr;
794}
795
796HRESULT CpiFindCollectionObjectByName(
797 ICatalogCollection* piColl,
798 LPCWSTR pwzName,
799 ICatalogObject** ppiObj
800 )
801{
802 HRESULT hr = S_OK;
803
804 IDispatch* piDisp = NULL;
805 ICatalogObject* piObj = NULL;
806
807 VARIANT vtVal;
808 ::VariantInit(&vtVal);
809
810 long lCnt;
811 hr = piColl->get_Count(&lCnt);
812 ExitOnFailure(hr, "Failed to get to number of items in collection");
813
814 for (long i = 0; i < lCnt; i++)
815 {
816 // get ICatalogObject interface
817 hr = piColl->get_Item(i, &piDisp);
818 ExitOnFailure(hr, "Failed to get object from collection");
819
820 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
821 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
822
823 // compare key
824 hr = piObj->get_Name(&vtVal);
825 ExitOnFailure(hr, "Failed to get key");
826
827 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
828 ExitOnFailure(hr, "Failed to change variant type");
829
830 if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
831 {
832 if (ppiObj)
833 {
834 *ppiObj = piObj;
835 piObj = NULL;
836 }
837 ExitFunction1(hr = S_OK);
838 }
839
840 // clean up
841 ReleaseNullObject(piDisp);
842 ReleaseNullObject(piObj);
843
844 ::VariantClear(&vtVal);
845 }
846
847 hr = S_FALSE;
848
849LExit:
850 // clean up
851 ReleaseObject(piDisp);
852 ReleaseObject(piObj);
853
854 ::VariantClear(&vtVal);
855
856 return hr;
857}
858
859HRESULT CpiFindUserCollectionObject(
860 ICatalogCollection* piColl,
861 PSID pSid,
862 ICatalogObject** ppiObj
863 )
864{
865 HRESULT hr = S_OK;
866
867 int i = 0;
868
869 IDispatch* piDisp = NULL;
870
871 // find index
872 hr = FindUserCollectionObjectIndex(piColl, pSid, &i);
873 ExitOnFailure(hr, "Failed to find user collection index");
874
875 if (S_FALSE == hr)
876 ExitFunction(); // not found, exit with hr = S_FALSE
877
878 // get object
879 if (ppiObj)
880 {
881 hr = piColl->get_Item(i, &piDisp);
882 ExitOnFailure(hr, "Failed to get object from collection");
883
884 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)ppiObj);
885 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
886 }
887
888 hr = S_OK;
889
890LExit:
891 // clean up
892 ReleaseObject(piDisp);
893
894 return hr;
895}
896
897HRESULT CpiGetPartitionsCollection(
898 ICatalogCollection** ppiPartColl
899 )
900{
901 HRESULT hr = S_OK;
902
903 // get collection
904 hr = CpiGetCatalogCollection(L"Partitions", ppiPartColl);
905 ExitOnFailure(hr, "Failed to get catalog collection");
906
907 hr = S_OK;
908
909LExit:
910 return hr;
911}
912
913HRESULT CpiGetPartitionRolesCollection(
914 LPCWSTR pwzPartID,
915 ICatalogCollection** ppiRolesColl
916 )
917{
918 HRESULT hr = S_OK;
919
920 ICatalogCollection* piPartColl = NULL;
921 ICatalogObject* piPartObj = NULL;
922
923 // get partitions collection
924 hr = CpiGetPartitionsCollection(&piPartColl);
925 ExitOnFailure(hr, "Failed to get partitions collection");
926
927 if (S_FALSE == hr)
928 ExitFunction(); // partitions collection not found, exit with hr = S_FALSE
929
930 // find object
931 hr = CpiFindCollectionObjectByStringKey(piPartColl, pwzPartID, &piPartObj);
932 ExitOnFailure(hr, "Failed to find collection object");
933
934 if (S_FALSE == hr)
935 ExitFunction(); // partition not found, exit with hr = S_FALSE
936
937 // get roles collection
938 hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", ppiRolesColl);
939 ExitOnFailure(hr, "Failed to get catalog collection");
940
941 hr = S_OK;
942
943LExit:
944 // clean up
945 ReleaseObject(piPartColl);
946 ReleaseObject(piPartObj);
947
948 return hr;
949}
950
951HRESULT CpiGetUsersInPartitionRoleCollection(
952 LPCWSTR pwzPartID,
953 LPCWSTR pwzRoleName,
954 ICatalogCollection** ppiUsrInRoleColl
955 )
956{
957 HRESULT hr = S_OK;
958
959 ICatalogCollection* piRoleColl = NULL;
960 ICatalogObject* piRoleObj = NULL;
961
962 // get roles collection
963 hr = CpiGetPartitionRolesCollection(pwzPartID, &piRoleColl);
964 ExitOnFailure(hr, "Failed to get roles collection");
965
966 if (S_FALSE == hr)
967 ExitFunction(); // partition roles collection not found, exit with hr = S_FALSE
968
969 // find object
970 hr = CpiFindCollectionObjectByName(piRoleColl, pwzRoleName, &piRoleObj);
971 ExitOnFailure(hr, "Failed to find collection object");
972
973 if (S_FALSE == hr)
974 ExitFunction(); // user not found, exit with hr = S_FALSE
975
976 // get roles collection
977 hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInPartitionRole", ppiUsrInRoleColl);
978 ExitOnFailure(hr, "Failed to get catalog collection");
979
980 hr = S_OK;
981
982LExit:
983 // clean up
984 ReleaseObject(piRoleColl);
985 ReleaseObject(piRoleObj);
986
987 return hr;
988}
989
990HRESULT CpiGetPartitionUsersCollection(
991 ICatalogCollection** ppiUserColl
992 )
993{
994 HRESULT hr = S_OK;
995
996 // get roles collection
997 hr = CpiGetCatalogCollection(L"PartitionUsers", ppiUserColl);
998 ExitOnFailure(hr, "Failed to get catalog collection");
999
1000 hr = S_OK;
1001
1002LExit:
1003 return hr;
1004}
1005
1006HRESULT CpiGetApplicationsCollection(
1007 LPCWSTR pwzPartID,
1008 ICatalogCollection** ppiAppColl
1009 )
1010{
1011 HRESULT hr = S_OK;
1012
1013 ICOMAdminCatalog* piCatalog = NULL;
1014 ICOMAdminCatalog2* piCatalog2 = NULL;
1015 BSTR bstrGlobPartID = NULL;
1016
1017 ICatalogCollection* piPartColl = NULL;
1018 ICatalogObject* piPartObj = NULL;
1019
1020 // get catalog
1021 hr = CpiGetAdminCatalog(&piCatalog);
1022 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
1023
1024 // get ICOMAdminCatalog2 interface
1025 hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2);
1026
1027 // COM+ 1.5 or later
1028 if (E_NOINTERFACE != hr)
1029 {
1030 ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface");
1031
1032 // partition id
1033 if (!pwzPartID || !*pwzPartID)
1034 {
1035 // get global partition id
1036 hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID);
1037 ExitOnFailure(hr, "Failed to get global partition id");
1038 }
1039
1040 // get partitions collection
1041 hr = CpiGetPartitionsCollection(&piPartColl);
1042 ExitOnFailure(hr, "Failed to get partitions collection");
1043
1044 // find object
1045 hr = CpiFindCollectionObjectByStringKey(piPartColl, bstrGlobPartID ? bstrGlobPartID : pwzPartID, &piPartObj);
1046 ExitOnFailure(hr, "Failed to find collection object");
1047
1048 if (S_FALSE == hr)
1049 ExitFunction(); // partition not found, exit with hr = S_FALSE
1050
1051 // get applications collection
1052 hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", ppiAppColl);
1053 ExitOnFailure(hr, "Failed to get catalog collection for partition");
1054 }
1055
1056 // COM+ pre 1.5
1057 else
1058 {
1059 // this version of COM+ does not support partitions, make sure a partition was not specified
1060 if (pwzPartID && *pwzPartID)
1061 ExitOnFailure(hr = E_FAIL, "Partitions are not supported by this version of COM+");
1062
1063 // get applications collection
1064 hr = CpiGetCatalogCollection(L"Applications", ppiAppColl);
1065 ExitOnFailure(hr, "Failed to get catalog collection");
1066 }
1067
1068 hr = S_OK;
1069
1070LExit:
1071 // clean up
1072 ReleaseObject(piCatalog);
1073 ReleaseObject(piCatalog2);
1074 ReleaseBSTR(bstrGlobPartID);
1075
1076 ReleaseObject(piPartColl);
1077 ReleaseObject(piPartObj);
1078
1079 return hr;
1080}
1081
1082HRESULT CpiGetRolesCollection(
1083 LPCWSTR pwzPartID,
1084 LPCWSTR pwzAppID,
1085 ICatalogCollection** ppiRolesColl
1086 )
1087{
1088 HRESULT hr = S_OK;
1089
1090 ICatalogCollection* piAppColl = NULL;
1091 ICatalogObject* piAppObj = NULL;
1092
1093 // get applications collection
1094 hr = CpiGetApplicationsCollection(pwzPartID, &piAppColl);
1095 ExitOnFailure(hr, "Failed to get applications collection");
1096
1097 if (S_FALSE == hr)
1098 ExitFunction(); // applications collection not found, exit with hr = S_FALSE
1099
1100 // find object
1101 hr = CpiFindCollectionObjectByStringKey(piAppColl, pwzAppID, &piAppObj);
1102 ExitOnFailure(hr, "Failed to find collection object");
1103
1104 if (S_FALSE == hr)
1105 ExitFunction(); // application not found, exit with hr = S_FALSE
1106
1107 // get roles collection
1108 hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Roles", ppiRolesColl);
1109 ExitOnFailure(hr, "Failed to catalog collection");
1110
1111 hr = S_OK;
1112
1113LExit:
1114 // clean up
1115 ReleaseObject(piAppColl);
1116 ReleaseObject(piAppObj);
1117
1118 return hr;
1119}
1120
1121HRESULT CpiGetUsersInRoleCollection(
1122 LPCWSTR pwzPartID,
1123 LPCWSTR pwzAppID,
1124 LPCWSTR pwzRoleName,
1125 ICatalogCollection** ppiUsrInRoleColl
1126 )
1127{
1128 HRESULT hr = S_OK;
1129
1130 ICatalogCollection* piRoleColl = NULL;
1131 ICatalogObject* piRoleObj = NULL;
1132
1133 // get roles collection
1134 hr = CpiGetRolesCollection(pwzPartID, pwzAppID, &piRoleColl);
1135 ExitOnFailure(hr, "Failed to get roles collection");
1136
1137 if (S_FALSE == hr)
1138 ExitFunction(); // roles collection not found, exit with hr = S_FALSE
1139
1140 // find object
1141 hr = CpiFindCollectionObjectByName(piRoleColl, pwzRoleName, &piRoleObj);
1142 ExitOnFailure(hr, "Failed to find collection object");
1143
1144 if (S_FALSE == hr)
1145 ExitFunction(); // role not found, exit with hr = S_FALSE
1146
1147 // get roles collection
1148 hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", ppiUsrInRoleColl);
1149 ExitOnFailure(hr, "Failed to get catalog collection");
1150
1151 hr = S_OK;
1152
1153LExit:
1154 // clean up
1155 ReleaseObject(piRoleColl);
1156 ReleaseObject(piRoleObj);
1157
1158 return hr;
1159}
1160
1161HRESULT CpiGetComponentsCollection(
1162 LPCWSTR pwzPartID,
1163 LPCWSTR pwzAppID,
1164 ICatalogCollection** ppiCompsColl
1165 )
1166{
1167 HRESULT hr = S_OK;
1168
1169 ICatalogCollection* piAppColl = NULL;
1170 ICatalogObject* piAppObj = NULL;
1171
1172 // get applications collection
1173 hr = CpiGetApplicationsCollection(pwzPartID, &piAppColl);
1174 ExitOnFailure(hr, "Failed to get applications collection");
1175
1176 if (S_FALSE == hr)
1177 ExitFunction(); // applications collection not found, exit with hr = S_FALSE
1178
1179 // find object
1180 hr = CpiFindCollectionObjectByStringKey(piAppColl, pwzAppID, &piAppObj);
1181 ExitOnFailure(hr, "Failed to find collection object");
1182
1183 if (S_FALSE == hr)
1184 ExitFunction(); // application not found, exit with hr = S_FALSE
1185
1186 // get components collection
1187 hr = CpiGetCatalogCollection(piAppColl, piAppObj, L"Components", ppiCompsColl);
1188 ExitOnFailure(hr, "Failed to get catalog collection");
1189
1190 hr = S_OK;
1191
1192LExit:
1193 // clean up
1194 ReleaseObject(piAppColl);
1195 ReleaseObject(piAppObj);
1196
1197 return hr;
1198}
1199
1200HRESULT CpiGetInterfacesCollection(
1201 ICatalogCollection* piCompColl,
1202 ICatalogObject* piCompObj,
1203 ICatalogCollection** ppiIntfColl
1204 )
1205{
1206 HRESULT hr = S_OK;
1207
1208 // get interfaces collection
1209 hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"InterfacesForComponent", ppiIntfColl);
1210 ExitOnFailure(hr, "Failed to get catalog collection");
1211
1212 hr = S_OK;
1213
1214LExit:
1215 return hr;
1216}
1217
1218HRESULT CpiGetMethodsCollection(
1219 ICatalogCollection* piIntfColl,
1220 ICatalogObject* piIntfObj,
1221 ICatalogCollection** ppiMethColl
1222 )
1223{
1224 HRESULT hr = S_OK;
1225
1226 // get interfaces collection
1227 hr = CpiGetCatalogCollection(piIntfColl, piIntfObj, L"MethodsForInterface", ppiMethColl);
1228 ExitOnFailure(hr, "Failed to get catalog collection");
1229
1230 hr = S_OK;
1231
1232LExit:
1233 return hr;
1234}
1235
1236HRESULT CpiGetSubscriptionsCollection(
1237 LPCWSTR pwzPartID,
1238 LPCWSTR pwzAppID,
1239 LPCWSTR pwzCompCLSID,
1240 ICatalogCollection** ppiSubsColl
1241 )
1242{
1243 HRESULT hr = S_OK;
1244
1245 ICatalogCollection* piCompColl = NULL;
1246 ICatalogObject* piCompObj = NULL;
1247
1248 // get components collection
1249 hr = CpiGetComponentsCollection(pwzPartID, pwzAppID, &piCompColl);
1250 ExitOnFailure(hr, "Failed to get components collection");
1251
1252 if (S_FALSE == hr)
1253 ExitFunction(); // components collection not found, exit with hr = S_FALSE
1254
1255 // find object
1256 hr = CpiFindCollectionObjectByStringKey(piCompColl, pwzCompCLSID, &piCompObj);
1257 ExitOnFailure(hr, "Failed to find collection object");
1258
1259 if (S_FALSE == hr)
1260 ExitFunction(); // component not found, exit with hr = S_FALSE
1261
1262 // get subscriptions collection
1263 hr = CpiGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", ppiSubsColl);
1264 ExitOnFailure(hr, "Failed to get catalog collection");
1265
1266 hr = S_OK;
1267
1268LExit:
1269 // clean up
1270 ReleaseObject(piCompColl);
1271 ReleaseObject(piCompObj);
1272
1273 return hr;
1274}
1275
1276HRESULT CpiReadPropertyList(
1277 LPWSTR* ppwzData,
1278 CPI_PROPERTY** ppPropList
1279 )
1280{
1281 HRESULT hr = S_OK;
1282
1283 CPI_PROPERTY* pItm = NULL;
1284 LPWSTR pwzName = NULL;
1285
1286 // clear list if it already contains items
1287 if (*ppPropList)
1288 CpiFreePropertyList(*ppPropList);
1289 *ppPropList = NULL;
1290
1291 // read property count
1292 int iPropCnt = 0;
1293 hr = WcaReadIntegerFromCaData(ppwzData, &iPropCnt);
1294 ExitOnFailure(hr, "Failed to read property count");
1295
1296 for (int i = 0; i < iPropCnt; i++)
1297 {
1298 // allocate new element
1299 pItm = (CPI_PROPERTY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PROPERTY));
1300 if (!pItm)
1301 ExitFunction1(hr = E_OUTOFMEMORY);
1302
1303 // Name
1304 hr = WcaReadStringFromCaData(ppwzData, &pwzName);
1305 ExitOnFailure(hr, "Failed to read name");
1306 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzName);
1307
1308 // Value
1309 hr = WcaReadStringFromCaData(ppwzData, &pItm->pwzValue);
1310 ExitOnFailure(hr, "Failed to read property value");
1311
1312 // add to list
1313 if (*ppPropList)
1314 pItm->pNext = *ppPropList;
1315 *ppPropList = pItm;
1316 pItm = NULL;
1317 }
1318
1319 hr = S_OK;
1320
1321LExit:
1322 // clean up
1323 ReleaseStr(pwzName);
1324
1325 if (pItm)
1326 CpiFreePropertyList(pItm);
1327
1328 return hr;
1329}
1330
1331void CpiFreePropertyList(
1332 CPI_PROPERTY* pList
1333 )
1334{
1335 while (pList)
1336 {
1337 ReleaseStr(pList->pwzValue);
1338
1339 CPI_PROPERTY* pDelete = pList;
1340 pList = pList->pNext;
1341 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1342 }
1343}
1344
1345HRESULT CpiWriteKeyToRollbackFile(
1346 HANDLE hFile,
1347 LPCWSTR pwzKey
1348 )
1349{
1350 HRESULT hr = S_OK;
1351
1352 WCHAR wzKey[MAX_DARWIN_KEY + 1];
1353 ::ZeroMemory(wzKey, sizeof(wzKey));
1354 hr = StringCchCopyW(wzKey, countof(wzKey), pwzKey);
1355 ExitOnFailure(hr, "Failed to copy key");
1356
1357 hr = WriteFileAll(hFile, (PBYTE)wzKey, MAX_DARWIN_KEY * sizeof(WCHAR));
1358 ExitOnFailure(hr, "Failed to write buffer");
1359
1360 FlushFileBuffers(hFile);
1361
1362 hr = S_OK;
1363
1364LExit:
1365 return hr;
1366}
1367
1368HRESULT CpiWriteIntegerToRollbackFile(
1369 HANDLE hFile,
1370 int i
1371 )
1372{
1373 HRESULT hr = S_OK;
1374
1375 hr = WriteFileAll(hFile, (PBYTE)&i, sizeof(int));
1376 ExitOnFailure(hr, "Failed to write buffer");
1377
1378 FlushFileBuffers(hFile);
1379
1380 hr = S_OK;
1381
1382LExit:
1383 return hr;
1384}
1385
1386HRESULT CpiReadRollbackDataList(
1387 HANDLE hFile,
1388 CPI_ROLLBACK_DATA** pprdList
1389 )
1390{
1391 HRESULT hr = S_OK;
1392
1393 int iCount;
1394
1395 CPI_ROLLBACK_DATA* pItm = NULL;
1396
1397 // read count
1398 hr = ReadFileAll(hFile, (PBYTE)&iCount, sizeof(int));
1399 if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
1400 ExitFunction1(hr = S_OK); // EOF reached, nothing left to read
1401 ExitOnFailure(hr, "Failed to read count");
1402
1403 for (int i = 0; i < iCount; i++)
1404 {
1405 // allocate new element
1406 pItm = (CPI_ROLLBACK_DATA*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLLBACK_DATA));
1407 if (!pItm)
1408 ExitFunction1(hr = E_OUTOFMEMORY);
1409
1410 // read from file
1411 hr = ReadFileAll(hFile, (PBYTE)pItm->wzKey, MAX_DARWIN_KEY * sizeof(WCHAR));
1412 if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
1413 break; // EOF reached, nothing left to read
1414 ExitOnFailure(hr, "Failed to read key");
1415
1416 hr = ReadFileAll(hFile, (PBYTE)&pItm->iStatus, sizeof(int));
1417 if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
1418 pItm->iStatus = 0; // EOF reached, the operation was interupted; set status to zero
1419 else
1420 ExitOnFailure(hr, "Failed to read status");
1421
1422 // add to list
1423 if (*pprdList)
1424 pItm->pNext = *pprdList;
1425 *pprdList = pItm;
1426 pItm = NULL;
1427 }
1428
1429 hr = S_OK;
1430
1431LExit:
1432 // clean up
1433 if (pItm)
1434 CpiFreeRollbackDataList(pItm);
1435
1436 return hr;
1437}
1438
1439void CpiFreeRollbackDataList(
1440 CPI_ROLLBACK_DATA* pList
1441 )
1442{
1443 while (pList)
1444 {
1445 CPI_ROLLBACK_DATA* pDelete = pList;
1446 pList = pList->pNext;
1447 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1448 }
1449}
1450
1451HRESULT CpiFindRollbackStatus(
1452 CPI_ROLLBACK_DATA* pList,
1453 LPCWSTR pwzKey,
1454 int* piStatus
1455 )
1456{
1457 HRESULT hr = S_OK;
1458
1459 for (; pList; pList = pList->pNext)
1460 {
1461 if (0 == lstrcmpW(pList->wzKey, pwzKey))
1462 {
1463 *piStatus = pList->iStatus;
1464 ExitFunction1(hr = S_OK);
1465 }
1466 }
1467
1468 hr = S_FALSE;
1469
1470LExit:
1471 return hr;
1472}
1473
1474HRESULT CpiAccountNameToSid(
1475 LPCWSTR pwzAccountName,
1476 PSID* ppSid
1477 )
1478{
1479 HRESULT hr = S_OK;
1480 UINT er = ERROR_SUCCESS;
1481 NTSTATUS st = 0;
1482
1483 PSID pSid = NULL;
1484 LSA_OBJECT_ATTRIBUTES loaAttributes;
1485 LSA_HANDLE lsahPolicy = NULL;
1486 LSA_UNICODE_STRING lusName;
1487 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
1488 PLSA_TRANSLATED_SID pltsSid = NULL;
1489
1490 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
1491 ::ZeroMemory(&lusName, sizeof(lusName));
1492
1493 // identify well known SIDs
1494 for (CPI_WELLKNOWN_SID* pWS = wsWellKnownSids; pWS->pwzName; pWS++)
1495 {
1496 if (0 == lstrcmpiW(pwzAccountName, pWS->pwzName))
1497 {
1498 // allocate SID buffer
1499 pSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, ::GetSidLengthRequired(pWS->nSubAuthorityCount));
1500 ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID");
1501
1502 // initialize SID
1503 ::InitializeSid(pSid, &pWS->iaIdentifierAuthority, pWS->nSubAuthorityCount);
1504
1505 // copy sub autorities
1506 for (DWORD i = 0; i < pWS->nSubAuthorityCount; i++)
1507 *::GetSidSubAuthority(pSid, i) = pWS->dwSubAuthority[i];
1508
1509 break;
1510 }
1511 }
1512
1513 // lookup name
1514 if (!pSid)
1515 {
1516 // open policy handle
1517 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
1518 er = ::LsaNtStatusToWinError(st);
1519 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
1520
1521 // create account name lsa unicode string
1522 hr = InitLsaUnicodeString(&lusName, pwzAccountName, (DWORD)wcslen(pwzAccountName));
1523 ExitOnFailure(hr, "Failed to initialize account name string");
1524
1525 // lookup name
1526 st = ::LsaLookupNames(lsahPolicy, 1, &lusName, &plrdsDomains, &pltsSid);
1527 er = ::LsaNtStatusToWinError(st);
1528 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names");
1529
1530 if (SidTypeDomain == pltsSid->Use)
1531 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported");
1532
1533 // convert sid
1534 hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pSid);
1535 ExitOnFailure(hr, "Failed to convert SID");
1536 }
1537
1538 *ppSid = pSid;
1539 pSid = NULL;
1540
1541 hr = S_OK;
1542
1543LExit:
1544 // clean up
1545 if (pSid)
1546 ::HeapFree(::GetProcessHeap(), 0, pSid);
1547 if (lsahPolicy)
1548 ::LsaClose(lsahPolicy);
1549 if (plrdsDomains)
1550 ::LsaFreeMemory(plrdsDomains);
1551 if (pltsSid)
1552 ::LsaFreeMemory(pltsSid);
1553 FreeLsaUnicodeString(&lusName);
1554
1555 return hr;
1556}
1557
1558HRESULT CpiSidToAccountName(
1559 PSID pSid,
1560 LPWSTR* ppwzAccountName
1561 )
1562{
1563 HRESULT hr = S_OK;
1564 UINT er = ERROR_SUCCESS;
1565 NTSTATUS st = 0;
1566
1567 LSA_OBJECT_ATTRIBUTES loaAttributes;
1568 LSA_HANDLE lsahPolicy = NULL;
1569 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
1570 PLSA_TRANSLATED_NAME pltnName = NULL;
1571
1572 LPWSTR pwzDomain = NULL;
1573 LPWSTR pwzName = NULL;
1574
1575 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
1576
1577 // open policy handle
1578 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
1579 er = ::LsaNtStatusToWinError(st);
1580 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
1581
1582 // lookup SID
1583 st = ::LsaLookupSids(lsahPolicy, 1, &pSid, &plrdsDomains, &pltnName);
1584 er = ::LsaNtStatusToWinError(st);
1585 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed lookup SID");
1586
1587 if (SidTypeDomain == pltnName->Use)
1588 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported");
1589
1590 // format account name string
1591 if (SidTypeWellKnownGroup != pltnName->Use)
1592 {
1593 PLSA_UNICODE_STRING plusDomain = &plrdsDomains->Domains[pltnName->DomainIndex].Name;
1594 hr = StrAllocString(&pwzDomain, plusDomain->Buffer, plusDomain->Length / sizeof(WCHAR));
1595 ExitOnFailure(hr, "Failed to allocate name string");
1596 }
1597
1598 hr = StrAllocString(&pwzName, pltnName->Name.Buffer, pltnName->Name.Length / sizeof(WCHAR));
1599 ExitOnFailure(hr, "Failed to allocate domain string");
1600
1601 hr = StrAllocFormatted(ppwzAccountName, L"%s\\%s", pwzDomain ? pwzDomain : L"", pwzName);
1602 ExitOnFailure(hr, "Failed to format account name string");
1603
1604 hr = S_OK;
1605
1606LExit:
1607 // clean up
1608 if (lsahPolicy)
1609 ::LsaClose(lsahPolicy);
1610 if (plrdsDomains)
1611 ::LsaFreeMemory(plrdsDomains);
1612 if (pltnName)
1613 ::LsaFreeMemory(pltnName);
1614
1615 ReleaseStr(pwzDomain);
1616 ReleaseStr(pwzName);
1617
1618 return hr;
1619}
1620
1621// helper function definitions
1622
1623static HRESULT FindUserCollectionObjectIndex(
1624 ICatalogCollection* piColl,
1625 PSID pSid,
1626 int* pi
1627 )
1628{
1629 HRESULT hr = S_OK;
1630 UINT er = ERROR_SUCCESS;
1631 NTSTATUS st = 0;
1632
1633 long i = 0;
1634 long lCollCnt = 0;
1635
1636 LSA_OBJECT_ATTRIBUTES loaAttributes;
1637 LSA_HANDLE lsahPolicy = NULL;
1638 PLSA_UNICODE_STRING plusNames = NULL;
1639 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
1640 PLSA_TRANSLATED_SID pltsSids = NULL;
1641
1642 IDispatch* piDisp = NULL;
1643 ICatalogObject* piObj = NULL;
1644 VARIANT vtVal;
1645
1646 PSID pTmpSid = NULL;
1647
1648 PLSA_TRANSLATED_SID pltsSid;
1649
1650 ::VariantInit(&vtVal);
1651 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
1652
1653 // open policy handle
1654 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
1655 er = ::LsaNtStatusToWinError(st);
1656 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
1657
1658 // get number of elements in collection
1659 hr = piColl->get_Count(&lCollCnt);
1660 ExitOnFailure(hr, "Failed to get to number of objects in collection");
1661
1662 if (0 == lCollCnt)
1663 ExitFunction1(hr = S_FALSE); // not found
1664
1665 // allocate name buffer
1666 plusNames = (PLSA_UNICODE_STRING)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LSA_UNICODE_STRING) * lCollCnt);
1667 ExitOnNull(plusNames, hr, E_OUTOFMEMORY, "Failed to allocate names buffer");
1668
1669 // get accounts in collection
1670 for (i = 0; i < lCollCnt; i++)
1671 {
1672 // get ICatalogObject interface
1673 hr = piColl->get_Item(i, &piDisp);
1674 ExitOnFailure(hr, "Failed to get object from collection");
1675
1676 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
1677 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
1678
1679 // get value
1680 hr = piObj->get_Key(&vtVal);
1681 ExitOnFailure(hr, "Failed to get key");
1682
1683 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
1684 ExitOnFailure(hr, "Failed to change variant type");
1685
1686 // copy account name string
1687 hr = InitLsaUnicodeString(&plusNames[i], vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal));
1688 ExitOnFailure(hr, "Failed to initialize account name string");
1689
1690 // clean up
1691 ReleaseNullObject(piDisp);
1692 ReleaseNullObject(piObj);
1693 ::VariantClear(&vtVal);
1694 }
1695
1696 // lookup names
1697 st = ::LsaLookupNames(lsahPolicy, lCollCnt, plusNames, &plrdsDomains, &pltsSids);
1698 er = ::LsaNtStatusToWinError(st);
1699 if (ERROR_NONE_MAPPED != er && ERROR_SOME_NOT_MAPPED != er)
1700 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names");
1701
1702 // compare SIDs
1703 for (i = 0; i < lCollCnt; i++)
1704 {
1705 // get SID
1706 pltsSid = &pltsSids[i];
1707 if (SidTypeDomain == pltsSid->Use || SidTypeInvalid == pltsSid->Use || SidTypeUnknown == pltsSid->Use)
1708 continue; // ignore...
1709
1710 hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pTmpSid);
1711 ExitOnFailure(hr, "Failed to convert SID");
1712
1713 // compare SIDs
1714 if (::EqualSid(pSid, pTmpSid))
1715 {
1716 *pi = i;
1717 ExitFunction1(hr = S_OK);
1718 }
1719 }
1720
1721 if (ERROR_NONE_MAPPED == er || ERROR_SOME_NOT_MAPPED == er)
1722 hr = HRESULT_FROM_WIN32(er);
1723 else
1724 hr = S_FALSE; // not found
1725
1726LExit:
1727 // clean up
1728 ReleaseObject(piDisp);
1729 ReleaseObject(piObj);
1730 ::VariantClear(&vtVal);
1731
1732 if (plusNames)
1733 {
1734 for (i = 0; i < lCollCnt; i++)
1735 FreeLsaUnicodeString(&plusNames[i]);
1736 ::HeapFree(::GetProcessHeap(), 0, plusNames);
1737 }
1738
1739 if (lsahPolicy)
1740 ::LsaClose(lsahPolicy);
1741 if (plrdsDomains)
1742 ::LsaFreeMemory(plrdsDomains);
1743 if (pltsSids)
1744 ::LsaFreeMemory(pltsSids);
1745
1746 if (pTmpSid)
1747 ::HeapFree(::GetProcessHeap(), 0, pTmpSid);
1748
1749 return hr;
1750}
1751
1752static HRESULT CreateSidFromDomainRidPair(
1753 PSID pDomainSid,
1754 DWORD dwRid,
1755 PSID* ppSid
1756 )
1757{
1758 HRESULT hr = S_OK;
1759 PSID pSid = NULL;
1760
1761 // get domain SID sub authority count
1762 UCHAR ucSubAuthorityCount = *::GetSidSubAuthorityCount(pDomainSid);
1763
1764 // allocate SID buffer
1765 DWORD dwLengthRequired = ::GetSidLengthRequired(ucSubAuthorityCount + (UCHAR)1);
1766 if (*ppSid)
1767 {
1768 SIZE_T ccb = ::HeapSize(::GetProcessHeap(), 0, *ppSid);
1769 if (-1 == ccb)
1770 ExitOnFailure(hr = E_FAIL, "Failed to get size of SID buffer");
1771
1772 if (ccb < dwLengthRequired)
1773 {
1774 pSid = (PSID)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, *ppSid, dwLengthRequired);
1775 ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for SID, len: %d", dwLengthRequired);
1776 *ppSid = pSid;
1777 }
1778 }
1779 else
1780 {
1781 *ppSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwLengthRequired);
1782 ExitOnNull(*ppSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID, len: %d", dwLengthRequired);
1783 }
1784
1785 ::InitializeSid(*ppSid, ::GetSidIdentifierAuthority(pDomainSid), ucSubAuthorityCount + (UCHAR)1);
1786
1787 // copy sub autorities
1788 DWORD i = 0;
1789 for (; i < ucSubAuthorityCount; i++)
1790 *::GetSidSubAuthority(*ppSid, i) = *::GetSidSubAuthority(pDomainSid, i);
1791 *::GetSidSubAuthority(*ppSid, i) = dwRid;
1792
1793 hr = S_OK;
1794
1795LExit:
1796 return hr;
1797}
1798
1799static HRESULT InitLsaUnicodeString(
1800 PLSA_UNICODE_STRING plusStr,
1801 LPCWSTR pwzStr,
1802 DWORD dwLen
1803 )
1804{
1805 HRESULT hr = S_OK;
1806
1807 plusStr->Length = (USHORT)dwLen * sizeof(WCHAR);
1808 plusStr->MaximumLength = (USHORT)(dwLen + 1) * sizeof(WCHAR);
1809
1810 plusStr->Buffer = (WCHAR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * (dwLen + 1));
1811 ExitOnNull(plusStr->Buffer, hr, E_OUTOFMEMORY, "Failed to allocate account name string");
1812
1813 hr = StringCchCopyW(plusStr->Buffer, dwLen + 1, pwzStr);
1814 ExitOnFailure(hr, "Failed to copy buffer");
1815
1816 hr = S_OK;
1817
1818LExit:
1819 return hr;
1820}
1821
1822static void FreeLsaUnicodeString(
1823 PLSA_UNICODE_STRING plusStr
1824 )
1825{
1826 if (plusStr->Buffer)
1827 ::HeapFree(::GetProcessHeap(), 0, plusStr->Buffer);
1828}
1829
1830static HRESULT WriteFileAll(
1831 HANDLE hFile,
1832 PBYTE pbBuffer,
1833 DWORD dwBufferLength
1834 )
1835{
1836 HRESULT hr = S_OK;
1837
1838 DWORD dwBytesWritten;
1839
1840 while (dwBufferLength)
1841 {
1842 if (!::WriteFile(hFile, pbBuffer, dwBufferLength, &dwBytesWritten, NULL))
1843 ExitFunction1(hr = HRESULT_FROM_WIN32(::GetLastError()));
1844
1845 dwBufferLength -= dwBytesWritten;
1846 pbBuffer += dwBytesWritten;
1847 }
1848
1849 hr = S_OK;
1850
1851LExit:
1852 return hr;
1853}
1854
1855static HRESULT ReadFileAll(
1856 HANDLE hFile,
1857 PBYTE pbBuffer,
1858 DWORD dwBufferLength
1859 )
1860{
1861 HRESULT hr = S_OK;
1862
1863 DWORD dwBytesRead;
1864
1865 while (dwBufferLength)
1866 {
1867 if (!::ReadFile(hFile, pbBuffer, dwBufferLength, &dwBytesRead, NULL))
1868 ExitFunction1(hr = HRESULT_FROM_WIN32(::GetLastError()));
1869
1870 if (0 == dwBytesRead)
1871 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF));
1872
1873 dwBufferLength -= dwBytesRead;
1874 pbBuffer += dwBytesRead;
1875 }
1876
1877 hr = S_OK;
1878
1879LExit:
1880 return hr;
1881}
diff --git a/src/ca/cputilexec.h b/src/ca/cputilexec.h
new file mode 100644
index 00000000..51b47583
--- /dev/null
+++ b/src/ca/cputilexec.h
@@ -0,0 +1,193 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#define CPI_MAX_GUID 38
6
7enum eActionType { atNoOp = 0, atCreate, atRemove };
8
9
10// structs
11
12struct CPI_PROPERTY
13{
14 WCHAR wzName[MAX_DARWIN_KEY + 1];
15 LPWSTR pwzValue;
16
17 CPI_PROPERTY* pNext;
18};
19
20struct CPI_ROLLBACK_DATA
21{
22 WCHAR wzKey[MAX_DARWIN_KEY + 1];
23 int iStatus;
24
25 CPI_ROLLBACK_DATA* pNext;
26};
27
28
29// function prototypes
30
31void CpiInitialize();
32void CpiFinalize();
33HRESULT CpiActionStartMessage(
34 LPWSTR* ppwzActionData,
35 BOOL fSuppress
36 );
37HRESULT CpiActionDataMessage(
38 DWORD cArgs,
39 ...
40 );
41HRESULT CpiGetAdminCatalog(
42 ICOMAdminCatalog** ppiCatalog
43 );
44HRESULT CpiLogCatalogErrorInfo();
45HRESULT CpiGetCatalogCollection(
46 LPCWSTR pwzName,
47 ICatalogCollection** ppiColl
48 );
49HRESULT CpiGetCatalogCollection(
50 ICatalogCollection* piColl,
51 ICatalogObject* piObj,
52 LPCWSTR pwzName,
53 ICatalogCollection** ppiColl
54 );
55HRESULT CpiAddCollectionObject(
56 ICatalogCollection* piColl,
57 ICatalogObject** ppiObj
58 );
59HRESULT CpiPutCollectionObjectValue(
60 ICatalogObject* piObj,
61 LPCWSTR pwzPropName,
62 LPCWSTR pwzValue
63 );
64HRESULT CpiPutCollectionObjectValues(
65 ICatalogObject* piObj,
66 CPI_PROPERTY* pPropList
67 );
68HRESULT CpiGetCollectionObjectValue(
69 ICatalogObject* piObj,
70 LPCWSTR szPropName,
71 LPWSTR* ppwzValue
72 );
73HRESULT CpiResetObjectProperty(
74 ICatalogCollection* piColl,
75 ICatalogObject* piObj,
76 LPCWSTR pwzPropName
77 );
78HRESULT CpiRemoveCollectionObject(
79 ICatalogCollection* piColl,
80 LPCWSTR pwzID,
81 LPCWSTR pwzName,
82 BOOL fResetDeleteable
83 );
84HRESULT CpiRemoveUserCollectionObject(
85 ICatalogCollection* piColl,
86 PSID pSid
87 );
88HRESULT CpiFindCollectionObjectByStringKey(
89 ICatalogCollection* piColl,
90 LPCWSTR pwzKey,
91 ICatalogObject** ppiObj
92 );
93HRESULT CpiFindCollectionObjectByIntegerKey(
94 ICatalogCollection* piColl,
95 long lKey,
96 ICatalogObject** ppiObj
97 );
98HRESULT CpiFindCollectionObjectByName(
99 ICatalogCollection* piColl,
100 LPCWSTR pwzName,
101 ICatalogObject** ppiObj
102 );
103HRESULT CpiFindUserCollectionObject(
104 ICatalogCollection* piColl,
105 PSID pSid,
106 ICatalogObject** ppiObj
107 );
108HRESULT CpiGetPartitionsCollection(
109 ICatalogCollection** ppiPartColl
110 );
111HRESULT CpiGetPartitionRolesCollection(
112 LPCWSTR pwzPartID,
113 ICatalogCollection** ppiRolesColl
114 );
115HRESULT CpiGetUsersInPartitionRoleCollection(
116 LPCWSTR pwzPartID,
117 LPCWSTR pwzRoleName,
118 ICatalogCollection** ppiUsrInRoleColl
119 );
120HRESULT CpiGetPartitionUsersCollection(
121 ICatalogCollection** ppiUserColl
122 );
123HRESULT CpiGetApplicationsCollection(
124 LPCWSTR pwzPartID,
125 ICatalogCollection** ppiAppColl
126 );
127HRESULT CpiGetRolesCollection(
128 LPCWSTR pwzPartID,
129 LPCWSTR pwzAppID,
130 ICatalogCollection** ppiRolesColl
131 );
132HRESULT CpiGetUsersInRoleCollection(
133 LPCWSTR pwzPartID,
134 LPCWSTR pwzAppID,
135 LPCWSTR pwzRoleName,
136 ICatalogCollection** ppiUsrInRoleColl
137 );
138HRESULT CpiGetComponentsCollection(
139 LPCWSTR pwzPartID,
140 LPCWSTR pwzAppID,
141 ICatalogCollection** ppiCompsColl
142 );
143HRESULT CpiGetInterfacesCollection(
144 ICatalogCollection* piCompColl,
145 ICatalogObject* piCompObj,
146 ICatalogCollection** ppiIntfColl
147 );
148HRESULT CpiGetMethodsCollection(
149 ICatalogCollection* piIntfColl,
150 ICatalogObject* piIntfObj,
151 ICatalogCollection** ppiMethColl
152 );
153HRESULT CpiGetSubscriptionsCollection(
154 LPCWSTR pwzPartID,
155 LPCWSTR pwzAppID,
156 LPCWSTR pwzCompCLSID,
157 ICatalogCollection** ppiCompsColl
158 );
159HRESULT CpiReadPropertyList(
160 LPWSTR* ppwzData,
161 CPI_PROPERTY** ppPropList
162 );
163void CpiFreePropertyList(
164 CPI_PROPERTY* pList
165 );
166HRESULT CpiWriteKeyToRollbackFile(
167 HANDLE hFile,
168 LPCWSTR pwzKey
169 );
170HRESULT CpiWriteIntegerToRollbackFile(
171 HANDLE hFile,
172 int i
173 );
174HRESULT CpiReadRollbackDataList(
175 HANDLE hFile,
176 CPI_ROLLBACK_DATA** pprdList
177 );
178void CpiFreeRollbackDataList(
179 CPI_ROLLBACK_DATA* pList
180 );
181HRESULT CpiFindRollbackStatus(
182 CPI_ROLLBACK_DATA* pList,
183 LPCWSTR pwzKey,
184 int* piStatus
185 );
186HRESULT CpiAccountNameToSid(
187 LPCWSTR pwzAccountName,
188 PSID* ppSid
189 );
190HRESULT CpiSidToAccountName(
191 PSID pSid,
192 LPWSTR* ppwzAccountName
193 );
diff --git a/src/ca/cputilsched.cpp b/src/ca/cputilsched.cpp
new file mode 100644
index 00000000..9dbe21ec
--- /dev/null
+++ b/src/ca/cputilsched.cpp
@@ -0,0 +1,885 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsActionTextQuery =
9 L"SELECT `Description`, `Template` FROM `ActionText` WHERE `Action` = ?";
10enum eActionTextQuery { atqDescription = 1, atqTemplate };
11
12LPCWSTR vcsComponentAttributesQuery =
13 L"SELECT `Attributes` FROM `Component` WHERE `Component` = ?";
14enum eComponentAttributesQuery { caqAttributes = 1 };
15
16LPCWSTR vcsUserQuery = L"SELECT `Domain`, `Name` FROM `User` WHERE `User` = ?";
17enum eUserQuery { uqDomain = 1, uqName };
18
19enum ePropertyQuery { pqName = 1, pqValue };
20
21
22// prototypes for private helper functions
23
24static HRESULT FindPropertyDefinition(
25 CPI_PROPERTY_DEFINITION* pPropDefList,
26 LPCWSTR pwzName,
27 CPI_PROPERTY_DEFINITION** ppPropDef
28 );
29static HRESULT GetUserAccountName(
30 LPCWSTR pwzKey,
31 LPWSTR* ppwzAccount
32 );
33
34
35// variables
36
37static ICOMAdminCatalog* gpiCatalog;
38static ICatalogCollection* gpiPartColl;
39static ICatalogCollection* gpiAppColl;
40
41static int giTables;
42
43
44// function definitions
45
46void CpiInitialize()
47{
48 // collections
49 gpiCatalog = NULL;
50 gpiPartColl = NULL;
51 gpiAppColl = NULL;
52
53 // tables
54 giTables = 0;
55
56 if (S_OK == WcaTableExists(L"ComPlusPartition")) giTables |= cptComPlusPartition;
57 if (S_OK == WcaTableExists(L"ComPlusPartitionProperty")) giTables |= cptComPlusPartitionProperty;
58 if (S_OK == WcaTableExists(L"ComPlusPartitionRole")) giTables |= cptComPlusPartitionRole;
59 if (S_OK == WcaTableExists(L"ComPlusUserInPartitionRole")) giTables |= cptComPlusUserInPartitionRole;
60 if (S_OK == WcaTableExists(L"ComPlusGroupInPartitionRole")) giTables |= cptComPlusGroupInPartitionRole;
61 if (S_OK == WcaTableExists(L"ComPlusPartitionUser")) giTables |= cptComPlusPartitionUser;
62 if (S_OK == WcaTableExists(L"ComPlusApplication")) giTables |= cptComPlusApplication;
63 if (S_OK == WcaTableExists(L"ComPlusApplicationProperty")) giTables |= cptComPlusApplicationProperty;
64 if (S_OK == WcaTableExists(L"ComPlusApplicationRole")) giTables |= cptComPlusApplicationRole;
65 if (S_OK == WcaTableExists(L"ComPlusApplicationRoleProperty")) giTables |= cptComPlusApplicationRoleProperty;
66 if (S_OK == WcaTableExists(L"ComPlusUserInApplicationRole")) giTables |= cptComPlusUserInApplicationRole;
67 if (S_OK == WcaTableExists(L"ComPlusGroupInApplicationRole")) giTables |= cptComPlusGroupInApplicationRole;
68 if (S_OK == WcaTableExists(L"ComPlusAssembly")) giTables |= cptComPlusAssembly;
69 if (S_OK == WcaTableExists(L"ComPlusAssemblyDependency")) giTables |= cptComPlusAssemblyDependency;
70 if (S_OK == WcaTableExists(L"ComPlusComponent")) giTables |= cptComPlusComponent;
71 if (S_OK == WcaTableExists(L"ComPlusComponentProperty")) giTables |= cptComPlusComponentProperty;
72 if (S_OK == WcaTableExists(L"ComPlusRoleForComponent")) giTables |= cptComPlusRoleForComponent;
73 if (S_OK == WcaTableExists(L"ComPlusInterface")) giTables |= cptComPlusInterface;
74 if (S_OK == WcaTableExists(L"ComPlusInterfaceProperty")) giTables |= cptComPlusInterfaceProperty;
75 if (S_OK == WcaTableExists(L"ComPlusRoleForInterface")) giTables |= cptComPlusRoleForInterface;
76 if (S_OK == WcaTableExists(L"ComPlusMethod")) giTables |= cptComPlusMethod;
77 if (S_OK == WcaTableExists(L"ComPlusMethodProperty")) giTables |= cptComPlusMethodProperty;
78 if (S_OK == WcaTableExists(L"ComPlusRoleForMethod")) giTables |= cptComPlusRoleForMethod;
79 if (S_OK == WcaTableExists(L"ComPlusSubscription")) giTables |= cptComPlusSubscription;
80 if (S_OK == WcaTableExists(L"ComPlusSubscriptionProperty")) giTables |= cptComPlusSubscriptionProperty;
81}
82
83void CpiFinalize()
84{
85 // collections
86 ReleaseObject(gpiCatalog);
87 ReleaseObject(gpiPartColl);
88 ReleaseObject(gpiAppColl);
89}
90
91BOOL CpiTableExists(
92 int iTable
93 )
94{
95 return (giTables & iTable) == iTable;
96}
97
98HRESULT CpiGetAdminCatalog(
99 ICOMAdminCatalog** ppiCatalog
100 )
101{
102 HRESULT hr = S_OK;
103
104 if (!gpiCatalog)
105 {
106 // get collection
107 hr = ::CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_ALL, IID_ICOMAdminCatalog, (void**)&gpiCatalog);
108 ExitOnFailure(hr, "Failed to create COM+ admin catalog object");
109 }
110
111 // return value
112 gpiCatalog->AddRef();
113 *ppiCatalog = gpiCatalog;
114
115 hr = S_OK;
116
117LExit:
118 return hr;
119}
120
121HRESULT CpiGetCatalogCollection(
122 LPCWSTR pwzName,
123 ICatalogCollection** ppiColl
124 )
125{
126 HRESULT hr = S_OK;
127
128 ICOMAdminCatalog* piCatalog = NULL;
129 IDispatch* piDisp = NULL;
130 BSTR bstrName = NULL;
131
132 // copy name string
133 bstrName = ::SysAllocString(pwzName);
134 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name");
135
136 // get catalog
137 hr = CpiGetAdminCatalog(&piCatalog);
138 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
139
140 // get collecton from catalog
141 hr = piCatalog->GetCollection(bstrName, &piDisp);
142 ExitOnFailure(hr, "Failed to get collection");
143
144 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
145 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
146
147 // populate collection
148 hr = (*ppiColl)->Populate();
149 ExitOnFailure(hr, "Failed to populate collection");
150
151 hr = S_OK;
152
153LExit:
154 // clean up
155 ReleaseObject(piCatalog);
156 ReleaseObject(piDisp);
157 ReleaseBSTR(bstrName);
158
159 return hr;
160}
161
162HRESULT CpiGetCatalogCollection(
163 ICatalogCollection* piColl,
164 ICatalogObject* piObj,
165 LPCWSTR pwzName,
166 ICatalogCollection** ppiColl
167 )
168{
169 HRESULT hr = S_OK;
170
171 ICOMAdminCatalog* piCatalog = NULL;
172 IDispatch* piDisp = NULL;
173 BSTR bstrName = NULL;
174
175 VARIANT vtKey;
176 ::VariantInit(&vtKey);
177
178 // copy name string
179 bstrName = ::SysAllocString(pwzName);
180 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name");
181
182 // get catalog
183 hr = CpiGetAdminCatalog(&piCatalog);
184 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
185
186 // get key
187 hr = piObj->get_Key(&vtKey);
188 ExitOnFailure(hr, "Failed to get object key");
189
190 // get collecton from catalog
191 hr = piColl->GetCollection(bstrName, vtKey, &piDisp);
192 ExitOnFailure(hr, "Failed to get collection");
193
194 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
195 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
196
197 // populate collection
198 hr = (*ppiColl)->Populate();
199 ExitOnFailure(hr, "Failed to populate collection");
200
201 hr = S_OK;
202
203LExit:
204 // clean up
205 ReleaseObject(piCatalog);
206 ReleaseObject(piDisp);
207 ReleaseBSTR(bstrName);
208 ::VariantClear(&vtKey);
209
210 return hr;
211}
212
213HRESULT CpiGetKeyForObject(
214 ICatalogObject* piObj,
215 LPWSTR pwzKey,
216 SIZE_T cchKey
217 )
218{
219 HRESULT hr = S_OK;
220
221 VARIANT vtKey;
222 ::VariantInit(&vtKey);
223
224 // get key
225 hr = piObj->get_Key(&vtKey);
226 ExitOnFailure(hr, "Failed to get key");
227
228 // change variant type
229 hr = ::VariantChangeType(&vtKey, &vtKey, 0, VT_BSTR);
230 ExitOnFailure(hr, "Failed to change variant type");
231
232 // copy key
233 hr = StringCchCopyW(pwzKey, cchKey, vtKey.bstrVal);
234 ExitOnFailure(hr, "Failed to copy key");
235
236 hr = S_OK;
237
238LExit:
239 // clean up
240 ::VariantClear(&vtKey);
241
242 return hr;
243}
244
245HRESULT CpiFindCollectionObject(
246 ICatalogCollection* piColl,
247 LPCWSTR pwzID,
248 LPCWSTR pwzName,
249 ICatalogObject** ppiObj
250 )
251{
252 HRESULT hr = S_OK;
253
254 IDispatch* piDisp = NULL;
255 ICatalogObject* piObj = NULL;
256
257 VARIANT vtVal;
258 ::VariantInit(&vtVal);
259
260 long lCnt;
261 hr = piColl->get_Count(&lCnt);
262 ExitOnFailure(hr, "Failed to get to number of items in collection");
263
264 for (long i = 0; i < lCnt; i++)
265 {
266 // get ICatalogObject interface
267 hr = piColl->get_Item(i, &piDisp);
268 ExitOnFailure(hr, "Failed to get object from collection");
269
270 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
271 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
272
273 // compare id
274 if (pwzID && *pwzID)
275 {
276 hr = piObj->get_Key(&vtVal);
277 ExitOnFailure(hr, "Failed to get key");
278
279 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
280 ExitOnFailure(hr, "Failed to change variant type");
281
282 if (0 == lstrcmpiW(vtVal.bstrVal, pwzID))
283 {
284 if (ppiObj)
285 {
286 *ppiObj = piObj;
287 piObj = NULL;
288 }
289 ExitFunction1(hr = S_OK);
290 }
291
292 ::VariantClear(&vtVal);
293 }
294
295 // compare name
296 if (pwzName && *pwzName)
297 {
298 hr = piObj->get_Name(&vtVal);
299 ExitOnFailure(hr, "Failed to get name");
300
301 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
302 ExitOnFailure(hr, "Failed to change variant type");
303
304 if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
305 {
306 if (ppiObj)
307 {
308 *ppiObj = piObj;
309 piObj = NULL;
310 }
311 ExitFunction1(hr = S_OK);
312 }
313
314 ::VariantClear(&vtVal);
315 }
316
317 // release interface pointers
318 ReleaseNullObject(piDisp);
319 ReleaseNullObject(piObj);
320 }
321
322 hr = S_FALSE;
323
324LExit:
325 // clean up
326 ReleaseObject(piDisp);
327 ReleaseObject(piObj);
328
329 ::VariantClear(&vtVal);
330
331 return hr;
332}
333
334HRESULT CpiGetPartitionsCollection(
335 ICatalogCollection** ppiPartColl
336 )
337{
338 HRESULT hr = S_OK;
339
340 if (!gpiPartColl)
341 {
342 // get collection
343 hr = CpiGetCatalogCollection(L"Partitions", &gpiPartColl);
344 ExitOnFailure(hr, "Failed to get partitions collection");
345 }
346
347 // return value
348 gpiPartColl->AddRef();
349 *ppiPartColl = gpiPartColl;
350
351 hr = S_OK;
352
353LExit:
354 return hr;
355}
356
357HRESULT CpiGetApplicationsCollection(
358 ICatalogCollection** ppiAppColl
359 )
360{
361 HRESULT hr = S_OK;
362
363 ICOMAdminCatalog* piCatalog = NULL;
364 ICOMAdminCatalog2* piCatalog2 = NULL;
365 ICatalogCollection* piPartColl = NULL;
366 ICatalogObject* piPartObj = NULL;
367 BSTR bstrGlobPartID = NULL;
368
369 if (!gpiAppColl)
370 {
371 // get catalog
372 hr = CpiGetAdminCatalog(&piCatalog);
373 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
374
375 // get ICOMAdminCatalog2 interface
376 hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2);
377
378 // COM+ 1.5 or later
379 if (E_NOINTERFACE != hr)
380 {
381 ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface");
382
383 // get global partition id
384 hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID);
385 ExitOnFailure(hr, "Failed to get global partition id");
386
387 // get partitions collection
388 hr = CpiGetPartitionsCollection(&piPartColl);
389 ExitOnFailure(hr, "Failed to get partitions collection");
390
391 // find object
392 hr = CpiFindCollectionObject(piPartColl, bstrGlobPartID, NULL, &piPartObj);
393 ExitOnFailure(hr, "Failed to find collection object");
394
395 if (S_FALSE == hr)
396 ExitFunction(); // partition not found, exit with hr = S_FALSE
397
398 // get applications collection
399 hr = CpiGetCatalogCollection(piPartColl, piPartObj, L"Applications", &gpiAppColl);
400 ExitOnFailure(hr, "Failed to get applications collection");
401 }
402
403 // COM+ pre 1.5
404 else
405 {
406 // get applications collection
407 hr = CpiGetCatalogCollection(L"Applications", &gpiAppColl);
408 ExitOnFailure(hr, "Failed to get applications collection");
409 }
410 }
411
412 // return value
413 gpiAppColl->AddRef();
414 *ppiAppColl = gpiAppColl;
415
416 hr = S_OK;
417
418LExit:
419 // clean up
420 ReleaseObject(piCatalog);
421 ReleaseObject(piCatalog2);
422 ReleaseObject(piPartColl);
423 ReleaseObject(piPartObj);
424 ReleaseBSTR(bstrGlobPartID);
425
426 return hr;
427}
428
429HRESULT CpiAddActionTextToActionData(
430 LPCWSTR pwzAction,
431 LPWSTR* ppwzActionData
432 )
433{
434 HRESULT hr = S_OK;
435
436 PMSIHANDLE hView, hRecKey, hRec;
437
438 LPWSTR pwzDescription = NULL;
439 LPWSTR pwzTemplate = NULL;
440
441 if (S_OK == WcaTableExists(L"ActionText"))
442 {
443 // create parameter record
444 hRecKey = ::MsiCreateRecord(1);
445 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
446 hr = WcaSetRecordString(hRecKey, 1, pwzAction);
447 ExitOnFailure(hr, "Failed to set record string");
448
449 // open view
450 hr = WcaOpenView(vcsActionTextQuery, &hView);
451 ExitOnFailure(hr, "Failed to open view on ActionText table");
452 hr = WcaExecuteView(hView, hRecKey);
453 ExitOnFailure(hr, "Failed to execute view on ActionText table");
454
455 // fetch record
456 hr = WcaFetchSingleRecord(hView, &hRec);
457 if (S_FALSE != hr)
458 {
459 ExitOnFailure(hr, "Failed to fetch action text record");
460
461 // get description
462 hr = WcaGetRecordString(hRec, atqDescription, &pwzDescription);
463 ExitOnFailure(hr, "Failed to get description");
464
465 // get template
466 hr = WcaGetRecordString(hRec, atqTemplate, &pwzTemplate);
467 ExitOnFailure(hr, "Failed to get template");
468 }
469 }
470
471 // add action name to action data
472 hr = WcaWriteStringToCaData(pwzAction, ppwzActionData);
473 ExitOnFailure(hr, "Failed to add action name to custom action data");
474
475 // add description to action data
476 hr = WcaWriteStringToCaData(pwzDescription ? pwzDescription : L"", ppwzActionData);
477 ExitOnFailure(hr, "Failed to add description to custom action data");
478
479 // add template to action data
480 hr = WcaWriteStringToCaData(pwzTemplate ? pwzTemplate : L"", ppwzActionData);
481 ExitOnFailure(hr, "Failed to add template to custom action data");
482
483 hr = S_OK;
484
485LExit:
486 // clean up
487 ReleaseStr(pwzDescription);
488 ReleaseStr(pwzTemplate);
489
490 return hr;
491}
492
493HRESULT CpiVerifyComponentArchitecure(
494 LPCWSTR pwzComponent,
495 BOOL* pfMatchingArchitecture
496 )
497{
498 HRESULT hr = S_OK;
499
500 PMSIHANDLE hView, hRecKey, hRec;
501
502 int iAttributes = 0;
503
504 if (S_OK == WcaTableExists(L"Component"))
505 {
506 // create parameter record
507 hRecKey = ::MsiCreateRecord(1);
508 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
509 hr = WcaSetRecordString(hRecKey, 1, pwzComponent);
510 ExitOnFailure(hr, "Failed to set record string");
511
512 // open view
513 hr = WcaOpenView(vcsComponentAttributesQuery, &hView);
514 ExitOnFailure(hr, "Failed to open view on ActionText table");
515 hr = WcaExecuteView(hView, hRecKey);
516 ExitOnFailure(hr, "Failed to execute view on ActionText table");
517
518 // fetch record
519 hr = WcaFetchSingleRecord(hView, &hRec);
520 if (S_FALSE != hr)
521 {
522 ExitOnFailure(hr, "Failed to fetch component record");
523
524 hr = WcaGetRecordInteger(hRec, caqAttributes, &iAttributes);
525 ExitOnFailure(hr, "Failed to get component attributes");
526 }
527 }
528
529 // return values
530#ifdef _WIN64
531 *pfMatchingArchitecture = 256 == (iAttributes & 256);
532#else
533 *pfMatchingArchitecture = 256 != (iAttributes & 256);
534#endif
535
536 hr = S_OK;
537
538LExit:
539 return hr;
540}
541
542HRESULT CpiPropertiesRead(
543 LPCWSTR pwzQuery,
544 LPCWSTR pwzKey,
545 CPI_PROPERTY_DEFINITION* pPropDefList,
546 CPI_PROPERTY** ppPropList,
547 int* piCount
548 )
549{
550 HRESULT hr = S_OK;
551
552 PMSIHANDLE hView, hRecKey, hRec;
553
554 CPI_PROPERTY* pItm = NULL;
555 LPWSTR pwzData = NULL;
556
557 int iVersionNT = 0;
558
559 CPI_PROPERTY_DEFINITION* pPropDef;
560
561 *piCount = 0;
562
563 // get NT version
564 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
565 ExitOnFailure(hr, "Failed to set record string");
566
567 // create parameter record
568 hRecKey = ::MsiCreateRecord(1);
569 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
570 hr = WcaSetRecordString(hRecKey, 1, pwzKey);
571 ExitOnFailure(hr, "Failed to set record string");
572
573 // open view
574 hr = WcaOpenView(pwzQuery, &hView);
575 ExitOnFailure(hr, "Failed to open view on property table");
576 hr = WcaExecuteView(hView, hRecKey);
577 ExitOnFailure(hr, "Failed to execute view on property table");
578
579 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
580 {
581 // create entry
582 pItm = (CPI_PROPERTY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PROPERTY));
583 if (!pItm)
584 ExitFunction1(hr = E_OUTOFMEMORY);
585
586 // get name
587 hr = WcaGetRecordString(hRec, pqName, &pwzData);
588 ExitOnFailure(hr, "Failed to get name");
589 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
590
591 // get value
592 hr = WcaGetRecordFormattedString(hRec, pqValue, &pItm->pwzValue);
593 ExitOnFailure(hr, "Failed to get value");
594
595 // find property definition
596 hr = FindPropertyDefinition(pPropDefList, pItm->wzName, &pPropDef);
597 ExitOnFailure(hr, "Failed to find property definition");
598
599 if (S_FALSE == hr)
600 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Unknown property, key: %S, property: %S", pwzKey, pItm->wzName);
601
602 // check version, ignore if catalog version is too low
603 if (iVersionNT < pPropDef->iMinVersionNT)
604 {
605 WcaLog(LOGMSG_VERBOSE, "Skipping property since NT version is too low, key: %S, property: %S", pwzKey, pItm->wzName);
606 CpiPropertiesFreeList(pItm);
607 pItm = NULL;
608 continue;
609 }
610
611 // if the property is a user, replace the User table key with a user account name
612 if (cpptUser == pPropDef->iType)
613 {
614 hr = GetUserAccountName(pItm->pwzValue, &pItm->pwzValue);
615 ExitOnFailure(hr, "Failed to get user account name");
616 }
617
618 // add entry
619 ++*piCount;
620 if (*ppPropList)
621 pItm->pNext = *ppPropList;
622 *ppPropList = pItm;
623 pItm = NULL;
624 }
625
626 if (E_NOMOREITEMS == hr)
627 hr = S_OK;
628
629LExit:
630 // clean up
631 if (pItm)
632 CpiPropertiesFreeList(pItm);
633
634 ReleaseStr(pwzData);
635
636 return hr;
637}
638
639void CpiPropertiesFreeList(
640 CPI_PROPERTY* pList
641 )
642{
643 while (pList)
644 {
645 ReleaseStr(pList->pwzValue);
646
647 CPI_PROPERTY* pDelete = pList;
648 pList = pList->pNext;
649 ::HeapFree(::GetProcessHeap(), 0, pDelete);
650 }
651}
652
653HRESULT CpiAddPropertiesToActionData(
654 int iPropCount,
655 CPI_PROPERTY* pPropList,
656 LPWSTR* ppwzActionData
657 )
658{
659 HRESULT hr = S_OK;
660
661 hr = WcaWriteIntegerToCaData(iPropCount, ppwzActionData);
662 ExitOnFailure(hr, "Failed to add count to custom action data");
663
664 if (iPropCount) // count might be 0 event thought there are elements in the list
665 {
666 for (CPI_PROPERTY* pProp = pPropList; pProp; pProp = pProp->pNext)
667 {
668 hr = WcaWriteStringToCaData(pProp->wzName, ppwzActionData);
669 ExitOnFailure(hr, "Failed to add property name to custom action data, name: %S", pProp->wzName);
670
671 hr = WcaWriteStringToCaData(pProp->pwzValue, ppwzActionData);
672 ExitOnFailure(hr, "Failed to add property value to custom action data, name: %S", pProp->wzName);
673 }
674 }
675
676 hr = S_OK;
677
678LExit:
679 return hr;
680}
681
682HRESULT CpiBuildAccountName(
683 LPCWSTR pwzDomain,
684 LPCWSTR pwzName,
685 LPWSTR* ppwzAccount
686 )
687{
688 HRESULT hr = S_OK;
689
690 WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1];
691 ::ZeroMemory(wzComputerName, sizeof(wzComputerName));
692
693 // if domain is '.', get computer name
694 if (0 == lstrcmpW(pwzDomain, L"."))
695 {
696 DWORD dwSize = countof(wzComputerName);
697 if (!::GetComputerNameW(wzComputerName, &dwSize))
698 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get computer name");
699 }
700
701 // build account name
702 hr = StrAllocFormatted(ppwzAccount, L"%s\\%s", *wzComputerName ? wzComputerName : pwzDomain, pwzName);
703 ExitOnFailure(hr, "Failed to build domain user name");
704
705 hr = S_OK;
706
707LExit:
708 return hr;
709}
710
711HRESULT CpiGetTempFileName(
712 LPWSTR* ppwzTempFile
713 )
714{
715 HRESULT hr = S_OK;
716
717 // get temp path
718 WCHAR wzTempPath[MAX_PATH];
719 DWORD dw = ::GetTempPathW(countof(wzTempPath), wzTempPath);
720 if (countof(wzTempPath) <= dw)
721 ExitOnFailure(hr = E_FAIL, "TEMP directory path too long");
722
723 // get unique number
724 LARGE_INTEGER liCount;
725 if (!::QueryPerformanceCounter(&liCount))
726 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to query performance counter");
727
728 // create temp file name
729 hr = StrAllocFormatted(ppwzTempFile, L"%sCPI%I64X.tmp", wzTempPath, liCount.QuadPart);
730 ExitOnFailure(hr, "Failed to create temp file name string");
731
732 hr = S_OK;
733
734LExit:
735 return hr;
736}
737
738HRESULT CpiCreateId(
739 LPWSTR pwzDest,
740 SIZE_T cchDest
741 )
742{
743 HRESULT hr = S_OK;
744
745 GUID guid;
746
747 // create new guid
748 hr = ::CoCreateGuid(&guid);
749 ExitOnFailure(hr, "Failed to create new guid");
750
751 // convert guid to string
752 if (0 == ::StringFromGUID2(guid, pwzDest, (int)cchDest))
753 ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string");
754
755 hr = S_OK;
756
757LExit:
758 return hr;
759}
760
761BOOL CpiIsInstalled(
762 INSTALLSTATE isInstalled
763 )
764{
765 return INSTALLSTATE_LOCAL == isInstalled || INSTALLSTATE_SOURCE == isInstalled;
766}
767
768BOOL CpiWillBeInstalled(
769 INSTALLSTATE isInstalled,
770 INSTALLSTATE isAction
771 )
772{
773 return WcaIsInstalling(isInstalled, isAction) ||
774 (CpiIsInstalled(isInstalled) && !WcaIsUninstalling(isInstalled, isAction));
775}
776
777HRESULT PcaGuidToRegFormat(
778 LPWSTR pwzGuid,
779 LPWSTR pwzDest,
780 SIZE_T cchDest
781 )
782{
783 HRESULT hr = S_OK;
784
785 GUID guid = GUID_NULL;
786 int cch = 0;
787
788 WCHAR wz[39];
789 ::ZeroMemory(wz, sizeof(wz));
790
791 cch = lstrlenW(pwzGuid);
792
793 if (38 == cch && L'{' == pwzGuid[0] && L'}' == pwzGuid[37])
794 StringCchCopyW(wz, countof(wz), pwzGuid);
795 else if (36 == cch)
796 StringCchPrintfW(wz, countof(wz), L"{%s}", pwzGuid);
797 else
798 ExitFunction1(hr = E_INVALIDARG);
799
800 // convert string to guid
801 hr = ::CLSIDFromString(wz, &guid);
802 ExitOnFailure(hr, "Failed to parse guid string");
803
804 // convert guid to string
805 if (0 == ::StringFromGUID2(guid, pwzDest, (int)cchDest))
806 ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string");
807
808 hr = S_OK;
809
810LExit:
811 return hr;
812}
813
814
815// helper function definitions
816
817static HRESULT FindPropertyDefinition(
818 CPI_PROPERTY_DEFINITION* pPropDefList,
819 LPCWSTR pwzName,
820 CPI_PROPERTY_DEFINITION** ppPropDef
821 )
822{
823 for (CPI_PROPERTY_DEFINITION* pItm = pPropDefList; pItm->pwzName; pItm++)
824 {
825 if (0 == lstrcmpW(pItm->pwzName, pwzName))
826 {
827 *ppPropDef = pItm;
828 return S_OK;
829 }
830 }
831
832 return S_FALSE;
833}
834
835static HRESULT GetUserAccountName(
836 LPCWSTR pwzKey,
837 LPWSTR* ppwzAccount
838 )
839{
840 HRESULT hr = S_OK;
841
842 PMSIHANDLE hView, hRecKey, hRec;
843
844 LPWSTR pwzDomain = NULL;
845 LPWSTR pwzName = NULL;
846
847 // create parameter record
848 hRecKey = ::MsiCreateRecord(1);
849 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
850 hr = WcaSetRecordString(hRecKey, 1, pwzKey);
851 ExitOnFailure(hr, "Failed to set record string");
852
853 // open view
854 hr = WcaOpenView(vcsUserQuery, &hView);
855 ExitOnFailure(hr, "Failed to open view on User table");
856 hr = WcaExecuteView(hView, hRecKey);
857 ExitOnFailure(hr, "Failed to execute view on User table");
858
859 // fetch record
860 hr = WcaFetchSingleRecord(hView, &hRec);
861 if (S_FALSE == hr)
862 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "User not found, key: %S", pwzKey);
863 ExitOnFailure(hr, "Failed to fetch user record");
864
865 // get user domain
866 hr = WcaGetRecordFormattedString(hRec, uqDomain, &pwzDomain);
867 ExitOnFailure(hr, "Failed to get domain");
868
869 // get user name
870 hr = WcaGetRecordFormattedString(hRec, uqName, &pwzName);
871 ExitOnFailure(hr, "Failed to get name");
872
873 // build account name
874 hr = CpiBuildAccountName(pwzDomain, pwzName, ppwzAccount);
875 ExitOnFailure(hr, "Failed to build account name");
876
877 hr = S_OK;
878
879LExit:
880 // clean up
881 ReleaseStr(pwzDomain);
882 ReleaseStr(pwzName);
883
884 return hr;
885}
diff --git a/src/ca/cputilsched.h b/src/ca/cputilsched.h
new file mode 100644
index 00000000..61aaab84
--- /dev/null
+++ b/src/ca/cputilsched.h
@@ -0,0 +1,144 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#define CPI_MAX_GUID 38
6
7enum eRunMode { rmDeferred = 1, rmCommit, rmRollback };
8
9enum eActionType { atNoOp = 0, atCreate, atRemove };
10
11enum eComPlusPropertyType { cpptNone = 0, cpptBoolean, cpptInteger, cpptString, cpptUser };
12
13enum eComPlusTables
14{
15 cptComPlusPartition = (1 << 0),
16 cptComPlusPartitionProperty = (1 << 1),
17 cptComPlusPartitionRole = (1 << 2),
18 cptComPlusUserInPartitionRole = (1 << 3),
19 cptComPlusGroupInPartitionRole = (1 << 4),
20 cptComPlusPartitionUser = (1 << 5),
21 cptComPlusApplication = (1 << 6),
22 cptComPlusApplicationProperty = (1 << 7),
23 cptComPlusApplicationRole = (1 << 8),
24 cptComPlusApplicationRoleProperty = (1 << 9),
25 cptComPlusUserInApplicationRole = (1 << 10),
26 cptComPlusGroupInApplicationRole = (1 << 11),
27 cptComPlusAssembly = (1 << 12),
28 cptComPlusAssemblyDependency = (1 << 13),
29 cptComPlusComponent = (1 << 14),
30 cptComPlusComponentProperty = (1 << 15),
31 cptComPlusRoleForComponent = (1 << 16),
32 cptComPlusInterface = (1 << 17),
33 cptComPlusInterfaceProperty = (1 << 18),
34 cptComPlusRoleForInterface = (1 << 19),
35 cptComPlusMethod = (1 << 20),
36 cptComPlusMethodProperty = (1 << 21),
37 cptComPlusRoleForMethod = (1 << 22),
38 cptComPlusSubscription = (1 << 23),
39 cptComPlusSubscriptionProperty = (1 << 24)
40};
41
42
43// structs
44
45struct CPI_PROPERTY
46{
47 WCHAR wzName[MAX_DARWIN_KEY + 1];
48 LPWSTR pwzValue;
49
50 CPI_PROPERTY* pNext;
51};
52
53struct CPI_PROPERTY_DEFINITION
54{
55 LPCWSTR pwzName;
56 int iType;
57 int iMinVersionNT;
58};
59
60
61// function prototypes
62
63void CpiInitialize();
64void CpiFinalize();
65BOOL CpiTableExists(
66 int iTable
67 );
68HRESULT CpiGetAdminCatalog(
69 ICOMAdminCatalog** ppiCatalog
70 );
71HRESULT CpiGetCatalogCollection(
72 LPCWSTR pwzName,
73 ICatalogCollection** ppiColl
74 );
75HRESULT CpiGetCatalogCollection(
76 ICatalogCollection* piColl,
77 ICatalogObject* piObj,
78 LPCWSTR pwzName,
79 ICatalogCollection** ppiColl
80 );
81HRESULT CpiGetKeyForObject(
82 ICatalogObject* piObj,
83 LPWSTR pwzKey,
84 SIZE_T cchKey
85 );
86HRESULT CpiFindCollectionObject(
87 ICatalogCollection* piColl,
88 LPCWSTR pwzID,
89 LPCWSTR pwzName,
90 ICatalogObject** ppiObj
91 );
92HRESULT CpiGetPartitionsCollection(
93 ICatalogCollection** ppiPartColl
94 );
95HRESULT CpiGetApplicationsCollection(
96 ICatalogCollection** ppiAppColl
97 );
98HRESULT CpiAddActionTextToActionData(
99 LPCWSTR pwzAction,
100 LPWSTR* ppwzActionData
101 );
102HRESULT CpiVerifyComponentArchitecure(
103 LPCWSTR pwzComponent,
104 BOOL* pfMatchingArchitecture
105 );
106HRESULT CpiPropertiesRead(
107 LPCWSTR pwzQuery,
108 LPCWSTR pwzKey,
109 CPI_PROPERTY_DEFINITION* pPropDefList,
110 CPI_PROPERTY** ppPropList,
111 int* piCount
112 );
113void CpiPropertiesFreeList(
114 CPI_PROPERTY* pList
115 );
116HRESULT CpiAddPropertiesToActionData(
117 int iPropCount,
118 CPI_PROPERTY* pPropList,
119 LPWSTR* ppwzActionData
120 );
121HRESULT CpiBuildAccountName(
122 LPCWSTR pwzDomain,
123 LPCWSTR pwzName,
124 LPWSTR* ppwzAccount
125 );
126HRESULT CpiGetTempFileName(
127 LPWSTR* ppwzTempFile
128 );
129HRESULT CpiCreateId(
130 LPWSTR pwzDest,
131 SIZE_T cchDest
132 );
133BOOL CpiIsInstalled(
134 INSTALLSTATE isInstalled
135 );
136BOOL CpiWillBeInstalled(
137 INSTALLSTATE isInstalled,
138 INSTALLSTATE isAction
139 );
140HRESULT PcaGuidToRegFormat(
141 LPWSTR pwzGuid,
142 LPWSTR pwzDest,
143 SIZE_T cchDest
144 );