diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2019-02-04 20:05:54 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2019-02-04 20:05:54 -0600 |
commit | cbc09b6cd6d0d0b8bf095a88d4d8333616637f71 (patch) | |
tree | a0893e8b8772765747630052018312a2d77f97e4 /src/ca | |
parent | c94f50e3d8dc958f8a0b9540e63e920a079c1779 (diff) | |
download | wix-cbc09b6cd6d0d0b8bf095a88d4d8333616637f71.tar.gz wix-cbc09b6cd6d0d0b8bf095a88d4d8333616637f71.tar.bz2 wix-cbc09b6cd6d0d0b8bf095a88d4d8333616637f71.zip |
Import code from old v4 repo
Diffstat (limited to 'src/ca')
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 | |||
8 | struct 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 | |||
22 | static HRESULT ReadApplicationAttributes( | ||
23 | LPWSTR* ppwzData, | ||
24 | CPI_APPLICATION_ATTRIBUTES* pAttrs | ||
25 | ); | ||
26 | static void FreeApplicationAttributes( | ||
27 | CPI_APPLICATION_ATTRIBUTES* pAttrs | ||
28 | ); | ||
29 | static HRESULT CreateApplication( | ||
30 | CPI_APPLICATION_ATTRIBUTES* pAttrs | ||
31 | ); | ||
32 | static HRESULT RemoveApplication( | ||
33 | CPI_APPLICATION_ATTRIBUTES* pAttrs | ||
34 | ); | ||
35 | |||
36 | |||
37 | // function definitions | ||
38 | |||
39 | HRESULT 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 | |||
103 | LExit: | ||
104 | // clean up | ||
105 | FreeApplicationAttributes(&attrs); | ||
106 | |||
107 | return hr; | ||
108 | } | ||
109 | |||
110 | HRESULT 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 | |||
176 | LExit: | ||
177 | // clean up | ||
178 | FreeApplicationAttributes(&attrs); | ||
179 | |||
180 | return hr; | ||
181 | } | ||
182 | |||
183 | |||
184 | // helper function definitions | ||
185 | |||
186 | static 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 | |||
210 | LExit: | ||
211 | return hr; | ||
212 | } | ||
213 | |||
214 | static 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 | |||
227 | static 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 | |||
285 | LExit: | ||
286 | // clean up | ||
287 | ReleaseObject(piAppColl); | ||
288 | ReleaseObject(piAppObj); | ||
289 | |||
290 | return hr; | ||
291 | } | ||
292 | |||
293 | static 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 | |||
339 | LExit: | ||
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 | |||
5 | HRESULT CpiConfigureApplications( | ||
6 | LPWSTR* ppwzData, | ||
7 | HANDLE hRollbackFile | ||
8 | ); | ||
9 | HRESULT 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 | |||
8 | struct 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 | |||
19 | struct 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 | |||
33 | static HRESULT ReadApplicationRoleAttributes( | ||
34 | LPWSTR* ppwzData, | ||
35 | CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs | ||
36 | ); | ||
37 | static void FreeApplicationRoleAttributes( | ||
38 | CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs | ||
39 | ); | ||
40 | static HRESULT CreateApplicationRole( | ||
41 | CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs | ||
42 | ); | ||
43 | static HRESULT RemoveApplicationRole( | ||
44 | CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs | ||
45 | ); | ||
46 | static HRESULT ReadUsersInApplicationRoleAttributes( | ||
47 | LPWSTR* ppwzData, | ||
48 | CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs | ||
49 | ); | ||
50 | static void FreeUsersInApplicationRoleAttributes( | ||
51 | CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs | ||
52 | ); | ||
53 | static HRESULT CreateUsersInApplicationRole( | ||
54 | CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs | ||
55 | ); | ||
56 | static HRESULT RemoveUsersInApplicationRole( | ||
57 | CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs | ||
58 | ); | ||
59 | |||
60 | |||
61 | // function definitions | ||
62 | |||
63 | HRESULT 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 | |||
127 | LExit: | ||
128 | // clean up | ||
129 | FreeApplicationRoleAttributes(&attrs); | ||
130 | |||
131 | return hr; | ||
132 | } | ||
133 | |||
134 | HRESULT 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 | |||
200 | LExit: | ||
201 | // clean up | ||
202 | FreeApplicationRoleAttributes(&attrs); | ||
203 | |||
204 | return hr; | ||
205 | } | ||
206 | |||
207 | HRESULT 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 | |||
271 | LExit: | ||
272 | // clean up | ||
273 | FreeUsersInApplicationRoleAttributes(&attrs); | ||
274 | |||
275 | return hr; | ||
276 | } | ||
277 | |||
278 | HRESULT 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 | |||
344 | LExit: | ||
345 | // clean up | ||
346 | FreeUsersInApplicationRoleAttributes(&attrs); | ||
347 | |||
348 | return hr; | ||
349 | } | ||
350 | |||
351 | |||
352 | // helper function definitions | ||
353 | |||
354 | static 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 | |||
378 | LExit: | ||
379 | return hr; | ||
380 | } | ||
381 | |||
382 | static 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 | |||
395 | static 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 | |||
444 | LExit: | ||
445 | // clean up | ||
446 | ReleaseObject(piRolesColl); | ||
447 | ReleaseObject(piRoleObj); | ||
448 | |||
449 | return hr; | ||
450 | } | ||
451 | |||
452 | static 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 | |||
498 | LExit: | ||
499 | // clean up | ||
500 | ReleaseObject(piRolesColl); | ||
501 | |||
502 | return hr; | ||
503 | } | ||
504 | |||
505 | static 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 | |||
529 | LExit: | ||
530 | return hr; | ||
531 | } | ||
532 | |||
533 | static 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 | |||
544 | static 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 | |||
624 | LExit: | ||
625 | // clean up | ||
626 | ReleaseObject(piUsrInRoleColl); | ||
627 | ReleaseObject(piUsrInRoleObj); | ||
628 | |||
629 | if (pSid) | ||
630 | ::HeapFree(::GetProcessHeap(), 0, pSid); | ||
631 | |||
632 | return hr; | ||
633 | } | ||
634 | |||
635 | static 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 | |||
712 | LExit: | ||
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 | |||
5 | HRESULT CpiConfigureApplicationRoles( | ||
6 | LPWSTR* ppwzData, | ||
7 | HANDLE hRollbackFile | ||
8 | ); | ||
9 | HRESULT CpiRollbackConfigureApplicationRoles( | ||
10 | LPWSTR* ppwzData, | ||
11 | CPI_ROLLBACK_DATA* pRollbackDataList | ||
12 | ); | ||
13 | HRESULT CpiConfigureUsersInApplicationRoles( | ||
14 | LPWSTR* ppwzData, | ||
15 | HANDLE hRollbackFile | ||
16 | ); | ||
17 | HRESULT 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 | |||
8 | LPCWSTR vcsApplicationRoleQuery = | ||
9 | L"SELECT `ApplicationRole`, `Application_`, `Component_`, `Name` FROM `ComPlusApplicationRole`"; | ||
10 | enum eApplicationRoleQuery { arqApplicationRole = 1, arqApplication, arqComponent, arqName }; | ||
11 | |||
12 | LPCWSTR vcsUserInApplicationRoleQuery = | ||
13 | L"SELECT `UserInApplicationRole`, `ApplicationRole_`, `ComPlusUserInApplicationRole`.`Component_`, `Domain`, `Name` FROM `ComPlusUserInApplicationRole`, `User` WHERE `User_` = `User`"; | ||
14 | LPCWSTR vcsGroupInApplicationRoleQuery = | ||
15 | L"SELECT `GroupInApplicationRole`, `ApplicationRole_`, `ComPlusGroupInApplicationRole`.`Component_`, `Domain`, `Name` FROM `ComPlusGroupInApplicationRole`, `Group` WHERE `Group_` = `Group`"; | ||
16 | enum eTrusteeInApplicationRoleQuery { tiarqUserInApplicationRole = 1, tiarqApplicationRole, tiarqComponent, tiarqDomain, tiarqName }; | ||
17 | |||
18 | LPCWSTR vcsApplicationRolePropertyQuery = | ||
19 | L"SELECT `Name`, `Value` FROM `ComPlusApplicationRoleProperty` WHERE `ApplicationRole_` = ?"; | ||
20 | |||
21 | |||
22 | // property definitions | ||
23 | |||
24 | CPI_PROPERTY_DEFINITION pdlApplicationRoleProperties[] = | ||
25 | { | ||
26 | {L"Description", cpptString, 500}, | ||
27 | {NULL, cpptNone, 0} | ||
28 | }; | ||
29 | |||
30 | |||
31 | // prototypes for private helper functions | ||
32 | |||
33 | static HRESULT TrusteesInApplicationRolesRead( | ||
34 | LPCWSTR pwzQuery, | ||
35 | CPI_APPLICATION_ROLE_LIST* pAppRoleList, | ||
36 | CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList | ||
37 | ); | ||
38 | static void FreeApplicationRole( | ||
39 | CPI_APPLICATION_ROLE* pItm | ||
40 | ); | ||
41 | static void FreeUserInApplicationRole( | ||
42 | CPI_USER_IN_APPLICATION_ROLE* pItm | ||
43 | ); | ||
44 | //static HRESULT GetUsersCollForApplicationRole( | ||
45 | // CPI_APPLICATION_ROLE* pAppRole, | ||
46 | // ICatalogCollection** ppiUsersColl | ||
47 | // ); | ||
48 | static HRESULT FindObjectForApplicationRole( | ||
49 | CPI_APPLICATION_ROLE* pItm, | ||
50 | ICatalogObject** ppiRoleObj | ||
51 | ); | ||
52 | static HRESULT AddApplicationRoleToActionData( | ||
53 | CPI_APPLICATION_ROLE* pItm, | ||
54 | int iActionType, | ||
55 | int iActionCost, | ||
56 | LPWSTR* ppwzActionData | ||
57 | ); | ||
58 | static 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 | |||
68 | void 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 | |||
82 | HRESULT 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 | |||
183 | LExit: | ||
184 | // clean up | ||
185 | if (pItm) | ||
186 | FreeApplicationRole(pItm); | ||
187 | |||
188 | ReleaseStr(pwzData); | ||
189 | |||
190 | return hr; | ||
191 | } | ||
192 | |||
193 | HRESULT 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 | |||
256 | LExit: | ||
257 | // clean up | ||
258 | ReleaseObject(piRoleObj); | ||
259 | |||
260 | return hr; | ||
261 | } | ||
262 | |||
263 | HRESULT 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 | |||
290 | LExit: | ||
291 | return hr; | ||
292 | } | ||
293 | |||
294 | void CpiApplicationRoleAddReferenceInstall( | ||
295 | CPI_APPLICATION_ROLE* pItm | ||
296 | ) | ||
297 | { | ||
298 | pItm->fReferencedForInstall = TRUE; | ||
299 | CpiApplicationAddReferenceInstall(pItm->pApplication); | ||
300 | } | ||
301 | |||
302 | void CpiApplicationRoleAddReferenceUninstall( | ||
303 | CPI_APPLICATION_ROLE* pItm | ||
304 | ) | ||
305 | { | ||
306 | pItm->fReferencedForUninstall = TRUE; | ||
307 | CpiApplicationAddReferenceUninstall(pItm->pApplication); | ||
308 | } | ||
309 | |||
310 | HRESULT 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 | |||
358 | LExit: | ||
359 | return hr; | ||
360 | } | ||
361 | |||
362 | HRESULT 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 | |||
405 | LExit: | ||
406 | return hr; | ||
407 | } | ||
408 | |||
409 | HRESULT 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 | |||
427 | void 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 | |||
441 | HRESULT 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 | |||
464 | LExit: | ||
465 | return hr; | ||
466 | } | ||
467 | |||
468 | HRESULT 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 | |||
516 | LExit: | ||
517 | return hr; | ||
518 | } | ||
519 | |||
520 | HRESULT 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 | |||
563 | LExit: | ||
564 | return hr; | ||
565 | } | ||
566 | |||
567 | |||
568 | // helper function definitions | ||
569 | |||
570 | static 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 | |||
663 | LExit: | ||
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 | |||
675 | static 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 | |||
687 | static 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 | |||
739 | static 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 | |||
761 | LExit: | ||
762 | // clean up | ||
763 | ReleaseObject(piRoleColl); | ||
764 | |||
765 | return hr; | ||
766 | } | ||
767 | |||
768 | static 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 | |||
803 | LExit: | ||
804 | return hr; | ||
805 | } | ||
806 | |||
807 | static 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 | |||
841 | LExit: | ||
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 | |||
5 | struct 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 | |||
27 | struct CPI_APPLICATION_ROLE_LIST | ||
28 | { | ||
29 | CPI_APPLICATION_ROLE* pFirst; | ||
30 | |||
31 | int iInstallCount; | ||
32 | int iUninstallCount; | ||
33 | }; | ||
34 | |||
35 | struct 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 | |||
47 | struct 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 | |||
58 | void CpiApplicationRoleListFree( | ||
59 | CPI_APPLICATION_ROLE_LIST* pList | ||
60 | ); | ||
61 | HRESULT CpiApplicationRolesRead( | ||
62 | CPI_APPLICATION_LIST* pAppList, | ||
63 | CPI_APPLICATION_ROLE_LIST* pAppRoleList | ||
64 | ); | ||
65 | HRESULT CpiApplicationRolesVerifyInstall( | ||
66 | CPI_APPLICATION_ROLE_LIST* pList | ||
67 | ); | ||
68 | HRESULT CpiApplicationRolesVerifyUninstall( | ||
69 | CPI_APPLICATION_ROLE_LIST* pList | ||
70 | ); | ||
71 | void CpiApplicationRoleAddReferenceInstall( | ||
72 | CPI_APPLICATION_ROLE* pItm | ||
73 | ); | ||
74 | void CpiApplicationRoleAddReferenceUninstall( | ||
75 | CPI_APPLICATION_ROLE* pItm | ||
76 | ); | ||
77 | HRESULT CpiApplicationRolesInstall( | ||
78 | CPI_APPLICATION_ROLE_LIST* pList, | ||
79 | int iRunMode, | ||
80 | LPWSTR* ppwzActionData, | ||
81 | int* piProgress | ||
82 | ); | ||
83 | HRESULT CpiApplicationRolesUninstall( | ||
84 | CPI_APPLICATION_ROLE_LIST* pList, | ||
85 | int iRunMode, | ||
86 | LPWSTR* ppwzActionData, | ||
87 | int* piProgress | ||
88 | ); | ||
89 | HRESULT CpiApplicationRoleFindByKey( | ||
90 | CPI_APPLICATION_ROLE_LIST* pList, | ||
91 | LPCWSTR pwzKey, | ||
92 | CPI_APPLICATION_ROLE** ppAppRole | ||
93 | ); | ||
94 | void CpiUserInApplicationRoleListFree( | ||
95 | CPI_USER_IN_APPLICATION_ROLE_LIST* pList | ||
96 | ); | ||
97 | HRESULT CpiUsersInApplicationRolesRead( | ||
98 | CPI_APPLICATION_ROLE_LIST* pAppRoleList, | ||
99 | CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList | ||
100 | ); | ||
101 | HRESULT CpiUsersInApplicationRolesInstall( | ||
102 | CPI_USER_IN_APPLICATION_ROLE_LIST* pList, | ||
103 | int iRunMode, | ||
104 | LPWSTR* ppwzActionData, | ||
105 | int* piProgress | ||
106 | ); | ||
107 | HRESULT 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 | |||
8 | LPCWSTR vcsApplicationQuery = | ||
9 | L"SELECT `Application`, `Component_`, `Partition_`, `Id`, `Name` FROM `ComPlusApplication`"; | ||
10 | enum eApplicationQuery { aqApplication = 1, aqComponent, aqPartition, aqID, aqName }; | ||
11 | |||
12 | LPCWSTR vcsApplicationPropertyQuery = | ||
13 | L"SELECT `Name`, `Value` FROM `ComPlusApplicationProperty` WHERE `Application_` = ?"; | ||
14 | |||
15 | |||
16 | // property definitions | ||
17 | |||
18 | CPI_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 | |||
69 | static void FreeApplication( | ||
70 | CPI_APPLICATION* pItm | ||
71 | ); | ||
72 | static HRESULT FindObjectForApplication( | ||
73 | CPI_APPLICATION* pItm, | ||
74 | BOOL fFindId, | ||
75 | BOOL fFindName, | ||
76 | ICatalogObject** ppiAppObj | ||
77 | ); | ||
78 | static HRESULT AddApplicationToActionData( | ||
79 | CPI_APPLICATION* pItm, | ||
80 | int iActionType, | ||
81 | int iActionCost, | ||
82 | LPWSTR* ppwzActionData | ||
83 | ); | ||
84 | |||
85 | |||
86 | // function definitions | ||
87 | |||
88 | void 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 | |||
102 | HRESULT 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 | |||
233 | LExit: | ||
234 | // clean up | ||
235 | if (pItm) | ||
236 | FreeApplication(pItm); | ||
237 | |||
238 | ReleaseStr(pwzData); | ||
239 | |||
240 | return hr; | ||
241 | } | ||
242 | |||
243 | HRESULT 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 | |||
370 | LExit: | ||
371 | // clean up | ||
372 | ReleaseObject(piAppObj); | ||
373 | |||
374 | return hr; | ||
375 | } | ||
376 | |||
377 | HRESULT 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 | |||
419 | LExit: | ||
420 | // clean up | ||
421 | ReleaseObject(piAppObj); | ||
422 | |||
423 | return hr; | ||
424 | } | ||
425 | |||
426 | void CpiApplicationAddReferenceInstall( | ||
427 | CPI_APPLICATION* pItm | ||
428 | ) | ||
429 | { | ||
430 | pItm->fReferencedForInstall = TRUE; | ||
431 | if (pItm->pPartition) | ||
432 | CpiPartitionAddReferenceInstall(pItm->pPartition); | ||
433 | } | ||
434 | |||
435 | void CpiApplicationAddReferenceUninstall( | ||
436 | CPI_APPLICATION* pItm | ||
437 | ) | ||
438 | { | ||
439 | pItm->fReferencedForUninstall = TRUE; | ||
440 | if (pItm->pPartition) | ||
441 | CpiPartitionAddReferenceUninstall(pItm->pPartition); | ||
442 | } | ||
443 | |||
444 | HRESULT 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 | |||
492 | LExit: | ||
493 | return hr; | ||
494 | } | ||
495 | |||
496 | HRESULT 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 | |||
539 | LExit: | ||
540 | return hr; | ||
541 | } | ||
542 | |||
543 | HRESULT 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 | |||
561 | HRESULT 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 | |||
606 | LExit: | ||
607 | // clean up | ||
608 | ReleaseObject(piAppColl); | ||
609 | ReleaseObject(piAppObj); | ||
610 | |||
611 | return hr; | ||
612 | } | ||
613 | |||
614 | HRESULT 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 | |||
659 | LExit: | ||
660 | // clean up | ||
661 | ReleaseObject(piAppColl); | ||
662 | ReleaseObject(piAppObj); | ||
663 | |||
664 | return hr; | ||
665 | } | ||
666 | |||
667 | |||
668 | // helper function definitions | ||
669 | |||
670 | static 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 | |||
683 | static 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 | |||
710 | LExit: | ||
711 | // clean up | ||
712 | ReleaseObject(piAppColl); | ||
713 | |||
714 | return hr; | ||
715 | } | ||
716 | |||
717 | static 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 | |||
750 | LExit: | ||
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 | |||
5 | struct 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 | |||
29 | struct CPI_APPLICATION_LIST | ||
30 | { | ||
31 | CPI_APPLICATION* pFirst; | ||
32 | |||
33 | int iInstallCount; | ||
34 | int iUninstallCount; | ||
35 | }; | ||
36 | |||
37 | |||
38 | // function prototypes | ||
39 | |||
40 | void CpiApplicationListFree( | ||
41 | CPI_APPLICATION_LIST* pList | ||
42 | ); | ||
43 | HRESULT CpiApplicationsRead( | ||
44 | CPI_PARTITION_LIST* pPartList, | ||
45 | CPI_APPLICATION_LIST* pAppList | ||
46 | ); | ||
47 | HRESULT CpiApplicationsVerifyInstall( | ||
48 | CPI_APPLICATION_LIST* pList | ||
49 | ); | ||
50 | HRESULT CpiApplicationsVerifyUninstall( | ||
51 | CPI_APPLICATION_LIST* pList | ||
52 | ); | ||
53 | void CpiApplicationAddReferenceInstall( | ||
54 | CPI_APPLICATION* pItm | ||
55 | ); | ||
56 | void CpiApplicationAddReferenceUninstall( | ||
57 | CPI_APPLICATION* pItm | ||
58 | ); | ||
59 | HRESULT CpiApplicationsInstall( | ||
60 | CPI_APPLICATION_LIST* pList, | ||
61 | int iRunMode, | ||
62 | LPWSTR* ppwzActionData, | ||
63 | int* piProgress | ||
64 | ); | ||
65 | HRESULT CpiApplicationsUninstall( | ||
66 | CPI_APPLICATION_LIST* pList, | ||
67 | int iRunMode, | ||
68 | LPWSTR* ppwzActionData, | ||
69 | int* piProgress | ||
70 | ); | ||
71 | HRESULT CpiApplicationFindByKey( | ||
72 | CPI_APPLICATION_LIST* pList, | ||
73 | LPCWSTR pwzKey, | ||
74 | CPI_APPLICATION** ppApp | ||
75 | ); | ||
76 | HRESULT CpiGetRolesCollForApplication( | ||
77 | CPI_APPLICATION* pApp, | ||
78 | ICatalogCollection** ppiRolesColl | ||
79 | ); | ||
80 | HRESULT 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 | |||
8 | typedef 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 | |||
17 | typedef struct _FUSION_INSTALL_REFERENCE_ *LPFUSION_INSTALL_REFERENCE; | ||
18 | |||
19 | typedef const FUSION_INSTALL_REFERENCE *LPCFUSION_INSTALL_REFERENCE; | ||
20 | |||
21 | typedef struct _ASSEMBLY_INFO | ||
22 | { | ||
23 | ULONG cbAssemblyInfo; | ||
24 | DWORD dwAssemblyFlags; | ||
25 | ULARGE_INTEGER uliAssemblySizeInKB; | ||
26 | LPWSTR pszCurrentAssemblyPathBuf; | ||
27 | ULONG cchBuf; | ||
28 | } ASSEMBLY_INFO; | ||
29 | |||
30 | typedef interface IAssemblyCacheItem IAssemblyCacheItem; | ||
31 | |||
32 | MIDL_INTERFACE("e707dcde-d1cd-11d2-bab9-00c04f8eceae") | ||
33 | IAssemblyCache : public IUnknown | ||
34 | { | ||
35 | public: | ||
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 | |||
62 | typedef HRESULT (__stdcall *LoadLibraryShimFunc)(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll); | ||
63 | typedef HRESULT (__stdcall *CreateAssemblyCacheFunc)(IAssemblyCache **ppAsmCache, DWORD dwReserved); | ||
64 | |||
65 | |||
66 | // RegistrationHelper related declarations | ||
67 | |||
68 | static const GUID CLSID_RegistrationHelper = | ||
69 | { 0x89a86e7b, 0xc229, 0x4008, { 0x9b, 0xaa, 0x2f, 0x5c, 0x84, 0x11, 0xd7, 0xe0 } }; | ||
70 | |||
71 | enum eInstallationFlags { | ||
72 | ifConfigureComponentsOnly = 16, | ||
73 | ifFindOrCreateTargetApplication = 4, | ||
74 | ifExpectExistingTypeLib = 1 | ||
75 | }; | ||
76 | |||
77 | |||
78 | // private constants | ||
79 | |||
80 | enum 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 | |||
91 | struct 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 | |||
99 | struct 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 | |||
110 | struct 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 | |||
121 | struct 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 | |||
132 | struct 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 | |||
147 | struct 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 | |||
161 | static HRESULT RegisterAssembly( | ||
162 | CPI_ASSEMBLY_ATTRIBUTES* pAttrs | ||
163 | ); | ||
164 | static HRESULT UnregisterAssembly( | ||
165 | CPI_ASSEMBLY_ATTRIBUTES* pAttrs | ||
166 | ); | ||
167 | static void InitAssemblyExec(); | ||
168 | static void UninitAssemblyExec(); | ||
169 | static HRESULT GetRegistrationHelper( | ||
170 | IDispatch** ppiRegHlp | ||
171 | ); | ||
172 | static HRESULT GetAssemblyCacheObject( | ||
173 | IAssemblyCache** ppAssemblyCache | ||
174 | ); | ||
175 | static HRESULT GetAssemblyPathFromGAC( | ||
176 | LPCWSTR pwzAssemblyName, | ||
177 | LPWSTR* ppwzAssemblyPath | ||
178 | ); | ||
179 | static HRESULT RegisterDotNetAssembly( | ||
180 | CPI_ASSEMBLY_ATTRIBUTES* pAttrs | ||
181 | ); | ||
182 | static HRESULT RegisterNativeAssembly( | ||
183 | CPI_ASSEMBLY_ATTRIBUTES* pAttrs | ||
184 | ); | ||
185 | static HRESULT UnregisterDotNetAssembly( | ||
186 | CPI_ASSEMBLY_ATTRIBUTES* pAttrs | ||
187 | ); | ||
188 | static HRESULT RemoveComponents( | ||
189 | ICatalogCollection* piCompColl, | ||
190 | CPI_COMPONENT* pCompList | ||
191 | ); | ||
192 | static HRESULT ReadAssemblyAttributes( | ||
193 | LPWSTR* ppwzData, | ||
194 | CPI_ASSEMBLY_ATTRIBUTES* pAttrs | ||
195 | ); | ||
196 | static void FreeAssemblyAttributes( | ||
197 | CPI_ASSEMBLY_ATTRIBUTES* pAttrs | ||
198 | ); | ||
199 | static HRESULT ReadRoleAssignmentsAttributes( | ||
200 | LPWSTR* ppwzData, | ||
201 | CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs | ||
202 | ); | ||
203 | static void FreeRoleAssignmentsAttributes( | ||
204 | CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs | ||
205 | ); | ||
206 | static HRESULT ConfigureComponents( | ||
207 | LPCWSTR pwzPartID, | ||
208 | LPCWSTR pwzAppID, | ||
209 | CPI_COMPONENT* pCompList, | ||
210 | BOOL fCreate, | ||
211 | BOOL fProgress | ||
212 | ); | ||
213 | static HRESULT ConfigureInterfaces( | ||
214 | ICatalogCollection* piCompColl, | ||
215 | ICatalogObject* piCompObj, | ||
216 | CPI_INTERFACE* pIntfList, | ||
217 | BOOL fCreate | ||
218 | ); | ||
219 | static HRESULT ConfigureMethods( | ||
220 | ICatalogCollection* piIntfColl, | ||
221 | ICatalogObject* piIntfObj, | ||
222 | CPI_METHOD* pMethList, | ||
223 | BOOL fCreate | ||
224 | ); | ||
225 | static HRESULT ConfigureRoleAssignments( | ||
226 | LPCWSTR pwzCollName, | ||
227 | ICatalogCollection* piCompColl, | ||
228 | ICatalogObject* piCompObj, | ||
229 | CPI_ROLE_ASSIGNMENT* pRoleList, | ||
230 | BOOL fCreate | ||
231 | ); | ||
232 | static HRESULT ReadComponentList( | ||
233 | LPWSTR* ppwzData, | ||
234 | CPI_COMPONENT** ppCompList | ||
235 | ); | ||
236 | static HRESULT ReadInterfaceList( | ||
237 | LPWSTR* ppwzData, | ||
238 | CPI_INTERFACE** ppIntfList | ||
239 | ); | ||
240 | static HRESULT ReadMethodList( | ||
241 | LPWSTR* ppwzData, | ||
242 | CPI_METHOD** ppMethList | ||
243 | ); | ||
244 | static HRESULT ReadRoleAssignmentList( | ||
245 | LPWSTR* ppwzData, | ||
246 | CPI_ROLE_ASSIGNMENT** ppRoleList | ||
247 | ); | ||
248 | static void FreeComponentList( | ||
249 | CPI_COMPONENT* pList | ||
250 | ); | ||
251 | static void FreeInterfaceList( | ||
252 | CPI_INTERFACE* pList | ||
253 | ); | ||
254 | static void FreeMethodList( | ||
255 | CPI_METHOD* pList | ||
256 | ); | ||
257 | static void FreeRoleAssignmentList( | ||
258 | CPI_ROLE_ASSIGNMENT* pList | ||
259 | ); | ||
260 | |||
261 | |||
262 | // variables | ||
263 | |||
264 | static IDispatch* gpiRegHlp; | ||
265 | static IAssemblyCache* gpAssemblyCache; | ||
266 | static HMODULE ghMscoree; | ||
267 | static HMODULE ghFusion; | ||
268 | |||
269 | |||
270 | // function definitions | ||
271 | |||
272 | HRESULT 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 | |||
338 | LExit: | ||
339 | // clean up | ||
340 | FreeAssemblyAttributes(&attrs); | ||
341 | |||
342 | // uninitialize | ||
343 | UninitAssemblyExec(); | ||
344 | |||
345 | return hr; | ||
346 | } | ||
347 | |||
348 | HRESULT 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 | |||
410 | LExit: | ||
411 | // clean up | ||
412 | FreeAssemblyAttributes(&attrs); | ||
413 | |||
414 | // uninitialize | ||
415 | UninitAssemblyExec(); | ||
416 | |||
417 | return hr; | ||
418 | } | ||
419 | |||
420 | HRESULT 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 | |||
474 | LExit: | ||
475 | // clean up | ||
476 | FreeRoleAssignmentsAttributes(&attrs); | ||
477 | |||
478 | return hr; | ||
479 | } | ||
480 | |||
481 | HRESULT 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 | |||
535 | LExit: | ||
536 | // clean up | ||
537 | FreeRoleAssignmentsAttributes(&attrs); | ||
538 | |||
539 | return hr; | ||
540 | } | ||
541 | |||
542 | |||
543 | // helper function definitions | ||
544 | |||
545 | static 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 | |||
596 | LExit: | ||
597 | return hr; | ||
598 | } | ||
599 | |||
600 | static 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 | |||
709 | LExit: | ||
710 | // clean up | ||
711 | ReleaseObject(piColl); | ||
712 | ReleaseObject(piObj); | ||
713 | |||
714 | return hr; | ||
715 | } | ||
716 | |||
717 | static void InitAssemblyExec() | ||
718 | { | ||
719 | gpiRegHlp = NULL; | ||
720 | gpAssemblyCache = NULL; | ||
721 | ghMscoree = NULL; | ||
722 | ghFusion = NULL; | ||
723 | } | ||
724 | |||
725 | static void UninitAssemblyExec() | ||
726 | { | ||
727 | ReleaseObject(gpiRegHlp); | ||
728 | ReleaseObject(gpAssemblyCache); | ||
729 | if (ghFusion) | ||
730 | ::FreeLibrary(ghFusion); | ||
731 | if (ghMscoree) | ||
732 | ::FreeLibrary(ghMscoree); | ||
733 | } | ||
734 | |||
735 | static 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 | |||
753 | LExit: | ||
754 | return hr; | ||
755 | } | ||
756 | |||
757 | static 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 | |||
799 | LExit: | ||
800 | return hr; | ||
801 | } | ||
802 | |||
803 | static 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 | |||
838 | LExit: | ||
839 | // clean up | ||
840 | ReleaseObject(pAssemblyCache); | ||
841 | |||
842 | return hr; | ||
843 | } | ||
844 | |||
845 | static 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 | |||
942 | LExit: | ||
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 | |||
960 | static 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 | |||
1048 | LExit: | ||
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 | |||
1063 | static 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 | |||
1138 | LExit: | ||
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 | |||
1155 | static 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 | |||
1174 | LExit: | ||
1175 | return hr; | ||
1176 | } | ||
1177 | |||
1178 | static 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 | |||
1220 | LExit: | ||
1221 | return hr; | ||
1222 | } | ||
1223 | |||
1224 | static 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 | |||
1240 | static 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 | |||
1274 | LExit: | ||
1275 | return hr; | ||
1276 | } | ||
1277 | |||
1278 | static 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 | |||
1291 | static 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 | |||
1367 | LExit: | ||
1368 | // clean up | ||
1369 | ReleaseObject(piCompColl); | ||
1370 | ReleaseObject(piCompObj); | ||
1371 | |||
1372 | return hr; | ||
1373 | } | ||
1374 | |||
1375 | static 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 | |||
1440 | LExit: | ||
1441 | // clean up | ||
1442 | ReleaseObject(piIntfColl); | ||
1443 | ReleaseObject(piIntfObj); | ||
1444 | |||
1445 | return hr; | ||
1446 | } | ||
1447 | |||
1448 | static 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 | |||
1510 | LExit: | ||
1511 | // clean up | ||
1512 | ReleaseObject(piMethColl); | ||
1513 | ReleaseObject(piMethObj); | ||
1514 | |||
1515 | return hr; | ||
1516 | } | ||
1517 | |||
1518 | static 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 | |||
1581 | LExit: | ||
1582 | // clean up | ||
1583 | ReleaseObject(piRoleColl); | ||
1584 | ReleaseObject(piRoleObj); | ||
1585 | |||
1586 | return hr; | ||
1587 | } | ||
1588 | |||
1589 | static 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 | |||
1639 | LExit: | ||
1640 | // clean up | ||
1641 | ReleaseStr(pwzData); | ||
1642 | |||
1643 | if (pItm) | ||
1644 | FreeComponentList(pItm); | ||
1645 | |||
1646 | return hr; | ||
1647 | } | ||
1648 | |||
1649 | static 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 | |||
1699 | LExit: | ||
1700 | // clean up | ||
1701 | ReleaseStr(pwzData); | ||
1702 | |||
1703 | if (pItm) | ||
1704 | FreeInterfaceList(pItm); | ||
1705 | |||
1706 | return hr; | ||
1707 | } | ||
1708 | |||
1709 | static 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 | |||
1760 | LExit: | ||
1761 | // clean up | ||
1762 | ReleaseStr(pwzData); | ||
1763 | |||
1764 | if (pItm) | ||
1765 | FreeMethodList(pItm); | ||
1766 | |||
1767 | return hr; | ||
1768 | } | ||
1769 | |||
1770 | static 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 | |||
1813 | LExit: | ||
1814 | // clean up | ||
1815 | ReleaseStr(pwzData); | ||
1816 | |||
1817 | if (pItm) | ||
1818 | FreeRoleAssignmentList(pItm); | ||
1819 | |||
1820 | return hr; | ||
1821 | } | ||
1822 | |||
1823 | static 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 | |||
1842 | static 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 | |||
1861 | static 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 | |||
1878 | static 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 | |||
5 | HRESULT CpiConfigureAssemblies( | ||
6 | LPWSTR* ppwzData, | ||
7 | HANDLE hRollbackFile | ||
8 | ); | ||
9 | HRESULT CpiRollbackConfigureAssemblies( | ||
10 | LPWSTR* ppwzData, | ||
11 | CPI_ROLLBACK_DATA* pRollbackDataList | ||
12 | ); | ||
13 | HRESULT CpiConfigureRoleAssignments( | ||
14 | LPWSTR* ppwzData, | ||
15 | HANDLE hRollbackFile | ||
16 | ); | ||
17 | HRESULT 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 | |||
8 | LPCWSTR vcsMsiAssemblyNameQuery = | ||
9 | L"SELECT `Name`, `Value` FROM `MsiAssemblyName` WHERE `Component_` = ?"; | ||
10 | enum eMsiAssemblyNameQuery { manqName = 1, manqValue }; | ||
11 | |||
12 | LPCWSTR vcsModuleQuery = | ||
13 | L"SELECT `ModuleID` FROM `ModuleSignature`"; | ||
14 | enum eModuleQuery { mqModule = 1 }; | ||
15 | |||
16 | LPCWSTR vcsAssemblyQuery = | ||
17 | L"SELECT `Assembly`, `Component_`, `Application_`, `AssemblyName`, `DllPath`, `TlbPath`, `PSDllPath`, `Attributes` FROM `ComPlusAssembly`"; | ||
18 | enum eAssemblyQuery { aqAssembly = 1, aqComponent, aqApplication, aqAssemblyName, aqDllPath, aqTlbPath, aqPSDllPath, aqAttributes }; | ||
19 | |||
20 | LPCWSTR vcsComponentQuery = | ||
21 | L"SELECT `ComPlusComponent`, `CLSID` FROM `ComPlusComponent` WHERE `Assembly_` = ?"; | ||
22 | enum eComponentQuery { cqComponent = 1, cqCLSID }; | ||
23 | |||
24 | LPCWSTR vcsComponentPropertyQuery = | ||
25 | L"SELECT `Name`, `Value` FROM `ComPlusComponentProperty` WHERE `ComPlusComponent_` = ?"; | ||
26 | |||
27 | LPCWSTR vcsInterfaceQuery = | ||
28 | L"SELECT `Interface`, `IID` FROM `ComPlusInterface` WHERE `ComPlusComponent_` = ?"; | ||
29 | enum eInterfaceQuery { iqInterface = 1, iqIID }; | ||
30 | |||
31 | LPCWSTR vcsInterfacePropertyQuery = | ||
32 | L"SELECT `Name`, `Value` FROM `ComPlusInterfaceProperty` WHERE `Interface_` = ?"; | ||
33 | |||
34 | LPCWSTR vcsMethodQuery = | ||
35 | L"SELECT `Method`, `Index`, `Name` FROM `ComPlusMethod` WHERE `Interface_` = ?"; | ||
36 | enum eMethodQuery { mqMethod = 1, mqIndex, mqName }; | ||
37 | |||
38 | LPCWSTR vcsMethodPropertyQuery = | ||
39 | L"SELECT `Name`, `Value` FROM `ComPlusMethodProperty` WHERE `Method_` = ?"; | ||
40 | |||
41 | LPCWSTR vcsRoleForComponentQuery = | ||
42 | L"SELECT `RoleForComponent`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForComponent` WHERE `ComPlusComponent_` = ?"; | ||
43 | LPCWSTR vcsRoleForInterfaceQuery = | ||
44 | L"SELECT `RoleForInterface`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForInterface` WHERE `Interface_` = ?"; | ||
45 | LPCWSTR vcsRoleForMethodQuery = | ||
46 | L"SELECT `RoleForMethod`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForMethod` WHERE `Method_` = ?"; | ||
47 | |||
48 | enum eRoleAssignmentQuery { raqKey = 1, raqApplicationRole, raqComponent }; | ||
49 | |||
50 | LPCWSTR vcsModuleComponentsQuery = | ||
51 | L"SELECT `Component`, `ModuleID` FROM `ModuleComponents`"; | ||
52 | LPCWSTR vcsModuleDependencyQuery = | ||
53 | L"SELECT `ModuleID`, `RequiredID` FROM `ModuleDependency`"; | ||
54 | LPCWSTR vcsAssemblyDependencyQuery = | ||
55 | L"SELECT `Assembly_`, `RequiredAssembly_` FROM `ComPlusAssemblyDependency`"; | ||
56 | |||
57 | enum eKeyPairQuery { kpqFirstKey = 1, kpqSecondKey }; | ||
58 | |||
59 | |||
60 | // private structs | ||
61 | |||
62 | struct 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 | |||
70 | struct CPI_DEPENDENCY_CHAIN | ||
71 | { | ||
72 | LPCWSTR pwzKey; | ||
73 | |||
74 | CPI_DEPENDENCY_CHAIN* pPrev; | ||
75 | }; | ||
76 | |||
77 | struct CPI_MODULE | ||
78 | { | ||
79 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
80 | |||
81 | CPI_MODULE* pPrev; | ||
82 | CPI_MODULE* pNext; | ||
83 | }; | ||
84 | |||
85 | struct CPI_MODULE_LIST | ||
86 | { | ||
87 | CPI_MODULE* pFirst; | ||
88 | CPI_MODULE* pLast; | ||
89 | }; | ||
90 | |||
91 | |||
92 | // property definitions | ||
93 | |||
94 | CPI_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 | |||
129 | CPI_PROPERTY_DEFINITION pdlInterfaceProperties[] = | ||
130 | { | ||
131 | {L"Description", cpptString, 500}, | ||
132 | {L"QueuingEnabled", cpptBoolean, 500}, | ||
133 | {NULL, cpptNone, 0} | ||
134 | }; | ||
135 | |||
136 | CPI_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 | |||
146 | static HRESULT GetAssemblyName( | ||
147 | LPCWSTR pwzComponent, | ||
148 | LPWSTR* ppwzAssemblyName | ||
149 | ); | ||
150 | static HRESULT KeyPairsRead( | ||
151 | LPCWSTR pwzQuery, | ||
152 | CPI_KEY_PAIR** ppKeyPairList | ||
153 | ); | ||
154 | static HRESULT ModulesRead( | ||
155 | CPI_MODULE_LIST* pModList | ||
156 | ); | ||
157 | static HRESULT AssembliesRead( | ||
158 | CPI_KEY_PAIR* pModCompList, | ||
159 | CPI_APPLICATION_LIST* pAppList, | ||
160 | CPI_APPLICATION_ROLE_LIST* pAppRoleList, | ||
161 | CPI_ASSEMBLY_LIST* pAsmList | ||
162 | ); | ||
163 | static HRESULT ComponentsRead( | ||
164 | LPCWSTR pwzAsmKey, | ||
165 | CPI_APPLICATION_ROLE_LIST* pAppRoleList, | ||
166 | CPI_ASSEMBLY* pAsm | ||
167 | ); | ||
168 | static HRESULT InterfacesRead( | ||
169 | LPCWSTR pwzCompKey, | ||
170 | CPI_APPLICATION_ROLE_LIST* pAppRoleList, | ||
171 | CPI_ASSEMBLY* pAsm, | ||
172 | CPI_COMPONENT* pComp | ||
173 | ); | ||
174 | static HRESULT MethodsRead( | ||
175 | LPCWSTR pwzIntfKey, | ||
176 | CPI_APPLICATION_ROLE_LIST* pAppRoleList, | ||
177 | CPI_ASSEMBLY* pAsm, | ||
178 | CPI_INTERFACE* pIntf | ||
179 | ); | ||
180 | static 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 | ); | ||
188 | static HRESULT TopSortModuleList( | ||
189 | CPI_KEY_PAIR* pDepList, | ||
190 | CPI_MODULE_LIST* pList | ||
191 | ); | ||
192 | static 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 | ); | ||
199 | static HRESULT ModuleFindByKey( | ||
200 | CPI_MODULE* pItm, | ||
201 | LPCWSTR pwzKey, | ||
202 | BOOL fReverse, | ||
203 | CPI_MODULE** ppItm | ||
204 | ); | ||
205 | static void SortAssemblyListByModule( | ||
206 | CPI_MODULE_LIST* pModList, | ||
207 | CPI_ASSEMBLY_LIST* pAsmList | ||
208 | ); | ||
209 | static HRESULT TopSortAssemblyList( | ||
210 | CPI_KEY_PAIR* pDepList, | ||
211 | CPI_ASSEMBLY_LIST* pList | ||
212 | ); | ||
213 | static 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 | ); | ||
220 | static HRESULT AssemblyFindByKey( | ||
221 | CPI_ASSEMBLY* pItm, | ||
222 | LPCWSTR pwzKey, | ||
223 | BOOL fReverse, | ||
224 | CPI_ASSEMBLY** ppItm | ||
225 | ); | ||
226 | static HRESULT AddAssemblyToActionData( | ||
227 | CPI_ASSEMBLY* pItm, | ||
228 | BOOL fInstall, | ||
229 | int iActionType, | ||
230 | int iActionCost, | ||
231 | LPWSTR* ppwzActionData | ||
232 | ); | ||
233 | static HRESULT AddRoleAssignmentsToActionData( | ||
234 | CPI_ASSEMBLY* pItm, | ||
235 | BOOL fInstall, | ||
236 | int iActionType, | ||
237 | int iActionCost, | ||
238 | LPWSTR* ppwzActionData | ||
239 | ); | ||
240 | static HRESULT AddComponentToActionData( | ||
241 | CPI_COMPONENT* pItm, | ||
242 | BOOL fInstall, | ||
243 | BOOL fProps, | ||
244 | BOOL fRoles, | ||
245 | LPWSTR* ppwzActionData | ||
246 | ); | ||
247 | static HRESULT AddInterfaceToActionData( | ||
248 | CPI_INTERFACE* pItm, | ||
249 | BOOL fInstall, | ||
250 | BOOL fProps, | ||
251 | BOOL fRoles, | ||
252 | LPWSTR* ppwzActionData | ||
253 | ); | ||
254 | static HRESULT AddMethodToActionData( | ||
255 | CPI_METHOD* pItm, | ||
256 | BOOL fInstall, | ||
257 | BOOL fProps, | ||
258 | BOOL fRoles, | ||
259 | LPWSTR* ppwzActionData | ||
260 | ); | ||
261 | static HRESULT AddRolesToActionData( | ||
262 | int iRoleInstallCount, | ||
263 | int iRoleUninstallCount, | ||
264 | CPI_ROLE_ASSIGNMENT* pRoleList, | ||
265 | BOOL fInstall, | ||
266 | BOOL fRoles, | ||
267 | LPWSTR* ppwzActionData | ||
268 | ); | ||
269 | static HRESULT KeyPairFindByFirstKey( | ||
270 | CPI_KEY_PAIR* pList, | ||
271 | LPCWSTR pwzKey, | ||
272 | CPI_KEY_PAIR** ppItm | ||
273 | ); | ||
274 | static void AssemblyFree( | ||
275 | CPI_ASSEMBLY* pItm | ||
276 | ); | ||
277 | static void KeyPairsFreeList( | ||
278 | CPI_KEY_PAIR* pList | ||
279 | ); | ||
280 | void ModuleListFree( | ||
281 | CPI_MODULE_LIST* pList | ||
282 | ); | ||
283 | static void ModuleFree( | ||
284 | CPI_MODULE* pItm | ||
285 | ); | ||
286 | static void ComponentsFreeList( | ||
287 | CPI_COMPONENT* pList | ||
288 | ); | ||
289 | static void InterfacesFreeList( | ||
290 | CPI_INTERFACE* pList | ||
291 | ); | ||
292 | static void MethodsFreeList( | ||
293 | CPI_METHOD* pList | ||
294 | ); | ||
295 | static void RoleAssignmentsFreeList( | ||
296 | CPI_ROLE_ASSIGNMENT* pList | ||
297 | ); | ||
298 | |||
299 | |||
300 | // function definitions | ||
301 | |||
302 | void 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 | |||
316 | HRESULT 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 | |||
386 | LExit: | ||
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 | |||
399 | HRESULT 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 | |||
418 | LExit: | ||
419 | return hr; | ||
420 | } | ||
421 | |||
422 | HRESULT 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 | |||
449 | HRESULT 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 | |||
517 | LExit: | ||
518 | return hr; | ||
519 | } | ||
520 | |||
521 | HRESULT 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 | |||
564 | LExit: | ||
565 | return hr; | ||
566 | } | ||
567 | |||
568 | HRESULT 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 | |||
636 | LExit: | ||
637 | return hr; | ||
638 | } | ||
639 | |||
640 | HRESULT 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 | |||
683 | LExit: | ||
684 | return hr; | ||
685 | } | ||
686 | |||
687 | HRESULT 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 | |||
726 | LExit: | ||
727 | // clean up | ||
728 | ReleaseObject(piCompColl); | ||
729 | ReleaseObject(piCompObj); | ||
730 | |||
731 | return hr; | ||
732 | } | ||
733 | |||
734 | |||
735 | // helper function definitions | ||
736 | |||
737 | static 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 | |||
805 | LExit: | ||
806 | // clean up | ||
807 | ReleaseStr(pwzKey); | ||
808 | ReleaseStr(pwzName); | ||
809 | ReleaseStr(pwzVersion); | ||
810 | ReleaseStr(pwzCulture); | ||
811 | ReleaseStr(pwzPublicKeyToken); | ||
812 | |||
813 | return hr; | ||
814 | } | ||
815 | |||
816 | static 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 | |||
859 | LExit: | ||
860 | // clean up | ||
861 | if (pItm) | ||
862 | KeyPairsFreeList(pItm); | ||
863 | |||
864 | ReleaseStr(pwzData); | ||
865 | |||
866 | return hr; | ||
867 | } | ||
868 | |||
869 | static 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 | |||
911 | LExit: | ||
912 | // clean up | ||
913 | if (pItm) | ||
914 | ModuleFree(pItm); | ||
915 | |||
916 | ReleaseStr(pwzData); | ||
917 | |||
918 | return hr; | ||
919 | } | ||
920 | |||
921 | static 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 | |||
1067 | LExit: | ||
1068 | // clean up | ||
1069 | if (pItm) | ||
1070 | AssemblyFree(pItm); | ||
1071 | |||
1072 | ReleaseStr(pwzData); | ||
1073 | ReleaseStr(pwzComponent); | ||
1074 | |||
1075 | return hr; | ||
1076 | } | ||
1077 | |||
1078 | static 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 | |||
1095 | LExit: | ||
1096 | return hr; | ||
1097 | } | ||
1098 | |||
1099 | static 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 | |||
1172 | LExit: | ||
1173 | return hr; | ||
1174 | } | ||
1175 | |||
1176 | static 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 | |||
1195 | static 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 | |||
1241 | static 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 | |||
1258 | LExit: | ||
1259 | return hr; | ||
1260 | } | ||
1261 | |||
1262 | static 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 | |||
1342 | LExit: | ||
1343 | return hr; | ||
1344 | } | ||
1345 | |||
1346 | static 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 | |||
1365 | static 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 | |||
1444 | LExit: | ||
1445 | // clean up | ||
1446 | if (pItm) | ||
1447 | ComponentsFreeList(pItm); | ||
1448 | |||
1449 | ReleaseStr(pwzData); | ||
1450 | |||
1451 | return hr; | ||
1452 | } | ||
1453 | |||
1454 | static 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 | |||
1534 | LExit: | ||
1535 | // clean up | ||
1536 | if (pItm) | ||
1537 | InterfacesFreeList(pItm); | ||
1538 | |||
1539 | ReleaseStr(pwzData); | ||
1540 | |||
1541 | return hr; | ||
1542 | } | ||
1543 | |||
1544 | static 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 | |||
1624 | LExit: | ||
1625 | // clean up | ||
1626 | if (pItm) | ||
1627 | MethodsFreeList(pItm); | ||
1628 | |||
1629 | ReleaseStr(pwzData); | ||
1630 | |||
1631 | return hr; | ||
1632 | } | ||
1633 | |||
1634 | static 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 | |||
1724 | LExit: | ||
1725 | // clean up | ||
1726 | if (pItm) | ||
1727 | RoleAssignmentsFreeList(pItm); | ||
1728 | |||
1729 | ReleaseStr(pwzData); | ||
1730 | |||
1731 | return hr; | ||
1732 | } | ||
1733 | |||
1734 | static 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 | |||
1798 | LExit: | ||
1799 | return hr; | ||
1800 | } | ||
1801 | |||
1802 | static 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 | |||
1845 | LExit: | ||
1846 | return hr; | ||
1847 | } | ||
1848 | |||
1849 | static 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 | |||
1887 | LExit: | ||
1888 | return hr; | ||
1889 | } | ||
1890 | |||
1891 | static 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 | |||
1925 | LExit: | ||
1926 | return hr; | ||
1927 | } | ||
1928 | |||
1929 | static 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 | |||
1956 | LExit: | ||
1957 | return hr; | ||
1958 | } | ||
1959 | |||
1960 | static 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 | |||
1993 | LExit: | ||
1994 | return hr; | ||
1995 | } | ||
1996 | |||
1997 | static 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 | |||
2015 | static 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 | |||
2030 | static 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 | |||
2042 | void 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 | |||
2056 | static void ModuleFree( | ||
2057 | CPI_MODULE* pItm | ||
2058 | ) | ||
2059 | { | ||
2060 | ::HeapFree(::GetProcessHeap(), 0, pItm); | ||
2061 | } | ||
2062 | |||
2063 | static 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 | |||
2086 | static 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 | |||
2107 | static 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 | |||
2125 | static 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 | |||
5 | enum eAssemblyAttributes | ||
6 | { | ||
7 | aaEventClass = (1 << 0), | ||
8 | aaDotNetAssembly = (1 << 1), | ||
9 | aaPathFromGAC = (1 << 2), | ||
10 | aaRunInCommit = (1 << 3) | ||
11 | }; | ||
12 | |||
13 | |||
14 | // structs | ||
15 | |||
16 | struct 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 | |||
27 | struct 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 | |||
43 | struct 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 | |||
61 | struct 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 | |||
81 | struct 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 | |||
109 | struct 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 | |||
126 | void CpiAssemblyListFree( | ||
127 | CPI_ASSEMBLY_LIST* pList | ||
128 | ); | ||
129 | HRESULT CpiAssembliesRead( | ||
130 | CPI_APPLICATION_LIST* pAppList, | ||
131 | CPI_APPLICATION_ROLE_LIST* pAppRoleList, | ||
132 | CPI_ASSEMBLY_LIST* pAsmList | ||
133 | ); | ||
134 | HRESULT CpiAssembliesVerifyInstall( | ||
135 | CPI_ASSEMBLY_LIST* pList | ||
136 | ); | ||
137 | HRESULT CpiAssembliesVerifyUninstall( | ||
138 | CPI_ASSEMBLY_LIST* pList | ||
139 | ); | ||
140 | HRESULT CpiAssembliesInstall( | ||
141 | CPI_ASSEMBLY_LIST* pList, | ||
142 | int iRunMode, | ||
143 | LPWSTR* ppwzActionData, | ||
144 | int* piProgress | ||
145 | ); | ||
146 | HRESULT CpiAssembliesUninstall( | ||
147 | CPI_ASSEMBLY_LIST* pList, | ||
148 | int iRunMode, | ||
149 | LPWSTR* ppwzActionData, | ||
150 | int* piProgress | ||
151 | ); | ||
152 | HRESULT CpiRoleAssignmentsInstall( | ||
153 | CPI_ASSEMBLY_LIST* pList, | ||
154 | int iRunMode, | ||
155 | LPWSTR* ppwzActionData, | ||
156 | int* piProgress | ||
157 | ); | ||
158 | HRESULT CpiRoleAssignmentsUninstall( | ||
159 | CPI_ASSEMBLY_LIST* pList, | ||
160 | int iRunMode, | ||
161 | LPWSTR* ppwzActionData, | ||
162 | int* piProgress | ||
163 | ); | ||
164 | HRESULT 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 | ********************************************************************/ | ||
9 | extern "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 | ********************************************************************/ | ||
33 | extern "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 | |||
59 | LExit: | ||
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 | ********************************************************************/ | ||
75 | extern "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 | |||
102 | LExit: | ||
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 | ********************************************************************/ | ||
115 | extern "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 | |||
198 | LExit: | ||
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 | ********************************************************************/ | ||
221 | extern "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 | |||
277 | LExit: | ||
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 | ********************************************************************/ | ||
299 | extern "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 | |||
414 | LExit: | ||
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 | ********************************************************************/ | ||
456 | extern "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 | |||
539 | LExit: | ||
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 | ********************************************************************/ | ||
562 | extern "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 | |||
669 | LExit: | ||
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 | |||
4 | EXPORTS | ||
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 | |||
8 | struct 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 | |||
18 | struct 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 | |||
30 | static HRESULT ReadPartitionAttributes( | ||
31 | LPWSTR* ppwzData, | ||
32 | CPI_PARTITION_ATTRIBUTES* pAttrs | ||
33 | ); | ||
34 | static void FreePartitionAttributes( | ||
35 | CPI_PARTITION_ATTRIBUTES* pAttrs | ||
36 | ); | ||
37 | static HRESULT CreatePartition( | ||
38 | CPI_PARTITION_ATTRIBUTES* pAttrs | ||
39 | ); | ||
40 | static HRESULT RemovePartition( | ||
41 | CPI_PARTITION_ATTRIBUTES* pAttrs | ||
42 | ); | ||
43 | static HRESULT ReadPartitionUserAttributes( | ||
44 | LPWSTR* ppwzData, | ||
45 | CPI_PARTITION_USER_ATTRIBUTES* pAttrs | ||
46 | ); | ||
47 | static void FreePartitionUserAttributes( | ||
48 | CPI_PARTITION_USER_ATTRIBUTES* pAttrs | ||
49 | ); | ||
50 | static HRESULT CreatePartitionUser( | ||
51 | CPI_PARTITION_USER_ATTRIBUTES* pAttrs | ||
52 | ); | ||
53 | static HRESULT RemovePartitionUser( | ||
54 | CPI_PARTITION_USER_ATTRIBUTES* pAttrs | ||
55 | ); | ||
56 | |||
57 | |||
58 | // function definitions | ||
59 | |||
60 | HRESULT 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 | |||
124 | LExit: | ||
125 | // clean up | ||
126 | FreePartitionAttributes(&attrs); | ||
127 | |||
128 | return hr; | ||
129 | } | ||
130 | |||
131 | HRESULT 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 | |||
197 | LExit: | ||
198 | // clean up | ||
199 | FreePartitionAttributes(&attrs); | ||
200 | |||
201 | return hr; | ||
202 | } | ||
203 | |||
204 | HRESULT 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 | |||
268 | LExit: | ||
269 | // clean up | ||
270 | FreePartitionUserAttributes(&attrs); | ||
271 | |||
272 | return hr; | ||
273 | } | ||
274 | |||
275 | HRESULT 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 | |||
339 | LExit: | ||
340 | // clean up | ||
341 | FreePartitionUserAttributes(&attrs); | ||
342 | |||
343 | return hr; | ||
344 | } | ||
345 | |||
346 | |||
347 | // helper function definitions | ||
348 | |||
349 | static 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 | |||
371 | LExit: | ||
372 | return hr; | ||
373 | } | ||
374 | |||
375 | static 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 | |||
387 | static 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 | |||
437 | LExit: | ||
438 | // clean up | ||
439 | ReleaseObject(piPartColl); | ||
440 | ReleaseObject(piPartObj); | ||
441 | |||
442 | return hr; | ||
443 | } | ||
444 | |||
445 | static 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 | |||
484 | LExit: | ||
485 | // clean up | ||
486 | ReleaseObject(piPartColl); | ||
487 | |||
488 | return hr; | ||
489 | } | ||
490 | |||
491 | static 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 | |||
511 | LExit: | ||
512 | return hr; | ||
513 | } | ||
514 | |||
515 | static void FreePartitionUserAttributes( | ||
516 | CPI_PARTITION_USER_ATTRIBUTES* pAttrs | ||
517 | ) | ||
518 | { | ||
519 | ReleaseStr(pAttrs->pwzKey); | ||
520 | ReleaseStr(pAttrs->pwzAccount); | ||
521 | ReleaseStr(pAttrs->pwzPartID); | ||
522 | } | ||
523 | |||
524 | static 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 | |||
601 | LExit: | ||
602 | // clean up | ||
603 | ReleaseObject(piUserColl); | ||
604 | ReleaseObject(piUserObj); | ||
605 | |||
606 | if (pSid) | ||
607 | ::HeapFree(::GetProcessHeap(), 0, pSid); | ||
608 | |||
609 | return hr; | ||
610 | } | ||
611 | |||
612 | static 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 | |||
682 | LExit: | ||
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 | |||
5 | HRESULT CpiConfigurePartitions( | ||
6 | LPWSTR* ppwzData, | ||
7 | HANDLE hRollbackFile | ||
8 | ); | ||
9 | HRESULT CpiRollbackConfigurePartitions( | ||
10 | LPWSTR* ppwzData, | ||
11 | CPI_ROLLBACK_DATA* pRollbackDataList | ||
12 | ); | ||
13 | HRESULT CpiConfigurePartitionUsers( | ||
14 | LPWSTR* ppwzData, | ||
15 | HANDLE hRollbackFile | ||
16 | ); | ||
17 | HRESULT 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 | |||
8 | struct 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 | |||
21 | static HRESULT ReadUserInPartitionRoleAttributes( | ||
22 | LPWSTR* ppwzData, | ||
23 | CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs | ||
24 | ); | ||
25 | static void FreeUserInPartitionRoleAttributes( | ||
26 | CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs | ||
27 | ); | ||
28 | static HRESULT CreateUserInPartitionRole( | ||
29 | CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs | ||
30 | ); | ||
31 | static HRESULT RemoveUserInPartitionRole( | ||
32 | CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs | ||
33 | ); | ||
34 | |||
35 | |||
36 | // function definitions | ||
37 | |||
38 | HRESULT 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 | |||
102 | LExit: | ||
103 | // clean up | ||
104 | FreeUserInPartitionRoleAttributes(&attrs); | ||
105 | |||
106 | return hr; | ||
107 | } | ||
108 | |||
109 | HRESULT 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 | |||
175 | LExit: | ||
176 | // clean up | ||
177 | FreeUserInPartitionRoleAttributes(&attrs); | ||
178 | |||
179 | return hr; | ||
180 | } | ||
181 | |||
182 | |||
183 | // helper function definitions | ||
184 | |||
185 | static 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 | |||
207 | LExit: | ||
208 | return hr; | ||
209 | } | ||
210 | |||
211 | static 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 | |||
221 | static 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 | |||
301 | LExit: | ||
302 | // clean up | ||
303 | ReleaseObject(piUsrInRoleColl); | ||
304 | ReleaseObject(piUsrInRoleObj); | ||
305 | |||
306 | if (pSid) | ||
307 | ::HeapFree(::GetProcessHeap(), 0, pSid); | ||
308 | |||
309 | return hr; | ||
310 | } | ||
311 | |||
312 | static 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 | |||
389 | LExit: | ||
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 | |||
5 | HRESULT CpiConfigureUsersInPartitionRoles( | ||
6 | LPWSTR* ppwzData, | ||
7 | HANDLE hRollbackFile | ||
8 | ); | ||
9 | HRESULT 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 | |||
8 | LPCWSTR vcsPartitionRoleQuery = | ||
9 | L"SELECT `PartitionRole`, `Partition_`, `Component_`, `Name` FROM `ComPlusPartitionRole`"; | ||
10 | enum ePartitionRoleQuery { prqPartitionRole = 1, prqPartition, prqComponent, prqName }; | ||
11 | |||
12 | LPCWSTR vcsUserInPartitionRoleQuery = | ||
13 | L"SELECT `UserInPartitionRole`, `PartitionRole_`, `ComPlusUserInPartitionRole`.`Component_`, `Domain`, `Name` FROM `ComPlusUserInPartitionRole`, `User` WHERE `User_` = `User`"; | ||
14 | LPCWSTR vcsGroupInPartitionRoleQuery = | ||
15 | L"SELECT `GroupInPartitionRole`, `PartitionRole_`, `ComPlusGroupInPartitionRole`.`Component_`, `Domain`, `Name` FROM `ComPlusGroupInPartitionRole`, `Group` WHERE `Group_` = `Group`"; | ||
16 | enum eTrusteeInPartitionRoleQuery { tiprqUserInPartitionRole = 1, tiprqPartitionRole, tiprqComponent, tiprqDomain, tiprqName }; | ||
17 | |||
18 | |||
19 | // prototypes for private helper functions | ||
20 | |||
21 | static HRESULT TrusteesInPartitionRolesRead( | ||
22 | LPCWSTR pwzQuery, | ||
23 | CPI_PARTITION_ROLE_LIST* pPartRoleList, | ||
24 | CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList | ||
25 | ); | ||
26 | static void FreePartitionRole( | ||
27 | CPI_PARTITION_ROLE* pItm | ||
28 | ); | ||
29 | static void FreeUserInPartitionRole( | ||
30 | CPI_USER_IN_PARTITION_ROLE* pItm | ||
31 | ); | ||
32 | static 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 | |||
42 | void 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 | |||
56 | HRESULT 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 | |||
106 | LExit: | ||
107 | // clean up | ||
108 | if (pItm) | ||
109 | FreePartitionRole(pItm); | ||
110 | |||
111 | ReleaseStr(pwzData); | ||
112 | |||
113 | return hr; | ||
114 | } | ||
115 | |||
116 | HRESULT 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 | |||
134 | void 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 | |||
148 | HRESULT 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 | |||
171 | LExit: | ||
172 | return hr; | ||
173 | } | ||
174 | |||
175 | HRESULT 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 | |||
223 | LExit: | ||
224 | return hr; | ||
225 | } | ||
226 | |||
227 | HRESULT 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 | |||
270 | LExit: | ||
271 | return hr; | ||
272 | } | ||
273 | |||
274 | |||
275 | // helper function definitions | ||
276 | |||
277 | static 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 | |||
362 | LExit: | ||
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 | |||
374 | static void FreePartitionRole( | ||
375 | CPI_PARTITION_ROLE* pItm | ||
376 | ) | ||
377 | { | ||
378 | ::HeapFree(::GetProcessHeap(), 0, pItm); | ||
379 | } | ||
380 | |||
381 | static void FreeUserInPartitionRole( | ||
382 | CPI_USER_IN_PARTITION_ROLE* pItm | ||
383 | ) | ||
384 | { | ||
385 | ReleaseStr(pItm->pwzAccount); | ||
386 | |||
387 | ::HeapFree(::GetProcessHeap(), 0, pItm); | ||
388 | } | ||
389 | |||
390 | static 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 | |||
419 | LExit: | ||
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 | |||
5 | struct 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 | |||
17 | struct CPI_PARTITION_ROLE_LIST | ||
18 | { | ||
19 | CPI_PARTITION_ROLE* pFirst; | ||
20 | }; | ||
21 | |||
22 | struct 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 | |||
34 | struct 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 | |||
45 | void CpiPartitionRoleListFree( | ||
46 | CPI_PARTITION_ROLE_LIST* pList | ||
47 | ); | ||
48 | HRESULT CpiPartitionRolesRead( | ||
49 | CPI_PARTITION_LIST* pPartList, | ||
50 | CPI_PARTITION_ROLE_LIST* pPartRoleList | ||
51 | ); | ||
52 | HRESULT CpiPartitionRoleFindByKey( | ||
53 | CPI_PARTITION_ROLE_LIST* pList, | ||
54 | LPCWSTR pwzKey, | ||
55 | CPI_PARTITION_ROLE** ppPartRole | ||
56 | ); | ||
57 | |||
58 | void CpiUserInPartitionRoleListFree( | ||
59 | CPI_USER_IN_PARTITION_ROLE_LIST* pList | ||
60 | ); | ||
61 | HRESULT CpiUsersInPartitionRolesRead( | ||
62 | CPI_PARTITION_ROLE_LIST* pPartRoleList, | ||
63 | CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList | ||
64 | ); | ||
65 | HRESULT CpiUsersInPartitionRolesInstall( | ||
66 | CPI_USER_IN_PARTITION_ROLE_LIST* pList, | ||
67 | int iRunMode, | ||
68 | LPWSTR* ppwzActionData, | ||
69 | int* piProgress | ||
70 | ); | ||
71 | HRESULT 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 | |||
8 | LPCWSTR vcsPartitionQuery = | ||
9 | L"SELECT `Partition`, `Component_`, `Id`, `Name` FROM `ComPlusPartition`"; | ||
10 | enum ePartitionQuery { pqPartition = 1, pqComponent, pqID, pqName }; | ||
11 | |||
12 | LPCWSTR vcsPartitionPropertyQuery = | ||
13 | L"SELECT `Name`, `Value` FROM `ComPlusPartitionProperty` WHERE `Partition_` = ?"; | ||
14 | |||
15 | LPCWSTR vcsPartitionUserQuery = | ||
16 | L"SELECT `PartitionUser`, `Partition_`, `ComPlusPartitionUser`.`Component_`, `Domain`, `Name` FROM `ComPlusPartitionUser`, `User` WHERE `User_` = `User`"; | ||
17 | enum ePartitionUserQuery { puqPartitionUser = 1, puqPartition, puqComponent, puqDomain, puqName }; | ||
18 | |||
19 | |||
20 | // property definitions | ||
21 | |||
22 | CPI_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 | |||
33 | static void FreePartition( | ||
34 | CPI_PARTITION* pItm | ||
35 | ); | ||
36 | static void FreePartitionUser( | ||
37 | CPI_PARTITION_USER* pItm | ||
38 | ); | ||
39 | static HRESULT AddPartitionToActionData( | ||
40 | CPI_PARTITION* pItm, | ||
41 | int iActionType, | ||
42 | int iActionCost, | ||
43 | LPWSTR* ppwzActionData | ||
44 | ); | ||
45 | static HRESULT AddPartitionUserToActionData( | ||
46 | CPI_PARTITION_USER* pItm, | ||
47 | int iActionType, | ||
48 | int iActionCost, | ||
49 | LPWSTR* ppwzActionData | ||
50 | ); | ||
51 | |||
52 | |||
53 | // function definitions | ||
54 | |||
55 | void 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 | |||
69 | HRESULT 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 | |||
169 | LExit: | ||
170 | // clean up | ||
171 | if (pItm) | ||
172 | FreePartition(pItm); | ||
173 | |||
174 | ReleaseStr(pwzData); | ||
175 | |||
176 | return hr; | ||
177 | } | ||
178 | |||
179 | HRESULT 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 | |||
314 | LExit: | ||
315 | // clean up | ||
316 | ReleaseObject(piPartColl); | ||
317 | ReleaseObject(piPartObj); | ||
318 | |||
319 | return hr; | ||
320 | } | ||
321 | |||
322 | HRESULT 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 | |||
372 | LExit: | ||
373 | // clean up | ||
374 | ReleaseObject(piPartColl); | ||
375 | ReleaseObject(piPartObj); | ||
376 | |||
377 | return hr; | ||
378 | } | ||
379 | |||
380 | void CpiPartitionAddReferenceInstall( | ||
381 | CPI_PARTITION* pItm | ||
382 | ) | ||
383 | { | ||
384 | pItm->fReferencedForInstall = TRUE; | ||
385 | } | ||
386 | |||
387 | void CpiPartitionAddReferenceUninstall( | ||
388 | CPI_PARTITION* pItm | ||
389 | ) | ||
390 | { | ||
391 | pItm->fReferencedForUninstall = TRUE; | ||
392 | } | ||
393 | |||
394 | HRESULT 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 | |||
442 | LExit: | ||
443 | return hr; | ||
444 | } | ||
445 | |||
446 | HRESULT 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 | |||
489 | LExit: | ||
490 | return hr; | ||
491 | } | ||
492 | |||
493 | HRESULT 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 | |||
511 | HRESULT 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 | |||
553 | LExit: | ||
554 | // clean up | ||
555 | ReleaseObject(piPartColl); | ||
556 | ReleaseObject(piPartObj); | ||
557 | |||
558 | return hr; | ||
559 | } | ||
560 | |||
561 | HRESULT 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 | |||
600 | LExit: | ||
601 | // clean up | ||
602 | ReleaseObject(piPartColl); | ||
603 | ReleaseObject(piPartObj); | ||
604 | |||
605 | return hr; | ||
606 | } | ||
607 | |||
608 | void 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 | |||
622 | HRESULT 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 | |||
714 | LExit: | ||
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 | |||
726 | HRESULT 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 | |||
774 | LExit: | ||
775 | return hr; | ||
776 | } | ||
777 | |||
778 | HRESULT 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 | |||
821 | LExit: | ||
822 | return hr; | ||
823 | } | ||
824 | |||
825 | |||
826 | // helper function definitions | ||
827 | |||
828 | static 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 | |||
841 | static void FreePartitionUser( | ||
842 | CPI_PARTITION_USER* pItm | ||
843 | ) | ||
844 | { | ||
845 | ReleaseStr(pItm->pwzAccount); | ||
846 | |||
847 | ::HeapFree(::GetProcessHeap(), 0, pItm); | ||
848 | } | ||
849 | |||
850 | static 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 | |||
879 | LExit: | ||
880 | return hr; | ||
881 | } | ||
882 | |||
883 | static 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 | |||
910 | LExit: | ||
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 | |||
5 | struct 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 | |||
27 | struct CPI_PARTITION_LIST | ||
28 | { | ||
29 | CPI_PARTITION* pFirst; | ||
30 | |||
31 | int iInstallCount; | ||
32 | int iUninstallCount; | ||
33 | }; | ||
34 | |||
35 | struct 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 | |||
49 | struct CPI_PARTITION_USER_LIST | ||
50 | { | ||
51 | CPI_PARTITION_USER* pFirst; | ||
52 | |||
53 | int iInstallCount; | ||
54 | int iUninstallCount; | ||
55 | }; | ||
56 | |||
57 | |||
58 | // function prototypes | ||
59 | |||
60 | void CpiPartitionListFree( | ||
61 | CPI_PARTITION_LIST* pList | ||
62 | ); | ||
63 | HRESULT CpiPartitionsRead( | ||
64 | CPI_PARTITION_LIST* pPartList | ||
65 | ); | ||
66 | HRESULT CpiPartitionsVerifyInstall( | ||
67 | CPI_PARTITION_LIST* pList | ||
68 | ); | ||
69 | HRESULT CpiPartitionsVerifyUninstall( | ||
70 | CPI_PARTITION_LIST* pList | ||
71 | ); | ||
72 | void CpiPartitionAddReferenceInstall( | ||
73 | CPI_PARTITION* pItm | ||
74 | ); | ||
75 | void CpiPartitionAddReferenceUninstall( | ||
76 | CPI_PARTITION* pItm | ||
77 | ); | ||
78 | HRESULT CpiPartitionsInstall( | ||
79 | CPI_PARTITION_LIST* pList, | ||
80 | int iRunMode, | ||
81 | LPWSTR* ppwzActionData, | ||
82 | int* piProgress | ||
83 | ); | ||
84 | HRESULT CpiPartitionsUninstall( | ||
85 | CPI_PARTITION_LIST* pList, | ||
86 | int iRunMode, | ||
87 | LPWSTR* ppwzActionData, | ||
88 | int* piProgress | ||
89 | ); | ||
90 | HRESULT CpiPartitionFindByKey( | ||
91 | CPI_PARTITION_LIST* pList, | ||
92 | LPCWSTR wzKey, | ||
93 | CPI_PARTITION** ppItm | ||
94 | ); | ||
95 | HRESULT CpiGetApplicationsCollForPartition( | ||
96 | CPI_PARTITION* pPart, | ||
97 | ICatalogCollection** ppiAppColl | ||
98 | ); | ||
99 | HRESULT CpiGetPartitionUsersCollection( | ||
100 | CPI_PARTITION* pPart, | ||
101 | ICatalogCollection** ppiPartUsrColl | ||
102 | ); | ||
103 | HRESULT CpiGetRolesCollForPartition( | ||
104 | CPI_PARTITION* pPart, | ||
105 | ICatalogCollection** ppiRolesColl | ||
106 | ); | ||
107 | void CpiPartitionUserListFree( | ||
108 | CPI_PARTITION_USER_LIST* pList | ||
109 | ); | ||
110 | HRESULT CpiPartitionUsersRead( | ||
111 | CPI_PARTITION_LIST* pPartList, | ||
112 | CPI_PARTITION_USER_LIST* pPartUsrList | ||
113 | ); | ||
114 | HRESULT CpiPartitionUsersInstall( | ||
115 | CPI_PARTITION_USER_LIST* pList, | ||
116 | int iRunMode, | ||
117 | LPWSTR* ppwzActionData, | ||
118 | int* piProgress | ||
119 | ); | ||
120 | HRESULT 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 | ********************************************************************/ | ||
37 | extern "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 | ********************************************************************/ | ||
60 | extern "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 | |||
303 | LExit: | ||
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 | ********************************************************************/ | ||
337 | extern "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 | |||
564 | LExit: | ||
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 | |||
8 | struct 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 | |||
26 | static HRESULT ReadSubscriptionAttributes( | ||
27 | LPWSTR* ppwzData, | ||
28 | CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs | ||
29 | ); | ||
30 | static void FreeSubscriptionAttributes( | ||
31 | CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs | ||
32 | ); | ||
33 | static HRESULT CreateSubscription( | ||
34 | CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs | ||
35 | ); | ||
36 | static HRESULT RemoveSubscription( | ||
37 | CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs | ||
38 | ); | ||
39 | |||
40 | |||
41 | // function definitions | ||
42 | |||
43 | HRESULT 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 | |||
107 | LExit: | ||
108 | // clean up | ||
109 | FreeSubscriptionAttributes(&attrs); | ||
110 | |||
111 | return hr; | ||
112 | } | ||
113 | |||
114 | HRESULT 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 | |||
180 | LExit: | ||
181 | // clean up | ||
182 | FreeSubscriptionAttributes(&attrs); | ||
183 | |||
184 | return hr; | ||
185 | } | ||
186 | |||
187 | |||
188 | // helper function definitions | ||
189 | |||
190 | static 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 | |||
223 | LExit: | ||
224 | return hr; | ||
225 | } | ||
226 | |||
227 | static 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 | |||
244 | static 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 | |||
356 | LExit: | ||
357 | // clean up | ||
358 | ReleaseObject(piSubsColl); | ||
359 | ReleaseObject(piSubsObj); | ||
360 | |||
361 | if (pSid) | ||
362 | ::HeapFree(::GetProcessHeap(), 0, pSid); | ||
363 | |||
364 | return hr; | ||
365 | } | ||
366 | |||
367 | static 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 | |||
406 | LExit: | ||
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 | |||
5 | HRESULT CpiConfigureSubscriptions( | ||
6 | LPWSTR* ppwzData, | ||
7 | HANDLE hRollbackFile | ||
8 | ); | ||
9 | HRESULT 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 | |||
8 | LPCWSTR vcsSubscriptionQuery = | ||
9 | L"SELECT `Subscription`, `ComPlusComponent_`, `Component_`, `Id`, `Name`, `EventCLSID`, `PublisherID` FROM `ComPlusSubscription`"; | ||
10 | enum eSubscriptionQuery { sqSubscription = 1, sqComPlusComponent, sqComponent, sqID, sqName, sqEventCLSID, sqPublisherID }; | ||
11 | |||
12 | LPCWSTR vcsSubscriptionPropertyQuery = | ||
13 | L"SELECT `Name`, `Value` FROM `ComPlusSubscriptionProperty` WHERE `Subscription_` = ?"; | ||
14 | |||
15 | |||
16 | // property definitions | ||
17 | |||
18 | CPI_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 | |||
37 | static void FreeSubscription( | ||
38 | CPI_SUBSCRIPTION* pItm | ||
39 | ); | ||
40 | static HRESULT FindObjectForSubscription( | ||
41 | CPI_SUBSCRIPTION* pItm, | ||
42 | BOOL fFindId, | ||
43 | BOOL fFindName, | ||
44 | ICatalogObject** ppiSubsObj | ||
45 | ); | ||
46 | static HRESULT AddSubscriptionToActionData( | ||
47 | CPI_SUBSCRIPTION* pItm, | ||
48 | int iActionType, | ||
49 | int iActionCost, | ||
50 | LPWSTR* ppwzActionData | ||
51 | ); | ||
52 | static 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 | |||
62 | void 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 | |||
76 | HRESULT 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 | |||
193 | LExit: | ||
194 | // clean up | ||
195 | if (pItm) | ||
196 | FreeSubscription(pItm); | ||
197 | |||
198 | ReleaseStr(pwzData); | ||
199 | |||
200 | return hr; | ||
201 | } | ||
202 | |||
203 | HRESULT 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 | |||
320 | LExit: | ||
321 | // clean up | ||
322 | ReleaseObject(piSubsObj); | ||
323 | |||
324 | return hr; | ||
325 | } | ||
326 | |||
327 | HRESULT 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 | |||
368 | LExit: | ||
369 | // clean up | ||
370 | ReleaseObject(piSubsObj); | ||
371 | |||
372 | return hr; | ||
373 | } | ||
374 | |||
375 | HRESULT 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 | |||
440 | LExit: | ||
441 | return hr; | ||
442 | } | ||
443 | |||
444 | HRESULT 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 | |||
487 | LExit: | ||
488 | return hr; | ||
489 | } | ||
490 | |||
491 | |||
492 | // helper function definitions | ||
493 | |||
494 | static void FreeSubscription( | ||
495 | CPI_SUBSCRIPTION* pItm | ||
496 | ) | ||
497 | { | ||
498 | if (pItm->pProperties) | ||
499 | CpiPropertiesFreeList(pItm->pProperties); | ||
500 | |||
501 | ::HeapFree(::GetProcessHeap(), 0, pItm); | ||
502 | } | ||
503 | |||
504 | static 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 | |||
528 | LExit: | ||
529 | // clean up | ||
530 | ReleaseObject(piSubsColl); | ||
531 | |||
532 | return hr; | ||
533 | } | ||
534 | |||
535 | static 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 | |||
581 | LExit: | ||
582 | return hr; | ||
583 | } | ||
584 | |||
585 | static 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 | |||
5 | struct 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 | |||
26 | struct 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 | |||
38 | void CpiSubscriptionListFree( | ||
39 | CPI_SUBSCRIPTION_LIST* pList | ||
40 | ); | ||
41 | HRESULT CpiSubscriptionsRead( | ||
42 | CPI_ASSEMBLY_LIST* pAsmList, | ||
43 | CPI_SUBSCRIPTION_LIST* pSubList | ||
44 | ); | ||
45 | HRESULT CpiSubscriptionsVerifyInstall( | ||
46 | CPI_SUBSCRIPTION_LIST* pList | ||
47 | ); | ||
48 | HRESULT CpiSubscriptionsVerifyUninstall( | ||
49 | CPI_SUBSCRIPTION_LIST* pList | ||
50 | ); | ||
51 | HRESULT CpiSubscriptionsInstall( | ||
52 | CPI_SUBSCRIPTION_LIST* pList, | ||
53 | int iRunMode, | ||
54 | LPWSTR* ppwzActionData, | ||
55 | int* piProgress | ||
56 | ); | ||
57 | HRESULT 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 | |||
8 | struct 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 | |||
19 | CPI_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 | |||
35 | static HRESULT FindUserCollectionObjectIndex( | ||
36 | ICatalogCollection* piColl, | ||
37 | PSID pSid, | ||
38 | int* pi | ||
39 | ); | ||
40 | static HRESULT CreateSidFromDomainRidPair( | ||
41 | PSID pDomainSid, | ||
42 | DWORD dwRid, | ||
43 | PSID* ppSid | ||
44 | ); | ||
45 | static HRESULT InitLsaUnicodeString( | ||
46 | PLSA_UNICODE_STRING plusStr, | ||
47 | LPCWSTR pwzStr, | ||
48 | DWORD dwLen | ||
49 | ); | ||
50 | static void FreeLsaUnicodeString( | ||
51 | PLSA_UNICODE_STRING plusStr | ||
52 | ); | ||
53 | static HRESULT WriteFileAll( | ||
54 | HANDLE hFile, | ||
55 | PBYTE pbBuffer, | ||
56 | DWORD dwBufferLength | ||
57 | ); | ||
58 | static HRESULT ReadFileAll( | ||
59 | HANDLE hFile, | ||
60 | PBYTE pbBuffer, | ||
61 | DWORD dwBufferLength | ||
62 | ); | ||
63 | |||
64 | |||
65 | // variables | ||
66 | |||
67 | static ICOMAdminCatalog* gpiCatalog; | ||
68 | |||
69 | |||
70 | // function definitions | ||
71 | |||
72 | void CpiInitialize() | ||
73 | { | ||
74 | // collections | ||
75 | gpiCatalog = NULL; | ||
76 | } | ||
77 | |||
78 | void CpiFinalize() | ||
79 | { | ||
80 | // collections | ||
81 | ReleaseObject(gpiCatalog); | ||
82 | } | ||
83 | |||
84 | HRESULT 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 | |||
138 | LExit: | ||
139 | // clean up | ||
140 | ReleaseStr(pwzData); | ||
141 | |||
142 | return hr; | ||
143 | } | ||
144 | |||
145 | HRESULT 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 | |||
186 | LExit: | ||
187 | return hr; | ||
188 | } | ||
189 | |||
190 | HRESULT 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 | |||
209 | LExit: | ||
210 | return hr; | ||
211 | } | ||
212 | |||
213 | HRESULT 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 | |||
270 | LExit: | ||
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 | |||
285 | HRESULT 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 | |||
320 | LExit: | ||
321 | // clean up | ||
322 | ReleaseObject(piCatalog); | ||
323 | ReleaseObject(piDisp); | ||
324 | ReleaseBSTR(bstrName); | ||
325 | |||
326 | return hr; | ||
327 | } | ||
328 | |||
329 | HRESULT 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 | |||
373 | LExit: | ||
374 | // clean up | ||
375 | ReleaseObject(piCatalog); | ||
376 | ReleaseObject(piDisp); | ||
377 | ReleaseBSTR(bstrName); | ||
378 | ::VariantClear(&vtKey); | ||
379 | |||
380 | return hr; | ||
381 | } | ||
382 | |||
383 | HRESULT 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 | |||
400 | LExit: | ||
401 | // clean up | ||
402 | ReleaseObject(piDisp); | ||
403 | |||
404 | return hr; | ||
405 | } | ||
406 | |||
407 | HRESULT 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 | |||
435 | LExit: | ||
436 | // clean up | ||
437 | ReleaseBSTR(bstrPropName); | ||
438 | ::VariantClear(&vtVal); | ||
439 | |||
440 | return hr; | ||
441 | } | ||
442 | |||
443 | HRESULT 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 | |||
459 | LExit: | ||
460 | return hr; | ||
461 | } | ||
462 | |||
463 | HRESULT 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 | |||
492 | LExit: | ||
493 | // clean up | ||
494 | ReleaseBSTR(bstrPropName); | ||
495 | ::VariantClear(&vtVal); | ||
496 | |||
497 | return hr; | ||
498 | } | ||
499 | |||
500 | HRESULT 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 | |||
544 | LExit: | ||
545 | // clean up | ||
546 | ReleaseBSTR(bstrPropName); | ||
547 | ::VariantClear(&vtVal); | ||
548 | |||
549 | return hr; | ||
550 | } | ||
551 | |||
552 | HRESULT 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 | |||
634 | LExit: | ||
635 | // clean up | ||
636 | ReleaseObject(piDisp); | ||
637 | ReleaseObject(piObj); | ||
638 | |||
639 | ::VariantClear(&vtVal); | ||
640 | |||
641 | return hr; | ||
642 | } | ||
643 | |||
644 | HRESULT 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 | |||
666 | LExit: | ||
667 | return hr; | ||
668 | } | ||
669 | |||
670 | HRESULT 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 | |||
723 | LExit: | ||
724 | // clean up | ||
725 | ReleaseObject(piDisp); | ||
726 | ReleaseObject(piObj); | ||
727 | |||
728 | ::VariantClear(&vtVal); | ||
729 | |||
730 | return hr; | ||
731 | } | ||
732 | |||
733 | HRESULT 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 | |||
786 | LExit: | ||
787 | // clean up | ||
788 | ReleaseObject(piDisp); | ||
789 | ReleaseObject(piObj); | ||
790 | |||
791 | ::VariantClear(&vtVal); | ||
792 | |||
793 | return hr; | ||
794 | } | ||
795 | |||
796 | HRESULT 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 | |||
849 | LExit: | ||
850 | // clean up | ||
851 | ReleaseObject(piDisp); | ||
852 | ReleaseObject(piObj); | ||
853 | |||
854 | ::VariantClear(&vtVal); | ||
855 | |||
856 | return hr; | ||
857 | } | ||
858 | |||
859 | HRESULT 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 | |||
890 | LExit: | ||
891 | // clean up | ||
892 | ReleaseObject(piDisp); | ||
893 | |||
894 | return hr; | ||
895 | } | ||
896 | |||
897 | HRESULT 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 | |||
909 | LExit: | ||
910 | return hr; | ||
911 | } | ||
912 | |||
913 | HRESULT 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 | |||
943 | LExit: | ||
944 | // clean up | ||
945 | ReleaseObject(piPartColl); | ||
946 | ReleaseObject(piPartObj); | ||
947 | |||
948 | return hr; | ||
949 | } | ||
950 | |||
951 | HRESULT 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 | |||
982 | LExit: | ||
983 | // clean up | ||
984 | ReleaseObject(piRoleColl); | ||
985 | ReleaseObject(piRoleObj); | ||
986 | |||
987 | return hr; | ||
988 | } | ||
989 | |||
990 | HRESULT 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 | |||
1002 | LExit: | ||
1003 | return hr; | ||
1004 | } | ||
1005 | |||
1006 | HRESULT 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 | |||
1070 | LExit: | ||
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 | |||
1082 | HRESULT 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 | |||
1113 | LExit: | ||
1114 | // clean up | ||
1115 | ReleaseObject(piAppColl); | ||
1116 | ReleaseObject(piAppObj); | ||
1117 | |||
1118 | return hr; | ||
1119 | } | ||
1120 | |||
1121 | HRESULT 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 | |||
1153 | LExit: | ||
1154 | // clean up | ||
1155 | ReleaseObject(piRoleColl); | ||
1156 | ReleaseObject(piRoleObj); | ||
1157 | |||
1158 | return hr; | ||
1159 | } | ||
1160 | |||
1161 | HRESULT 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 | |||
1192 | LExit: | ||
1193 | // clean up | ||
1194 | ReleaseObject(piAppColl); | ||
1195 | ReleaseObject(piAppObj); | ||
1196 | |||
1197 | return hr; | ||
1198 | } | ||
1199 | |||
1200 | HRESULT 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 | |||
1214 | LExit: | ||
1215 | return hr; | ||
1216 | } | ||
1217 | |||
1218 | HRESULT 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 | |||
1232 | LExit: | ||
1233 | return hr; | ||
1234 | } | ||
1235 | |||
1236 | HRESULT 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 | |||
1268 | LExit: | ||
1269 | // clean up | ||
1270 | ReleaseObject(piCompColl); | ||
1271 | ReleaseObject(piCompObj); | ||
1272 | |||
1273 | return hr; | ||
1274 | } | ||
1275 | |||
1276 | HRESULT 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 | |||
1321 | LExit: | ||
1322 | // clean up | ||
1323 | ReleaseStr(pwzName); | ||
1324 | |||
1325 | if (pItm) | ||
1326 | CpiFreePropertyList(pItm); | ||
1327 | |||
1328 | return hr; | ||
1329 | } | ||
1330 | |||
1331 | void 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 | |||
1345 | HRESULT 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 | |||
1364 | LExit: | ||
1365 | return hr; | ||
1366 | } | ||
1367 | |||
1368 | HRESULT 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 | |||
1382 | LExit: | ||
1383 | return hr; | ||
1384 | } | ||
1385 | |||
1386 | HRESULT 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 | |||
1431 | LExit: | ||
1432 | // clean up | ||
1433 | if (pItm) | ||
1434 | CpiFreeRollbackDataList(pItm); | ||
1435 | |||
1436 | return hr; | ||
1437 | } | ||
1438 | |||
1439 | void 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 | |||
1451 | HRESULT 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 | |||
1470 | LExit: | ||
1471 | return hr; | ||
1472 | } | ||
1473 | |||
1474 | HRESULT 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 | |||
1543 | LExit: | ||
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 | |||
1558 | HRESULT 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 | |||
1606 | LExit: | ||
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 | |||
1623 | static 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 | |||
1726 | LExit: | ||
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 | |||
1752 | static 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 | |||
1795 | LExit: | ||
1796 | return hr; | ||
1797 | } | ||
1798 | |||
1799 | static 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 | |||
1818 | LExit: | ||
1819 | return hr; | ||
1820 | } | ||
1821 | |||
1822 | static void FreeLsaUnicodeString( | ||
1823 | PLSA_UNICODE_STRING plusStr | ||
1824 | ) | ||
1825 | { | ||
1826 | if (plusStr->Buffer) | ||
1827 | ::HeapFree(::GetProcessHeap(), 0, plusStr->Buffer); | ||
1828 | } | ||
1829 | |||
1830 | static 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 | |||
1851 | LExit: | ||
1852 | return hr; | ||
1853 | } | ||
1854 | |||
1855 | static 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 | |||
1879 | LExit: | ||
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 | |||
7 | enum eActionType { atNoOp = 0, atCreate, atRemove }; | ||
8 | |||
9 | |||
10 | // structs | ||
11 | |||
12 | struct CPI_PROPERTY | ||
13 | { | ||
14 | WCHAR wzName[MAX_DARWIN_KEY + 1]; | ||
15 | LPWSTR pwzValue; | ||
16 | |||
17 | CPI_PROPERTY* pNext; | ||
18 | }; | ||
19 | |||
20 | struct 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 | |||
31 | void CpiInitialize(); | ||
32 | void CpiFinalize(); | ||
33 | HRESULT CpiActionStartMessage( | ||
34 | LPWSTR* ppwzActionData, | ||
35 | BOOL fSuppress | ||
36 | ); | ||
37 | HRESULT CpiActionDataMessage( | ||
38 | DWORD cArgs, | ||
39 | ... | ||
40 | ); | ||
41 | HRESULT CpiGetAdminCatalog( | ||
42 | ICOMAdminCatalog** ppiCatalog | ||
43 | ); | ||
44 | HRESULT CpiLogCatalogErrorInfo(); | ||
45 | HRESULT CpiGetCatalogCollection( | ||
46 | LPCWSTR pwzName, | ||
47 | ICatalogCollection** ppiColl | ||
48 | ); | ||
49 | HRESULT CpiGetCatalogCollection( | ||
50 | ICatalogCollection* piColl, | ||
51 | ICatalogObject* piObj, | ||
52 | LPCWSTR pwzName, | ||
53 | ICatalogCollection** ppiColl | ||
54 | ); | ||
55 | HRESULT CpiAddCollectionObject( | ||
56 | ICatalogCollection* piColl, | ||
57 | ICatalogObject** ppiObj | ||
58 | ); | ||
59 | HRESULT CpiPutCollectionObjectValue( | ||
60 | ICatalogObject* piObj, | ||
61 | LPCWSTR pwzPropName, | ||
62 | LPCWSTR pwzValue | ||
63 | ); | ||
64 | HRESULT CpiPutCollectionObjectValues( | ||
65 | ICatalogObject* piObj, | ||
66 | CPI_PROPERTY* pPropList | ||
67 | ); | ||
68 | HRESULT CpiGetCollectionObjectValue( | ||
69 | ICatalogObject* piObj, | ||
70 | LPCWSTR szPropName, | ||
71 | LPWSTR* ppwzValue | ||
72 | ); | ||
73 | HRESULT CpiResetObjectProperty( | ||
74 | ICatalogCollection* piColl, | ||
75 | ICatalogObject* piObj, | ||
76 | LPCWSTR pwzPropName | ||
77 | ); | ||
78 | HRESULT CpiRemoveCollectionObject( | ||
79 | ICatalogCollection* piColl, | ||
80 | LPCWSTR pwzID, | ||
81 | LPCWSTR pwzName, | ||
82 | BOOL fResetDeleteable | ||
83 | ); | ||
84 | HRESULT CpiRemoveUserCollectionObject( | ||
85 | ICatalogCollection* piColl, | ||
86 | PSID pSid | ||
87 | ); | ||
88 | HRESULT CpiFindCollectionObjectByStringKey( | ||
89 | ICatalogCollection* piColl, | ||
90 | LPCWSTR pwzKey, | ||
91 | ICatalogObject** ppiObj | ||
92 | ); | ||
93 | HRESULT CpiFindCollectionObjectByIntegerKey( | ||
94 | ICatalogCollection* piColl, | ||
95 | long lKey, | ||
96 | ICatalogObject** ppiObj | ||
97 | ); | ||
98 | HRESULT CpiFindCollectionObjectByName( | ||
99 | ICatalogCollection* piColl, | ||
100 | LPCWSTR pwzName, | ||
101 | ICatalogObject** ppiObj | ||
102 | ); | ||
103 | HRESULT CpiFindUserCollectionObject( | ||
104 | ICatalogCollection* piColl, | ||
105 | PSID pSid, | ||
106 | ICatalogObject** ppiObj | ||
107 | ); | ||
108 | HRESULT CpiGetPartitionsCollection( | ||
109 | ICatalogCollection** ppiPartColl | ||
110 | ); | ||
111 | HRESULT CpiGetPartitionRolesCollection( | ||
112 | LPCWSTR pwzPartID, | ||
113 | ICatalogCollection** ppiRolesColl | ||
114 | ); | ||
115 | HRESULT CpiGetUsersInPartitionRoleCollection( | ||
116 | LPCWSTR pwzPartID, | ||
117 | LPCWSTR pwzRoleName, | ||
118 | ICatalogCollection** ppiUsrInRoleColl | ||
119 | ); | ||
120 | HRESULT CpiGetPartitionUsersCollection( | ||
121 | ICatalogCollection** ppiUserColl | ||
122 | ); | ||
123 | HRESULT CpiGetApplicationsCollection( | ||
124 | LPCWSTR pwzPartID, | ||
125 | ICatalogCollection** ppiAppColl | ||
126 | ); | ||
127 | HRESULT CpiGetRolesCollection( | ||
128 | LPCWSTR pwzPartID, | ||
129 | LPCWSTR pwzAppID, | ||
130 | ICatalogCollection** ppiRolesColl | ||
131 | ); | ||
132 | HRESULT CpiGetUsersInRoleCollection( | ||
133 | LPCWSTR pwzPartID, | ||
134 | LPCWSTR pwzAppID, | ||
135 | LPCWSTR pwzRoleName, | ||
136 | ICatalogCollection** ppiUsrInRoleColl | ||
137 | ); | ||
138 | HRESULT CpiGetComponentsCollection( | ||
139 | LPCWSTR pwzPartID, | ||
140 | LPCWSTR pwzAppID, | ||
141 | ICatalogCollection** ppiCompsColl | ||
142 | ); | ||
143 | HRESULT CpiGetInterfacesCollection( | ||
144 | ICatalogCollection* piCompColl, | ||
145 | ICatalogObject* piCompObj, | ||
146 | ICatalogCollection** ppiIntfColl | ||
147 | ); | ||
148 | HRESULT CpiGetMethodsCollection( | ||
149 | ICatalogCollection* piIntfColl, | ||
150 | ICatalogObject* piIntfObj, | ||
151 | ICatalogCollection** ppiMethColl | ||
152 | ); | ||
153 | HRESULT CpiGetSubscriptionsCollection( | ||
154 | LPCWSTR pwzPartID, | ||
155 | LPCWSTR pwzAppID, | ||
156 | LPCWSTR pwzCompCLSID, | ||
157 | ICatalogCollection** ppiCompsColl | ||
158 | ); | ||
159 | HRESULT CpiReadPropertyList( | ||
160 | LPWSTR* ppwzData, | ||
161 | CPI_PROPERTY** ppPropList | ||
162 | ); | ||
163 | void CpiFreePropertyList( | ||
164 | CPI_PROPERTY* pList | ||
165 | ); | ||
166 | HRESULT CpiWriteKeyToRollbackFile( | ||
167 | HANDLE hFile, | ||
168 | LPCWSTR pwzKey | ||
169 | ); | ||
170 | HRESULT CpiWriteIntegerToRollbackFile( | ||
171 | HANDLE hFile, | ||
172 | int i | ||
173 | ); | ||
174 | HRESULT CpiReadRollbackDataList( | ||
175 | HANDLE hFile, | ||
176 | CPI_ROLLBACK_DATA** pprdList | ||
177 | ); | ||
178 | void CpiFreeRollbackDataList( | ||
179 | CPI_ROLLBACK_DATA* pList | ||
180 | ); | ||
181 | HRESULT CpiFindRollbackStatus( | ||
182 | CPI_ROLLBACK_DATA* pList, | ||
183 | LPCWSTR pwzKey, | ||
184 | int* piStatus | ||
185 | ); | ||
186 | HRESULT CpiAccountNameToSid( | ||
187 | LPCWSTR pwzAccountName, | ||
188 | PSID* ppSid | ||
189 | ); | ||
190 | HRESULT 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 | |||
8 | LPCWSTR vcsActionTextQuery = | ||
9 | L"SELECT `Description`, `Template` FROM `ActionText` WHERE `Action` = ?"; | ||
10 | enum eActionTextQuery { atqDescription = 1, atqTemplate }; | ||
11 | |||
12 | LPCWSTR vcsComponentAttributesQuery = | ||
13 | L"SELECT `Attributes` FROM `Component` WHERE `Component` = ?"; | ||
14 | enum eComponentAttributesQuery { caqAttributes = 1 }; | ||
15 | |||
16 | LPCWSTR vcsUserQuery = L"SELECT `Domain`, `Name` FROM `User` WHERE `User` = ?"; | ||
17 | enum eUserQuery { uqDomain = 1, uqName }; | ||
18 | |||
19 | enum ePropertyQuery { pqName = 1, pqValue }; | ||
20 | |||
21 | |||
22 | // prototypes for private helper functions | ||
23 | |||
24 | static HRESULT FindPropertyDefinition( | ||
25 | CPI_PROPERTY_DEFINITION* pPropDefList, | ||
26 | LPCWSTR pwzName, | ||
27 | CPI_PROPERTY_DEFINITION** ppPropDef | ||
28 | ); | ||
29 | static HRESULT GetUserAccountName( | ||
30 | LPCWSTR pwzKey, | ||
31 | LPWSTR* ppwzAccount | ||
32 | ); | ||
33 | |||
34 | |||
35 | // variables | ||
36 | |||
37 | static ICOMAdminCatalog* gpiCatalog; | ||
38 | static ICatalogCollection* gpiPartColl; | ||
39 | static ICatalogCollection* gpiAppColl; | ||
40 | |||
41 | static int giTables; | ||
42 | |||
43 | |||
44 | // function definitions | ||
45 | |||
46 | void 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 | |||
83 | void CpiFinalize() | ||
84 | { | ||
85 | // collections | ||
86 | ReleaseObject(gpiCatalog); | ||
87 | ReleaseObject(gpiPartColl); | ||
88 | ReleaseObject(gpiAppColl); | ||
89 | } | ||
90 | |||
91 | BOOL CpiTableExists( | ||
92 | int iTable | ||
93 | ) | ||
94 | { | ||
95 | return (giTables & iTable) == iTable; | ||
96 | } | ||
97 | |||
98 | HRESULT 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 | |||
117 | LExit: | ||
118 | return hr; | ||
119 | } | ||
120 | |||
121 | HRESULT 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 | |||
153 | LExit: | ||
154 | // clean up | ||
155 | ReleaseObject(piCatalog); | ||
156 | ReleaseObject(piDisp); | ||
157 | ReleaseBSTR(bstrName); | ||
158 | |||
159 | return hr; | ||
160 | } | ||
161 | |||
162 | HRESULT 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 | |||
203 | LExit: | ||
204 | // clean up | ||
205 | ReleaseObject(piCatalog); | ||
206 | ReleaseObject(piDisp); | ||
207 | ReleaseBSTR(bstrName); | ||
208 | ::VariantClear(&vtKey); | ||
209 | |||
210 | return hr; | ||
211 | } | ||
212 | |||
213 | HRESULT 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 | |||
238 | LExit: | ||
239 | // clean up | ||
240 | ::VariantClear(&vtKey); | ||
241 | |||
242 | return hr; | ||
243 | } | ||
244 | |||
245 | HRESULT 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 | |||
324 | LExit: | ||
325 | // clean up | ||
326 | ReleaseObject(piDisp); | ||
327 | ReleaseObject(piObj); | ||
328 | |||
329 | ::VariantClear(&vtVal); | ||
330 | |||
331 | return hr; | ||
332 | } | ||
333 | |||
334 | HRESULT 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 | |||
353 | LExit: | ||
354 | return hr; | ||
355 | } | ||
356 | |||
357 | HRESULT 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 | |||
418 | LExit: | ||
419 | // clean up | ||
420 | ReleaseObject(piCatalog); | ||
421 | ReleaseObject(piCatalog2); | ||
422 | ReleaseObject(piPartColl); | ||
423 | ReleaseObject(piPartObj); | ||
424 | ReleaseBSTR(bstrGlobPartID); | ||
425 | |||
426 | return hr; | ||
427 | } | ||
428 | |||
429 | HRESULT 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 | |||
485 | LExit: | ||
486 | // clean up | ||
487 | ReleaseStr(pwzDescription); | ||
488 | ReleaseStr(pwzTemplate); | ||
489 | |||
490 | return hr; | ||
491 | } | ||
492 | |||
493 | HRESULT 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 | |||
538 | LExit: | ||
539 | return hr; | ||
540 | } | ||
541 | |||
542 | HRESULT 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 | |||
629 | LExit: | ||
630 | // clean up | ||
631 | if (pItm) | ||
632 | CpiPropertiesFreeList(pItm); | ||
633 | |||
634 | ReleaseStr(pwzData); | ||
635 | |||
636 | return hr; | ||
637 | } | ||
638 | |||
639 | void 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 | |||
653 | HRESULT 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 | |||
678 | LExit: | ||
679 | return hr; | ||
680 | } | ||
681 | |||
682 | HRESULT 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 | |||
707 | LExit: | ||
708 | return hr; | ||
709 | } | ||
710 | |||
711 | HRESULT 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 | |||
734 | LExit: | ||
735 | return hr; | ||
736 | } | ||
737 | |||
738 | HRESULT 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 | |||
757 | LExit: | ||
758 | return hr; | ||
759 | } | ||
760 | |||
761 | BOOL CpiIsInstalled( | ||
762 | INSTALLSTATE isInstalled | ||
763 | ) | ||
764 | { | ||
765 | return INSTALLSTATE_LOCAL == isInstalled || INSTALLSTATE_SOURCE == isInstalled; | ||
766 | } | ||
767 | |||
768 | BOOL CpiWillBeInstalled( | ||
769 | INSTALLSTATE isInstalled, | ||
770 | INSTALLSTATE isAction | ||
771 | ) | ||
772 | { | ||
773 | return WcaIsInstalling(isInstalled, isAction) || | ||
774 | (CpiIsInstalled(isInstalled) && !WcaIsUninstalling(isInstalled, isAction)); | ||
775 | } | ||
776 | |||
777 | HRESULT 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 | |||
810 | LExit: | ||
811 | return hr; | ||
812 | } | ||
813 | |||
814 | |||
815 | // helper function definitions | ||
816 | |||
817 | static 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 | |||
835 | static 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 | |||
879 | LExit: | ||
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 | |||
7 | enum eRunMode { rmDeferred = 1, rmCommit, rmRollback }; | ||
8 | |||
9 | enum eActionType { atNoOp = 0, atCreate, atRemove }; | ||
10 | |||
11 | enum eComPlusPropertyType { cpptNone = 0, cpptBoolean, cpptInteger, cpptString, cpptUser }; | ||
12 | |||
13 | enum 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 | |||
45 | struct CPI_PROPERTY | ||
46 | { | ||
47 | WCHAR wzName[MAX_DARWIN_KEY + 1]; | ||
48 | LPWSTR pwzValue; | ||
49 | |||
50 | CPI_PROPERTY* pNext; | ||
51 | }; | ||
52 | |||
53 | struct CPI_PROPERTY_DEFINITION | ||
54 | { | ||
55 | LPCWSTR pwzName; | ||
56 | int iType; | ||
57 | int iMinVersionNT; | ||
58 | }; | ||
59 | |||
60 | |||
61 | // function prototypes | ||
62 | |||
63 | void CpiInitialize(); | ||
64 | void CpiFinalize(); | ||
65 | BOOL CpiTableExists( | ||
66 | int iTable | ||
67 | ); | ||
68 | HRESULT CpiGetAdminCatalog( | ||
69 | ICOMAdminCatalog** ppiCatalog | ||
70 | ); | ||
71 | HRESULT CpiGetCatalogCollection( | ||
72 | LPCWSTR pwzName, | ||
73 | ICatalogCollection** ppiColl | ||
74 | ); | ||
75 | HRESULT CpiGetCatalogCollection( | ||
76 | ICatalogCollection* piColl, | ||
77 | ICatalogObject* piObj, | ||
78 | LPCWSTR pwzName, | ||
79 | ICatalogCollection** ppiColl | ||
80 | ); | ||
81 | HRESULT CpiGetKeyForObject( | ||
82 | ICatalogObject* piObj, | ||
83 | LPWSTR pwzKey, | ||
84 | SIZE_T cchKey | ||
85 | ); | ||
86 | HRESULT CpiFindCollectionObject( | ||
87 | ICatalogCollection* piColl, | ||
88 | LPCWSTR pwzID, | ||
89 | LPCWSTR pwzName, | ||
90 | ICatalogObject** ppiObj | ||
91 | ); | ||
92 | HRESULT CpiGetPartitionsCollection( | ||
93 | ICatalogCollection** ppiPartColl | ||
94 | ); | ||
95 | HRESULT CpiGetApplicationsCollection( | ||
96 | ICatalogCollection** ppiAppColl | ||
97 | ); | ||
98 | HRESULT CpiAddActionTextToActionData( | ||
99 | LPCWSTR pwzAction, | ||
100 | LPWSTR* ppwzActionData | ||
101 | ); | ||
102 | HRESULT CpiVerifyComponentArchitecure( | ||
103 | LPCWSTR pwzComponent, | ||
104 | BOOL* pfMatchingArchitecture | ||
105 | ); | ||
106 | HRESULT CpiPropertiesRead( | ||
107 | LPCWSTR pwzQuery, | ||
108 | LPCWSTR pwzKey, | ||
109 | CPI_PROPERTY_DEFINITION* pPropDefList, | ||
110 | CPI_PROPERTY** ppPropList, | ||
111 | int* piCount | ||
112 | ); | ||
113 | void CpiPropertiesFreeList( | ||
114 | CPI_PROPERTY* pList | ||
115 | ); | ||
116 | HRESULT CpiAddPropertiesToActionData( | ||
117 | int iPropCount, | ||
118 | CPI_PROPERTY* pPropList, | ||
119 | LPWSTR* ppwzActionData | ||
120 | ); | ||
121 | HRESULT CpiBuildAccountName( | ||
122 | LPCWSTR pwzDomain, | ||
123 | LPCWSTR pwzName, | ||
124 | LPWSTR* ppwzAccount | ||
125 | ); | ||
126 | HRESULT CpiGetTempFileName( | ||
127 | LPWSTR* ppwzTempFile | ||
128 | ); | ||
129 | HRESULT CpiCreateId( | ||
130 | LPWSTR pwzDest, | ||
131 | SIZE_T cchDest | ||
132 | ); | ||
133 | BOOL CpiIsInstalled( | ||
134 | INSTALLSTATE isInstalled | ||
135 | ); | ||
136 | BOOL CpiWillBeInstalled( | ||
137 | INSTALLSTATE isInstalled, | ||
138 | INSTALLSTATE isAction | ||
139 | ); | ||
140 | HRESULT PcaGuidToRegFormat( | ||
141 | LPWSTR pwzGuid, | ||
142 | LPWSTR pwzDest, | ||
143 | SIZE_T cchDest | ||
144 | ); | ||