aboutsummaryrefslogtreecommitdiff
path: root/src/ext/ComPlus/ca
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-05-11 07:50:20 -0700
committerRob Mensching <rob@firegiant.com>2021-05-11 07:50:20 -0700
commit4608361a88ef82e15caf3574ac107486f5fe135c (patch)
tree2fdc12df96dda724bfc6b5c87edf7eded1bb6249 /src/ext/ComPlus/ca
parent499ea135605261f631650b6c383f6e5063b097d5 (diff)
parent337124bed6a57b40fca11c5c2f5b554f570522a6 (diff)
downloadwix-4608361a88ef82e15caf3574ac107486f5fe135c.tar.gz
wix-4608361a88ef82e15caf3574ac107486f5fe135c.tar.bz2
wix-4608361a88ef82e15caf3574ac107486f5fe135c.zip
Merge ComPlus.wixext
Diffstat (limited to 'src/ext/ComPlus/ca')
-rw-r--r--src/ext/ComPlus/ca/complusca.def15
-rw-r--r--src/ext/ComPlus/ca/complusca.vcxproj95
-rw-r--r--src/ext/ComPlus/ca/cpappexec.cpp344
-rw-r--r--src/ext/ComPlus/ca/cpappexec.h12
-rw-r--r--src/ext/ComPlus/ca/cpapproleexec.cpp720
-rw-r--r--src/ext/ComPlus/ca/cpapproleexec.h20
-rw-r--r--src/ext/ComPlus/ca/cpapprolesched.cpp843
-rw-r--r--src/ext/ComPlus/ca/cpapprolesched.h112
-rw-r--r--src/ext/ComPlus/ca/cpappsched.cpp752
-rw-r--r--src/ext/ComPlus/ca/cpappsched.h83
-rw-r--r--src/ext/ComPlus/ca/cpasmexec.cpp1877
-rw-r--r--src/ext/ComPlus/ca/cpasmexec.h20
-rw-r--r--src/ext/ComPlus/ca/cpasmsched.cpp2135
-rw-r--r--src/ext/ComPlus/ca/cpasmsched.h168
-rw-r--r--src/ext/ComPlus/ca/cpcost.h30
-rw-r--r--src/ext/ComPlus/ca/cpexec.cpp681
-rw-r--r--src/ext/ComPlus/ca/cppartexec.cpp690
-rw-r--r--src/ext/ComPlus/ca/cppartexec.h20
-rw-r--r--src/ext/ComPlus/ca/cppartroleexec.cpp397
-rw-r--r--src/ext/ComPlus/ca/cppartroleexec.h12
-rw-r--r--src/ext/ComPlus/ca/cppartrolesched.cpp421
-rw-r--r--src/ext/ComPlus/ca/cppartrolesched.h76
-rw-r--r--src/ext/ComPlus/ca/cppartsched.cpp912
-rw-r--r--src/ext/ComPlus/ca/cppartsched.h125
-rw-r--r--src/ext/ComPlus/ca/cpsched.cpp566
-rw-r--r--src/ext/ComPlus/ca/cpsubsexec.cpp411
-rw-r--r--src/ext/ComPlus/ca/cpsubsexec.h12
-rw-r--r--src/ext/ComPlus/ca/cpsubssched.cpp606
-rw-r--r--src/ext/ComPlus/ca/cpsubssched.h62
-rw-r--r--src/ext/ComPlus/ca/cputilexec.cpp1881
-rw-r--r--src/ext/ComPlus/ca/cputilexec.h193
-rw-r--r--src/ext/ComPlus/ca/cputilsched.cpp885
-rw-r--r--src/ext/ComPlus/ca/cputilsched.h132
-rw-r--r--src/ext/ComPlus/ca/custommsierrors.h29
-rw-r--r--src/ext/ComPlus/ca/dllmain.cpp27
-rw-r--r--src/ext/ComPlus/ca/packages.config5
-rw-r--r--src/ext/ComPlus/ca/precomp.h33
37 files changed, 15402 insertions, 0 deletions
diff --git a/src/ext/ComPlus/ca/complusca.def b/src/ext/ComPlus/ca/complusca.def
new file mode 100644
index 00000000..7c475759
--- /dev/null
+++ b/src/ext/ComPlus/ca/complusca.def
@@ -0,0 +1,15 @@
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
4LIBRARY "complusca"
5
6EXPORTS
7 ComPlusPrepare
8 ComPlusCleanup
9 ComPlusInstallExecute
10 ComPlusInstallExecuteCommit
11 ComPlusRollbackInstallExecute
12 ComPlusUninstallExecute
13 ComPlusRollbackUninstallExecute
14 ConfigureComPlusInstall
15 ConfigureComPlusUninstall
diff --git a/src/ext/ComPlus/ca/complusca.vcxproj b/src/ext/ComPlus/ca/complusca.vcxproj
new file mode 100644
index 00000000..3a7f6e64
--- /dev/null
+++ b/src/ext/ComPlus/ca/complusca.vcxproj
@@ -0,0 +1,95 @@
1<?xml version="1.0" encoding="utf-8"?>
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<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup Label="ProjectConfigurations">
6 <ProjectConfiguration Include="Debug|Win32">
7 <Configuration>Debug</Configuration>
8 <Platform>Win32</Platform>
9 </ProjectConfiguration>
10 <ProjectConfiguration Include="Release|Win32">
11 <Configuration>Release</Configuration>
12 <Platform>Win32</Platform>
13 </ProjectConfiguration>
14 <ProjectConfiguration Include="Debug|x64">
15 <Configuration>Debug</Configuration>
16 <Platform>x64</Platform>
17 </ProjectConfiguration>
18 <ProjectConfiguration Include="Release|x64">
19 <Configuration>Release</Configuration>
20 <Platform>x64</Platform>
21 </ProjectConfiguration>
22 </ItemGroup>
23
24 <PropertyGroup Label="Globals">
25 <ProjectGuid>{BDEF51ED-E242-4FA2-801A-01B127DF851A}</ProjectGuid>
26 <ConfigurationType>DynamicLibrary</ConfigurationType>
27 <PlatformToolset>v142</PlatformToolset>
28 <CharacterSet>Unicode</CharacterSet>
29 <TargetName>complusca</TargetName>
30 <ProjectModuleDefinitionFile>complusca.def</ProjectModuleDefinitionFile>
31 <Description>WiX Toolset ComPlus CustomAction</Description>
32 <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
33 </PropertyGroup>
34
35 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
36 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
37
38 <PropertyGroup>
39 <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries>
40 </PropertyGroup>
41
42 <ItemGroup>
43 <ClCompile Include="cpappexec.cpp" />
44 <ClCompile Include="cpapproleexec.cpp" />
45 <ClCompile Include="cpapprolesched.cpp" />
46 <ClCompile Include="cpappsched.cpp" />
47 <ClCompile Include="cpasmexec.cpp" />
48 <ClCompile Include="cpasmsched.cpp" />
49 <ClCompile Include="cpexec.cpp" />
50 <ClCompile Include="cppartexec.cpp" />
51 <ClCompile Include="cppartroleexec.cpp" />
52 <ClCompile Include="cppartrolesched.cpp" />
53 <ClCompile Include="cppartsched.cpp" />
54 <ClCompile Include="cpsched.cpp" />
55 <ClCompile Include="cpsubsexec.cpp" />
56 <ClCompile Include="cpsubssched.cpp" />
57 <ClCompile Include="cputilexec.cpp" />
58 <ClCompile Include="cputilsched.cpp" />
59 <ClCompile Include="dllmain.cpp">
60 <PrecompiledHeader>Create</PrecompiledHeader>
61 </ClCompile>
62 </ItemGroup>
63
64 <ItemGroup>
65 <ClInclude Include="cpappexec.h" />
66 <ClInclude Include="cpapproleexec.h" />
67 <ClInclude Include="cpapprolesched.h" />
68 <ClInclude Include="cpappsched.h" />
69 <ClInclude Include="cpasmexec.h" />
70 <ClInclude Include="cpasmsched.h" />
71 <ClInclude Include="cpcost.h" />
72 <ClInclude Include="cppartexec.h" />
73 <ClInclude Include="cppartroleexec.h" />
74 <ClInclude Include="cppartrolesched.h" />
75 <ClInclude Include="cppartsched.h" />
76 <ClInclude Include="cpsubsexec.h" />
77 <ClInclude Include="cpsubssched.h" />
78 <ClInclude Include="cputilexec.h" />
79 <ClInclude Include="cputilsched.h" />
80 <ClInclude Include="precomp.h" />
81 </ItemGroup>
82
83 <ItemGroup>
84 <None Include="complusca.def" />
85 </ItemGroup>
86
87 <ItemGroup>
88 <PackageReference Include="WixToolset.Dutil" Version="4.0.62" />
89 <PackageReference Include="WixToolset.WcaUtil" Version="4.0.18" />
90 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" />
91 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" />
92 </ItemGroup>
93
94 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
95</Project> \ No newline at end of file
diff --git a/src/ext/ComPlus/ca/cpappexec.cpp b/src/ext/ComPlus/ca/cpappexec.cpp
new file mode 100644
index 00000000..48948210
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpappexec.cpp
@@ -0,0 +1,344 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_APPLICATION_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzID;
14 LPWSTR pwzName;
15 LPWSTR pwzPartID;
16 CPI_PROPERTY* pPropList;
17};
18
19
20// prototypes for private helper functions
21
22static HRESULT ReadApplicationAttributes(
23 LPWSTR* ppwzData,
24 CPI_APPLICATION_ATTRIBUTES* pAttrs
25 );
26static void FreeApplicationAttributes(
27 CPI_APPLICATION_ATTRIBUTES* pAttrs
28 );
29static HRESULT CreateApplication(
30 CPI_APPLICATION_ATTRIBUTES* pAttrs
31 );
32static HRESULT RemoveApplication(
33 CPI_APPLICATION_ATTRIBUTES* pAttrs
34 );
35
36
37// function definitions
38
39HRESULT CpiConfigureApplications(
40 LPWSTR* ppwzData,
41 HANDLE hRollbackFile
42 )
43{
44 HRESULT hr = S_OK;
45
46 CPI_APPLICATION_ATTRIBUTES attrs;
47 ::ZeroMemory(&attrs, sizeof(attrs));
48
49 // read action text
50 hr = CpiActionStartMessage(ppwzData, FALSE);
51 ExitOnFailure(hr, "Failed to send action start message");
52
53 // get count
54 int iCnt = 0;
55 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
56 ExitOnFailure(hr, "Failed to read count");
57
58 // write count to rollback file
59 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
60 ExitOnFailure(hr, "Failed to write count to rollback file");
61
62 for (int i = 0; i < iCnt; i++)
63 {
64 // read attributes from CustomActionData
65 hr = ReadApplicationAttributes(ppwzData, &attrs);
66 ExitOnFailure(hr, "Failed to read attributes");
67
68 // progress message
69 hr = CpiActionDataMessage(1, attrs.pwzName);
70 ExitOnFailure(hr, "Failed to send progress messages");
71
72 if (S_FALSE == hr)
73 ExitFunction();
74
75 // write key to rollback file
76 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
77 ExitOnFailure(hr, "Failed to write key to rollback file");
78
79 // action
80 switch (attrs.iActionType)
81 {
82 case atCreate:
83 hr = CreateApplication(&attrs);
84 ExitOnFailure(hr, "Failed to create application, key: %S", attrs.pwzKey);
85 break;
86 case atRemove:
87 hr = RemoveApplication(&attrs);
88 ExitOnFailure(hr, "Failed to remove application, key: %S", attrs.pwzKey);
89 break;
90 }
91
92 // write completion status to rollback file
93 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
94 ExitOnFailure(hr, "Failed to write completion status to rollback file");
95
96 // progress
97 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
98 ExitOnFailure(hr, "Failed to update progress");
99 }
100
101 hr = S_OK;
102
103LExit:
104 // clean up
105 FreeApplicationAttributes(&attrs);
106
107 return hr;
108}
109
110HRESULT CpiRollbackConfigureApplications(
111 LPWSTR* ppwzData,
112 CPI_ROLLBACK_DATA* pRollbackDataList
113 )
114{
115 HRESULT hr = S_OK;
116
117 int iRollbackStatus;
118
119 CPI_APPLICATION_ATTRIBUTES attrs;
120 ::ZeroMemory(&attrs, sizeof(attrs));
121
122 // read action text
123 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
124 ExitOnFailure(hr, "Failed to send action start message");
125
126 // get count
127 int iCnt = 0;
128 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
129 ExitOnFailure(hr, "Failed to read count");
130
131 for (int i = 0; i < iCnt; i++)
132 {
133 // read attributes from CustomActionData
134 hr = ReadApplicationAttributes(ppwzData, &attrs);
135 ExitOnFailure(hr, "Failed to read attributes");
136
137 // rollback status
138 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
139
140 if (S_FALSE == hr)
141 continue; // not found, nothing to rollback
142
143 // progress message
144 hr = CpiActionDataMessage(1, attrs.pwzName);
145 ExitOnFailure(hr, "Failed to send progress messages");
146
147 if (S_FALSE == hr)
148 ExitFunction();
149
150 // action
151 switch (attrs.iActionType)
152 {
153 case atCreate:
154 hr = CreateApplication(&attrs);
155 if (FAILED(hr))
156 WcaLog(LOGMSG_STANDARD, "Failed to create application, hr: 0x%x, key: %S", hr, attrs.pwzKey);
157 break;
158 case atRemove:
159 hr = RemoveApplication(&attrs);
160 if (FAILED(hr))
161 WcaLog(LOGMSG_STANDARD, "Failed to remove application, hr: 0x%x, key: %S", hr, attrs.pwzKey);
162 break;
163 }
164
165 // check rollback status
166 if (0 == iRollbackStatus)
167 continue; // operation did not complete, skip progress
168
169 // progress
170 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
171 ExitOnFailure(hr, "Failed to update progress");
172 }
173
174 hr = S_OK;
175
176LExit:
177 // clean up
178 FreeApplicationAttributes(&attrs);
179
180 return hr;
181}
182
183
184// helper function definitions
185
186static HRESULT ReadApplicationAttributes(
187 LPWSTR* ppwzData,
188 CPI_APPLICATION_ATTRIBUTES* pAttrs
189 )
190{
191 HRESULT hr = S_OK;
192
193 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
194 ExitOnFailure(hr, "Failed to read action type");
195 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
196 ExitOnFailure(hr, "Failed to read action cost");
197 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
198 ExitOnFailure(hr, "Failed to read key");
199 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID);
200 ExitOnFailure(hr, "Failed to read id");
201 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
202 ExitOnFailure(hr, "Failed to read name");
203 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
204 ExitOnFailure(hr, "Failed to read partition id");
205 hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList);
206 ExitOnFailure(hr, "Failed to read properties");
207
208 hr = S_OK;
209
210LExit:
211 return hr;
212}
213
214static void FreeApplicationAttributes(
215 CPI_APPLICATION_ATTRIBUTES* pAttrs
216 )
217{
218 ReleaseStr(pAttrs->pwzKey);
219 ReleaseStr(pAttrs->pwzID);
220 ReleaseStr(pAttrs->pwzName);
221 ReleaseStr(pAttrs->pwzPartID);
222
223 if (pAttrs->pPropList)
224 CpiFreePropertyList(pAttrs->pPropList);
225}
226
227static HRESULT CreateApplication(
228 CPI_APPLICATION_ATTRIBUTES* pAttrs
229 )
230{
231 HRESULT hr = S_OK;
232
233 ICatalogCollection* piAppColl = NULL;
234 ICatalogObject* piAppObj = NULL;
235
236 long lChanges = 0;
237
238 // log
239 WcaLog(LOGMSG_VERBOSE, "Creating application, key: %S", pAttrs->pwzKey);
240
241 // get applications collection
242 hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl);
243 if (S_FALSE == hr)
244 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
245 ExitOnFailure(hr, "Failed to get applications collection");
246
247 // check if application exists
248 hr = CpiFindCollectionObjectByStringKey(piAppColl, pAttrs->pwzID, &piAppObj);
249 ExitOnFailure(hr, "Failed to find application");
250
251 if (S_FALSE == hr)
252 {
253 // create application
254 hr = CpiAddCollectionObject(piAppColl, &piAppObj);
255 ExitOnFailure(hr, "Failed to add application to collection");
256
257 hr = CpiPutCollectionObjectValue(piAppObj, L"ID", pAttrs->pwzID);
258 ExitOnFailure(hr, "Failed to set application id property");
259
260 hr = CpiPutCollectionObjectValue(piAppObj, L"Name", pAttrs->pwzName);
261 ExitOnFailure(hr, "Failed to set application name property");
262
263 // save changes
264 hr = piAppColl->SaveChanges(&lChanges);
265 if (COMADMIN_E_OBJECTERRORS == hr)
266 CpiLogCatalogErrorInfo();
267 ExitOnFailure(hr, "Failed to add application");
268 }
269
270 // properties
271 hr = CpiPutCollectionObjectValues(piAppObj, pAttrs->pPropList);
272 ExitOnFailure(hr, "Failed to write properties");
273
274 // save changes
275 hr = piAppColl->SaveChanges(&lChanges);
276 if (COMADMIN_E_OBJECTERRORS == hr)
277 CpiLogCatalogErrorInfo();
278 ExitOnFailure(hr, "Failed to save changes");
279
280 // log
281 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
282
283 hr = S_OK;
284
285LExit:
286 // clean up
287 ReleaseObject(piAppColl);
288 ReleaseObject(piAppObj);
289
290 return hr;
291}
292
293static HRESULT RemoveApplication(
294 CPI_APPLICATION_ATTRIBUTES* pAttrs
295 )
296{
297 HRESULT hr = S_OK;
298
299 ICatalogCollection* piAppColl = NULL;
300
301 long lChanges = 0;
302
303 // log
304 WcaLog(LOGMSG_VERBOSE, "Removing application, key: %S", pAttrs->pwzKey);
305
306 // get applications collection
307 hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piAppColl);
308 ExitOnFailure(hr, "Failed to get applications collection");
309
310 if (S_FALSE == hr)
311 {
312 // applications collection not found
313 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve applications collection, nothing to delete, key: %S", pAttrs->pwzKey);
314 ExitFunction1(hr = S_OK);
315 }
316
317 // remove
318 hr = CpiRemoveCollectionObject(piAppColl, pAttrs->pwzID, NULL, TRUE);
319 ExitOnFailure(hr, "Failed to remove application");
320
321 if (S_FALSE == hr)
322 {
323 // application not found
324 WcaLog(LOGMSG_VERBOSE, "Application not found, nothing to delete, key: %S", pAttrs->pwzKey);
325 ExitFunction1(hr = S_OK);
326 }
327
328 // save changes
329 hr = piAppColl->SaveChanges(&lChanges);
330 if (COMADMIN_E_OBJECTERRORS == hr)
331 CpiLogCatalogErrorInfo();
332 ExitOnFailure(hr, "Failed to save changes");
333
334 // log
335 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
336
337 hr = S_OK;
338
339LExit:
340 // clean up
341 ReleaseObject(piAppColl);
342
343 return hr;
344}
diff --git a/src/ext/ComPlus/ca/cpappexec.h b/src/ext/ComPlus/ca/cpappexec.h
new file mode 100644
index 00000000..5003b046
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpappexec.h
@@ -0,0 +1,12 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureApplications(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureApplications(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
diff --git a/src/ext/ComPlus/ca/cpapproleexec.cpp b/src/ext/ComPlus/ca/cpapproleexec.cpp
new file mode 100644
index 00000000..e3b71e93
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpapproleexec.cpp
@@ -0,0 +1,720 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_APPLICATION_ROLE_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzName;
14 LPWSTR pwzAppID;
15 LPWSTR pwzPartID;
16 CPI_PROPERTY* pPropList;
17};
18
19struct CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES
20{
21 int iActionType;
22 int iActionCost;
23 LPWSTR pwzKey;
24 LPWSTR pwzRoleName;
25 LPWSTR pwzAccount;
26 LPWSTR pwzAppID;
27 LPWSTR pwzPartID;
28};
29
30
31// prototypes for private helper functions
32
33static HRESULT ReadApplicationRoleAttributes(
34 LPWSTR* ppwzData,
35 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
36 );
37static void FreeApplicationRoleAttributes(
38 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
39 );
40static HRESULT CreateApplicationRole(
41 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
42 );
43static HRESULT RemoveApplicationRole(
44 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
45 );
46static HRESULT ReadUsersInApplicationRoleAttributes(
47 LPWSTR* ppwzData,
48 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
49 );
50static void FreeUsersInApplicationRoleAttributes(
51 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
52 );
53static HRESULT CreateUsersInApplicationRole(
54 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
55 );
56static HRESULT RemoveUsersInApplicationRole(
57 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
58 );
59
60
61// function definitions
62
63HRESULT CpiConfigureApplicationRoles(
64 LPWSTR* ppwzData,
65 HANDLE hRollbackFile
66 )
67{
68 HRESULT hr = S_OK;
69
70 CPI_APPLICATION_ROLE_ATTRIBUTES attrs;
71 ::ZeroMemory(&attrs, sizeof(attrs));
72
73 // read action text
74 hr = CpiActionStartMessage(ppwzData, FALSE);
75 ExitOnFailure(hr, "Failed to send action start message");
76
77 // ger count
78 int iCnt = 0;
79 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
80 ExitOnFailure(hr, "Failed to read count");
81
82 // write count to rollback file
83 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
84 ExitOnFailure(hr, "Failed to write count to rollback file");
85
86 for (int i = 0; i < iCnt; i++)
87 {
88 // read attributes from CustomActionData
89 hr = ReadApplicationRoleAttributes(ppwzData, &attrs);
90 ExitOnFailure(hr, "Failed to read attributes");
91
92 // progress message
93 hr = CpiActionDataMessage(1, attrs.pwzName);
94 ExitOnFailure(hr, "Failed to send progress messages");
95
96 if (S_FALSE == hr)
97 ExitFunction();
98
99 // write key to rollback file
100 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
101 ExitOnFailure(hr, "Failed to write key to rollback file");
102
103 // action
104 switch (attrs.iActionType)
105 {
106 case atCreate:
107 hr = CreateApplicationRole(&attrs);
108 ExitOnFailure(hr, "Failed to create application role, key: %S", attrs.pwzKey);
109 break;
110 case atRemove:
111 hr = RemoveApplicationRole(&attrs);
112 ExitOnFailure(hr, "Failed to remove application role, key: %S", attrs.pwzKey);
113 break;
114 }
115
116 // write completion status to rollback file
117 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
118 ExitOnFailure(hr, "Failed to write completion status to rollback file");
119
120 // progress
121 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
122 ExitOnFailure(hr, "Failed to update progress");
123 }
124
125 hr = S_OK;
126
127LExit:
128 // clean up
129 FreeApplicationRoleAttributes(&attrs);
130
131 return hr;
132}
133
134HRESULT CpiRollbackConfigureApplicationRoles(
135 LPWSTR* ppwzData,
136 CPI_ROLLBACK_DATA* pRollbackDataList
137 )
138{
139 HRESULT hr = S_OK;
140
141 int iRollbackStatus;
142
143 CPI_APPLICATION_ROLE_ATTRIBUTES attrs;
144 ::ZeroMemory(&attrs, sizeof(attrs));
145
146 // read action text
147 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
148 ExitOnFailure(hr, "Failed to send action start message");
149
150 // get count
151 int iCnt = 0;
152 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
153 ExitOnFailure(hr, "Failed to read count");
154
155 for (int i = 0; i < iCnt; i++)
156 {
157 // read attributes from CustomActionData
158 hr = ReadApplicationRoleAttributes(ppwzData, &attrs);
159 ExitOnFailure(hr, "Failed to read attributes");
160
161 // rollback status
162 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
163
164 if (S_FALSE == hr)
165 continue; // not found, nothing to rollback
166
167 // progress message
168 hr = CpiActionDataMessage(1, attrs.pwzName);
169 ExitOnFailure(hr, "Failed to send progress messages");
170
171 if (S_FALSE == hr)
172 ExitFunction();
173
174 // action
175 switch (attrs.iActionType)
176 {
177 case atCreate:
178 hr = CreateApplicationRole(&attrs);
179 if (FAILED(hr))
180 WcaLog(LOGMSG_STANDARD, "Failed to create application role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
181 break;
182 case atRemove:
183 hr = RemoveApplicationRole(&attrs);
184 if (FAILED(hr))
185 WcaLog(LOGMSG_STANDARD, "Failed to remove application role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
186 break;
187 }
188
189 // check rollback status
190 if (0 == iRollbackStatus)
191 continue; // operation did not complete, skip progress
192
193 // progress
194 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
195 ExitOnFailure(hr, "Failed to update progress");
196 }
197
198 hr = S_OK;
199
200LExit:
201 // clean up
202 FreeApplicationRoleAttributes(&attrs);
203
204 return hr;
205}
206
207HRESULT CpiConfigureUsersInApplicationRoles(
208 LPWSTR* ppwzData,
209 HANDLE hRollbackFile
210 )
211{
212 HRESULT hr = S_OK;
213
214 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES attrs;
215 ::ZeroMemory(&attrs, sizeof(attrs));
216
217 // read action text
218 hr = CpiActionStartMessage(ppwzData, FALSE);
219 ExitOnFailure(hr, "Failed to send action start message");
220
221 // ger count
222 int iCnt = 0;
223 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
224 ExitOnFailure(hr, "Failed to read count");
225
226 // write count to rollback file
227 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
228 ExitOnFailure(hr, "Failed to write count to rollback file");
229
230 for (int i = 0; i < iCnt; i++)
231 {
232 // read attributes from CustomActionData
233 hr = ReadUsersInApplicationRoleAttributes(ppwzData, &attrs);
234 ExitOnFailure(hr, "Failed to read attributes");
235
236 // progress message
237 hr = CpiActionDataMessage(1, attrs.pwzRoleName);
238 ExitOnFailure(hr, "Failed to send progress messages");
239
240 if (S_FALSE == hr)
241 ExitFunction();
242
243 // write key to rollback file
244 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
245 ExitOnFailure(hr, "Failed to write key to rollback file");
246
247 // action
248 switch (attrs.iActionType)
249 {
250 case atCreate:
251 hr = CreateUsersInApplicationRole(&attrs);
252 ExitOnFailure(hr, "Failed to create user in application role, key: %S", attrs.pwzKey);
253 break;
254 case atRemove:
255 hr = RemoveUsersInApplicationRole(&attrs);
256 ExitOnFailure(hr, "Failed to remove user from application role, key: %S", attrs.pwzKey);
257 break;
258 }
259
260 // write completion status to rollback file
261 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
262 ExitOnFailure(hr, "Failed to write completion status to rollback file");
263
264 // progress
265 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
266 ExitOnFailure(hr, "Failed to update progress");
267 }
268
269 hr = S_OK;
270
271LExit:
272 // clean up
273 FreeUsersInApplicationRoleAttributes(&attrs);
274
275 return hr;
276}
277
278HRESULT CpiRollbackConfigureUsersInApplicationRoles(
279 LPWSTR* ppwzData,
280 CPI_ROLLBACK_DATA* pRollbackDataList
281 )
282{
283 HRESULT hr = S_OK;
284
285 int iRollbackStatus;
286
287 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES attrs;
288 ::ZeroMemory(&attrs, sizeof(attrs));
289
290 // read action text
291 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
292 ExitOnFailure(hr, "Failed to send action start message");
293
294 // get count
295 int iCnt = 0;
296 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
297 ExitOnFailure(hr, "Failed to read count");
298
299 for (int i = 0; i < iCnt; i++)
300 {
301 // read attributes from CustomActionData
302 hr = ReadUsersInApplicationRoleAttributes(ppwzData, &attrs);
303 ExitOnFailure(hr, "Failed to read attributes");
304
305 // rollback status
306 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
307
308 if (S_FALSE == hr)
309 continue; // not found, nothing to rollback
310
311 // progress message
312 hr = CpiActionDataMessage(1, attrs.pwzRoleName);
313 ExitOnFailure(hr, "Failed to send progress messages");
314
315 if (S_FALSE == hr)
316 ExitFunction();
317
318 // action
319 switch (attrs.iActionType)
320 {
321 case atCreate:
322 hr = CreateUsersInApplicationRole(&attrs);
323 if (FAILED(hr))
324 WcaLog(LOGMSG_STANDARD, "Failed to add user to application role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
325 break;
326 case atRemove:
327 hr = RemoveUsersInApplicationRole(&attrs);
328 if (FAILED(hr))
329 WcaLog(LOGMSG_STANDARD, "Failed to remove user from application role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
330 break;
331 }
332
333 // check rollback status
334 if (0 == iRollbackStatus)
335 continue; // operation did not complete, skip progress
336
337 // progress
338 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
339 ExitOnFailure(hr, "Failed to update progress");
340 }
341
342 hr = S_OK;
343
344LExit:
345 // clean up
346 FreeUsersInApplicationRoleAttributes(&attrs);
347
348 return hr;
349}
350
351
352// helper function definitions
353
354static HRESULT ReadApplicationRoleAttributes(
355 LPWSTR* ppwzData,
356 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
357 )
358{
359 HRESULT hr = S_OK;
360
361 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
362 ExitOnFailure(hr, "Failed to read action type");
363 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
364 ExitOnFailure(hr, "Failed to read action cost");
365 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
366 ExitOnFailure(hr, "Failed to read key");
367 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
368 ExitOnFailure(hr, "Failed to read name");
369 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
370 ExitOnFailure(hr, "Failed to read application id");
371 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
372 ExitOnFailure(hr, "Failed to read partition id");
373 hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList);
374 ExitOnFailure(hr, "Failed to read properties");
375
376 hr = S_OK;
377
378LExit:
379 return hr;
380}
381
382static void FreeApplicationRoleAttributes(
383 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
384 )
385{
386 ReleaseStr(pAttrs->pwzKey);
387 ReleaseStr(pAttrs->pwzName);
388 ReleaseStr(pAttrs->pwzAppID);
389 ReleaseStr(pAttrs->pwzPartID);
390
391 if (pAttrs->pPropList)
392 CpiFreePropertyList(pAttrs->pPropList);
393}
394
395static HRESULT CreateApplicationRole(
396 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
397 )
398{
399 HRESULT hr = S_OK;
400
401 ICatalogCollection* piRolesColl = NULL;
402 ICatalogObject* piRoleObj = NULL;
403
404 long lChanges = 0;
405
406 // log
407 WcaLog(LOGMSG_VERBOSE, "Creating application role, key: %S", pAttrs->pwzKey);
408
409 // get roles collection
410 hr = CpiGetRolesCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piRolesColl);
411 if (S_FALSE == hr)
412 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
413 ExitOnFailure(hr, "Failed to get roles collection");
414
415 // check if role exists
416 hr = CpiFindCollectionObjectByName(piRolesColl, pAttrs->pwzName, &piRoleObj);
417 ExitOnFailure(hr, "Failed to find role");
418
419 if (S_FALSE == hr)
420 {
421 // create role
422 hr = CpiAddCollectionObject(piRolesColl, &piRoleObj);
423 ExitOnFailure(hr, "Failed to add role to collection");
424
425 hr = CpiPutCollectionObjectValue(piRoleObj, L"Name", pAttrs->pwzName);
426 ExitOnFailure(hr, "Failed to set role name property");
427 }
428
429 // properties
430 hr = CpiPutCollectionObjectValues(piRoleObj, pAttrs->pPropList);
431 ExitOnFailure(hr, "Failed to write properties");
432
433 // save changes
434 hr = piRolesColl->SaveChanges(&lChanges);
435 if (COMADMIN_E_OBJECTERRORS == hr)
436 CpiLogCatalogErrorInfo();
437 ExitOnFailure(hr, "Failed to save changes");
438
439 // log
440 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
441
442 hr = S_OK;
443
444LExit:
445 // clean up
446 ReleaseObject(piRolesColl);
447 ReleaseObject(piRoleObj);
448
449 return hr;
450}
451
452static HRESULT RemoveApplicationRole(
453 CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs
454 )
455{
456 HRESULT hr = S_OK;
457
458 ICatalogCollection* piRolesColl = NULL;
459
460 long lChanges = 0;
461
462 // log
463 WcaLog(LOGMSG_VERBOSE, "Removing application role, key: %S", pAttrs->pwzKey);
464
465 // get roles collection
466 hr = CpiGetRolesCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piRolesColl);
467 ExitOnFailure(hr, "Failed to get roles collection");
468
469 if (S_FALSE == hr)
470 {
471 // roles collection not found
472 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve roles collection, nothing to delete, key: %S", pAttrs->pwzKey);
473 ExitFunction1(hr = S_OK);
474 }
475
476 // remove
477 hr = CpiRemoveCollectionObject(piRolesColl, NULL, pAttrs->pwzName, FALSE);
478 ExitOnFailure(hr, "Failed to remove role");
479
480 if (S_FALSE == hr)
481 {
482 // role not found
483 WcaLog(LOGMSG_VERBOSE, "Role not found, nothing to delete, key: %S", pAttrs->pwzKey);
484 ExitFunction1(hr = S_OK);
485 }
486
487 // save changes
488 hr = piRolesColl->SaveChanges(&lChanges);
489 if (COMADMIN_E_OBJECTERRORS == hr)
490 CpiLogCatalogErrorInfo();
491 ExitOnFailure(hr, "Failed to save changes");
492
493 // log
494 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
495
496 hr = S_OK;
497
498LExit:
499 // clean up
500 ReleaseObject(piRolesColl);
501
502 return hr;
503}
504
505static HRESULT ReadUsersInApplicationRoleAttributes(
506 LPWSTR* ppwzData,
507 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
508 )
509{
510 HRESULT hr = S_OK;
511
512 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
513 ExitOnFailure(hr, "Failed to read action type");
514 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
515 ExitOnFailure(hr, "Failed to read action cost");
516 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
517 ExitOnFailure(hr, "Failed to read key");
518 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzRoleName);
519 ExitOnFailure(hr, "Failed to read role name");
520 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount);
521 ExitOnFailure(hr, "Failed to read account name");
522 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
523 ExitOnFailure(hr, "Failed to read application id");
524 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
525 ExitOnFailure(hr, "Failed to read partition id");
526
527 hr = S_OK;
528
529LExit:
530 return hr;
531}
532
533static void FreeUsersInApplicationRoleAttributes(
534 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
535 )
536{
537 ReleaseStr(pAttrs->pwzKey);
538 ReleaseStr(pAttrs->pwzRoleName);
539 ReleaseStr(pAttrs->pwzAccount);
540 ReleaseStr(pAttrs->pwzAppID);
541 ReleaseStr(pAttrs->pwzPartID);
542}
543
544static HRESULT CreateUsersInApplicationRole(
545 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
546 )
547{
548 HRESULT hr = S_OK;
549 UINT er = ERROR_SUCCESS;
550
551 ICatalogCollection* piUsrInRoleColl = NULL;
552 ICatalogObject* piUsrInRoleObj = NULL;
553
554 PSID pSid = NULL;
555 long lChanges = 0;
556
557 // log
558 WcaLog(LOGMSG_VERBOSE, "Adding user to application role, key: %S", pAttrs->pwzKey);
559
560 // get users in role collection
561 hr = CpiGetUsersInRoleCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzRoleName, &piUsrInRoleColl);
562 if (S_FALSE == hr)
563 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
564 ExitOnFailure(hr, "Failed to get users in role collection");
565
566 // get SID for account
567 do {
568 er = ERROR_SUCCESS;
569 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
570 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
571 {
572 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
573 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
574 switch (er)
575 {
576 case IDABORT:
577 ExitFunction(); // exit with error code from CpiAccountNameToSid()
578 case IDRETRY:
579 break;
580 case IDIGNORE:
581 default:
582 ExitFunction1(hr = S_OK);
583 }
584 }
585 else
586 ExitOnFailure(hr, "Failed to get SID for account");
587 } while (IDRETRY == er);
588
589 // find any existing entry
590 hr = CpiFindUserCollectionObject(piUsrInRoleColl, pSid, NULL);
591 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
592 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
593 else
594 ExitOnFailure(hr, "Failed to find user in application role");
595
596 if (S_OK == hr)
597 {
598 WcaLog(LOGMSG_VERBOSE, "User already assigned to application role, key: %S", pAttrs->pwzKey);
599 ExitFunction(); // exit with hr = S_OK
600 }
601
602 // convert SID back to account name
603 hr = CpiSidToAccountName(pSid, &pAttrs->pwzAccount);
604 ExitOnFailure(hr, "Failed to convert SID to account name");
605
606 // add user
607 hr = CpiAddCollectionObject(piUsrInRoleColl, &piUsrInRoleObj);
608 ExitOnFailure(hr, "Failed to add user in role to collection");
609
610 hr = CpiPutCollectionObjectValue(piUsrInRoleObj, L"User", pAttrs->pwzAccount);
611 ExitOnFailure(hr, "Failed to set role name property");
612
613 // save changes
614 hr = piUsrInRoleColl->SaveChanges(&lChanges);
615 if (COMADMIN_E_OBJECTERRORS == hr)
616 CpiLogCatalogErrorInfo();
617 ExitOnFailure(hr, "Failed to save changes");
618
619 // log
620 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
621
622 hr = S_OK;
623
624LExit:
625 // clean up
626 ReleaseObject(piUsrInRoleColl);
627 ReleaseObject(piUsrInRoleObj);
628
629 if (pSid)
630 ::HeapFree(::GetProcessHeap(), 0, pSid);
631
632 return hr;
633}
634
635static HRESULT RemoveUsersInApplicationRole(
636 CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs
637 )
638{
639 HRESULT hr = S_OK;
640 UINT er = ERROR_SUCCESS;
641
642 ICatalogCollection* piUsrInRoleColl = NULL;
643
644 PSID pSid = NULL;
645 long lChanges = 0;
646
647 // log
648 WcaLog(LOGMSG_VERBOSE, "Removing user from application role, key: %S", pAttrs->pwzKey);
649
650 // get users in role collection
651 hr = CpiGetUsersInRoleCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzRoleName, &piUsrInRoleColl);
652 ExitOnFailure(hr, "Failed to get users in role collection");
653
654 if (S_FALSE == hr)
655 {
656 // users in role collection not found
657 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve users in role collection, nothing to delete, key: %S", pAttrs->pwzKey);
658 ExitFunction1(hr = S_OK);
659 }
660
661 // get SID for account
662 do {
663 er = ERROR_SUCCESS;
664 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
665 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
666 {
667 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
668 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
669 switch (er)
670 {
671 case IDABORT:
672 ExitFunction(); // exit with error code from CpiAccountNameToSid()
673 case IDRETRY:
674 break;
675 case IDIGNORE:
676 default:
677 ExitFunction1(hr = S_OK);
678 }
679 }
680 else
681 ExitOnFailure(hr, "Failed to get SID for account");
682 } while (IDRETRY == er);
683
684 // remove
685 hr = CpiRemoveUserCollectionObject(piUsrInRoleColl, pSid);
686 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
687 {
688 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
689 hr = S_FALSE;
690 }
691 else
692 ExitOnFailure(hr, "Failed to remove user");
693
694 if (S_FALSE == hr)
695 {
696 // role not found
697 WcaLog(LOGMSG_VERBOSE, "User not found for application role, nothing to delete, key: %S", pAttrs->pwzKey);
698 ExitFunction1(hr = S_OK);
699 }
700
701 // save changes
702 hr = piUsrInRoleColl->SaveChanges(&lChanges);
703 if (COMADMIN_E_OBJECTERRORS == hr)
704 CpiLogCatalogErrorInfo();
705 ExitOnFailure(hr, "Failed to save changes");
706
707 // log
708 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
709
710 hr = S_OK;
711
712LExit:
713 // clean up
714 ReleaseObject(piUsrInRoleColl);
715
716 if (pSid)
717 ::HeapFree(::GetProcessHeap(), 0, pSid);
718
719 return hr;
720}
diff --git a/src/ext/ComPlus/ca/cpapproleexec.h b/src/ext/ComPlus/ca/cpapproleexec.h
new file mode 100644
index 00000000..1251cbdb
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpapproleexec.h
@@ -0,0 +1,20 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureApplicationRoles(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureApplicationRoles(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
13HRESULT CpiConfigureUsersInApplicationRoles(
14 LPWSTR* ppwzData,
15 HANDLE hRollbackFile
16 );
17HRESULT CpiRollbackConfigureUsersInApplicationRoles(
18 LPWSTR* ppwzData,
19 CPI_ROLLBACK_DATA* pRollbackDataList
20 );
diff --git a/src/ext/ComPlus/ca/cpapprolesched.cpp b/src/ext/ComPlus/ca/cpapprolesched.cpp
new file mode 100644
index 00000000..a268d156
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpapprolesched.cpp
@@ -0,0 +1,843 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsApplicationRoleQuery =
9 L"SELECT `ApplicationRole`, `Application_`, `Component_`, `Name` FROM `ComPlusApplicationRole`";
10enum eApplicationRoleQuery { arqApplicationRole = 1, arqApplication, arqComponent, arqName };
11
12LPCWSTR vcsUserInApplicationRoleQuery =
13 L"SELECT `UserInApplicationRole`, `ApplicationRole_`, `ComPlusUserInApplicationRole`.`Component_`, `Domain`, `Name` FROM `ComPlusUserInApplicationRole`, `User` WHERE `User_` = `User`";
14LPCWSTR vcsGroupInApplicationRoleQuery =
15 L"SELECT `GroupInApplicationRole`, `ApplicationRole_`, `ComPlusGroupInApplicationRole`.`Component_`, `Domain`, `Name` FROM `ComPlusGroupInApplicationRole`, `Group` WHERE `Group_` = `Group`";
16enum eTrusteeInApplicationRoleQuery { tiarqUserInApplicationRole = 1, tiarqApplicationRole, tiarqComponent, tiarqDomain, tiarqName };
17
18LPCWSTR vcsApplicationRolePropertyQuery =
19 L"SELECT `Name`, `Value` FROM `ComPlusApplicationRoleProperty` WHERE `ApplicationRole_` = ?";
20
21
22// property definitions
23
24CPI_PROPERTY_DEFINITION pdlApplicationRoleProperties[] =
25{
26 {L"Description", cpptString, 500},
27 {NULL, cpptNone, 0}
28};
29
30
31// prototypes for private helper functions
32
33static HRESULT TrusteesInApplicationRolesRead(
34 LPCWSTR pwzQuery,
35 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
36 CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList
37 );
38static void FreeApplicationRole(
39 CPI_APPLICATION_ROLE* pItm
40 );
41static void FreeUserInApplicationRole(
42 CPI_USER_IN_APPLICATION_ROLE* pItm
43 );
44//static HRESULT GetUsersCollForApplicationRole(
45// CPI_APPLICATION_ROLE* pAppRole,
46// ICatalogCollection** ppiUsersColl
47// );
48static HRESULT FindObjectForApplicationRole(
49 CPI_APPLICATION_ROLE* pItm,
50 ICatalogObject** ppiRoleObj
51 );
52static HRESULT AddApplicationRoleToActionData(
53 CPI_APPLICATION_ROLE* pItm,
54 int iActionType,
55 int iActionCost,
56 LPWSTR* ppwzActionData
57 );
58static HRESULT AddUserInApplicationRoleToActionData(
59 CPI_USER_IN_APPLICATION_ROLE* pItm,
60 int iActionType,
61 int iActionCost,
62 LPWSTR* ppwzActionData
63 );
64
65
66// function definitions
67
68void CpiApplicationRoleListFree(
69 CPI_APPLICATION_ROLE_LIST* pList
70 )
71{
72 CPI_APPLICATION_ROLE* pItm = pList->pFirst;
73
74 while (pItm)
75 {
76 CPI_APPLICATION_ROLE* pDelete = pItm;
77 pItm = pItm->pNext;
78 FreeApplicationRole(pDelete);
79 }
80}
81
82HRESULT CpiApplicationRolesRead(
83 CPI_APPLICATION_LIST* pAppList,
84 CPI_APPLICATION_ROLE_LIST* pAppRoleList
85 )
86{
87 HRESULT hr = S_OK;
88 UINT er = ERROR_SUCCESS;
89
90 PMSIHANDLE hView, hRec;
91
92 CPI_APPLICATION_ROLE* pItm = NULL;
93 LPWSTR pwzData = NULL;
94 BOOL fMatchingArchitecture = FALSE;
95
96 // loop through all application roles
97 hr = WcaOpenExecuteView(vcsApplicationRoleQuery, &hView);
98 ExitOnFailure(hr, "Failed to execute view on ComPlusApplicationRole table");
99
100 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
101 {
102 // get component
103 hr = WcaGetRecordString(hRec, arqComponent, &pwzData);
104 ExitOnFailure(hr, "Failed to get component");
105
106 // check if the component is our processor architecture
107 if (pwzData && *pwzData)
108 {
109 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
110 ExitOnFailure(hr, "Failed to get component architecture.");
111
112 if (!fMatchingArchitecture)
113 {
114 continue; // not the same architecture, ignore
115 }
116 }
117
118 // create entry
119 pItm = (CPI_APPLICATION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_APPLICATION_ROLE));
120 if (!pItm)
121 ExitFunction1(hr = E_OUTOFMEMORY);
122
123 // get component install state
124 if (pwzData && *pwzData)
125 {
126 pItm->fHasComponent = TRUE;
127
128 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
129 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
130 }
131
132 // get key
133 hr = WcaGetRecordString(hRec, arqApplicationRole, &pwzData);
134 ExitOnFailure(hr, "Failed to get key");
135 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
136
137 // get application
138 hr = WcaGetRecordString(hRec, arqApplication, &pwzData);
139 ExitOnFailure(hr, "Failed to get application");
140
141 hr = CpiApplicationFindByKey(pAppList, pwzData, &pItm->pApplication);
142 if (S_FALSE == hr)
143 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
144 ExitOnFailure(hr, "Failed to find application, key: %S", pwzData);
145
146 // get name
147 hr = WcaGetRecordFormattedString(hRec, arqName, &pwzData);
148 ExitOnFailure(hr, "Failed to get name");
149 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
150
151 // get properties
152 if (CpiTableExists(cptComPlusApplicationRoleProperty))
153 {
154 hr = CpiPropertiesRead(vcsApplicationRolePropertyQuery, pItm->wzKey, pdlApplicationRoleProperties, &pItm->pProperties, &pItm->iPropertyCount);
155 ExitOnFailure(hr, "Failed to get properties");
156 }
157
158 // set references & increment counters
159 if (pItm->fHasComponent)
160 {
161 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
162 {
163 CpiApplicationAddReferenceInstall(pItm->pApplication);
164 pAppRoleList->iInstallCount++;
165 }
166 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
167 {
168 CpiApplicationAddReferenceUninstall(pItm->pApplication);
169 pAppRoleList->iUninstallCount++;
170 }
171 }
172
173 // add entry
174 if (pAppRoleList->pFirst)
175 pItm->pNext = pAppRoleList->pFirst;
176 pAppRoleList->pFirst = pItm;
177 pItm = NULL;
178 }
179
180 if (E_NOMOREITEMS == hr)
181 hr = S_OK;
182
183LExit:
184 // clean up
185 if (pItm)
186 FreeApplicationRole(pItm);
187
188 ReleaseStr(pwzData);
189
190 return hr;
191}
192
193HRESULT CpiApplicationRolesVerifyInstall(
194 CPI_APPLICATION_ROLE_LIST* pList
195 )
196{
197 HRESULT hr = S_OK;
198 UINT er = ERROR_SUCCESS;
199
200 ICatalogObject* piRoleObj = NULL;
201
202 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
203 {
204 // referenced locaters or roles that are being installed
205 if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)))
206 continue;
207
208 // if the role is referensed and is not a locater, it must be installed
209 if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
210 MessageExitOnFailure(hr = E_FAIL, msierrComPlusApplicationRoleDependency, "An application role is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
211
212 // role is a locater
213 if (!pItm->fHasComponent)
214 {
215 // get collection object for role
216 hr = FindObjectForApplicationRole(pItm, &piRoleObj);
217 ExitOnFailure(hr, "Failed to find collection object for role");
218
219 // if the role was not found
220 if (S_FALSE == hr)
221 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationRoleNotFound, "An application role required by this installation was not found, key: %S", pItm->wzKey);
222 }
223
224 // role is supposed to be created
225 else if (!CpiIsInstalled(pItm->isInstalled))
226 {
227 do {
228 // find roles with conflicting name or id
229 hr = FindObjectForApplicationRole(pItm, NULL);
230 ExitOnFailure(hr, "Failed to find collection object for role");
231
232 if (S_OK == hr)
233 {
234 er = WcaErrorMessage(msierrComPlusApplicationRoleConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
235 switch (er)
236 {
237 case IDABORT:
238 ExitOnFailure(hr = E_FAIL, "An application with a conflictiong name exists, key: %S", pItm->wzKey);
239 break;
240 case IDRETRY:
241 break;
242 case IDIGNORE:
243 default:
244 hr = S_FALSE; // indicate that this is not a conflict
245 }
246 }
247 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
248 }
249
250 // clean up
251 ReleaseNullObject(piRoleObj);
252 }
253
254 hr = S_OK;
255
256LExit:
257 // clean up
258 ReleaseObject(piRoleObj);
259
260 return hr;
261}
262
263HRESULT CpiApplicationRolesVerifyUninstall(
264 CPI_APPLICATION_ROLE_LIST* pList
265 )
266{
267 HRESULT hr = S_OK;
268
269 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
270 {
271 // referenced locaters or roles that are being installed
272 if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction)))
273 continue;
274
275 // get collection object for role
276 hr = FindObjectForApplicationRole(pItm, NULL);
277 ExitOnFailure(hr, "Failed to find collection object for role");
278
279 // if the role was not found
280 if (S_FALSE == hr)
281 {
282 pItm->fObjectNotFound = TRUE;
283 if (pItm->fHasComponent)
284 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
285 }
286 }
287
288 hr = S_OK;
289
290LExit:
291 return hr;
292}
293
294void CpiApplicationRoleAddReferenceInstall(
295 CPI_APPLICATION_ROLE* pItm
296 )
297{
298 pItm->fReferencedForInstall = TRUE;
299 CpiApplicationAddReferenceInstall(pItm->pApplication);
300}
301
302void CpiApplicationRoleAddReferenceUninstall(
303 CPI_APPLICATION_ROLE* pItm
304 )
305{
306 pItm->fReferencedForUninstall = TRUE;
307 CpiApplicationAddReferenceUninstall(pItm->pApplication);
308}
309
310HRESULT CpiApplicationRolesInstall(
311 CPI_APPLICATION_ROLE_LIST* pList,
312 int iRunMode,
313 LPWSTR* ppwzActionData,
314 int* piProgress
315 )
316{
317 HRESULT hr = S_OK;
318
319 int iActionType;
320
321 // add action text
322 hr = CpiAddActionTextToActionData(L"CreateComPlusApplicationRoles", ppwzActionData);
323 ExitOnFailure(hr, "Failed to add action text to custom action data");
324
325 // add count to action data
326 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
327 ExitOnFailure(hr, "Failed to add count to custom action data");
328
329 // add roles to custom action data
330 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
331 {
332 // roles that are being installed only
333 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
334 continue;
335
336 // action type
337 if (rmRollback == iRunMode)
338 {
339 if (CpiIsInstalled(pItm->isInstalled))
340 iActionType = atNoOp;
341 else
342 iActionType = atRemove;
343 }
344 else
345 iActionType = atCreate;
346
347 // add to action data
348 hr = AddApplicationRoleToActionData(pItm, iActionType, COST_APPLICATION_ROLE_CREATE, ppwzActionData);
349 ExitOnFailure(hr, "Failed to add application role to custom action data, key: %S", pItm->wzKey);
350 }
351
352 // add progress tics
353 if (piProgress)
354 *piProgress += COST_APPLICATION_ROLE_CREATE * pList->iInstallCount;
355
356 hr = S_OK;
357
358LExit:
359 return hr;
360}
361
362HRESULT CpiApplicationRolesUninstall(
363 CPI_APPLICATION_ROLE_LIST* pList,
364 int iRunMode,
365 LPWSTR* ppwzActionData,
366 int* piProgress
367 )
368{
369 HRESULT hr = S_OK;
370
371 int iActionType;
372
373 // add action text
374 hr = CpiAddActionTextToActionData(L"RemoveComPlusApplicationRoles", ppwzActionData);
375 ExitOnFailure(hr, "Failed to add action text to custom action data");
376
377 // add count to action data
378 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
379 ExitOnFailure(hr, "Failed to add count to custom action data");
380
381 // add roles to custom action data
382 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
383 {
384 // roles that are being uninstalled only
385 if (pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
386 continue;
387
388 // action type
389 if (rmRollback == iRunMode)
390 iActionType = atCreate;
391 else
392 iActionType = atRemove;
393
394 // add to action data
395 hr = AddApplicationRoleToActionData(pItm, iActionType, COST_APPLICATION_ROLE_DELETE, ppwzActionData);
396 ExitOnFailure(hr, "Failed to add application role to custom action data, key: %S", pItm->wzKey);
397 }
398
399 // add progress tics
400 if (piProgress)
401 *piProgress += COST_APPLICATION_ROLE_DELETE * pList->iUninstallCount;
402
403 hr = S_OK;
404
405LExit:
406 return hr;
407}
408
409HRESULT CpiApplicationRoleFindByKey(
410 CPI_APPLICATION_ROLE_LIST* pList,
411 LPCWSTR pwzKey,
412 CPI_APPLICATION_ROLE** ppAppRole
413 )
414{
415 for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
416 {
417 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
418 {
419 *ppAppRole = pItm;
420 return S_OK;
421 }
422 }
423
424 return S_FALSE;
425}
426
427void CpiUserInApplicationRoleListFree(
428 CPI_USER_IN_APPLICATION_ROLE_LIST* pList
429 )
430{
431 CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst;
432
433 while (pItm)
434 {
435 CPI_USER_IN_APPLICATION_ROLE* pDelete = pItm;
436 pItm = pItm->pNext;
437 FreeUserInApplicationRole(pDelete);
438 }
439}
440
441HRESULT CpiUsersInApplicationRolesRead(
442 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
443 CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList
444 )
445{
446 HRESULT hr = S_OK;
447
448 // read users in application roles
449 if (CpiTableExists(cptComPlusUserInApplicationRole))
450 {
451 hr = TrusteesInApplicationRolesRead(vcsUserInApplicationRoleQuery, pAppRoleList, pUsrInAppRoleList);
452 ExitOnFailure(hr, "Failed to read users in application roles");
453 }
454
455 // read groups in application roles
456 if (CpiTableExists(cptComPlusGroupInApplicationRole))
457 {
458 hr = TrusteesInApplicationRolesRead(vcsGroupInApplicationRoleQuery, pAppRoleList, pUsrInAppRoleList);
459 ExitOnFailure(hr, "Failed to read groups in application roles");
460 }
461
462 hr = S_OK;
463
464LExit:
465 return hr;
466}
467
468HRESULT CpiUsersInApplicationRolesInstall(
469 CPI_USER_IN_APPLICATION_ROLE_LIST* pList,
470 int iRunMode,
471 LPWSTR* ppwzActionData,
472 int* piProgress
473 )
474{
475 HRESULT hr = S_OK;
476
477 int iActionType;
478
479 // add action text
480 hr = CpiAddActionTextToActionData(L"AddUsersToComPlusApplicationRoles", ppwzActionData);
481 ExitOnFailure(hr, "Failed to add action text to custom action data");
482
483 // add count to action data
484 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
485 ExitOnFailure(hr, "Failed to add count to custom action data");
486
487 // add roles to custom action data
488 for (CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
489 {
490 // roles that are being installed only
491 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
492 continue;
493
494 // action type
495 if (rmRollback == iRunMode)
496 {
497 if (CpiIsInstalled(pItm->isInstalled))
498 iActionType = atNoOp;
499 else
500 iActionType = atRemove;
501 }
502 else
503 iActionType = atCreate;
504
505 // add to action data
506 hr = AddUserInApplicationRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_CREATE, ppwzActionData);
507 ExitOnFailure(hr, "Failed to add user in application role to custom action data, key: %S", pItm->wzKey);
508 }
509
510 // add progress tics
511 if (piProgress)
512 *piProgress += COST_USER_IN_APPLICATION_ROLE_CREATE * pList->iInstallCount;
513
514 hr = S_OK;
515
516LExit:
517 return hr;
518}
519
520HRESULT CpiUsersInApplicationRolesUninstall(
521 CPI_USER_IN_APPLICATION_ROLE_LIST* pList,
522 int iRunMode,
523 LPWSTR* ppwzActionData,
524 int* piProgress
525 )
526{
527 HRESULT hr = S_OK;
528
529 int iActionType;
530
531 // add action text
532 hr = CpiAddActionTextToActionData(L"RemoveUsersFromComPlusAppRoles", ppwzActionData);
533 ExitOnFailure(hr, "Failed to add action text to custom action data");
534
535 // add count to action data
536 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
537 ExitOnFailure(hr, "Failed to add count to custom action data");
538
539 // add roles to custom action data
540 for (CPI_USER_IN_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
541 {
542 // roles that are being uninstalled only
543 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
544 continue;
545
546 // action type
547 if (rmRollback == iRunMode)
548 iActionType = atCreate;
549 else
550 iActionType = atRemove;
551
552 // add to action data
553 hr = AddUserInApplicationRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_DELETE, ppwzActionData);
554 ExitOnFailure(hr, "Failed to add user in application role to custom action data, key: %S", pItm->wzKey);
555 }
556
557 // add progress tics
558 if (piProgress)
559 *piProgress += COST_USER_IN_APPLICATION_ROLE_DELETE * pList->iUninstallCount;
560
561 hr = S_OK;
562
563LExit:
564 return hr;
565}
566
567
568// helper function definitions
569
570static HRESULT TrusteesInApplicationRolesRead(
571 LPCWSTR pwzQuery,
572 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
573 CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList
574 )
575{
576 HRESULT hr = S_OK;
577 UINT er = ERROR_SUCCESS;
578
579 PMSIHANDLE hView, hRec;
580
581 CPI_USER_IN_APPLICATION_ROLE* pItm = NULL;
582 LPWSTR pwzData = NULL;
583 LPWSTR pwzDomain = NULL;
584 LPWSTR pwzName = NULL;
585 BOOL fMatchingArchitecture = FALSE;
586
587 // loop through all application roles
588 hr = WcaOpenExecuteView(pwzQuery, &hView);
589 ExitOnFailure(hr, "Failed to execute view on table");
590
591 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
592 {
593 // get component
594 hr = WcaGetRecordString(hRec, tiarqComponent, &pwzData);
595 ExitOnFailure(hr, "Failed to get component");
596
597 // check if the component is our processor architecture
598 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
599 ExitOnFailure(hr, "Failed to get component architecture.");
600
601 if (!fMatchingArchitecture)
602 {
603 continue; // not the same architecture, ignore
604 }
605
606 // create entry
607 pItm = (CPI_USER_IN_APPLICATION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_USER_IN_APPLICATION_ROLE));
608 if (!pItm)
609 ExitFunction1(hr = E_OUTOFMEMORY);
610
611 // get component install state
612 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
613 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
614
615 // get key
616 hr = WcaGetRecordString(hRec, tiarqUserInApplicationRole, &pwzData);
617 ExitOnFailure(hr, "Failed to get key");
618 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
619
620 // get application role
621 hr = WcaGetRecordString(hRec, tiarqApplicationRole, &pwzData);
622 ExitOnFailure(hr, "Failed to get application role");
623
624 hr = CpiApplicationRoleFindByKey(pAppRoleList, pwzData, &pItm->pApplicationRole);
625 if (S_FALSE == hr)
626 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
627 ExitOnFailure(hr, "Failed to find application role, key: %S", pwzData);
628
629 // get user domain
630 hr = WcaGetRecordFormattedString(hRec, tiarqDomain, &pwzDomain);
631 ExitOnFailure(hr, "Failed to get domain");
632
633 // get user name
634 hr = WcaGetRecordFormattedString(hRec, tiarqName, &pwzName);
635 ExitOnFailure(hr, "Failed to get name");
636
637 // build account name
638 hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount);
639 ExitOnFailure(hr, "Failed to build account name");
640
641 // set references & increment counters
642 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
643 {
644 CpiApplicationRoleAddReferenceInstall(pItm->pApplicationRole);
645 pUsrInAppRoleList->iInstallCount++;
646 }
647 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
648 {
649 CpiApplicationRoleAddReferenceUninstall(pItm->pApplicationRole);
650 pUsrInAppRoleList->iUninstallCount++;
651 }
652
653 // add entry
654 if (pUsrInAppRoleList->pFirst)
655 pItm->pNext = pUsrInAppRoleList->pFirst;
656 pUsrInAppRoleList->pFirst = pItm;
657 pItm = NULL;
658 }
659
660 if (E_NOMOREITEMS == hr)
661 hr = S_OK;
662
663LExit:
664 // clean up
665 if (pItm)
666 FreeUserInApplicationRole(pItm);
667
668 ReleaseStr(pwzData);
669 ReleaseStr(pwzDomain);
670 ReleaseStr(pwzName);
671
672 return hr;
673}
674
675static void FreeApplicationRole(
676 CPI_APPLICATION_ROLE* pItm
677 )
678{
679 if (pItm->pProperties)
680 CpiPropertiesFreeList(pItm->pProperties);
681
682 ReleaseObject(pItm->piUsersColl);
683
684 ::HeapFree(::GetProcessHeap(), 0, pItm);
685}
686
687static void FreeUserInApplicationRole(
688 CPI_USER_IN_APPLICATION_ROLE* pItm
689 )
690{
691 ReleaseStr(pItm->pwzAccount);
692
693 ::HeapFree(::GetProcessHeap(), 0, pItm);
694}
695
696//static HRESULT GetUsersCollForApplicationRole(
697// CPI_APPLICATION_ROLE* pAppRole,
698// ICatalogCollection** ppiUsersColl
699// )
700//{
701// HRESULT hr = S_OK;
702//
703// ICatalogCollection* piRoleColl = NULL;
704// ICatalogObject* piRoleObj = NULL;
705//
706// // if a previous attempt to locate the collection object failed
707// if (pAppRole->fObjectNotFound)
708// ExitFunction1(hr = S_FALSE);
709//
710// // get applications collection
711// if (!pAppRole->piUsersColl)
712// {
713// // get collection object for role
714// hr = FindObjectForApplicationRole(pAppRole, &piRoleObj);
715// ExitOnFailure(hr, "Failed to find collection object for role");
716//
717// if (S_FALSE == hr)
718// ExitFunction(); // exit with hr = S_FALSE
719//
720// // get users collection
721// hr = CpiGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", &pAppRole->piUsersColl);
722// ExitOnFailure(hr, "Failed to get users in role collection");
723// }
724//
725// // return value
726// *ppiUsersColl = pAppRole->piUsersColl;
727// (*ppiUsersColl)->AddRef();
728//
729// hr = S_OK;
730//
731//LExit:
732// // clean up
733// ReleaseObject(piRoleColl);
734// ReleaseObject(piRoleObj);
735//
736// return hr;
737//}
738
739static HRESULT FindObjectForApplicationRole(
740 CPI_APPLICATION_ROLE* pItm,
741 ICatalogObject** ppiRoleObj
742 )
743{
744 HRESULT hr = S_OK;
745
746 ICatalogCollection* piRoleColl = NULL;
747
748 // get roles collection
749 hr = CpiGetRolesCollForApplication(pItm->pApplication, &piRoleColl);
750 ExitOnFailure(hr, "Failed to get collection");
751
752 if (S_FALSE == hr)
753 ExitFunction(); // exit with hr = S_FALSE
754
755 // find role object
756 hr = CpiFindCollectionObject(piRoleColl, NULL, pItm->wzName, ppiRoleObj);
757 ExitOnFailure(hr, "Failed to find object");
758
759 // exit with hr from CpiFindCollectionObject()
760
761LExit:
762 // clean up
763 ReleaseObject(piRoleColl);
764
765 return hr;
766}
767
768static HRESULT AddApplicationRoleToActionData(
769 CPI_APPLICATION_ROLE* pItm,
770 int iActionType,
771 int iActionCost,
772 LPWSTR* ppwzActionData
773 )
774{
775 HRESULT hr = S_OK;
776
777 // add action information to custom action data
778 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
779 ExitOnFailure(hr, "Failed to add action type to custom action data");
780 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
781 ExitOnFailure(hr, "Failed to add action cost to custom action data");
782
783 // add application role information to custom action data
784 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
785 ExitOnFailure(hr, "Failed to add application role key to custom action data");
786 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
787 ExitOnFailure(hr, "Failed to add application role name to custom action data");
788
789 // add application information to custom action data
790 hr = WcaWriteStringToCaData(pItm->pApplication->wzID, ppwzActionData);
791 ExitOnFailure(hr, "Failed to add application id to custom action data");
792
793 // add partition information to custom action data
794 hr = WcaWriteStringToCaData(pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"", ppwzActionData);
795 ExitOnFailure(hr, "Failed to add partition id to custom action data");
796
797 // add properties to custom action data
798 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
799 ExitOnFailure(hr, "Failed to add properties to custom action data");
800
801 hr = S_OK;
802
803LExit:
804 return hr;
805}
806
807static HRESULT AddUserInApplicationRoleToActionData(
808 CPI_USER_IN_APPLICATION_ROLE* pItm,
809 int iActionType,
810 int iActionCost,
811 LPWSTR* ppwzActionData
812 )
813{
814 HRESULT hr = S_OK;
815
816 // add action information to custom action data
817 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
818 ExitOnFailure(hr, "Failed to add action type to custom action data");
819 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
820 ExitOnFailure(hr, "Failed to add action cost to custom action data");
821
822 // add application role information to custom action data
823 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
824 ExitOnFailure(hr, "Failed to add key to custom action data");
825 hr = WcaWriteStringToCaData(pItm->pApplicationRole->wzName, ppwzActionData);
826 ExitOnFailure(hr, "Failed to add role name to custom action data");
827 hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData);
828 ExitOnFailure(hr, "Failed to add user account to custom action data");
829
830 // add application information to custom action data
831 CPI_APPLICATION* pApplication = pItm->pApplicationRole->pApplication;
832 hr = WcaWriteStringToCaData(pApplication->wzID, ppwzActionData);
833 ExitOnFailure(hr, "Failed to add application id to custom action data");
834
835 // add partition information to custom action data
836 hr = WcaWriteStringToCaData(pApplication->pPartition ? pApplication->pPartition->wzID : L"", ppwzActionData);
837 ExitOnFailure(hr, "Failed to add partition id to custom action data");
838
839 hr = S_OK;
840
841LExit:
842 return hr;
843}
diff --git a/src/ext/ComPlus/ca/cpapprolesched.h b/src/ext/ComPlus/ca/cpapprolesched.h
new file mode 100644
index 00000000..02852eef
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpapprolesched.h
@@ -0,0 +1,112 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_APPLICATION_ROLE
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
9
10 int iPropertyCount;
11 CPI_PROPERTY* pProperties;
12
13 BOOL fHasComponent;
14 BOOL fReferencedForInstall;
15 BOOL fReferencedForUninstall;
16 BOOL fObjectNotFound;
17
18 INSTALLSTATE isInstalled, isAction;
19
20 CPI_APPLICATION* pApplication;
21
22 ICatalogCollection* piUsersColl;
23
24 CPI_APPLICATION_ROLE* pNext;
25};
26
27struct CPI_APPLICATION_ROLE_LIST
28{
29 CPI_APPLICATION_ROLE* pFirst;
30
31 int iInstallCount;
32 int iUninstallCount;
33};
34
35struct CPI_USER_IN_APPLICATION_ROLE
36{
37 WCHAR wzKey[MAX_DARWIN_KEY + 1];
38 LPWSTR pwzAccount;
39
40 INSTALLSTATE isInstalled, isAction;
41
42 CPI_APPLICATION_ROLE* pApplicationRole;
43
44 CPI_USER_IN_APPLICATION_ROLE* pNext;
45};
46
47struct CPI_USER_IN_APPLICATION_ROLE_LIST
48{
49 CPI_USER_IN_APPLICATION_ROLE* pFirst;
50
51 int iInstallCount;
52 int iUninstallCount;
53};
54
55
56// function prototypes
57
58void CpiApplicationRoleListFree(
59 CPI_APPLICATION_ROLE_LIST* pList
60 );
61HRESULT CpiApplicationRolesRead(
62 CPI_APPLICATION_LIST* pAppList,
63 CPI_APPLICATION_ROLE_LIST* pAppRoleList
64 );
65HRESULT CpiApplicationRolesVerifyInstall(
66 CPI_APPLICATION_ROLE_LIST* pList
67 );
68HRESULT CpiApplicationRolesVerifyUninstall(
69 CPI_APPLICATION_ROLE_LIST* pList
70 );
71void CpiApplicationRoleAddReferenceInstall(
72 CPI_APPLICATION_ROLE* pItm
73 );
74void CpiApplicationRoleAddReferenceUninstall(
75 CPI_APPLICATION_ROLE* pItm
76 );
77HRESULT CpiApplicationRolesInstall(
78 CPI_APPLICATION_ROLE_LIST* pList,
79 int iRunMode,
80 LPWSTR* ppwzActionData,
81 int* piProgress
82 );
83HRESULT CpiApplicationRolesUninstall(
84 CPI_APPLICATION_ROLE_LIST* pList,
85 int iRunMode,
86 LPWSTR* ppwzActionData,
87 int* piProgress
88 );
89HRESULT CpiApplicationRoleFindByKey(
90 CPI_APPLICATION_ROLE_LIST* pList,
91 LPCWSTR pwzKey,
92 CPI_APPLICATION_ROLE** ppAppRole
93 );
94void CpiUserInApplicationRoleListFree(
95 CPI_USER_IN_APPLICATION_ROLE_LIST* pList
96 );
97HRESULT CpiUsersInApplicationRolesRead(
98 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
99 CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList
100 );
101HRESULT CpiUsersInApplicationRolesInstall(
102 CPI_USER_IN_APPLICATION_ROLE_LIST* pList,
103 int iRunMode,
104 LPWSTR* ppwzActionData,
105 int* piProgress
106 );
107HRESULT CpiUsersInApplicationRolesUninstall(
108 CPI_USER_IN_APPLICATION_ROLE_LIST* pList,
109 int iRunMode,
110 LPWSTR* ppwzActionData,
111 int* piProgress
112 );
diff --git a/src/ext/ComPlus/ca/cpappsched.cpp b/src/ext/ComPlus/ca/cpappsched.cpp
new file mode 100644
index 00000000..1fb2203b
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpappsched.cpp
@@ -0,0 +1,752 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsApplicationQuery =
9 L"SELECT `Application`, `Component_`, `Partition_`, `Id`, `Name` FROM `ComPlusApplication`";
10enum eApplicationQuery { aqApplication = 1, aqComponent, aqPartition, aqID, aqName };
11
12LPCWSTR vcsApplicationPropertyQuery =
13 L"SELECT `Name`, `Value` FROM `ComPlusApplicationProperty` WHERE `Application_` = ?";
14
15
16// property definitions
17
18CPI_PROPERTY_DEFINITION pdlApplicationProperties[] =
19{
20 {L"3GigSupportEnabled", cpptBoolean, 500},
21 {L"AccessChecksLevel", cpptInteger, 500},
22 {L"Activation", cpptInteger, 500},
23 {L"ApplicationAccessChecksEnabled", cpptBoolean, 500},
24 {L"ApplicationDirectory", cpptString, 501},
25 {L"Authentication", cpptInteger, 500},
26 {L"AuthenticationCapability", cpptInteger, 500},
27 {L"Changeable", cpptBoolean, 500},
28 {L"CommandLine", cpptString, 500},
29 {L"ConcurrentApps", cpptInteger, 501},
30 {L"CreatedBy", cpptString, 500},
31 {L"CRMEnabled", cpptBoolean, 500},
32 {L"CRMLogFile", cpptString, 500},
33 {L"Deleteable", cpptBoolean, 500},
34 {L"Description", cpptString, 500},
35 {L"DumpEnabled", cpptBoolean, 501},
36 {L"DumpOnException", cpptBoolean, 501},
37 {L"DumpOnFailfast", cpptBoolean, 501},
38 {L"DumpPath", cpptString, 501},
39 {L"EventsEnabled", cpptBoolean, 500},
40 {L"Identity", cpptString, 500},
41 {L"ImpersonationLevel", cpptInteger, 500},
42 {L"IsEnabled", cpptBoolean, 501},
43 {L"MaxDumpCount", cpptInteger, 501},
44 {L"Password", cpptString, 500},
45 {L"QCAuthenticateMsgs", cpptInteger, 501},
46 {L"QCListenerMaxThreads", cpptInteger, 501},
47 {L"QueueListenerEnabled", cpptBoolean, 500},
48 {L"QueuingEnabled", cpptBoolean, 500},
49 {L"RecycleActivationLimit", cpptInteger, 501},
50 {L"RecycleCallLimit", cpptInteger, 501},
51 {L"RecycleExpirationTimeout", cpptInteger, 501},
52 {L"RecycleLifetimeLimit", cpptInteger, 501},
53 {L"RecycleMemoryLimit", cpptInteger, 501},
54 {L"Replicable", cpptBoolean, 501},
55 {L"RunForever", cpptBoolean, 500},
56 {L"ShutdownAfter", cpptInteger, 500},
57 {L"SoapActivated", cpptBoolean, 502},
58 {L"SoapBaseUrl", cpptString, 502},
59 {L"SoapMailTo", cpptString, 502},
60 {L"SoapVRoot", cpptString, 502},
61 {L"SRPEnabled", cpptBoolean, 501},
62 {L"SRPTrustLevel", cpptInteger, 501},
63 {NULL, cpptNone, 0}
64};
65
66
67// prototypes for private helper functions
68
69static void FreeApplication(
70 CPI_APPLICATION* pItm
71 );
72static HRESULT FindObjectForApplication(
73 CPI_APPLICATION* pItm,
74 BOOL fFindId,
75 BOOL fFindName,
76 ICatalogObject** ppiAppObj
77 );
78static HRESULT AddApplicationToActionData(
79 CPI_APPLICATION* pItm,
80 int iActionType,
81 int iActionCost,
82 LPWSTR* ppwzActionData
83 );
84
85
86// function definitions
87
88void CpiApplicationListFree(
89 CPI_APPLICATION_LIST* pList
90 )
91{
92 CPI_APPLICATION* pItm = pList->pFirst;
93
94 while (pItm)
95 {
96 CPI_APPLICATION* pDelete = pItm;
97 pItm = pItm->pNext;
98 FreeApplication(pDelete);
99 }
100}
101
102HRESULT CpiApplicationsRead(
103 CPI_PARTITION_LIST* pPartList,
104 CPI_APPLICATION_LIST* pAppList
105 )
106{
107 HRESULT hr = S_OK;
108 UINT er = ERROR_SUCCESS;
109
110 int iVersionNT = 0;
111
112 PMSIHANDLE hView, hRec;
113
114 CPI_APPLICATION* pItm = NULL;
115 LPWSTR pwzData = NULL;
116 BOOL fMatchingArchitecture = FALSE;
117
118 // get NT version
119 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
120 ExitOnFailure(hr, "Failed to get VersionNT property");
121
122 // loop through all applications
123 hr = WcaOpenExecuteView(vcsApplicationQuery, &hView);
124 ExitOnFailure(hr, "Failed to execute view on ComPlusApplication table");
125
126 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
127 {
128 // get component
129 hr = WcaGetRecordString(hRec, aqComponent, &pwzData);
130 ExitOnFailure(hr, "Failed to get component");
131
132 // check if the component is our processor architecture
133 if (pwzData && *pwzData)
134 {
135 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
136 ExitOnFailure(hr, "Failed to get component architecture.");
137
138 if (!fMatchingArchitecture)
139 {
140 continue; // not the same architecture, ignore
141 }
142 }
143
144 // create entry
145 pItm = (CPI_APPLICATION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_APPLICATION));
146 if (!pItm)
147 ExitFunction1(hr = E_OUTOFMEMORY);
148
149 // get component install state
150 if (pwzData && *pwzData)
151 {
152 pItm->fHasComponent = TRUE;
153
154 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
155 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
156 }
157
158 // get key
159 hr = WcaGetRecordString(hRec, aqApplication, &pwzData);
160 ExitOnFailure(hr, "Failed to get key");
161 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
162
163 // get partition
164 if (502 <= iVersionNT)
165 {
166 hr = WcaGetRecordString(hRec, aqPartition, &pwzData);
167 ExitOnFailure(hr, "Failed to get partition");
168
169 if (pwzData && *pwzData)
170 {
171 hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition);
172 ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData);
173 }
174 }
175
176 // get id
177 hr = WcaGetRecordFormattedString(hRec, aqID, &pwzData);
178 ExitOnFailure(hr, "Failed to get id");
179
180 if (pwzData && *pwzData)
181 {
182 hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID));
183 ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData);
184 }
185
186 // get name
187 hr = WcaGetRecordFormattedString(hRec, aqName, &pwzData);
188 ExitOnFailure(hr, "Failed to get name");
189 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
190
191 // if application is a locater, either an id or a name must be provided
192 if (!pItm->fHasComponent && !*pItm->wzID && !*pItm->wzName)
193 ExitOnFailure(hr = E_FAIL, "An application locater must have either an id or a name associated, key: %S", pItm->wzKey);
194
195 // if application is not a locater, an name must be provided
196 if (pItm->fHasComponent && !*pItm->wzName)
197 ExitOnFailure(hr = E_FAIL, "An application must have a name associated, key: %S", pItm->wzKey);
198
199 // get properties
200 if (CpiTableExists(cptComPlusApplicationProperty) && pItm->fHasComponent)
201 {
202 hr = CpiPropertiesRead(vcsApplicationPropertyQuery, pItm->wzKey, pdlApplicationProperties, &pItm->pProperties, &pItm->iPropertyCount);
203 ExitOnFailure(hr, "Failed to get properties");
204 }
205
206 // set references & increment counters
207 if (pItm->fHasComponent)
208 {
209 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
210 {
211 if (pItm->pPartition)
212 CpiPartitionAddReferenceInstall(pItm->pPartition);
213 pAppList->iInstallCount++;
214 }
215 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
216 {
217 if (pItm->pPartition)
218 CpiPartitionAddReferenceUninstall(pItm->pPartition);
219 pAppList->iUninstallCount++;
220 }
221 }
222
223 // add entry
224 if (pAppList->pFirst)
225 pItm->pNext = pAppList->pFirst;
226 pAppList->pFirst = pItm;
227 pItm = NULL;
228 }
229
230 if (E_NOMOREITEMS == hr)
231 hr = S_OK;
232
233LExit:
234 // clean up
235 if (pItm)
236 FreeApplication(pItm);
237
238 ReleaseStr(pwzData);
239
240 return hr;
241}
242
243HRESULT CpiApplicationsVerifyInstall(
244 CPI_APPLICATION_LIST* pList
245 )
246{
247 HRESULT hr = S_OK;
248 UINT er = ERROR_SUCCESS;
249
250 ICatalogObject* piAppObj = NULL;
251
252 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
253 {
254 // referenced locaters or applications that are being installed
255 if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)))
256 continue;
257
258 // if the application is referensed and is not a locater, it must be installed
259 if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
260 MessageExitOnFailure(hr = E_FAIL, msierrComPlusApplicationDependency, "An application is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
261
262 // application is supposed to exist
263 if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled))
264 {
265 // get collection object for application
266 hr = FindObjectForApplication(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piAppObj);
267 ExitOnFailure(hr, "Failed to find collection object for application");
268
269 // if the application was found
270 if (S_OK == hr)
271 {
272 // if we don't have an id, copy id from object
273 if (!*pItm->wzID)
274 {
275 hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID));
276 ExitOnFailure(hr, "Failed to get id");
277 }
278 }
279
280 // if the application was not found
281 else
282 {
283 // if the application is a locater, this is an error
284 if (!pItm->fHasComponent)
285 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationNotFound, "An application required by this installation was not found, key: %S", pItm->wzKey);
286
287 // create a new id if one is missing
288 if (!*pItm->wzID)
289 {
290 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
291 ExitOnFailure(hr, "Failed to create id");
292 }
293 }
294 }
295
296 // application is supposed to be created
297 else
298 {
299 // check for conflicts
300 do {
301 if (*pItm->wzID)
302 {
303 // find applications with conflicting id
304 hr = FindObjectForApplication(pItm, TRUE, FALSE, &piAppObj);
305 ExitOnFailure(hr, "Failed to find collection object for application");
306
307 if (S_FALSE == hr)
308 {
309 // find applications with conflicting name
310 hr = FindObjectForApplication(pItm, FALSE, TRUE, &piAppObj);
311 ExitOnFailure(hr, "Failed to find collection object for application");
312
313 if (S_OK == hr)
314 // "A application with a conflictiong name exists. retry cancel"
315 er = WcaErrorMessage(msierrComPlusApplicationNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
316 else
317 break; // no conflicting entry found, break loop
318 }
319 else
320 // "A application with a conflicting id exists. abort retry ignore"
321 er = WcaErrorMessage(msierrComPlusApplicationIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
322 }
323 else
324 {
325 // find applications with conflicting name
326 hr = FindObjectForApplication(pItm, FALSE, TRUE, &piAppObj);
327 ExitOnFailure(hr, "Failed to find collection object for application");
328
329 if (S_OK == hr)
330 // "A subscription with a conflictiong name exists. abort retry ignore"
331 er = WcaErrorMessage(msierrComPlusApplicationNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
332 else
333 break; // no conflicting entry found, break loop
334 }
335
336 switch (er)
337 {
338 case IDCANCEL:
339 case IDABORT:
340 ExitOnFailure(hr = E_FAIL, "An application with a conflictiong name or id exists, key: %S", pItm->wzKey);
341 break;
342 case IDRETRY:
343 break;
344 case IDIGNORE:
345 default:
346 // if we don't have an id, copy id from object
347 if (!*pItm->wzID)
348 {
349 hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID));
350 ExitOnFailure(hr, "Failed to get id");
351 }
352 hr = S_FALSE; // indicate that this is not a conflict
353 }
354 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
355
356 // create a new id if one is missing
357 if (!*pItm->wzID)
358 {
359 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
360 ExitOnFailure(hr, "Failed to create id");
361 }
362 }
363
364 // clean up
365 ReleaseNullObject(piAppObj);
366 }
367
368 hr = S_OK;
369
370LExit:
371 // clean up
372 ReleaseObject(piAppObj);
373
374 return hr;
375}
376
377HRESULT CpiApplicationsVerifyUninstall(
378 CPI_APPLICATION_LIST* pList
379 )
380{
381 HRESULT hr = S_OK;
382 ICatalogObject* piAppObj = NULL;
383
384 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
385 {
386 // referenced locaters or applications that are being installed
387 if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction)))
388 continue;
389
390 // get collection object for application
391 hr = FindObjectForApplication(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piAppObj);
392 ExitOnFailure(hr, "Failed to find collection object for application");
393
394 // if the application was found
395 if (S_OK == hr)
396 {
397 // if we don't have an id, copy id from object
398 if (!*pItm->wzID)
399 {
400 hr = CpiGetKeyForObject(piAppObj, pItm->wzID, countof(pItm->wzID));
401 ExitOnFailure(hr, "Failed to get id");
402 }
403 }
404
405 // if the application was not found
406 else
407 {
408 pItm->fObjectNotFound = TRUE;
409 if (pItm->fHasComponent)
410 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
411 }
412
413 // clean up
414 ReleaseNullObject(piAppObj);
415 }
416
417 hr = S_OK;
418
419LExit:
420 // clean up
421 ReleaseObject(piAppObj);
422
423 return hr;
424}
425
426void CpiApplicationAddReferenceInstall(
427 CPI_APPLICATION* pItm
428 )
429{
430 pItm->fReferencedForInstall = TRUE;
431 if (pItm->pPartition)
432 CpiPartitionAddReferenceInstall(pItm->pPartition);
433}
434
435void CpiApplicationAddReferenceUninstall(
436 CPI_APPLICATION* pItm
437 )
438{
439 pItm->fReferencedForUninstall = TRUE;
440 if (pItm->pPartition)
441 CpiPartitionAddReferenceUninstall(pItm->pPartition);
442}
443
444HRESULT CpiApplicationsInstall(
445 CPI_APPLICATION_LIST* pList,
446 int iRunMode,
447 LPWSTR* ppwzActionData,
448 int* piProgress
449 )
450{
451 HRESULT hr = S_OK;
452
453 int iActionType;
454
455 // add action text
456 hr = CpiAddActionTextToActionData(L"CreateComPlusApplications", ppwzActionData);
457 ExitOnFailure(hr, "Failed to add action text to custom action data");
458
459 // add applicaton count to action data
460 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
461 ExitOnFailure(hr, "Failed to add count to custom action data");
462
463 // add applications to custom action data
464 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
465 {
466 // applications that are being installed only
467 if (!pItm->fHasComponent || !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
468 continue;
469
470 // action type
471 if (rmRollback == iRunMode)
472 {
473 if (CpiIsInstalled(pItm->isInstalled))
474 iActionType = atNoOp;
475 else
476 iActionType = atRemove;
477 }
478 else
479 iActionType = atCreate;
480
481 // add to action data
482 hr = AddApplicationToActionData(pItm, iActionType, COST_APPLICATION_CREATE, ppwzActionData);
483 ExitOnFailure(hr, "Failed to add applicaton to custom action data, key: %S", pItm->wzKey);
484 }
485
486 // add progress tics
487 if (piProgress)
488 *piProgress += COST_APPLICATION_CREATE * pList->iInstallCount;
489
490 hr = S_OK;
491
492LExit:
493 return hr;
494}
495
496HRESULT CpiApplicationsUninstall(
497 CPI_APPLICATION_LIST* pList,
498 int iRunMode,
499 LPWSTR* ppwzActionData,
500 int* piProgress
501 )
502{
503 HRESULT hr = S_OK;
504
505 int iActionType;
506
507 // add action text
508 hr = CpiAddActionTextToActionData(L"RemoveComPlusApplications", ppwzActionData);
509 ExitOnFailure(hr, "Failed to add action text to custom action data");
510
511 // add applicaton count to action data
512 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
513 ExitOnFailure(hr, "Failed to add count to custom action data");
514
515 // add applications to custom action data
516 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
517 {
518 // applications that are being uninstalled only
519 if (!pItm->fHasComponent || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
520 continue;
521
522 // action type
523 if (rmRollback == iRunMode)
524 iActionType = atCreate;
525 else
526 iActionType = atRemove;
527
528 // add to action data
529 hr = AddApplicationToActionData(pItm, iActionType, COST_APPLICATION_DELETE, ppwzActionData);
530 ExitOnFailure(hr, "Failed to add applicaton to custom action data, key: %S", pItm->wzKey);
531 }
532
533 // add progress tics
534 if (piProgress)
535 *piProgress += COST_APPLICATION_DELETE * pList->iUninstallCount;
536
537 hr = S_OK;
538
539LExit:
540 return hr;
541}
542
543HRESULT CpiApplicationFindByKey(
544 CPI_APPLICATION_LIST* pList,
545 LPCWSTR pwzKey,
546 CPI_APPLICATION** ppApp
547 )
548{
549 for (CPI_APPLICATION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
550 {
551 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
552 {
553 *ppApp = pItm;
554 return S_OK;
555 }
556 }
557
558 return S_FALSE;
559}
560
561HRESULT CpiGetRolesCollForApplication(
562 CPI_APPLICATION* pApp,
563 ICatalogCollection** ppiRolesColl
564 )
565{
566 HRESULT hr = S_OK;
567
568 ICatalogCollection* piAppColl = NULL;
569 ICatalogObject* piAppObj = NULL;
570
571 // if a previous attempt to locate the collection object failed
572 if (pApp->fObjectNotFound)
573 ExitFunction1(hr = S_FALSE);
574
575 // get applications collection
576 if (!pApp->piRolesColl)
577 {
578 // get applications collection
579 if (pApp->pPartition)
580 hr = CpiGetApplicationsCollForPartition(pApp->pPartition, &piAppColl);
581 else
582 hr = CpiSchedGetApplicationsCollection(&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 = CpiSchedGetCatalogCollection(piAppColl, piAppObj, L"Roles", &pApp->piRolesColl);
597 ExitOnFailure(hr, "Failed to get roles collection");
598 }
599
600 // return value
601 *ppiRolesColl = pApp->piRolesColl;
602 (*ppiRolesColl)->AddRef();
603
604 hr = S_OK;
605
606LExit:
607 // clean up
608 ReleaseObject(piAppColl);
609 ReleaseObject(piAppObj);
610
611 return hr;
612}
613
614HRESULT CpiGetComponentsCollForApplication(
615 CPI_APPLICATION* pApp,
616 ICatalogCollection** ppiCompsColl
617 )
618{
619 HRESULT hr = S_OK;
620
621 ICatalogCollection* piAppColl = NULL;
622 ICatalogObject* piAppObj = NULL;
623
624 // if a previous attempt to locate the collection object failed
625 if (pApp->fObjectNotFound)
626 ExitFunction1(hr = S_FALSE);
627
628 // get applications collection
629 if (!pApp->piCompsColl)
630 {
631 // get applications collection
632 if (pApp->pPartition)
633 hr = CpiGetApplicationsCollForPartition(pApp->pPartition, &piAppColl);
634 else
635 hr = CpiSchedGetApplicationsCollection(&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 = CpiSchedGetCatalogCollection(piAppColl, piAppObj, L"Components", &pApp->piCompsColl);
650 ExitOnFailure(hr, "Failed to get components collection");
651 }
652
653 // return value
654 *ppiCompsColl = pApp->piCompsColl;
655 (*ppiCompsColl)->AddRef();
656
657 hr = S_OK;
658
659LExit:
660 // clean up
661 ReleaseObject(piAppColl);
662 ReleaseObject(piAppObj);
663
664 return hr;
665}
666
667
668// helper function definitions
669
670static void FreeApplication(
671 CPI_APPLICATION* pItm
672 )
673{
674 if (pItm->pProperties)
675 CpiPropertiesFreeList(pItm->pProperties);
676
677 ReleaseObject(pItm->piRolesColl);
678 ReleaseObject(pItm->piCompsColl);
679
680 ::HeapFree(::GetProcessHeap(), 0, pItm);
681}
682
683static HRESULT FindObjectForApplication(
684 CPI_APPLICATION* pItm,
685 BOOL fFindId,
686 BOOL fFindName,
687 ICatalogObject** ppiAppObj
688 )
689{
690 HRESULT hr = S_OK;
691
692 ICatalogCollection* piAppColl = NULL;
693
694 // get applications collection
695 if (pItm->pPartition)
696 hr = CpiGetApplicationsCollForPartition(pItm->pPartition, &piAppColl);
697 else
698 hr = CpiSchedGetApplicationsCollection(&piAppColl);
699 ExitOnFailure(hr, "Failed to get applications collection");
700
701 if (S_FALSE == hr)
702 ExitFunction(); // exit with hr = S_FALSE
703
704 // find application object
705 hr = CpiFindCollectionObject(piAppColl, fFindId ? pItm->wzID : NULL, fFindName ? pItm->wzName : NULL, ppiAppObj);
706 ExitOnFailure(hr, "Failed to find application object");
707
708 // exit with hr from CpiFindCollectionObject()
709
710LExit:
711 // clean up
712 ReleaseObject(piAppColl);
713
714 return hr;
715}
716
717static HRESULT AddApplicationToActionData(
718 CPI_APPLICATION* pItm,
719 int iActionType,
720 int iActionCost,
721 LPWSTR* ppwzActionData
722 )
723{
724 HRESULT hr = S_OK;
725
726 // add action information to custom action data
727 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
728 ExitOnFailure(hr, "Failed to add action type to custom action data");
729 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
730 ExitOnFailure(hr, "Failed to add action cost to custom action data");
731
732 // add application information to custom action data
733 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
734 ExitOnFailure(hr, "Failed to add application key to custom action data");
735 hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
736 ExitOnFailure(hr, "Failed to add application id to custom action data");
737 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
738 ExitOnFailure(hr, "Failed to add application name to custom action data");
739
740 // add partition information to custom action data
741 hr = WcaWriteStringToCaData(pItm->pPartition ? pItm->pPartition->wzID : L"", ppwzActionData);
742 ExitOnFailure(hr, "Failed to add partition id to custom action data");
743
744 // add properties to custom action data
745 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
746 ExitOnFailure(hr, "Failed to add properties to custom action data");
747
748 hr = S_OK;
749
750LExit:
751 return hr;
752}
diff --git a/src/ext/ComPlus/ca/cpappsched.h b/src/ext/ComPlus/ca/cpappsched.h
new file mode 100644
index 00000000..2cd6a0ee
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpappsched.h
@@ -0,0 +1,83 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_APPLICATION
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzID[CPI_MAX_GUID + 1];
9 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
10
11 int iPropertyCount;
12 CPI_PROPERTY* pProperties;
13
14 BOOL fHasComponent;
15 BOOL fReferencedForInstall;
16 BOOL fReferencedForUninstall;
17 BOOL fObjectNotFound;
18
19 INSTALLSTATE isInstalled, isAction;
20
21 CPI_PARTITION* pPartition;
22
23 ICatalogCollection* piRolesColl;
24 ICatalogCollection* piCompsColl;
25
26 CPI_APPLICATION* pNext;
27};
28
29struct CPI_APPLICATION_LIST
30{
31 CPI_APPLICATION* pFirst;
32
33 int iInstallCount;
34 int iUninstallCount;
35};
36
37
38// function prototypes
39
40void CpiApplicationListFree(
41 CPI_APPLICATION_LIST* pList
42 );
43HRESULT CpiApplicationsRead(
44 CPI_PARTITION_LIST* pPartList,
45 CPI_APPLICATION_LIST* pAppList
46 );
47HRESULT CpiApplicationsVerifyInstall(
48 CPI_APPLICATION_LIST* pList
49 );
50HRESULT CpiApplicationsVerifyUninstall(
51 CPI_APPLICATION_LIST* pList
52 );
53void CpiApplicationAddReferenceInstall(
54 CPI_APPLICATION* pItm
55 );
56void CpiApplicationAddReferenceUninstall(
57 CPI_APPLICATION* pItm
58 );
59HRESULT CpiApplicationsInstall(
60 CPI_APPLICATION_LIST* pList,
61 int iRunMode,
62 LPWSTR* ppwzActionData,
63 int* piProgress
64 );
65HRESULT CpiApplicationsUninstall(
66 CPI_APPLICATION_LIST* pList,
67 int iRunMode,
68 LPWSTR* ppwzActionData,
69 int* piProgress
70 );
71HRESULT CpiApplicationFindByKey(
72 CPI_APPLICATION_LIST* pList,
73 LPCWSTR pwzKey,
74 CPI_APPLICATION** ppApp
75 );
76HRESULT CpiGetRolesCollForApplication(
77 CPI_APPLICATION* pApp,
78 ICatalogCollection** ppiRolesColl
79 );
80HRESULT CpiGetComponentsCollForApplication(
81 CPI_APPLICATION* pApp,
82 ICatalogCollection** ppiCompsColl
83 );
diff --git a/src/ext/ComPlus/ca/cpasmexec.cpp b/src/ext/ComPlus/ca/cpasmexec.cpp
new file mode 100644
index 00000000..3d140027
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpasmexec.cpp
@@ -0,0 +1,1877 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// GAC related declarations
7
8typedef struct _FUSION_INSTALL_REFERENCE_
9{
10 DWORD cbSize;
11 DWORD dwFlags;
12 GUID guidScheme;
13 LPCWSTR szIdentifier;
14 LPCWSTR szNonCannonicalData;
15} FUSION_INSTALL_REFERENCE;
16
17typedef struct _FUSION_INSTALL_REFERENCE_ *LPFUSION_INSTALL_REFERENCE;
18
19typedef const FUSION_INSTALL_REFERENCE *LPCFUSION_INSTALL_REFERENCE;
20
21typedef struct _ASSEMBLY_INFO
22{
23 ULONG cbAssemblyInfo;
24 DWORD dwAssemblyFlags;
25 ULARGE_INTEGER uliAssemblySizeInKB;
26 LPWSTR pszCurrentAssemblyPathBuf;
27 ULONG cchBuf;
28} ASSEMBLY_INFO;
29
30typedef interface IAssemblyCacheItem IAssemblyCacheItem;
31
32MIDL_INTERFACE("e707dcde-d1cd-11d2-bab9-00c04f8eceae")
33IAssemblyCache : public IUnknown
34{
35public:
36 virtual HRESULT STDMETHODCALLTYPE UninstallAssembly(
37 /* [in] */ DWORD dwFlags,
38 /* [in] */ LPCWSTR pszAssemblyName,
39 /* [in] */ LPCFUSION_INSTALL_REFERENCE pRefData,
40 /* [optional][out] */ ULONG *pulDisposition) = 0;
41
42 virtual HRESULT STDMETHODCALLTYPE QueryAssemblyInfo(
43 /* [in] */ DWORD dwFlags,
44 /* [in] */ LPCWSTR pszAssemblyName,
45 /* [out][in] */ ASSEMBLY_INFO *pAsmInfo) = 0;
46
47 virtual HRESULT STDMETHODCALLTYPE CreateAssemblyCacheItem(
48 /* [in] */ DWORD dwFlags,
49 /* [in] */ PVOID pvReserved,
50 /* [out] */ IAssemblyCacheItem **ppAsmItem,
51 /* [optional][in] */ LPCWSTR pszAssemblyName) = 0;
52
53 virtual HRESULT STDMETHODCALLTYPE CreateAssemblyScavenger(
54 /* [out] */ IUnknown **ppUnkReserved) = 0;
55
56 virtual HRESULT STDMETHODCALLTYPE InstallAssembly(
57 /* [in] */ DWORD dwFlags,
58 /* [in] */ LPCWSTR pszManifestFilePath,
59 /* [in] */ LPCFUSION_INSTALL_REFERENCE pRefData) = 0;
60};
61
62typedef HRESULT (__stdcall *LoadLibraryShimFunc)(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll);
63typedef HRESULT (__stdcall *CreateAssemblyCacheFunc)(IAssemblyCache **ppAsmCache, DWORD dwReserved);
64
65
66// RegistrationHelper related declarations
67
68static const GUID CLSID_RegistrationHelper =
69 { 0x89a86e7b, 0xc229, 0x4008, { 0x9b, 0xaa, 0x2f, 0x5c, 0x84, 0x11, 0xd7, 0xe0 } };
70
71enum eInstallationFlags {
72 ifConfigureComponentsOnly = 16,
73 ifFindOrCreateTargetApplication = 4,
74 ifExpectExistingTypeLib = 1
75};
76
77
78// private structs
79
80struct CPIEXEC_ROLE_ASSIGNMENT
81{
82 WCHAR wzKey[MAX_DARWIN_KEY + 1];
83 WCHAR wzRoleName[MAX_DARWIN_COLUMN + 1];
84
85 CPIEXEC_ROLE_ASSIGNMENT* pNext;
86};
87
88struct CPIEXEC_METHOD
89{
90 WCHAR wzIndex[11 + 1];
91 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
92
93 CPI_PROPERTY* pPropertyList;
94 CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList;
95
96 CPIEXEC_METHOD* pNext;
97};
98
99struct CPIEXEC_INTERFACE
100{
101 WCHAR wzIID[CPI_MAX_GUID + 1];
102
103 CPI_PROPERTY* pPropertyList;
104 CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList;
105 CPIEXEC_METHOD* pMethodList;
106
107 CPIEXEC_INTERFACE* pNext;
108};
109
110struct CPIEXEC_COMPONENT
111{
112 WCHAR wzCLSID[CPI_MAX_GUID + 1];
113
114 CPI_PROPERTY* pPropertyList;
115 CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList;
116 CPIEXEC_INTERFACE* pInterfaceList;
117
118 CPIEXEC_COMPONENT* pNext;
119};
120
121struct CPI_ASSEMBLY_ATTRIBUTES
122{
123 int iActionType;
124 int iActionCost;
125 LPWSTR pwzKey;
126 LPWSTR pwzAssemblyName;
127 LPWSTR pwzDllPath;
128 LPWSTR pwzTlbPath;
129 LPWSTR pwzPSDllPath;
130 LPWSTR pwzAppID;
131 LPWSTR pwzPartID;
132 int iAttributes;
133 CPIEXEC_COMPONENT* pCompList;
134};
135
136struct CPI_ROLE_ASSIGNMENTS_ATTRIBUTES
137{
138 int iActionType;
139 int iActionCost;
140 LPWSTR pwzKey;
141 LPWSTR pwzAppID;
142 LPWSTR pwzPartID;
143 int iRoleCount;
144 CPIEXEC_COMPONENT* pCompList;
145};
146
147
148// prototypes for private helper functions
149
150static HRESULT RegisterAssembly(
151 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
152 );
153static HRESULT UnregisterAssembly(
154 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
155 );
156static void InitAssemblyExec();
157static void UninitAssemblyExec();
158static HRESULT GetRegistrationHelper(
159 IDispatch** ppiRegHlp
160 );
161static HRESULT GetAssemblyCacheObject(
162 IAssemblyCache** ppAssemblyCache
163 );
164static HRESULT GetAssemblyPathFromGAC(
165 LPCWSTR pwzAssemblyName,
166 LPWSTR* ppwzAssemblyPath
167 );
168static HRESULT RegisterDotNetAssembly(
169 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
170 );
171static HRESULT RegisterNativeAssembly(
172 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
173 );
174static HRESULT UnregisterDotNetAssembly(
175 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
176 );
177static HRESULT RemoveComponents(
178 ICatalogCollection* piCompColl,
179 CPIEXEC_COMPONENT* pCompList
180 );
181static HRESULT ReadAssemblyAttributes(
182 LPWSTR* ppwzData,
183 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
184 );
185static void FreeAssemblyAttributes(
186 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
187 );
188static HRESULT ReadRoleAssignmentsAttributes(
189 LPWSTR* ppwzData,
190 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
191 );
192static void FreeRoleAssignmentsAttributes(
193 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
194 );
195static HRESULT ConfigureComponents(
196 LPCWSTR pwzPartID,
197 LPCWSTR pwzAppID,
198 CPIEXEC_COMPONENT* pCompList,
199 BOOL fCreate,
200 BOOL fProgress
201 );
202static HRESULT ConfigureInterfaces(
203 ICatalogCollection* piCompColl,
204 ICatalogObject* piCompObj,
205 CPIEXEC_INTERFACE* pIntfList,
206 BOOL fCreate
207 );
208static HRESULT ConfigureMethods(
209 ICatalogCollection* piIntfColl,
210 ICatalogObject* piIntfObj,
211 CPIEXEC_METHOD* pMethList,
212 BOOL fCreate
213 );
214static HRESULT ConfigureRoleAssignments(
215 LPCWSTR pwzCollName,
216 ICatalogCollection* piCompColl,
217 ICatalogObject* piCompObj,
218 CPIEXEC_ROLE_ASSIGNMENT* pRoleList,
219 BOOL fCreate
220 );
221static HRESULT ReadComponentList(
222 LPWSTR* ppwzData,
223 CPIEXEC_COMPONENT** ppCompList
224 );
225static HRESULT ReadInterfaceList(
226 LPWSTR* ppwzData,
227 CPIEXEC_INTERFACE** ppIntfList
228 );
229static HRESULT ReadMethodList(
230 LPWSTR* ppwzData,
231 CPIEXEC_METHOD** ppMethList
232 );
233static HRESULT ReadRoleAssignmentList(
234 LPWSTR* ppwzData,
235 CPIEXEC_ROLE_ASSIGNMENT** ppRoleList
236 );
237static void FreeComponentList(
238 CPIEXEC_COMPONENT* pList
239 );
240static void FreeInterfaceList(
241 CPIEXEC_INTERFACE* pList
242 );
243static void FreeMethodList(
244 CPIEXEC_METHOD* pList
245 );
246static void FreeRoleAssignmentList(
247 CPIEXEC_ROLE_ASSIGNMENT* pList
248 );
249
250
251// variables
252
253static IDispatch* gpiRegHlp;
254static IAssemblyCache* gpAssemblyCache;
255static HMODULE ghMscoree;
256static HMODULE ghFusion;
257
258
259// function definitions
260
261HRESULT CpiConfigureAssemblies(
262 LPWSTR* ppwzData,
263 HANDLE hRollbackFile
264 )
265{
266 HRESULT hr = S_OK;
267
268 CPI_ASSEMBLY_ATTRIBUTES attrs;
269 ::ZeroMemory(&attrs, sizeof(attrs));
270
271 // initialize
272 InitAssemblyExec();
273
274 // read action text
275 hr = CpiActionStartMessage(ppwzData, FALSE);
276 ExitOnFailure(hr, "Failed to send action start message");
277
278 // get count
279 int iCnt = 0;
280 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
281 ExitOnFailure(hr, "Failed to read count");
282
283 // write count to rollback file
284 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
285 ExitOnFailure(hr, "Failed to write count to rollback file");
286
287 for (int i = 0; i < iCnt; i++)
288 {
289 // read attributes from CustomActionData
290 hr = ReadAssemblyAttributes(ppwzData, &attrs);
291 ExitOnFailure(hr, "Failed to read assembly attributes");
292
293 // write key to rollback file
294 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
295 ExitOnFailure(hr, "Failed to write key to rollback file");
296
297 // action
298 switch (attrs.iActionType)
299 {
300 case atCreate:
301 hr = RegisterAssembly(&attrs);
302 ExitOnFailure(hr, "Failed to register assembly, key: %S", attrs.pwzKey);
303 break;
304 case atRemove:
305 hr = UnregisterAssembly(&attrs);
306 ExitOnFailure(hr, "Failed to unregister assembly, key: %S", attrs.pwzKey);
307 break;
308 default:
309 hr = S_OK;
310 break;
311 }
312
313 if (S_FALSE == hr)
314 ExitFunction(); // aborted by user
315
316 // write completion status to rollback file
317 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
318 ExitOnFailure(hr, "Failed to write completion status to rollback file");
319
320 // progress
321 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
322 ExitOnFailure(hr, "Failed to update progress");
323 }
324
325 hr = S_OK;
326
327LExit:
328 // clean up
329 FreeAssemblyAttributes(&attrs);
330
331 // uninitialize
332 UninitAssemblyExec();
333
334 return hr;
335}
336
337HRESULT CpiRollbackConfigureAssemblies(
338 LPWSTR* ppwzData,
339 CPI_ROLLBACK_DATA* pRollbackDataList
340 )
341{
342 HRESULT hr = S_OK;
343
344 int iRollbackStatus;
345
346 CPI_ASSEMBLY_ATTRIBUTES attrs;
347 ::ZeroMemory(&attrs, sizeof(attrs));
348
349 // initialize
350 InitAssemblyExec();
351
352 // read action text
353 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
354 ExitOnFailure(hr, "Failed to send action start message");
355
356 // get count
357 int iCnt = 0;
358 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
359 ExitOnFailure(hr, "Failed to read count");
360
361 for (int i = 0; i < iCnt; i++)
362 {
363 // read attributes from CustomActionData
364 hr = ReadAssemblyAttributes(ppwzData, &attrs);
365 ExitOnFailure(hr, "Failed to read assembly attributes");
366
367 // rollback status
368 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
369
370 if (S_FALSE == hr)
371 continue; // not found, nothing to rollback
372
373 // action
374 switch (attrs.iActionType)
375 {
376 case atCreate:
377 hr = RegisterAssembly(&attrs);
378 if (FAILED(hr))
379 WcaLog(LOGMSG_STANDARD, "Failed to register assembly, hr: 0x%x, key: %S", hr, attrs.pwzKey);
380 break;
381 case atRemove:
382 hr = UnregisterAssembly(&attrs);
383 if (FAILED(hr))
384 WcaLog(LOGMSG_STANDARD, "Failed to unregister assembly, hr: 0x%x, key: %S", hr, attrs.pwzKey);
385 break;
386 }
387
388 // check rollback status
389 if (0 == iRollbackStatus)
390 continue; // operation did not complete, skip progress
391
392 // progress
393 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
394 ExitOnFailure(hr, "Failed to update progress");
395 }
396
397 hr = S_OK;
398
399LExit:
400 // clean up
401 FreeAssemblyAttributes(&attrs);
402
403 // uninitialize
404 UninitAssemblyExec();
405
406 return hr;
407}
408
409HRESULT CpiConfigureRoleAssignments(
410 LPWSTR* ppwzData,
411 HANDLE hRollbackFile
412 )
413{
414 HRESULT hr = S_OK;
415
416 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES attrs;
417 ::ZeroMemory(&attrs, sizeof(attrs));
418
419 // read action text
420 hr = CpiActionStartMessage(ppwzData, FALSE);
421 ExitOnFailure(hr, "Failed to send action start message");
422
423 // get count
424 int iCnt = 0;
425 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
426 ExitOnFailure(hr, "Failed to read count");
427
428 // write count to rollback file
429 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
430 ExitOnFailure(hr, "Failed to write count to rollback file");
431
432 for (int i = 0; i < iCnt; i++)
433 {
434 // read attributes from CustomActionData
435 hr = ReadRoleAssignmentsAttributes(ppwzData, &attrs);
436 ExitOnFailure(hr, "Failed to read role assignments attributes");
437
438 // write key to rollback file
439 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
440 ExitOnFailure(hr, "Failed to write key to rollback file");
441
442 // action
443 if (atNoOp != attrs.iActionType)
444 {
445 hr = ConfigureComponents(attrs.pwzPartID, attrs.pwzAppID, attrs.pCompList, atCreate == attrs.iActionType, TRUE);
446 ExitOnFailure(hr, "Failed to configure components");
447
448 if (S_FALSE == hr)
449 ExitFunction(); // aborted by user
450 }
451
452 // write completion status to rollback file
453 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
454 ExitOnFailure(hr, "Failed to write completion status to rollback file");
455
456 // progress
457 hr = WcaProgressMessage(attrs.iActionCost * attrs.iRoleCount, FALSE);
458 ExitOnFailure(hr, "Failed to update progress");
459 }
460
461 hr = S_OK;
462
463LExit:
464 // clean up
465 FreeRoleAssignmentsAttributes(&attrs);
466
467 return hr;
468}
469
470HRESULT CpiRollbackConfigureRoleAssignments(
471 LPWSTR* ppwzData,
472 CPI_ROLLBACK_DATA* pRollbackDataList
473 )
474{
475 HRESULT hr = S_OK;
476
477 int iRollbackStatus;
478
479 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES attrs;
480 ::ZeroMemory(&attrs, sizeof(attrs));
481
482 // read action text
483 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
484 ExitOnFailure(hr, "Failed to send action start message");
485
486 // get count
487 int iCnt = 0;
488 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
489 ExitOnFailure(hr, "Failed to read count");
490
491 for (int i = 0; i < iCnt; i++)
492 {
493 // read attributes from CustomActionData
494 hr = ReadRoleAssignmentsAttributes(ppwzData, &attrs);
495 ExitOnFailure(hr, "Failed to read role assignments attributes");
496
497 // rollback status
498 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
499
500 if (S_FALSE == hr)
501 continue; // not found, nothing to rollback
502
503 // action
504 if (atNoOp != attrs.iActionType)
505 {
506 hr = ConfigureComponents(attrs.pwzPartID, attrs.pwzAppID, attrs.pCompList, atCreate == attrs.iActionType, TRUE);
507 ExitOnFailure(hr, "Failed to configure components");
508
509 if (S_FALSE == hr)
510 ExitFunction(); // aborted by user
511 }
512
513 // check rollback status
514 if (0 == iRollbackStatus)
515 continue; // operation did not complete, skip progress
516
517 // progress
518 hr = WcaProgressMessage(attrs.iActionCost * attrs.iRoleCount, FALSE);
519 ExitOnFailure(hr, "Failed to update progress");
520 }
521
522 hr = S_OK;
523
524LExit:
525 // clean up
526 FreeRoleAssignmentsAttributes(&attrs);
527
528 return hr;
529}
530
531
532// helper function definitions
533
534static HRESULT RegisterAssembly(
535 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
536 )
537{
538 HRESULT hr = S_OK;
539
540 // progress message
541 hr = CpiActionDataMessage(1, (pAttrs->iAttributes & aaPathFromGAC) ? pAttrs->pwzAssemblyName : pAttrs->pwzDllPath);
542 ExitOnFailure(hr, "Failed to send progress messages");
543
544 if (S_FALSE == hr)
545 ExitFunction(); // aborted by user
546
547 // log
548 WcaLog(LOGMSG_VERBOSE, "Registering assembly, key: %S", pAttrs->pwzKey);
549
550 // extract path from GAC
551 if (pAttrs->iAttributes & aaPathFromGAC)
552 {
553 hr = GetAssemblyPathFromGAC(pAttrs->pwzAssemblyName, &pAttrs->pwzDllPath);
554 if (S_FALSE == hr)
555 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
556 ExitOnFailure(hr, "Failed to get path for assembly from GAC");
557
558 // log
559 WcaLog(LOGMSG_VERBOSE, "Assembly path extracted from GAC, key: %S, path: '%S'", pAttrs->pwzKey, pAttrs->pwzDllPath);
560 }
561
562 // .net assembly
563 if (pAttrs->iAttributes & aaDotNetAssembly)
564 {
565 hr = RegisterDotNetAssembly(pAttrs);
566 ExitOnFailure(hr, "Failed to register .NET assembly");
567 }
568
569 // native assembly
570 else
571 {
572 hr = RegisterNativeAssembly(pAttrs);
573 ExitOnFailure(hr, "Failed to register native assembly");
574 }
575
576 // configure components
577 if (pAttrs->pCompList)
578 {
579 hr = ConfigureComponents(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pCompList, TRUE, FALSE);
580 ExitOnFailure(hr, "Failed to configure components");
581 }
582
583 hr = S_OK;
584
585LExit:
586 return hr;
587}
588
589static HRESULT UnregisterAssembly(
590 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
591 )
592{
593 HRESULT hr = S_OK;
594
595 long lChanges = 0;
596
597 ICatalogCollection* piColl = NULL;
598 ICatalogObject* piObj = NULL;
599
600 // progress message
601 hr = CpiActionDataMessage(1, (pAttrs->iAttributes & aaPathFromGAC) ? pAttrs->pwzAssemblyName : pAttrs->pwzDllPath);
602 ExitOnFailure(hr, "Failed to send progress messages");
603
604 if (S_FALSE == hr)
605 ExitFunction(); // aborted by user
606
607 // log
608 WcaLog(LOGMSG_VERBOSE, "Unregistering assembly, key: %S", pAttrs->pwzKey);
609
610 // extract path from GAC
611 if (pAttrs->iAttributes & aaPathFromGAC)
612 {
613 hr = GetAssemblyPathFromGAC(pAttrs->pwzAssemblyName, &pAttrs->pwzDllPath);
614 ExitOnFailure(hr, "Failed to get path for assembly from GAC");
615
616 if (S_FALSE == hr)
617 {
618 WcaLog(LOGMSG_VERBOSE, "Unable to locate assembly in GAC, assembly will not be unregistered from COM+, key: %S", pAttrs->pwzKey);
619 ExitFunction1(hr = S_OK);
620 }
621
622 // log
623 WcaLog(LOGMSG_VERBOSE, "Assembly path extracted from GAC, key: %S, path: '%S'", pAttrs->pwzKey, pAttrs->pwzDllPath);
624 }
625
626 // .NET assembly
627 if (pAttrs->iAttributes & aaDotNetAssembly)
628 {
629 if (pAttrs->pwzAppID && *pAttrs->pwzAppID)
630 {
631 // When unregistering a .net assembly using the RegistrationHelper class, and the application is
632 // left empty after all components in the assembly are removed, the RegistrationHelper class also
633 // attempts to remove the application for some reason. However, it does not handle the situation
634 // when the application has its deleteable property set to false, and will simply fail if this is
635 // the case. This is the reason we are clearing the deleatable property of the application here.
636 //
637 // TODO: handle rollbacks
638
639 // get applications collection
640 hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piColl);
641 ExitOnFailure(hr, "Failed to get applications collection");
642
643 if (S_FALSE == hr)
644 {
645 // applications collection not found
646 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve applications collection, nothing to delete, key: %S", pAttrs->pwzKey);
647 ExitFunction1(hr = S_OK);
648 }
649
650 // find application object
651 hr = CpiFindCollectionObjectByStringKey(piColl, pAttrs->pwzAppID, &piObj);
652 ExitOnFailure(hr, "Failed to find application object");
653
654 if (S_FALSE == hr)
655 {
656 // application not found
657 WcaLog(LOGMSG_VERBOSE, "Unable to find application object, nothing to delete, key: %S", pAttrs->pwzKey);
658 ExitFunction1(hr = S_OK);
659 }
660
661 // reset deleteable property
662 hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable");
663 ExitOnFailure(hr, "Failed to reset deleteable property");
664 }
665
666 // unregister assembly
667 hr = UnregisterDotNetAssembly(pAttrs);
668 ExitOnFailure(hr, "Failed to unregister .NET assembly");
669 }
670
671 // native assembly
672 else
673 {
674 // get components collection
675 hr = CpiGetComponentsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piColl);
676 ExitOnFailure(hr, "Failed to get components collection");
677
678 if (S_FALSE == hr)
679 {
680 // components collection not found
681 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve components collection, nothing to delete, key: %S", pAttrs->pwzKey);
682 ExitFunction1(hr = S_OK);
683 }
684
685 // remove components
686 hr = RemoveComponents(piColl, pAttrs->pCompList);
687 ExitOnFailure(hr, "Failed to get remove components");
688
689 // save changes
690 hr = piColl->SaveChanges(&lChanges);
691 if (COMADMIN_E_OBJECTERRORS == hr)
692 CpiLogCatalogErrorInfo();
693 ExitOnFailure(hr, "Failed to save changes");
694 }
695
696 hr = S_OK;
697
698LExit:
699 // clean up
700 ReleaseObject(piColl);
701 ReleaseObject(piObj);
702
703 return hr;
704}
705
706static void InitAssemblyExec()
707{
708 gpiRegHlp = NULL;
709 gpAssemblyCache = NULL;
710 ghMscoree = NULL;
711 ghFusion = NULL;
712}
713
714static void UninitAssemblyExec()
715{
716 ReleaseObject(gpiRegHlp);
717 ReleaseObject(gpAssemblyCache);
718 if (ghFusion)
719 ::FreeLibrary(ghFusion);
720 if (ghMscoree)
721 ::FreeLibrary(ghMscoree);
722}
723
724static HRESULT GetRegistrationHelper(
725 IDispatch** ppiRegHlp
726 )
727{
728 HRESULT hr = S_OK;
729
730 if (!gpiRegHlp)
731 {
732 // create registration helper object
733 hr = ::CoCreateInstance(CLSID_RegistrationHelper, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&gpiRegHlp);
734 ExitOnFailure(hr, "Failed to create registration helper object");
735 }
736
737 gpiRegHlp->AddRef();
738 *ppiRegHlp = gpiRegHlp;
739
740 hr = S_OK;
741
742LExit:
743 return hr;
744}
745
746static HRESULT GetAssemblyCacheObject(
747 IAssemblyCache** ppAssemblyCache
748 )
749{
750 HRESULT hr = S_OK;
751
752 if (!gpAssemblyCache)
753 {
754 // mscoree.dll
755 if (!ghMscoree)
756 {
757 // load mscoree.dll
758 ghMscoree = ::LoadLibraryW(L"mscoree.dll");
759 ExitOnNull(ghMscoree, hr, E_FAIL, "Failed to load mscoree.dll");
760 }
761
762 // fusion.dll
763 if (!ghFusion)
764 {
765 // get LoadLibraryShim function address
766 LoadLibraryShimFunc pfnLoadLibraryShim = (LoadLibraryShimFunc)::GetProcAddress(ghMscoree, "LoadLibraryShim");
767 ExitOnNull(pfnLoadLibraryShim, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for LoadLibraryShim() function");
768
769 // load fusion.dll
770 hr = pfnLoadLibraryShim(L"fusion.dll", NULL, NULL, &ghFusion);
771 ExitOnFailure(hr, "Failed to load fusion.dll");
772 }
773
774 // get CreateAssemblyCache function address
775 CreateAssemblyCacheFunc pfnCreateAssemblyCache = (CreateAssemblyCacheFunc)::GetProcAddress(ghFusion, "CreateAssemblyCache");
776 ExitOnNull(pfnCreateAssemblyCache, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for CreateAssemblyCache() function");
777
778 // create AssemblyCache object
779 hr = pfnCreateAssemblyCache(&gpAssemblyCache, 0);
780 ExitOnFailure(hr, "Failed to create AssemblyCache object");
781 }
782
783 gpAssemblyCache->AddRef();
784 *ppAssemblyCache = gpAssemblyCache;
785
786 hr = S_OK;
787
788LExit:
789 return hr;
790}
791
792static HRESULT GetAssemblyPathFromGAC(
793 LPCWSTR pwzAssemblyName,
794 LPWSTR* ppwzAssemblyPath
795 )
796{
797 HRESULT hr = S_OK;
798
799 IAssemblyCache* pAssemblyCache = NULL;
800
801 ASSEMBLY_INFO assemblyInfo;
802 WCHAR wzPathBuf[MAX_PATH];
803
804 ::ZeroMemory(&assemblyInfo, sizeof(ASSEMBLY_INFO));
805 ::ZeroMemory(wzPathBuf, countof(wzPathBuf));
806
807 // get AssemblyCache object
808 hr = GetAssemblyCacheObject(&pAssemblyCache);
809 ExitOnFailure(hr, "Failed to get AssemblyCache object");
810
811 // get assembly info
812 assemblyInfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
813 assemblyInfo.pszCurrentAssemblyPathBuf = wzPathBuf;
814 assemblyInfo.cchBuf = countof(wzPathBuf);
815
816 hr = pAssemblyCache->QueryAssemblyInfo(0, pwzAssemblyName, &assemblyInfo);
817 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
818 ExitFunction1(hr = S_FALSE);
819 ExitOnFailure(hr, "Failed to get assembly info");
820
821 // copy assembly path
822 hr = StrAllocString(ppwzAssemblyPath, wzPathBuf, 0);
823 ExitOnFailure(hr, "Failed to copy assembly path");
824
825 hr = S_OK;
826
827LExit:
828 // clean up
829 ReleaseObject(pAssemblyCache);
830
831 return hr;
832}
833
834static HRESULT RegisterDotNetAssembly(
835 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
836 )
837{
838 HRESULT hr = S_OK;
839
840 IDispatch* piRegHlp = NULL;
841
842 DISPID dispid;
843 BSTR bstrMember = NULL;
844
845 long lInstallationFlags = 0;
846
847 VARIANTARG rgvarg[5];
848 DISPPARAMS dispparams;
849 EXCEPINFO excepInfo;
850
851 BSTR bstrPartName = NULL;
852 BSTR bstrAppName = NULL;
853 BSTR bstrDllPath = NULL;
854 BSTR bstrTlbPath = NULL;
855
856 ::ZeroMemory(rgvarg, sizeof(rgvarg));
857 ::ZeroMemory(&dispparams, sizeof(dispparams));
858 ::ZeroMemory(&excepInfo, sizeof(excepInfo));
859
860 bstrMember = ::SysAllocString(L"InstallAssembly_2");
861 ExitOnNull(bstrMember, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for method name");
862
863 // create BSTRs for parameters
864 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
865 {
866 bstrPartName = ::SysAllocString(pAttrs->pwzPartID);
867 ExitOnNull(bstrPartName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
868 }
869
870 if (pAttrs->pwzAppID && *pAttrs->pwzAppID)
871 {
872 bstrAppName = ::SysAllocString(pAttrs->pwzAppID);
873 ExitOnNull(bstrAppName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
874 }
875
876 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
877 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
878
879 if (pAttrs->pwzTlbPath && *pAttrs->pwzTlbPath)
880 {
881 bstrTlbPath = ::SysAllocString(pAttrs->pwzTlbPath);
882 ExitOnNull(bstrTlbPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path");
883 }
884
885 // get registration helper object
886 hr = GetRegistrationHelper(&piRegHlp);
887 ExitOnFailure(hr, "Failed to get registration helper object");
888
889 // get dispatch id of InstallAssembly() method
890 hr = piRegHlp->GetIDsOfNames(IID_NULL, &bstrMember, 1, LOCALE_USER_DEFAULT, &dispid);
891 ExitOnFailure(hr, "Failed to get dispatch id of InstallAssembly() method");
892
893 // set installation flags
894 lInstallationFlags = ifExpectExistingTypeLib;
895
896 if (!bstrAppName)
897 lInstallationFlags |= ifFindOrCreateTargetApplication;
898
899 // invoke InstallAssembly() method
900 rgvarg[0].vt = VT_I4;
901 rgvarg[0].lVal = lInstallationFlags;
902 rgvarg[1].vt = VT_BYREF|VT_BSTR;
903 rgvarg[1].pbstrVal = &bstrTlbPath;
904 rgvarg[2].vt = VT_BSTR;
905 rgvarg[2].bstrVal = bstrPartName;
906 rgvarg[3].vt = VT_BYREF|VT_BSTR;
907 rgvarg[3].pbstrVal = &bstrAppName;
908 rgvarg[4].vt = VT_BSTR;
909 rgvarg[4].bstrVal = bstrDllPath;
910 dispparams.rgvarg = rgvarg;
911 dispparams.cArgs = 5;
912 dispparams.cNamedArgs = 0;
913
914 hr = piRegHlp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL);
915 if (DISP_E_EXCEPTION == hr)
916 {
917 // log exception information
918 if (!excepInfo.pfnDeferredFillIn || (excepInfo.pfnDeferredFillIn && SUCCEEDED(excepInfo.pfnDeferredFillIn(&excepInfo))))
919 {
920 WcaLog(LOGMSG_STANDARD, "ExceptionInfo: Code='%hu', Source='%S', Description='%S', HelpFile='%S', HelpContext='%u'",
921 excepInfo.wCode, excepInfo.bstrSource,
922 excepInfo.bstrDescription ? excepInfo.bstrDescription : L"",
923 excepInfo.bstrHelpFile ? excepInfo.bstrHelpFile : L"",
924 excepInfo.dwHelpContext);
925 }
926 }
927 ExitOnFailure(hr, "Failed to invoke RegistrationHelper.InstallAssembly() method");
928
929 hr = S_OK;
930
931LExit:
932 // clean up
933 ReleaseObject(piRegHlp);
934
935 ReleaseBSTR(bstrMember);
936
937 ReleaseBSTR(excepInfo.bstrSource);
938 ReleaseBSTR(excepInfo.bstrDescription);
939 ReleaseBSTR(excepInfo.bstrHelpFile);
940
941 ReleaseBSTR(bstrPartName);
942 ReleaseBSTR(bstrAppName);
943 ReleaseBSTR(bstrDllPath);
944 ReleaseBSTR(bstrTlbPath);
945
946 return hr;
947}
948
949static HRESULT RegisterNativeAssembly(
950 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
951 )
952{
953 HRESULT hr = S_OK;
954
955 ICOMAdminCatalog* piCatalog = NULL;
956 ICOMAdminCatalog2* piCatalog2 = NULL;
957 BSTR bstrGlobPartID = NULL;
958
959 BSTR bstrPartID = NULL;
960 BSTR bstrAppID = NULL;
961 BSTR bstrDllPath = NULL;
962 BSTR bstrTlbPath = NULL;
963 BSTR bstrPSDllPath = NULL;
964
965 // create BSTRs for parameters
966 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
967 {
968 bstrPartID = ::SysAllocString(pAttrs->pwzPartID);
969 ExitOnNull(bstrPartID, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
970 }
971
972 bstrAppID = ::SysAllocString(pAttrs->pwzAppID);
973 ExitOnNull(bstrAppID, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
974
975 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
976 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
977
978 bstrTlbPath = ::SysAllocString(pAttrs->pwzTlbPath ? pAttrs->pwzTlbPath : L"");
979 ExitOnNull(bstrTlbPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path");
980
981 bstrPSDllPath = ::SysAllocString(pAttrs->pwzPSDllPath ? pAttrs->pwzPSDllPath : L"");
982 ExitOnNull(bstrPSDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path");
983
984 // get catalog
985 hr = CpiExecGetAdminCatalog(&piCatalog);
986 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
987
988 // get ICOMAdminCatalog2 interface
989 hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2);
990
991 // COM+ 1.5 or later
992 if (E_NOINTERFACE != hr)
993 {
994 ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface");
995
996 // partition id
997 if (!bstrPartID)
998 {
999 // get global partition id
1000 hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID);
1001 ExitOnFailure(hr, "Failed to get global partition id");
1002 }
1003
1004 // set current partition
1005 hr = piCatalog2->put_CurrentPartition(bstrPartID ? bstrPartID : bstrGlobPartID);
1006 ExitOnFailure(hr, "Failed to set current partition");
1007 }
1008
1009 // COM+ pre 1.5
1010 else
1011 {
1012 // this version of COM+ does not support partitions, make sure a partition was not specified
1013 if (bstrPartID)
1014 ExitOnFailure(hr = E_FAIL, "Partitions are not supported by this version of COM+");
1015 }
1016
1017 // install event classes
1018 if (pAttrs->iAttributes & aaEventClass)
1019 {
1020 hr = piCatalog->InstallEventClass(bstrAppID, bstrDllPath, bstrTlbPath, bstrPSDllPath);
1021 if (COMADMIN_E_OBJECTERRORS == hr)
1022 CpiLogCatalogErrorInfo();
1023 ExitOnFailure(hr, "Failed to install event classes");
1024 }
1025
1026 // install components
1027 else
1028 {
1029 hr = piCatalog->InstallComponent(bstrAppID, bstrDllPath, bstrTlbPath, bstrPSDllPath);
1030 if (COMADMIN_E_OBJECTERRORS == hr)
1031 CpiLogCatalogErrorInfo();
1032 ExitOnFailure(hr, "Failed to install components");
1033 }
1034
1035 hr = S_OK;
1036
1037LExit:
1038 // clean up
1039 ReleaseObject(piCatalog);
1040 ReleaseObject(piCatalog2);
1041 ReleaseBSTR(bstrGlobPartID);
1042
1043 ReleaseBSTR(bstrPartID);
1044 ReleaseBSTR(bstrAppID);
1045 ReleaseBSTR(bstrDllPath);
1046 ReleaseBSTR(bstrTlbPath);
1047 ReleaseBSTR(bstrPSDllPath);
1048
1049 return hr;
1050}
1051
1052static HRESULT UnregisterDotNetAssembly(
1053 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1054 )
1055{
1056 HRESULT hr = S_OK;
1057
1058 IDispatch* piRegHlp = NULL;
1059
1060 DISPID dispid;
1061 BSTR bstrMember = NULL;
1062
1063 VARIANTARG rgvarg[3];
1064 DISPPARAMS dispparams;
1065 EXCEPINFO excepInfo;
1066
1067 BSTR bstrPartName = NULL;
1068 BSTR bstrAppName = NULL;
1069 BSTR bstrDllPath = NULL;
1070
1071 ::ZeroMemory(rgvarg, sizeof(rgvarg));
1072 ::ZeroMemory(&dispparams, sizeof(dispparams));
1073 ::ZeroMemory(&excepInfo, sizeof(excepInfo));
1074
1075 bstrMember = ::SysAllocString(L"UninstallAssembly_2");
1076 ExitOnNull(bstrMember, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for method name");
1077
1078 // create BSTRs for parameters
1079 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
1080 {
1081 bstrPartName = ::SysAllocString(pAttrs->pwzPartID);
1082 ExitOnNull(bstrPartName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
1083 }
1084
1085 bstrAppName = ::SysAllocString(pAttrs->pwzAppID);
1086 ExitOnNull(bstrAppName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
1087
1088 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
1089 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
1090
1091 // get registration helper object
1092 hr = GetRegistrationHelper(&piRegHlp);
1093 ExitOnFailure(hr, "Failed to get registration helper object");
1094
1095 // get dispatch id of UninstallAssembly() method
1096 hr = piRegHlp->GetIDsOfNames(IID_NULL, &bstrMember, 1, LOCALE_USER_DEFAULT, &dispid);
1097 ExitOnFailure(hr, "Failed to get dispatch id of UninstallAssembly() method");
1098
1099 // invoke UninstallAssembly() method
1100 rgvarg[0].vt = VT_BSTR;
1101 rgvarg[0].bstrVal = bstrPartName;
1102 rgvarg[1].vt = VT_BSTR;
1103 rgvarg[1].bstrVal = bstrAppName;
1104 rgvarg[2].vt = VT_BSTR;
1105 rgvarg[2].bstrVal = bstrDllPath;
1106 dispparams.rgvarg = rgvarg;
1107 dispparams.cArgs = 3;
1108 dispparams.cNamedArgs = 0;
1109
1110 hr = piRegHlp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL);
1111 if (DISP_E_EXCEPTION == hr)
1112 {
1113 // log exception information
1114 if (!excepInfo.pfnDeferredFillIn || (excepInfo.pfnDeferredFillIn && SUCCEEDED(excepInfo.pfnDeferredFillIn(&excepInfo))))
1115 {
1116 WcaLog(LOGMSG_STANDARD, "ExceptionInfo: Code='%hu', Source='%S', Description='%S', HelpFile='%S', HelpContext='%u'",
1117 excepInfo.wCode, excepInfo.bstrSource,
1118 excepInfo.bstrDescription ? excepInfo.bstrDescription : L"",
1119 excepInfo.bstrHelpFile ? excepInfo.bstrHelpFile : L"",
1120 excepInfo.dwHelpContext);
1121 }
1122 }
1123 ExitOnFailure(hr, "Failed to invoke RegistrationHelper.UninstallAssembly() method");
1124
1125 hr = S_OK;
1126
1127LExit:
1128 // clean up
1129 ReleaseObject(piRegHlp);
1130
1131 ReleaseBSTR(bstrMember);
1132
1133 ReleaseBSTR(excepInfo.bstrSource);
1134 ReleaseBSTR(excepInfo.bstrDescription);
1135 ReleaseBSTR(excepInfo.bstrHelpFile);
1136
1137 ReleaseBSTR(bstrPartName);
1138 ReleaseBSTR(bstrAppName);
1139 ReleaseBSTR(bstrDllPath);
1140
1141 return hr;
1142}
1143
1144static HRESULT RemoveComponents(
1145 ICatalogCollection* piCompColl,
1146 CPIEXEC_COMPONENT* pCompList
1147 )
1148{
1149 HRESULT hr = S_OK;
1150
1151 for (CPIEXEC_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext)
1152 {
1153 // remove
1154 hr = CpiRemoveCollectionObject(piCompColl, pItm->wzCLSID, NULL, FALSE);
1155 ExitOnFailure(hr, "Failed to remove component");
1156
1157 if (S_FALSE == hr)
1158 WcaLog(LOGMSG_VERBOSE, "Component not found, nothing to delete, key: %S", pItm->wzCLSID);
1159 }
1160
1161 hr = S_OK;
1162
1163LExit:
1164 return hr;
1165}
1166
1167static HRESULT ReadAssemblyAttributes(
1168 LPWSTR* ppwzData,
1169 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1170 )
1171{
1172 HRESULT hr = S_OK;
1173
1174 // read attributes
1175 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
1176 ExitOnFailure(hr, "Failed to read action type");
1177 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
1178 ExitOnFailure(hr, "Failed to read action cost");
1179 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
1180 ExitOnFailure(hr, "Failed to read key");
1181 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAssemblyName);
1182 ExitOnFailure(hr, "Failed to read assembly name");
1183 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzDllPath);
1184 ExitOnFailure(hr, "Failed to read dll path");
1185 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzTlbPath);
1186 ExitOnFailure(hr, "Failed to read tlb path");
1187 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPSDllPath);
1188 ExitOnFailure(hr, "Failed to read proxy-stub dll path");
1189 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iAttributes);
1190 ExitOnFailure(hr, "Failed to read attributes");
1191 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
1192 ExitOnFailure(hr, "Failed to read application id");
1193 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
1194 ExitOnFailure(hr, "Failed to read partition id");
1195
1196 // free existing component list
1197 if (pAttrs->pCompList)
1198 {
1199 FreeComponentList(pAttrs->pCompList);
1200 pAttrs->pCompList = NULL;
1201 }
1202
1203 // read components
1204 hr = ReadComponentList(ppwzData, &pAttrs->pCompList);
1205 ExitOnFailure(hr, "Failed to read components");
1206
1207 hr = S_OK;
1208
1209LExit:
1210 return hr;
1211}
1212
1213static void FreeAssemblyAttributes(
1214 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1215 )
1216{
1217 ReleaseStr(pAttrs->pwzKey);
1218 ReleaseStr(pAttrs->pwzAssemblyName);
1219 ReleaseStr(pAttrs->pwzDllPath);
1220 ReleaseStr(pAttrs->pwzTlbPath);
1221 ReleaseStr(pAttrs->pwzPSDllPath);
1222 ReleaseStr(pAttrs->pwzAppID);
1223 ReleaseStr(pAttrs->pwzPartID);
1224
1225 if (pAttrs->pCompList)
1226 FreeComponentList(pAttrs->pCompList);
1227}
1228
1229static HRESULT ReadRoleAssignmentsAttributes(
1230 LPWSTR* ppwzData,
1231 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
1232 )
1233{
1234 HRESULT hr = S_OK;
1235
1236 // read attributes
1237 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
1238 ExitOnFailure(hr, "Failed to read action type");
1239 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
1240 ExitOnFailure(hr, "Failed to read action cost");
1241 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
1242 ExitOnFailure(hr, "Failed to read key");
1243 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iRoleCount);
1244 ExitOnFailure(hr, "Failed to read role assignments count");
1245 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
1246 ExitOnFailure(hr, "Failed to read application id");
1247 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
1248 ExitOnFailure(hr, "Failed to read partition id");
1249
1250 // free existing component list
1251 if (pAttrs->pCompList)
1252 {
1253 FreeComponentList(pAttrs->pCompList);
1254 pAttrs->pCompList = NULL;
1255 }
1256
1257 // read components
1258 hr = ReadComponentList(ppwzData, &pAttrs->pCompList);
1259 ExitOnFailure(hr, "Failed to read components");
1260
1261 hr = S_OK;
1262
1263LExit:
1264 return hr;
1265}
1266
1267static void FreeRoleAssignmentsAttributes(
1268 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
1269 )
1270{
1271 ReleaseStr(pAttrs->pwzKey);
1272 ReleaseStr(pAttrs->pwzAppID);
1273 ReleaseStr(pAttrs->pwzPartID);
1274
1275 if (pAttrs->pCompList)
1276 FreeComponentList(pAttrs->pCompList);
1277}
1278
1279
1280static HRESULT ConfigureComponents(
1281 LPCWSTR pwzPartID,
1282 LPCWSTR pwzAppID,
1283 CPIEXEC_COMPONENT* pCompList,
1284 BOOL fCreate,
1285 BOOL fProgress
1286 )
1287{
1288 HRESULT hr = S_OK;
1289
1290 ICatalogCollection* piCompColl = NULL;
1291 ICatalogObject* piCompObj = NULL;
1292
1293 long lChanges = 0;
1294
1295 // get components collection
1296 hr = CpiGetComponentsCollection(pwzPartID, pwzAppID, &piCompColl);
1297 if (S_FALSE == hr)
1298 if (fCreate)
1299 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1300 else
1301 ExitFunction1(hr = S_OK);
1302 ExitOnFailure(hr, "Failed to get components collection");
1303
1304 // read components
1305 for (CPIEXEC_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext)
1306 {
1307 // progress message
1308 if (fProgress)
1309 {
1310 hr = CpiActionDataMessage(1, pItm->wzCLSID);
1311 ExitOnFailure(hr, "Failed to send progress messages");
1312
1313 if (S_FALSE == hr)
1314 ExitFunction(); // aborted by user
1315 }
1316
1317 // find component
1318 hr = CpiFindCollectionObjectByStringKey(piCompColl, pItm->wzCLSID, &piCompObj);
1319 if (S_FALSE == hr)
1320 if (fCreate)
1321 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1322 else
1323 continue;
1324 ExitOnFailure(hr, "Failed to find component object");
1325
1326 // properties
1327 hr = CpiPutCollectionObjectValues(piCompObj, pItm->pPropertyList);
1328 ExitOnFailure(hr, "Failed to write properties");
1329
1330 // read roles
1331 if (pItm->pRoleAssignmentList)
1332 {
1333 hr = ConfigureRoleAssignments(L"RolesForComponent", piCompColl, piCompObj, pItm->pRoleAssignmentList, fCreate);
1334 ExitOnFailure(hr, "Failed to read roles");
1335 }
1336
1337 // read interfaces
1338 if (pItm->pInterfaceList)
1339 {
1340 hr = ConfigureInterfaces(piCompColl, piCompObj, pItm->pInterfaceList, fCreate);
1341 ExitOnFailure(hr, "Failed to read interfaces");
1342 }
1343
1344 // clean up
1345 ReleaseNullObject(piCompObj);
1346 }
1347
1348 // save changes
1349 hr = piCompColl->SaveChanges(&lChanges);
1350 if (COMADMIN_E_OBJECTERRORS == hr)
1351 CpiLogCatalogErrorInfo();
1352 ExitOnFailure(hr, "Failed to save changes");
1353
1354 hr = S_OK;
1355
1356LExit:
1357 // clean up
1358 ReleaseObject(piCompColl);
1359 ReleaseObject(piCompObj);
1360
1361 return hr;
1362}
1363
1364static HRESULT ConfigureInterfaces(
1365 ICatalogCollection* piCompColl,
1366 ICatalogObject* piCompObj,
1367 CPIEXEC_INTERFACE* pIntfList,
1368 BOOL fCreate
1369 )
1370{
1371 HRESULT hr = S_OK;
1372
1373 ICatalogCollection* piIntfColl = NULL;
1374 ICatalogObject* piIntfObj = NULL;
1375
1376 long lChanges = 0;
1377
1378 // get interfaces collection
1379 hr = CpiGetInterfacesCollection(piCompColl, piCompObj, &piIntfColl);
1380 if (S_FALSE == hr)
1381 if (fCreate)
1382 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1383 else
1384 ExitFunction1(hr = S_OK);
1385 ExitOnFailure(hr, "Failed to get interfaces collection");
1386
1387 // read interfaces
1388 for (CPIEXEC_INTERFACE* pItm = pIntfList; pItm; pItm = pItm->pNext)
1389 {
1390 // find interface
1391 hr = CpiFindCollectionObjectByStringKey(piIntfColl, pItm->wzIID, &piIntfObj);
1392 if (S_FALSE == hr)
1393 if (fCreate)
1394 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1395 else
1396 continue;
1397 ExitOnFailure(hr, "Failed to find interface object");
1398
1399 // properties
1400 hr = CpiPutCollectionObjectValues(piIntfObj, pItm->pPropertyList);
1401 ExitOnFailure(hr, "Failed to write properties");
1402
1403 // read roles
1404 if (pItm->pRoleAssignmentList)
1405 {
1406 hr = ConfigureRoleAssignments(L"RolesForInterface", piIntfColl, piIntfObj, pItm->pRoleAssignmentList, fCreate);
1407 ExitOnFailure(hr, "Failed to read roles");
1408 }
1409
1410 // read methods
1411 if (pItm->pMethodList)
1412 {
1413 hr = ConfigureMethods(piIntfColl, piIntfObj, pItm->pMethodList, fCreate);
1414 ExitOnFailure(hr, "Failed to read methods");
1415 }
1416
1417 // clean up
1418 ReleaseNullObject(piIntfObj);
1419 }
1420
1421 // save changes
1422 hr = piIntfColl->SaveChanges(&lChanges);
1423 if (COMADMIN_E_OBJECTERRORS == hr)
1424 CpiLogCatalogErrorInfo();
1425 ExitOnFailure(hr, "Failed to save changes");
1426
1427 hr = S_OK;
1428
1429LExit:
1430 // clean up
1431 ReleaseObject(piIntfColl);
1432 ReleaseObject(piIntfObj);
1433
1434 return hr;
1435}
1436
1437static HRESULT ConfigureMethods(
1438 ICatalogCollection* piIntfColl,
1439 ICatalogObject* piIntfObj,
1440 CPIEXEC_METHOD* pMethList,
1441 BOOL fCreate
1442 )
1443{
1444 HRESULT hr = S_OK;
1445
1446 ICatalogCollection* piMethColl = NULL;
1447 ICatalogObject* piMethObj = NULL;
1448
1449 long lChanges = 0;
1450
1451 // get methods collection
1452 hr = CpiGetMethodsCollection(piIntfColl, piIntfObj, &piMethColl);
1453 if (S_FALSE == hr)
1454 if (fCreate)
1455 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1456 else
1457 ExitFunction1(hr = S_OK);
1458 ExitOnFailure(hr, "Failed to get methods collection");
1459
1460 // read methods
1461 for (CPIEXEC_METHOD* pItm = pMethList; pItm; pItm = pItm->pNext)
1462 {
1463 // find method
1464 if (*pItm->wzIndex)
1465 hr = CpiFindCollectionObjectByIntegerKey(piMethColl, _wtol(pItm->wzIndex), &piMethObj);
1466 else
1467 hr = CpiFindCollectionObjectByName(piMethColl, pItm->wzName, &piMethObj);
1468
1469 if (S_FALSE == hr)
1470 if (fCreate)
1471 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1472 else
1473 continue;
1474 ExitOnFailure(hr, "Failed to find method object");
1475
1476 // properties
1477 hr = CpiPutCollectionObjectValues(piMethObj, pItm->pPropertyList);
1478 ExitOnFailure(hr, "Failed to write properties");
1479
1480 // read roles
1481 if (pItm->pRoleAssignmentList)
1482 {
1483 hr = ConfigureRoleAssignments(L"RolesForMethod", piMethColl, piMethObj, pItm->pRoleAssignmentList, fCreate);
1484 ExitOnFailure(hr, "Failed to read roles");
1485 }
1486
1487 // clean up
1488 ReleaseNullObject(piMethObj);
1489 }
1490
1491 // save changes
1492 hr = piMethColl->SaveChanges(&lChanges);
1493 if (COMADMIN_E_OBJECTERRORS == hr)
1494 CpiLogCatalogErrorInfo();
1495 ExitOnFailure(hr, "Failed to save changes");
1496
1497 hr = S_OK;
1498
1499LExit:
1500 // clean up
1501 ReleaseObject(piMethColl);
1502 ReleaseObject(piMethObj);
1503
1504 return hr;
1505}
1506
1507static HRESULT ConfigureRoleAssignments(
1508 LPCWSTR pwzCollName,
1509 ICatalogCollection* piCompColl,
1510 ICatalogObject* piCompObj,
1511 CPIEXEC_ROLE_ASSIGNMENT* pRoleList,
1512 BOOL fCreate
1513 )
1514{
1515 HRESULT hr = S_OK;
1516
1517 ICatalogCollection* piRoleColl = NULL;
1518 ICatalogObject* piRoleObj = NULL;
1519
1520 long lChanges = 0;
1521
1522 // get roles collection
1523 hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, pwzCollName, &piRoleColl);
1524 if (S_FALSE == hr)
1525 if (fCreate)
1526 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1527 else
1528 ExitFunction1(hr = S_OK);
1529 ExitOnFailure(hr, "Failed to get role assignments collection");
1530
1531 // read roles
1532 for (CPIEXEC_ROLE_ASSIGNMENT* pItm = pRoleList; pItm; pItm = pItm->pNext)
1533 {
1534 if (fCreate)
1535 {
1536 // find existing role
1537 hr = CpiFindCollectionObjectByName(piRoleColl, pItm->wzRoleName, NULL);
1538 ExitOnFailure(hr, "Failed to find role, key: %S", pItm->wzKey);
1539
1540 if (S_OK == hr)
1541 continue; // role already exists
1542
1543 // add object
1544 hr = CpiAddCollectionObject(piRoleColl, &piRoleObj);
1545 ExitOnFailure(hr, "Failed to add role assignment to collection");
1546
1547 // role name
1548 hr = CpiPutCollectionObjectValue(piRoleObj, L"Name", pItm->wzRoleName);
1549 ExitOnFailure(hr, "Failed to set role name property, key: %S", pItm->wzKey);
1550
1551 // clean up
1552 ReleaseNullObject(piRoleObj);
1553 }
1554 else
1555 {
1556 // remove role
1557 hr = CpiRemoveCollectionObject(piRoleColl, NULL, pItm->wzRoleName, FALSE);
1558 ExitOnFailure(hr, "Failed to remove role, key: %S", pItm->wzKey);
1559 }
1560 }
1561
1562 // save changes
1563 hr = piRoleColl->SaveChanges(&lChanges);
1564 if (COMADMIN_E_OBJECTERRORS == hr)
1565 CpiLogCatalogErrorInfo();
1566 ExitOnFailure(hr, "Failed to save changes");
1567
1568 hr = S_OK;
1569
1570LExit:
1571 // clean up
1572 ReleaseObject(piRoleColl);
1573 ReleaseObject(piRoleObj);
1574
1575 return hr;
1576}
1577
1578static HRESULT ReadComponentList(
1579 LPWSTR* ppwzData,
1580 CPIEXEC_COMPONENT** ppCompList
1581 )
1582{
1583 HRESULT hr = S_OK;
1584
1585 LPWSTR pwzData = NULL;
1586
1587 CPIEXEC_COMPONENT* pItm = NULL;
1588
1589 int iCnt = 0;
1590
1591 // read count
1592 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1593 ExitOnFailure(hr, "Failed to read count");
1594
1595 // read components
1596 for (int i = 0; i < iCnt; i++)
1597 {
1598 pItm = (CPIEXEC_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_COMPONENT));
1599 if (!pItm)
1600 ExitFunction1(hr = E_OUTOFMEMORY);
1601
1602 // read clsid
1603 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1604 ExitOnFailure(hr, "Failed to read clsid");
1605 StringCchCopyW(pItm->wzCLSID, countof(pItm->wzCLSID), pwzData);
1606
1607 // read properties
1608 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1609 ExitOnFailure(hr, "Failed to read properties");
1610
1611 // read role assignments
1612 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1613 ExitOnFailure(hr, "Failed to read role assignments");
1614
1615 // read interfaces
1616 hr = ReadInterfaceList(ppwzData, &pItm->pInterfaceList);
1617 ExitOnFailure(hr, "Failed to read interfaces");
1618
1619 // add to list
1620 if (*ppCompList)
1621 pItm->pNext = *ppCompList;
1622 *ppCompList = pItm;
1623 pItm = NULL;
1624 }
1625
1626 hr = S_OK;
1627
1628LExit:
1629 // clean up
1630 ReleaseStr(pwzData);
1631
1632 if (pItm)
1633 FreeComponentList(pItm);
1634
1635 return hr;
1636}
1637
1638static HRESULT ReadInterfaceList(
1639 LPWSTR* ppwzData,
1640 CPIEXEC_INTERFACE** ppIntfList
1641 )
1642{
1643 HRESULT hr = S_OK;
1644
1645 LPWSTR pwzData = NULL;
1646
1647 CPIEXEC_INTERFACE* pItm = NULL;
1648
1649 int iCnt = 0;
1650
1651 // read count
1652 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1653 ExitOnFailure(hr, "Failed to read count");
1654
1655 // read interfaces
1656 for (int i = 0; i < iCnt; i++)
1657 {
1658 pItm = (CPIEXEC_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_INTERFACE));
1659 if (!pItm)
1660 ExitFunction1(hr = E_OUTOFMEMORY);
1661
1662 // read iid
1663 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1664 ExitOnFailure(hr, "Failed to read iid");
1665 StringCchCopyW(pItm->wzIID, countof(pItm->wzIID), pwzData);
1666
1667 // read properties
1668 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1669 ExitOnFailure(hr, "Failed to read properties");
1670
1671 // read role assignments
1672 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1673 ExitOnFailure(hr, "Failed to read role assignments");
1674
1675 // read methods
1676 hr = ReadMethodList(ppwzData, &pItm->pMethodList);
1677 ExitOnFailure(hr, "Failed to read methods");
1678
1679 // add to list
1680 if (*ppIntfList)
1681 pItm->pNext = *ppIntfList;
1682 *ppIntfList = pItm;
1683 pItm = NULL;
1684 }
1685
1686 hr = S_OK;
1687
1688LExit:
1689 // clean up
1690 ReleaseStr(pwzData);
1691
1692 if (pItm)
1693 FreeInterfaceList(pItm);
1694
1695 return hr;
1696}
1697
1698static HRESULT ReadMethodList(
1699 LPWSTR* ppwzData,
1700 CPIEXEC_METHOD** ppMethList
1701 )
1702{
1703 HRESULT hr = S_OK;
1704
1705 LPWSTR pwzData = NULL;
1706
1707 CPIEXEC_METHOD* pItm = NULL;
1708
1709 int iCnt = 0;
1710
1711 // read count
1712 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1713 ExitOnFailure(hr, "Failed to read count");
1714
1715 // read methods
1716 for (int i = 0; i < iCnt; i++)
1717 {
1718 pItm = (CPIEXEC_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_METHOD));
1719 if (!pItm)
1720 ExitFunction1(hr = E_OUTOFMEMORY);
1721
1722 // read index
1723 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1724 ExitOnFailure(hr, "Failed to read index");
1725 StringCchCopyW(pItm->wzIndex, countof(pItm->wzIndex), pwzData);
1726
1727 // read name
1728 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1729 ExitOnFailure(hr, "Failed to read name");
1730 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
1731
1732 // read properties
1733 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1734 ExitOnFailure(hr, "Failed to read properties");
1735
1736 // read role assignments
1737 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1738 ExitOnFailure(hr, "Failed to read role assignments");
1739
1740 // add to list
1741 if (*ppMethList)
1742 pItm->pNext = *ppMethList;
1743 *ppMethList = pItm;
1744 pItm = NULL;
1745 }
1746
1747 hr = S_OK;
1748
1749LExit:
1750 // clean up
1751 ReleaseStr(pwzData);
1752
1753 if (pItm)
1754 FreeMethodList(pItm);
1755
1756 return hr;
1757}
1758
1759static HRESULT ReadRoleAssignmentList(
1760 LPWSTR* ppwzData,
1761 CPIEXEC_ROLE_ASSIGNMENT** ppRoleList
1762 )
1763{
1764 HRESULT hr = S_OK;
1765
1766 LPWSTR pwzData = NULL;
1767
1768 CPIEXEC_ROLE_ASSIGNMENT* pItm = NULL;
1769
1770 int iCnt = 0;
1771
1772 // read role count
1773 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1774 ExitOnFailure(hr, "Failed to read role assignments count");
1775
1776 // read roles
1777 for (int i = 0; i < iCnt; i++)
1778 {
1779 pItm = (CPIEXEC_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_ROLE_ASSIGNMENT));
1780 if (!pItm)
1781 ExitFunction1(hr = E_OUTOFMEMORY);
1782
1783 // read key
1784 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1785 ExitOnFailure(hr, "Failed to read key");
1786 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1787
1788 // read role name
1789 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1790 ExitOnFailure(hr, "Failed to read role name");
1791 StringCchCopyW(pItm->wzRoleName, countof(pItm->wzRoleName), pwzData);
1792
1793 // add to list
1794 if (*ppRoleList)
1795 pItm->pNext = *ppRoleList;
1796 *ppRoleList = pItm;
1797 pItm = NULL;
1798 }
1799
1800 hr = S_OK;
1801
1802LExit:
1803 // clean up
1804 ReleaseStr(pwzData);
1805
1806 if (pItm)
1807 FreeRoleAssignmentList(pItm);
1808
1809 return hr;
1810}
1811
1812static void FreeComponentList(
1813 CPIEXEC_COMPONENT* pList
1814 )
1815{
1816 while (pList)
1817 {
1818 if (pList->pPropertyList)
1819 CpiFreePropertyList(pList->pPropertyList);
1820 if (pList->pRoleAssignmentList)
1821 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1822 if (pList->pInterfaceList)
1823 FreeInterfaceList(pList->pInterfaceList);
1824
1825 CPIEXEC_COMPONENT* pDelete = pList;
1826 pList = pList->pNext;
1827 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1828 }
1829}
1830
1831static void FreeInterfaceList(
1832 CPIEXEC_INTERFACE* pList
1833 )
1834{
1835 while (pList)
1836 {
1837 if (pList->pPropertyList)
1838 CpiFreePropertyList(pList->pPropertyList);
1839 if (pList->pRoleAssignmentList)
1840 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1841 if (pList->pMethodList)
1842 FreeMethodList(pList->pMethodList);
1843
1844 CPIEXEC_INTERFACE* pDelete = pList;
1845 pList = pList->pNext;
1846 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1847 }
1848}
1849
1850static void FreeMethodList(
1851 CPIEXEC_METHOD* pList
1852 )
1853{
1854 while (pList)
1855 {
1856 if (pList->pPropertyList)
1857 CpiFreePropertyList(pList->pPropertyList);
1858 if (pList->pRoleAssignmentList)
1859 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1860
1861 CPIEXEC_METHOD* pDelete = pList;
1862 pList = pList->pNext;
1863 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1864 }
1865}
1866
1867static void FreeRoleAssignmentList(
1868 CPIEXEC_ROLE_ASSIGNMENT* pList
1869 )
1870{
1871 while (pList)
1872 {
1873 CPIEXEC_ROLE_ASSIGNMENT* pDelete = pList;
1874 pList = pList->pNext;
1875 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1876 }
1877}
diff --git a/src/ext/ComPlus/ca/cpasmexec.h b/src/ext/ComPlus/ca/cpasmexec.h
new file mode 100644
index 00000000..56184c01
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpasmexec.h
@@ -0,0 +1,20 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureAssemblies(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureAssemblies(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
13HRESULT CpiConfigureRoleAssignments(
14 LPWSTR* ppwzData,
15 HANDLE hRollbackFile
16 );
17HRESULT CpiRollbackConfigureRoleAssignments(
18 LPWSTR* ppwzData,
19 CPI_ROLLBACK_DATA* pRollbackDataList
20 );
diff --git a/src/ext/ComPlus/ca/cpasmsched.cpp b/src/ext/ComPlus/ca/cpasmsched.cpp
new file mode 100644
index 00000000..2d0573a5
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpasmsched.cpp
@@ -0,0 +1,2135 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsMsiAssemblyNameQuery =
9 L"SELECT `Name`, `Value` FROM `MsiAssemblyName` WHERE `Component_` = ?";
10enum eMsiAssemblyNameQuery { manqName = 1, manqValue };
11
12LPCWSTR vcsModuleQuery =
13 L"SELECT `ModuleID` FROM `ModuleSignature`";
14enum eModuleQuery { mqModule = 1 };
15
16LPCWSTR vcsAssemblyQuery =
17 L"SELECT `Assembly`, `Component_`, `Application_`, `AssemblyName`, `DllPath`, `TlbPath`, `PSDllPath`, `Attributes` FROM `ComPlusAssembly`";
18enum eAssemblyQuery { aqAssembly = 1, aqComponent, aqApplication, aqAssemblyName, aqDllPath, aqTlbPath, aqPSDllPath, aqAttributes };
19
20LPCWSTR vcsComponentQuery =
21 L"SELECT `ComPlusComponent`, `CLSID` FROM `ComPlusComponent` WHERE `Assembly_` = ?";
22enum eComponentQuery { cqComponent = 1, cqCLSID };
23
24LPCWSTR vcsComponentPropertyQuery =
25 L"SELECT `Name`, `Value` FROM `ComPlusComponentProperty` WHERE `ComPlusComponent_` = ?";
26
27LPCWSTR vcsInterfaceQuery =
28 L"SELECT `Interface`, `IID` FROM `ComPlusInterface` WHERE `ComPlusComponent_` = ?";
29enum eInterfaceQuery { iqInterface = 1, iqIID };
30
31LPCWSTR vcsInterfacePropertyQuery =
32 L"SELECT `Name`, `Value` FROM `ComPlusInterfaceProperty` WHERE `Interface_` = ?";
33
34LPCWSTR vcsMethodQuery =
35 L"SELECT `Method`, `Index`, `Name` FROM `ComPlusMethod` WHERE `Interface_` = ?";
36enum eMethodQuery { mqMethod = 1, mqIndex, mqName };
37
38LPCWSTR vcsMethodPropertyQuery =
39 L"SELECT `Name`, `Value` FROM `ComPlusMethodProperty` WHERE `Method_` = ?";
40
41LPCWSTR vcsRoleForComponentQuery =
42 L"SELECT `RoleForComponent`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForComponent` WHERE `ComPlusComponent_` = ?";
43LPCWSTR vcsRoleForInterfaceQuery =
44 L"SELECT `RoleForInterface`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForInterface` WHERE `Interface_` = ?";
45LPCWSTR vcsRoleForMethodQuery =
46 L"SELECT `RoleForMethod`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForMethod` WHERE `Method_` = ?";
47
48enum eRoleAssignmentQuery { raqKey = 1, raqApplicationRole, raqComponent };
49
50LPCWSTR vcsModuleComponentsQuery =
51 L"SELECT `Component`, `ModuleID` FROM `ModuleComponents`";
52LPCWSTR vcsModuleDependencyQuery =
53 L"SELECT `ModuleID`, `RequiredID` FROM `ModuleDependency`";
54LPCWSTR vcsAssemblyDependencyQuery =
55 L"SELECT `Assembly_`, `RequiredAssembly_` FROM `ComPlusAssemblyDependency`";
56
57enum eKeyPairQuery { kpqFirstKey = 1, kpqSecondKey };
58
59
60// private structs
61
62struct CPI_KEY_PAIR
63{
64 WCHAR wzFirstKey[MAX_DARWIN_KEY + 1];
65 WCHAR wzSecondKey[MAX_DARWIN_KEY + 1];
66
67 CPI_KEY_PAIR* pNext;
68};
69
70struct CPI_DEPENDENCY_CHAIN
71{
72 LPCWSTR pwzKey;
73
74 CPI_DEPENDENCY_CHAIN* pPrev;
75};
76
77struct CPI_MODULE
78{
79 WCHAR wzKey[MAX_DARWIN_KEY + 1];
80
81 CPI_MODULE* pPrev;
82 CPI_MODULE* pNext;
83};
84
85struct CPI_MODULE_LIST
86{
87 CPI_MODULE* pFirst;
88 CPI_MODULE* pLast;
89};
90
91
92// property definitions
93
94CPI_PROPERTY_DEFINITION pdlComponentProperties[] =
95{
96 {L"AllowInprocSubscribers", cpptBoolean, 500},
97 {L"ComponentAccessChecksEnabled", cpptBoolean, 500},
98 {L"ComponentTransactionTimeout", cpptInteger, 500},
99 {L"ComponentTransactionTimeoutEnabled", cpptBoolean, 500},
100 {L"COMTIIntrinsics", cpptBoolean, 500},
101 {L"ConstructionEnabled", cpptBoolean, 500},
102 {L"ConstructorString", cpptString, 500},
103 {L"CreationTimeout", cpptInteger, 500},
104 {L"Description", cpptString, 500},
105 {L"EventTrackingEnabled", cpptBoolean, 500},
106 {L"ExceptionClass", cpptString, 500},
107 {L"FireInParallel", cpptBoolean, 500},
108 {L"IISIntrinsics", cpptBoolean, 500},
109 {L"InitializesServerApplication", cpptBoolean, 500},
110 {L"IsEnabled", cpptBoolean, 501},
111 {L"IsPrivateComponent", cpptBoolean, 501},
112 {L"JustInTimeActivation", cpptBoolean, 500},
113 {L"LoadBalancingSupported", cpptBoolean, 500},
114 {L"MaxPoolSize", cpptInteger, 500},
115 {L"MinPoolSize", cpptInteger, 500},
116 {L"MultiInterfacePublisherFilterCLSID", cpptString, 500},
117 {L"MustRunInClientContext", cpptBoolean, 500},
118 {L"MustRunInDefaultContext", cpptBoolean, 501},
119 {L"ObjectPoolingEnabled", cpptBoolean, 500},
120 {L"PublisherID", cpptString, 500},
121 {L"SoapAssemblyName", cpptString, 502},
122 {L"SoapTypeName", cpptString, 502},
123 {L"Synchronization", cpptInteger, 500},
124 {L"Transaction", cpptInteger, 500},
125 {L"TxIsolationLevel", cpptInteger, 501},
126 {NULL, cpptNone, 0}
127};
128
129CPI_PROPERTY_DEFINITION pdlInterfaceProperties[] =
130{
131 {L"Description", cpptString, 500},
132 {L"QueuingEnabled", cpptBoolean, 500},
133 {NULL, cpptNone, 0}
134};
135
136CPI_PROPERTY_DEFINITION pdlMethodProperties[] =
137{
138 {L"AutoComplete", cpptBoolean, 500},
139 {L"Description", cpptString, 500},
140 {NULL, cpptNone, 0}
141};
142
143
144// prototypes for private helper functions
145
146static HRESULT GetAssemblyName(
147 LPCWSTR pwzComponent,
148 LPWSTR* ppwzAssemblyName
149 );
150static HRESULT KeyPairsRead(
151 LPCWSTR pwzQuery,
152 CPI_KEY_PAIR** ppKeyPairList
153 );
154static HRESULT ModulesRead(
155 CPI_MODULE_LIST* pModList
156 );
157static HRESULT AssembliesRead(
158 CPI_KEY_PAIR* pModCompList,
159 CPI_APPLICATION_LIST* pAppList,
160 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
161 CPI_ASSEMBLY_LIST* pAsmList
162 );
163static HRESULT ComponentsRead(
164 LPCWSTR pwzAsmKey,
165 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
166 CPI_ASSEMBLY* pAsm
167 );
168static HRESULT InterfacesRead(
169 LPCWSTR pwzCompKey,
170 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
171 CPI_ASSEMBLY* pAsm,
172 CPISCHED_COMPONENT* pComp
173 );
174static HRESULT MethodsRead(
175 LPCWSTR pwzIntfKey,
176 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
177 CPI_ASSEMBLY* pAsm,
178 CPISCHED_INTERFACE* pIntf
179 );
180static HRESULT RoleAssignmentsRead(
181 LPCWSTR pwzQuery,
182 LPCWSTR pwzKey,
183 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
184 CPISCHED_ROLE_ASSIGNMENT** ppRoleList,
185 int* piInstallCount,
186 int* piUninstallCount
187 );
188static HRESULT TopSortModuleList(
189 CPI_KEY_PAIR* pDepList,
190 CPI_MODULE_LIST* pList
191 );
192static HRESULT SwapDependentModules(
193 CPI_DEPENDENCY_CHAIN* pdcPrev,
194 CPI_KEY_PAIR* pDepList,
195 CPI_MODULE_LIST* pList,
196 CPI_MODULE* pRoot,
197 CPI_MODULE* pItm
198 );
199static HRESULT ModuleFindByKey(
200 CPI_MODULE* pItm,
201 LPCWSTR pwzKey,
202 BOOL fReverse,
203 CPI_MODULE** ppItm
204 );
205static void SortAssemblyListByModule(
206 CPI_MODULE_LIST* pModList,
207 CPI_ASSEMBLY_LIST* pAsmList
208 );
209static HRESULT TopSortAssemblyList(
210 CPI_KEY_PAIR* pDepList,
211 CPI_ASSEMBLY_LIST* pList
212 );
213static HRESULT SwapDependentAssemblies(
214 CPI_DEPENDENCY_CHAIN* pdcPrev,
215 CPI_KEY_PAIR* pDepList,
216 CPI_ASSEMBLY_LIST* pList,
217 CPI_ASSEMBLY* pRoot,
218 CPI_ASSEMBLY* pItm
219 );
220static HRESULT AssemblyFindByKey(
221 CPI_ASSEMBLY* pItm,
222 LPCWSTR pwzKey,
223 BOOL fReverse,
224 CPI_ASSEMBLY** ppItm
225 );
226static HRESULT AddAssemblyToActionData(
227 CPI_ASSEMBLY* pItm,
228 BOOL fInstall,
229 int iActionType,
230 int iActionCost,
231 LPWSTR* ppwzActionData
232 );
233static HRESULT AddRoleAssignmentsToActionData(
234 CPI_ASSEMBLY* pItm,
235 BOOL fInstall,
236 int iActionType,
237 int iActionCost,
238 LPWSTR* ppwzActionData
239 );
240static HRESULT AddComponentToActionData(
241 CPISCHED_COMPONENT* pItm,
242 BOOL fInstall,
243 BOOL fProps,
244 BOOL fRoles,
245 LPWSTR* ppwzActionData
246 );
247static HRESULT AddInterfaceToActionData(
248 CPISCHED_INTERFACE* pItm,
249 BOOL fInstall,
250 BOOL fProps,
251 BOOL fRoles,
252 LPWSTR* ppwzActionData
253 );
254static HRESULT AddMethodToActionData(
255 CPISCHED_METHOD* pItm,
256 BOOL fInstall,
257 BOOL fProps,
258 BOOL fRoles,
259 LPWSTR* ppwzActionData
260 );
261static HRESULT AddRolesToActionData(
262 int iRoleInstallCount,
263 int iRoleUninstallCount,
264 CPISCHED_ROLE_ASSIGNMENT* pRoleList,
265 BOOL fInstall,
266 BOOL fRoles,
267 LPWSTR* ppwzActionData
268 );
269static HRESULT KeyPairFindByFirstKey(
270 CPI_KEY_PAIR* pList,
271 LPCWSTR pwzKey,
272 CPI_KEY_PAIR** ppItm
273 );
274static void AssemblyFree(
275 CPI_ASSEMBLY* pItm
276 );
277static void KeyPairsFreeList(
278 CPI_KEY_PAIR* pList
279 );
280void ModuleListFree(
281 CPI_MODULE_LIST* pList
282 );
283static void ModuleFree(
284 CPI_MODULE* pItm
285 );
286static void ComponentsFreeList(
287 CPISCHED_COMPONENT* pList
288 );
289static void InterfacesFreeList(
290 CPISCHED_INTERFACE* pList
291 );
292static void MethodsFreeList(
293 CPISCHED_METHOD* pList
294 );
295static void RoleAssignmentsFreeList(
296 CPISCHED_ROLE_ASSIGNMENT* pList
297 );
298
299
300// function definitions
301
302void CpiAssemblyListFree(
303 CPI_ASSEMBLY_LIST* pList
304 )
305{
306 CPI_ASSEMBLY* pItm = pList->pFirst;
307
308 while (pItm)
309 {
310 CPI_ASSEMBLY* pDelete = pItm;
311 pItm = pItm->pNext;
312 AssemblyFree(pDelete);
313 }
314}
315
316HRESULT CpiAssembliesRead(
317 CPI_APPLICATION_LIST* pAppList,
318 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
319 CPI_ASSEMBLY_LIST* pAsmList
320 )
321{
322 HRESULT hr = S_OK;
323 CPI_MODULE_LIST modList;
324 CPI_KEY_PAIR* pModCompList = NULL;
325 CPI_KEY_PAIR* pModDepList = NULL;
326 CPI_KEY_PAIR* pAsmDepList = NULL;
327
328 ::ZeroMemory(&modList, sizeof(CPI_MODULE_LIST));
329
330 BOOL fModuleSignatureTable = (S_OK == WcaTableExists(L"ModuleSignature"));
331 BOOL fModuleComponentsTable = (S_OK == WcaTableExists(L"ModuleComponents"));
332 BOOL fModuleDependencyTable = (S_OK == WcaTableExists(L"ModuleDependency"));
333
334 // read modules
335 if (fModuleSignatureTable)
336 {
337 hr = ModulesRead(&modList);
338 ExitOnFailure(hr, "Failed to read ModuleSignature table");
339 }
340
341 // read module components
342 if (fModuleComponentsTable)
343 {
344 hr = KeyPairsRead(vcsModuleComponentsQuery, &pModCompList);
345 ExitOnFailure(hr, "Failed to read ModuleComponents table");
346 }
347
348 // read module dependencies
349 if (fModuleDependencyTable)
350 {
351 hr = KeyPairsRead(vcsModuleDependencyQuery, &pModDepList);
352 ExitOnFailure(hr, "Failed to read ModuleDependency table");
353 }
354
355 // read assemblies
356 hr = AssembliesRead(pModCompList, pAppList, pAppRoleList, pAsmList);
357 ExitOnFailure(hr, "Failed to read ComPlusAssembly table");
358
359 // read assembly dependencies
360 if (CpiTableExists(cptComPlusAssemblyDependency))
361 {
362 hr = KeyPairsRead(vcsAssemblyDependencyQuery, &pAsmDepList);
363 ExitOnFailure(hr, "Failed to read ComPlusAssemblyDependency table");
364 }
365
366 // sort modules
367 if (modList.pFirst && pModDepList)
368 {
369 hr = TopSortModuleList(pModDepList, &modList);
370 ExitOnFailure(hr, "Failed to sort modules");
371 }
372
373 // sort assemblies by module
374 if (pAsmList->pFirst && modList.pFirst && pModDepList)
375 SortAssemblyListByModule(&modList, pAsmList);
376
377 // sort assemblies by dependency
378 if (pAsmList->pFirst && pAsmDepList)
379 {
380 hr = TopSortAssemblyList(pAsmDepList, pAsmList);
381 ExitOnFailure(hr, "Failed to sort assemblies");
382 }
383
384 hr = S_OK;
385
386LExit:
387 // clean up
388 ModuleListFree(&modList);
389 if (pModCompList)
390 KeyPairsFreeList(pModCompList);
391 if (pModDepList)
392 KeyPairsFreeList(pModDepList);
393 if (pAsmDepList)
394 KeyPairsFreeList(pAsmDepList);
395
396 return hr;
397}
398
399HRESULT CpiAssembliesVerifyInstall(
400 CPI_ASSEMBLY_LIST* pList
401 )
402{
403 HRESULT hr = S_OK;
404
405 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
406 {
407 // assemblies that are being installed
408 if (!pItm->fReferencedForInstall && !pItm->iRoleAssignmentsInstallCount && !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
409 continue;
410
411 // if the assembly is referensed, it must be installed
412 if ((pItm->fReferencedForInstall || pItm->iRoleAssignmentsInstallCount) && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
413 MessageExitOnFailure(hr = E_FAIL, msierrComPlusAssemblyDependency, "An assembly is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
414 }
415
416 hr = S_OK;
417
418LExit:
419 return hr;
420}
421
422HRESULT CpiAssembliesVerifyUninstall(
423 CPI_ASSEMBLY_LIST* pList
424 )
425{
426 HRESULT hr = S_OK;
427
428 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
429 {
430 // assemblies that are being uninstalled
431 if (!pItm->fReferencedForUninstall && !pItm->iRoleAssignmentsUninstallCount && (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction) && !WcaIsReInstalling(pItm->isInstalled, pItm->isAction)))
432 continue;
433
434 // if the application is not present, there is no need to remove the components
435 if (pItm->pApplication && pItm->pApplication->fObjectNotFound)
436 {
437 pItm->fIgnore = TRUE;
438 pList->iUninstallCount--; // elements with the fIgnore flag set will not be scheduled for uninstall
439 pList->iRoleUninstallCount--;
440 }
441 }
442
443 hr = S_OK;
444
445//LExit:
446 return hr;
447}
448
449HRESULT CpiAssembliesInstall(
450 CPI_ASSEMBLY_LIST* pList,
451 int iRunMode,
452 LPWSTR* ppwzActionData,
453 int* piProgress
454 )
455{
456 HRESULT hr = S_OK;
457
458 int iActionType;
459 int iCount = 0;
460
461 // add action text
462 hr = CpiAddActionTextToActionData(L"RegisterComPlusAssemblies", ppwzActionData);
463 ExitOnFailure(hr, "Failed to add action text to custom action data");
464
465 // assembly count
466 switch (iRunMode)
467 {
468 case rmDeferred:
469 iCount = pList->iInstallCount - pList->iCommitCount;
470 break;
471 case rmCommit:
472 iCount = pList->iCommitCount;
473 break;
474 case rmRollback:
475 iCount = pList->iInstallCount;
476 break;
477 }
478
479 // add assembly count to action data
480 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
481 ExitOnFailure(hr, "Failed to add count to custom action data");
482
483 // add assemblies to custom action data in forward order
484 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
485 {
486 // assemblies that are being installed, or contains roll assignments to install
487 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
488 continue;
489
490 // assemblies that are being installed must be scheduled during the right type of action
491 BOOL fRunInCommit = 0 != (pItm->iAttributes & aaRunInCommit);
492 if (((rmCommit == iRunMode && !fRunInCommit) || (rmDeferred == iRunMode && fRunInCommit)))
493 continue;
494
495 // action type
496 if (rmRollback == iRunMode)
497 {
498 if (CpiIsInstalled(pItm->isInstalled))
499 iActionType = atNoOp;
500 else
501 iActionType = atRemove;
502 }
503 else
504 iActionType = atCreate;
505
506 // add to action data
507 hr = AddAssemblyToActionData(pItm, TRUE, iActionType, COST_ASSEMBLY_REGISTER, ppwzActionData);
508 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
509 }
510
511 // add progress tics
512 if (piProgress)
513 *piProgress += COST_ASSEMBLY_REGISTER * iCount;
514
515 hr = S_OK;
516
517LExit:
518 return hr;
519}
520
521HRESULT CpiAssembliesUninstall(
522 CPI_ASSEMBLY_LIST* pList,
523 int iRunMode,
524 LPWSTR* ppwzActionData,
525 int* piProgress
526 )
527{
528 HRESULT hr = S_OK;
529
530 int iActionType;
531
532 // add action text
533 hr = CpiAddActionTextToActionData(L"UnregisterComPlusAssemblies", ppwzActionData);
534 ExitOnFailure(hr, "Failed to add action text to custom action data");
535
536 // add assembly count to action data
537 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
538 ExitOnFailure(hr, "Failed to add count to custom action data");
539
540 // add assemblies to custom action data in reverse order
541 for (CPI_ASSEMBLY* pItm = pList->pLast; pItm; pItm = pItm->pPrev)
542 {
543 // assemblies that are being uninstalled
544 if (pItm->fIgnore || (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction) && !WcaIsReInstalling(pItm->isInstalled, pItm->isAction)))
545 continue;
546
547 // action type
548 if (rmRollback == iRunMode)
549 iActionType = atCreate;
550 else
551 iActionType = atRemove;
552
553 // add to action data
554 hr = AddAssemblyToActionData(pItm, FALSE, iActionType, COST_ASSEMBLY_UNREGISTER, ppwzActionData);
555 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
556 }
557
558 // add progress tics
559 if (piProgress)
560 *piProgress += COST_ASSEMBLY_UNREGISTER * pList->iUninstallCount;
561
562 hr = S_OK;
563
564LExit:
565 return hr;
566}
567
568HRESULT CpiRoleAssignmentsInstall(
569 CPI_ASSEMBLY_LIST* pList,
570 int iRunMode,
571 LPWSTR* ppwzActionData,
572 int* piProgress
573 )
574{
575 HRESULT hr = S_OK;
576
577 int iActionType;
578 int iCount = 0;
579
580 // add action text
581 hr = CpiAddActionTextToActionData(L"AddComPlusRoleAssignments", ppwzActionData);
582 ExitOnFailure(hr, "Failed to add action text to custom action data");
583
584 // assembly count
585 switch (iRunMode)
586 {
587 case rmDeferred:
588 iCount = pList->iRoleInstallCount - pList->iRoleCommitCount;
589 break;
590 case rmCommit:
591 iCount = pList->iRoleCommitCount;
592 break;
593 case rmRollback:
594 iCount = pList->iRoleInstallCount;
595 break;
596 }
597
598 // add assembly count to action data
599 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
600 ExitOnFailure(hr, "Failed to add count to custom action data");
601
602 // add assemblies to custom action data in forward order
603 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
604 {
605 // assemblies that are being installed, or contains roll assignments to install
606 if (!pItm->iRoleAssignmentsInstallCount)
607 continue;
608
609 // assemblies that are being installed must be scheduled during the right type of action
610 BOOL fRunInCommit = 0 != (pItm->iAttributes & aaRunInCommit);
611 if (((rmCommit == iRunMode && !fRunInCommit) || (rmDeferred == iRunMode && fRunInCommit)))
612 continue;
613
614 // action type
615 if (rmRollback == iRunMode)
616 {
617 if (CpiIsInstalled(pItm->isInstalled))
618 iActionType = atNoOp;
619 else
620 iActionType = atRemove;
621 }
622 else
623 iActionType = atCreate;
624
625 // add to action data
626 hr = AddRoleAssignmentsToActionData(pItm, TRUE, iActionType, COST_ROLLASSIGNMENT_CREATE, ppwzActionData);
627 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
628
629 // add progress tics
630 if (piProgress)
631 *piProgress += COST_ROLLASSIGNMENT_CREATE * pItm->iRoleAssignmentsInstallCount;
632 }
633
634 hr = S_OK;
635
636LExit:
637 return hr;
638}
639
640HRESULT CpiRoleAssignmentsUninstall(
641 CPI_ASSEMBLY_LIST* pList,
642 int iRunMode,
643 LPWSTR* ppwzActionData,
644 int* piProgress
645 )
646{
647 HRESULT hr = S_OK;
648
649 int iActionType;
650
651 // add action text
652 hr = CpiAddActionTextToActionData(L"RemoveComPlusRoleAssignments", ppwzActionData);
653 ExitOnFailure(hr, "Failed to add action text to custom action data");
654
655 // add assembly count to action data
656 hr = WcaWriteIntegerToCaData(pList->iRoleUninstallCount, ppwzActionData);
657 ExitOnFailure(hr, "Failed to add count to custom action data");
658
659 // add assemblies to custom action data in reverse order
660 for (CPI_ASSEMBLY* pItm = pList->pLast; pItm; pItm = pItm->pPrev)
661 {
662 // assemblies that are being uninstalled
663 if (pItm->fIgnore || !pItm->iRoleAssignmentsUninstallCount)
664 continue;
665
666 // action type
667 if (rmRollback == iRunMode)
668 iActionType = atCreate;
669 else
670 iActionType = atRemove;
671
672 // add to action data
673 hr = AddRoleAssignmentsToActionData(pItm, FALSE, iActionType, COST_ROLLASSIGNMENT_DELETE, ppwzActionData);
674 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
675
676 // add progress tics
677 if (piProgress)
678 *piProgress += COST_ROLLASSIGNMENT_DELETE * pItm->iRoleAssignmentsUninstallCount;
679 }
680
681 hr = S_OK;
682
683LExit:
684 return hr;
685}
686
687HRESULT CpiGetSubscriptionsCollForComponent(
688 CPI_ASSEMBLY* pAsm,
689 CPISCHED_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 = CpiSchedGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", &pComp->piSubsColl);
717 ExitOnFailure(hr, "Failed to get subscriptions collection");
718 }
719
720 // return value
721 *ppiSubsColl = pComp->piSubsColl;
722 (*ppiSubsColl)->AddRef();
723
724 hr = S_OK;
725
726LExit:
727 // clean up
728 ReleaseObject(piCompColl);
729 ReleaseObject(piCompObj);
730
731 return hr;
732}
733
734
735// helper function definitions
736
737static HRESULT GetAssemblyName(
738 LPCWSTR pwzComponent,
739 LPWSTR* ppwzAssemblyName
740 )
741{
742 HRESULT hr = S_OK;
743
744 PMSIHANDLE hView, hRecKey, hRec;
745
746 LPWSTR pwzKey = NULL;
747
748 LPWSTR pwzName = NULL;
749 LPWSTR pwzVersion = NULL;
750 LPWSTR pwzCulture = NULL;
751 LPWSTR pwzPublicKeyToken = NULL;
752
753 // create parameter record
754 hRecKey = ::MsiCreateRecord(1);
755 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
756 hr = WcaSetRecordString(hRecKey, 1, pwzComponent);
757 ExitOnFailure(hr, "Failed to set record string");
758
759 // open view
760 hr = WcaOpenView(vcsMsiAssemblyNameQuery, &hView);
761 ExitOnFailure(hr, "Failed to open view on MsiAssemblyName table");
762 hr = WcaExecuteView(hView, hRecKey);
763 ExitOnFailure(hr, "Failed to execute view on MsiAssemblyName table");
764
765 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
766 {
767 // read key
768 hr = WcaGetRecordString(hRec, manqName, &pwzKey);
769 ExitOnFailure(hr, "Failed to get name");
770
771 // read value
772 if (0 == lstrcmpiW(L"name", pwzKey))
773 hr = WcaGetRecordString(hRec, manqValue, &pwzName);
774 else if (0 == lstrcmpiW(L"version", pwzKey))
775 hr = WcaGetRecordString(hRec, manqValue, &pwzVersion);
776 else if (0 == lstrcmpiW(L"culture", pwzKey))
777 hr = WcaGetRecordString(hRec, manqValue, &pwzCulture);
778 else if (0 == lstrcmpiW(L"publicKeyToken", pwzKey))
779 hr = WcaGetRecordString(hRec, manqValue, &pwzPublicKeyToken);
780 else
781 {
782 WcaLog(LOGMSG_VERBOSE, "Unknown name in MsiAssemblyName table: %S, %S", pwzComponent, pwzKey);
783 hr = S_OK;
784 }
785
786 ExitOnFailure(hr, "Failed to get value");
787 }
788
789 if (E_NOMOREITEMS != hr)
790 ExitOnFailure(hr, "Failed to fetch record");
791
792 // verify
793 if (!(pwzName && *pwzName) || !(pwzVersion && *pwzVersion))
794 ExitOnFailure(hr = E_FAIL, "Incomplete assembly name");
795
796 // build name string
797 hr = StrAllocFormatted(ppwzAssemblyName, L"%s, Version=%s, Culture=%s, PublicKeyToken=%s",
798 pwzName, pwzVersion,
799 pwzCulture && *pwzCulture ? pwzCulture : L"Neutral",
800 pwzPublicKeyToken && *pwzPublicKeyToken ? pwzPublicKeyToken : L"null");
801 ExitOnFailure(hr, "Failed to build assembly name string");
802
803 hr = S_OK;
804
805LExit:
806 // clean up
807 ReleaseStr(pwzKey);
808 ReleaseStr(pwzName);
809 ReleaseStr(pwzVersion);
810 ReleaseStr(pwzCulture);
811 ReleaseStr(pwzPublicKeyToken);
812
813 return hr;
814}
815
816static HRESULT KeyPairsRead(
817 LPCWSTR pwzQuery,
818 CPI_KEY_PAIR** ppKeyPairList
819 )
820{
821 HRESULT hr = S_OK;
822
823 PMSIHANDLE hView, hRec;
824
825 CPI_KEY_PAIR* pItm = NULL;
826 LPWSTR pwzData = NULL;
827
828 // loop through all dependencies
829 hr = WcaOpenExecuteView(pwzQuery, &hView);
830 ExitOnFailure(hr, "Failed to execute view on table");
831
832 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
833 {
834 // create entry
835 pItm = (CPI_KEY_PAIR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_KEY_PAIR));
836 if (!pItm)
837 ExitFunction1(hr = E_OUTOFMEMORY);
838
839 // get key
840 hr = WcaGetRecordString(hRec, kpqFirstKey, &pwzData);
841 ExitOnFailure(hr, "Failed to get first key");
842 StringCchCopyW(pItm->wzFirstKey, countof(pItm->wzFirstKey), pwzData);
843
844 // get key
845 hr = WcaGetRecordString(hRec, kpqSecondKey, &pwzData);
846 ExitOnFailure(hr, "Failed to get second key");
847 StringCchCopyW(pItm->wzSecondKey, countof(pItm->wzSecondKey), pwzData);
848
849 // add entry
850 if (*ppKeyPairList)
851 pItm->pNext = *ppKeyPairList;
852 *ppKeyPairList = pItm;
853 pItm = NULL;
854 }
855
856 if (E_NOMOREITEMS == hr)
857 hr = S_OK;
858
859LExit:
860 // clean up
861 if (pItm)
862 KeyPairsFreeList(pItm);
863
864 ReleaseStr(pwzData);
865
866 return hr;
867}
868
869static HRESULT ModulesRead(
870 CPI_MODULE_LIST* pModList
871 )
872{
873 HRESULT hr = S_OK;
874
875 PMSIHANDLE hView, hRec;
876
877 CPI_MODULE* pItm = NULL;
878 LPWSTR pwzData = NULL;
879
880 // loop through all modules
881 hr = WcaOpenExecuteView(vcsModuleQuery, &hView);
882 ExitOnFailure(hr, "Failed to execute view on ModuleSignature table");
883
884 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
885 {
886 // create entry
887 pItm = (CPI_MODULE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_MODULE));
888 if (!pItm)
889 ExitFunction1(hr = E_OUTOFMEMORY);
890
891 // get key
892 hr = WcaGetRecordString(hRec, mqModule, &pwzData);
893 ExitOnFailure(hr, "Failed to get key");
894 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
895
896 // add entry
897 if (pModList->pLast)
898 {
899 pModList->pLast->pNext = pItm;
900 pItm->pPrev = pModList->pLast;
901 }
902 else
903 pModList->pFirst = pItm;
904 pModList->pLast = pItm;
905 pItm = NULL;
906 }
907
908 if (E_NOMOREITEMS == hr)
909 hr = S_OK;
910
911LExit:
912 // clean up
913 if (pItm)
914 ModuleFree(pItm);
915
916 ReleaseStr(pwzData);
917
918 return hr;
919}
920
921static HRESULT AssembliesRead(
922 CPI_KEY_PAIR* pModCompList,
923 CPI_APPLICATION_LIST* pAppList,
924 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
925 CPI_ASSEMBLY_LIST* pAsmList
926 )
927{
928 HRESULT hr = S_OK;
929 UINT er = ERROR_SUCCESS;
930
931 PMSIHANDLE hView, hRec;
932
933 CPI_ASSEMBLY* pItm = NULL;
934 CPI_KEY_PAIR* pModComp;
935 LPWSTR pwzData = NULL;
936 LPWSTR pwzComponent = NULL;
937 BOOL fMatchingArchitecture = FALSE;
938
939 // loop through all assemblies
940 hr = WcaOpenExecuteView(vcsAssemblyQuery, &hView);
941 ExitOnFailure(hr, "Failed to execute view on ComPlusAssembly table");
942
943 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
944 {
945 // get component
946 hr = WcaGetRecordString(hRec, aqComponent, &pwzComponent);
947 ExitOnFailure(hr, "Failed to get component");
948
949 // check if the component is our processor architecture
950 hr = CpiVerifyComponentArchitecure(pwzComponent, &fMatchingArchitecture);
951 ExitOnFailure(hr, "Failed to get component architecture.");
952
953 if (!fMatchingArchitecture)
954 {
955 continue; // not the same architecture, ignore
956 }
957
958 // create entry
959 pItm = (CPI_ASSEMBLY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ASSEMBLY));
960 if (!pItm)
961 ExitFunction1(hr = E_OUTOFMEMORY);
962
963 // get component install state
964 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &pItm->isInstalled, &pItm->isAction);
965 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
966
967 // get key
968 hr = WcaGetRecordString(hRec, aqAssembly, &pwzData);
969 ExitOnFailure(hr, "Failed to get key");
970 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
971
972 // get attributes
973 hr = WcaGetRecordInteger(hRec, aqAttributes, &pItm->iAttributes);
974 ExitOnFailure(hr, "Failed to get attributes");
975
976 // get assembly name
977 hr = WcaGetRecordFormattedString(hRec, aqAssemblyName, &pItm->pwzAssemblyName);
978 ExitOnFailure(hr, "Failed to get assembly name");
979
980 if (!*pItm->pwzAssemblyName && (pItm->iAttributes & aaPathFromGAC))
981 {
982 // get assembly name for component
983 hr = GetAssemblyName(pwzComponent, &pItm->pwzAssemblyName);
984 ExitOnFailure(hr, "Failed to get assembly name for component");
985 }
986
987 // get dll path
988 hr = WcaGetRecordFormattedString(hRec, aqDllPath, &pItm->pwzDllPath);
989 ExitOnFailure(hr, "Failed to get assembly dll path");
990
991 // get module
992 // TODO: if there is a very large number of components belonging to modules, this search might be slow
993 hr = KeyPairFindByFirstKey(pModCompList, pwzData, &pModComp);
994
995 if (S_OK == hr)
996 StringCchCopyW(pItm->wzModule, countof(pItm->wzModule), pModComp->wzSecondKey);
997
998 // get application
999 hr = WcaGetRecordString(hRec, aqApplication, &pwzData);
1000 ExitOnFailure(hr, "Failed to get application");
1001
1002 if (pwzData && *pwzData)
1003 {
1004 hr = CpiApplicationFindByKey(pAppList, pwzData, &pItm->pApplication);
1005 if (S_FALSE == hr)
1006 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1007 ExitOnFailure(hr, "Failed to find application, key: %S", pwzData);
1008 }
1009
1010 // get tlb path
1011 hr = WcaGetRecordFormattedString(hRec, aqTlbPath, &pItm->pwzTlbPath);
1012 ExitOnFailure(hr, "Failed to get assembly tlb path");
1013
1014 // get proxy-stub dll path
1015 hr = WcaGetRecordFormattedString(hRec, aqPSDllPath, &pItm->pwzPSDllPath);
1016 ExitOnFailure(hr, "Failed to get assembly proxy-stub DLL path");
1017
1018 // read components
1019 if (CpiTableExists(cptComPlusComponent))
1020 {
1021 hr = ComponentsRead(pItm->wzKey, pAppRoleList, pItm);
1022 ExitOnFailure(hr, "Failed to read components for assembly");
1023 }
1024
1025 // set references & increment counters
1026 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1027 {
1028 pAsmList->iInstallCount++;
1029 if (pItm->iAttributes & aaRunInCommit)
1030 pAsmList->iCommitCount++;
1031 }
1032 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction) || WcaIsReInstalling(pItm->isInstalled, pItm->isAction))
1033 pAsmList->iUninstallCount++;
1034
1035 if (pItm->iRoleAssignmentsInstallCount)
1036 {
1037 pAsmList->iRoleInstallCount++;
1038 if (pItm->iAttributes & aaRunInCommit)
1039 pAsmList->iRoleCommitCount++;
1040 }
1041 if (pItm->iRoleAssignmentsUninstallCount)
1042 pAsmList->iRoleUninstallCount++;
1043
1044 if (pItm->pApplication)
1045 {
1046 if (pItm->iRoleAssignmentsInstallCount || WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1047 CpiApplicationAddReferenceInstall(pItm->pApplication);
1048 if (pItm->iRoleAssignmentsUninstallCount || WcaIsUninstalling(pItm->isInstalled, pItm->isAction) || WcaIsReInstalling(pItm->isInstalled, pItm->isAction))
1049 CpiApplicationAddReferenceUninstall(pItm->pApplication);
1050 }
1051
1052 // add entry
1053 if (pAsmList->pLast)
1054 {
1055 pAsmList->pLast->pNext = pItm;
1056 pItm->pPrev = pAsmList->pLast;
1057 }
1058 else
1059 pAsmList->pFirst = pItm;
1060 pAsmList->pLast = pItm;
1061 pItm = NULL;
1062 }
1063
1064 if (E_NOMOREITEMS == hr)
1065 hr = S_OK;
1066
1067LExit:
1068 // clean up
1069 if (pItm)
1070 AssemblyFree(pItm);
1071
1072 ReleaseStr(pwzData);
1073 ReleaseStr(pwzComponent);
1074
1075 return hr;
1076}
1077
1078static HRESULT TopSortModuleList(
1079 CPI_KEY_PAIR* pDepList,
1080 CPI_MODULE_LIST* pList
1081 )
1082{
1083 HRESULT hr = S_OK;
1084
1085 // top sort list
1086 for (CPI_MODULE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
1087 {
1088 // append module
1089 hr = SwapDependentModules(NULL, pDepList, pList, pItm, pItm);
1090 ExitOnFailure(hr, "Failed to swap dependent modules");
1091 }
1092
1093 hr = S_OK;
1094
1095LExit:
1096 return hr;
1097}
1098
1099static HRESULT SwapDependentModules(
1100 CPI_DEPENDENCY_CHAIN* pdcPrev, // list containing the entire dependency chain
1101 CPI_KEY_PAIR* pDepList, // module dependency list
1102 CPI_MODULE_LIST* pList, // module list being sorted
1103 CPI_MODULE* pRoot, // first module in the chain
1104 CPI_MODULE* pItm // current module to test for dependencies
1105 )
1106{
1107 HRESULT hr = S_OK;
1108
1109 CPI_MODULE* pDepItm;
1110
1111 // find dependencies
1112 for (CPI_KEY_PAIR* pDep = pDepList; pDep; pDep = pDep->pNext)
1113 {
1114 if (0 == lstrcmpW(pItm->wzKey, pDep->wzFirstKey))
1115 {
1116 CPI_DEPENDENCY_CHAIN dcItm;
1117 dcItm.pwzKey = pItm->wzKey;
1118 dcItm.pPrev = pdcPrev;
1119
1120 // check for circular dependencies
1121 for (CPI_DEPENDENCY_CHAIN* pdcItm = &dcItm; pdcItm; pdcItm = pdcItm->pPrev)
1122 {
1123 if (0 == lstrcmpW(pdcItm->pwzKey, pDep->wzSecondKey))
1124 {
1125 // circular dependency found
1126 ExitOnFailure(hr = E_FAIL, "Circular module dependency found, key: %S", pDep->wzSecondKey);
1127 }
1128 }
1129
1130 // make sure the item is not already in the list
1131 hr = ModuleFindByKey(pRoot->pPrev, pDep->wzSecondKey, TRUE, &pDepItm); // find in reverse order
1132
1133 if (S_OK == hr)
1134 continue; // item found, move on
1135
1136 // find item in the list
1137 hr = ModuleFindByKey(pRoot->pNext, pDep->wzSecondKey, FALSE, &pDepItm); // find in forward order
1138
1139 if (S_FALSE == hr)
1140 {
1141 // not found
1142 ExitOnFailure(hr = E_FAIL, "Module dependency not found, key: %S", pDep->wzSecondKey);
1143 }
1144
1145 // if this item in turn has dependencies, they have to be swaped first
1146 hr = SwapDependentModules(&dcItm, pDepList, pList, pRoot, pDepItm);
1147 ExitOnFailure(hr, "Failed to swap dependent module");
1148
1149 // remove item from its current position
1150 pDepItm->pPrev->pNext = pDepItm->pNext; // pDepItm can never be the first item, no need to check pPrev
1151 if (pDepItm->pNext)
1152 pDepItm->pNext->pPrev = pDepItm->pPrev;
1153 else
1154 {
1155 pList->pLast = pDepItm->pPrev;
1156 pList->pLast->pNext = NULL;
1157 }
1158
1159 // insert before the current item
1160 if (pRoot->pPrev)
1161 pRoot->pPrev->pNext = pDepItm;
1162 else
1163 pList->pFirst = pDepItm;
1164 pDepItm->pPrev = pRoot->pPrev;
1165 pRoot->pPrev = pDepItm;
1166 pDepItm->pNext = pRoot;
1167 }
1168 }
1169
1170 hr = S_OK;
1171
1172LExit:
1173 return hr;
1174}
1175
1176static HRESULT ModuleFindByKey(
1177 CPI_MODULE* pItm,
1178 LPCWSTR pwzKey,
1179 BOOL fReverse,
1180 CPI_MODULE** ppItm
1181 )
1182{
1183 for (; pItm; pItm = fReverse ? pItm->pPrev : pItm->pNext)
1184 {
1185 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
1186 {
1187 *ppItm = pItm;
1188 return S_OK;
1189 }
1190 }
1191
1192 return S_FALSE;
1193}
1194
1195static void SortAssemblyListByModule(
1196 CPI_MODULE_LIST* pModList,
1197 CPI_ASSEMBLY_LIST* pAsmList
1198 )
1199{
1200 CPI_ASSEMBLY* pMoved = NULL; // first moved item
1201
1202 // loop modules in reverse order
1203 for (CPI_MODULE* pMod = pModList->pLast; pMod; pMod = pMod->pPrev)
1204 {
1205 // loop assemblies in forward order, starting with the first unmoved item
1206 CPI_ASSEMBLY* pAsm = pMoved ? pMoved->pNext : pAsmList->pFirst;
1207 while (pAsm)
1208 {
1209 CPI_ASSEMBLY* pNext = pAsm->pNext;
1210
1211 // check if assembly belongs to the current module
1212 if (0 == lstrcmpW(pMod->wzKey, pAsm->wzModule))
1213 {
1214 // if the item is not already first in the list
1215 if (pAsm->pPrev)
1216 {
1217 // remove item from it's current position
1218 pAsm->pPrev->pNext = pAsm->pNext;
1219 if (pAsm->pNext)
1220 pAsm->pNext->pPrev = pAsm->pPrev;
1221 else
1222 pAsmList->pLast = pAsm->pPrev;
1223
1224 // insert item first in the list
1225 pAsmList->pFirst->pPrev = pAsm;
1226 pAsm->pNext = pAsmList->pFirst;
1227 pAsm->pPrev = NULL;
1228 pAsmList->pFirst = pAsm;
1229 }
1230
1231 // if we haven't moved any items yet, this is the first moved item
1232 if (!pMoved)
1233 pMoved = pAsm;
1234 }
1235
1236 pAsm = pNext;
1237 }
1238 }
1239}
1240
1241static HRESULT TopSortAssemblyList(
1242 CPI_KEY_PAIR* pDepList,
1243 CPI_ASSEMBLY_LIST* pList
1244 )
1245{
1246 HRESULT hr = S_OK;
1247
1248 // top sort list
1249 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
1250 {
1251 // append module
1252 hr = SwapDependentAssemblies(NULL, pDepList, pList, pItm, pItm);
1253 ExitOnFailure(hr, "Failed to swap dependent assemblies");
1254 }
1255
1256 hr = S_OK;
1257
1258LExit:
1259 return hr;
1260}
1261
1262static HRESULT SwapDependentAssemblies(
1263 CPI_DEPENDENCY_CHAIN* pdcPrev, // list containing the entire dependency chain
1264 CPI_KEY_PAIR* pDepList, // assembly dependency list
1265 CPI_ASSEMBLY_LIST* pList, // assembly list being sorted
1266 CPI_ASSEMBLY* pRoot, // first assembly in the chain
1267 CPI_ASSEMBLY* pItm // current assembly to test for dependencies
1268 )
1269{
1270 HRESULT hr = S_OK;
1271
1272 CPI_ASSEMBLY* pDepItm;
1273
1274 // find dependencies
1275 for (CPI_KEY_PAIR* pDep = pDepList; pDep; pDep = pDep->pNext)
1276 {
1277 if (0 == lstrcmpW(pItm->wzKey, pDep->wzFirstKey))
1278 {
1279 CPI_DEPENDENCY_CHAIN dcItm;
1280 dcItm.pwzKey = pItm->wzKey;
1281 dcItm.pPrev = pdcPrev;
1282
1283 // check for circular dependencies
1284 for (CPI_DEPENDENCY_CHAIN* pdcItm = &dcItm; pdcItm; pdcItm = pdcItm->pPrev)
1285 {
1286 if (0 == lstrcmpW(pdcItm->pwzKey, pDep->wzSecondKey))
1287 {
1288 // circular dependency found
1289 ExitOnFailure(hr = E_FAIL, "Circular assembly dependency found, key: %S", pDep->wzSecondKey);
1290 }
1291 }
1292
1293 // make sure the item is not already in the list
1294 hr = AssemblyFindByKey(pRoot->pPrev, pDep->wzSecondKey, TRUE, &pDepItm); // find in reverse order
1295
1296 if (S_OK == hr)
1297 continue; // item found, move on
1298
1299 // find item in the list
1300 hr = AssemblyFindByKey(pRoot->pNext, pDep->wzSecondKey, FALSE, &pDepItm); // find in forward order
1301
1302 if (S_FALSE == hr)
1303 {
1304 // not found
1305 ExitOnFailure(hr = E_FAIL, "Assembly dependency not found, key: %S", pDep->wzSecondKey);
1306 }
1307
1308 // if the root item belongs to a module, this item must also belong to the same module
1309 if (*pItm->wzModule)
1310 {
1311 if (0 != lstrcmpW(pDepItm->wzModule, pItm->wzModule))
1312 ExitOnFailure(hr = E_FAIL, "An assembly dependency can only exist between two assemblies not belonging to modules, or belonging to the same module. assembly: %S, required assembly: %S", pItm->wzKey, pDepItm->wzKey);
1313 }
1314
1315 // if this item in turn has dependencies, they have to be swaped first
1316 hr = SwapDependentAssemblies(&dcItm, pDepList, pList, pRoot, pDepItm);
1317 ExitOnFailure(hr, "Failed to swap dependent assemblies");
1318
1319 // remove item from its current position
1320 pDepItm->pPrev->pNext = pDepItm->pNext; // pDepItm can never be the first item, no need to check pPrev
1321 if (pDepItm->pNext)
1322 pDepItm->pNext->pPrev = pDepItm->pPrev;
1323 else
1324 {
1325 pList->pLast = pDepItm->pPrev;
1326 pList->pLast->pNext = NULL;
1327 }
1328
1329 // insert before the current item
1330 if (pRoot->pPrev)
1331 pRoot->pPrev->pNext = pDepItm;
1332 else
1333 pList->pFirst = pDepItm;
1334 pDepItm->pPrev = pRoot->pPrev;
1335 pRoot->pPrev = pDepItm;
1336 pDepItm->pNext = pRoot;
1337 }
1338 }
1339
1340 hr = S_OK;
1341
1342LExit:
1343 return hr;
1344}
1345
1346static HRESULT AssemblyFindByKey(
1347 CPI_ASSEMBLY* pItm,
1348 LPCWSTR pwzKey,
1349 BOOL fReverse,
1350 CPI_ASSEMBLY** ppItm
1351 )
1352{
1353 for (; pItm; pItm = fReverse ? pItm->pPrev : pItm->pNext)
1354 {
1355 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
1356 {
1357 *ppItm = pItm;
1358 return S_OK;
1359 }
1360 }
1361
1362 return S_FALSE;
1363}
1364
1365static HRESULT ComponentsRead(
1366 LPCWSTR pwzAsmKey,
1367 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1368 CPI_ASSEMBLY* pAsm
1369 )
1370{
1371 HRESULT hr = S_OK;
1372 PMSIHANDLE hView;
1373 PMSIHANDLE hRec;
1374 PMSIHANDLE hRecKey;
1375 CPISCHED_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 = (CPISCHED_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_COMPONENT));
1394 if (!pItm)
1395 ExitFunction1(hr = E_OUTOFMEMORY);
1396
1397 // get key
1398 hr = WcaGetRecordString(hRec, cqComponent, &pwzData);
1399 ExitOnFailure(hr, "Failed to get key");
1400 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1401
1402 // get clsid
1403 hr = WcaGetRecordFormattedString(hRec, cqCLSID, &pwzData);
1404 ExitOnFailure(hr, "Failed to get clsid");
1405 StringCchCopyW(pItm->wzCLSID, countof(pItm->wzCLSID), pwzData);
1406
1407 // read properties
1408 if (CpiTableExists(cptComPlusComponentProperty))
1409 {
1410 hr = CpiPropertiesRead(vcsComponentPropertyQuery, pItm->wzKey, pdlComponentProperties, &pItm->pProperties, &pItm->iPropertyCount);
1411 ExitOnFailure(hr, "Failed to get component properties");
1412 }
1413
1414 // read roles
1415 if (CpiTableExists(cptComPlusRoleForComponent))
1416 {
1417 hr = RoleAssignmentsRead(vcsRoleForComponentQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1418 ExitOnFailure(hr, "Failed to get roles for component");
1419 }
1420
1421 if (pItm->iRoleInstallCount)
1422 pAsm->iRoleAssignmentsInstallCount++;
1423 if (pItm->iRoleUninstallCount)
1424 pAsm->iRoleAssignmentsUninstallCount++;
1425
1426 // read interfaces
1427 if (CpiTableExists(cptComPlusInterface))
1428 {
1429 hr = InterfacesRead(pItm->wzKey, pAppRoleList, pAsm, pItm);
1430 ExitOnFailure(hr, "Failed to get interfaces for component");
1431 }
1432
1433 // add entry
1434 pAsm->iComponentCount++;
1435 if (pAsm->pComponents)
1436 pItm->pNext = pAsm->pComponents;
1437 pAsm->pComponents = pItm;
1438 pItm = NULL;
1439 }
1440
1441 if (E_NOMOREITEMS == hr)
1442 hr = S_OK;
1443
1444LExit:
1445 // clean up
1446 if (pItm)
1447 ComponentsFreeList(pItm);
1448
1449 ReleaseStr(pwzData);
1450
1451 return hr;
1452}
1453
1454static HRESULT InterfacesRead(
1455 LPCWSTR pwzCompKey,
1456 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1457 CPI_ASSEMBLY* pAsm,
1458 CPISCHED_COMPONENT* pComp
1459 )
1460{
1461 HRESULT hr = S_OK;
1462 PMSIHANDLE hView;
1463 PMSIHANDLE hRec;
1464 PMSIHANDLE hRecKey;
1465 CPISCHED_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 = (CPISCHED_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_INTERFACE));
1484 if (!pItm)
1485 ExitFunction1(hr = E_OUTOFMEMORY);
1486
1487 // get key
1488 hr = WcaGetRecordString(hRec, iqInterface, &pwzData);
1489 ExitOnFailure(hr, "Failed to get key");
1490 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1491
1492 // get iid
1493 hr = WcaGetRecordFormattedString(hRec, iqIID, &pwzData);
1494 ExitOnFailure(hr, "Failed to get iid");
1495 StringCchCopyW(pItm->wzIID, countof(pItm->wzIID), pwzData);
1496
1497 // read properties
1498 if (CpiTableExists(cptComPlusInterfaceProperty))
1499 {
1500 hr = CpiPropertiesRead(vcsInterfacePropertyQuery, pItm->wzKey, pdlInterfaceProperties, &pItm->pProperties, &pItm->iPropertyCount);
1501 ExitOnFailure(hr, "Failed to get interface properties");
1502 }
1503
1504 // read roles
1505 if (CpiTableExists(cptComPlusRoleForInterface))
1506 {
1507 hr = RoleAssignmentsRead(vcsRoleForInterfaceQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1508 ExitOnFailure(hr, "Failed to get roles for interface");
1509 }
1510
1511 if (pItm->iRoleInstallCount)
1512 pAsm->iRoleAssignmentsInstallCount++;
1513 if (pItm->iRoleUninstallCount)
1514 pAsm->iRoleAssignmentsUninstallCount++;
1515
1516 // read methods
1517 if (CpiTableExists(cptComPlusMethod))
1518 {
1519 hr = MethodsRead(pItm->wzKey, pAppRoleList, pAsm, pItm);
1520 ExitOnFailure(hr, "Failed to get methods for interface");
1521 }
1522
1523 // add entry
1524 pComp->iInterfaceCount++;
1525 if (pComp->pInterfaces)
1526 pItm->pNext = pComp->pInterfaces;
1527 pComp->pInterfaces = pItm;
1528 pItm = NULL;
1529 }
1530
1531 if (E_NOMOREITEMS == hr)
1532 hr = S_OK;
1533
1534LExit:
1535 // clean up
1536 if (pItm)
1537 InterfacesFreeList(pItm);
1538
1539 ReleaseStr(pwzData);
1540
1541 return hr;
1542}
1543
1544static HRESULT MethodsRead(
1545 LPCWSTR pwzIntfKey,
1546 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1547 CPI_ASSEMBLY* pAsm,
1548 CPISCHED_INTERFACE* pIntf
1549 )
1550{
1551 HRESULT hr = S_OK;
1552 PMSIHANDLE hView, hRec, hRecKey;
1553 CPISCHED_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 = (CPISCHED_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_METHOD));
1572 if (!pItm)
1573 ExitFunction1(hr = E_OUTOFMEMORY);
1574
1575 // get key
1576 hr = WcaGetRecordString(hRec, iqInterface, &pwzData);
1577 ExitOnFailure(hr, "Failed to get key");
1578 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1579
1580 // get index
1581 hr = WcaGetRecordFormattedString(hRec, mqIndex, &pwzData);
1582 ExitOnFailure(hr, "Failed to get index");
1583 StringCchCopyW(pItm->wzIndex, countof(pItm->wzIndex), pwzData);
1584
1585 // get name
1586 hr = WcaGetRecordFormattedString(hRec, mqName, &pwzData);
1587 ExitOnFailure(hr, "Failed to get name");
1588 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
1589
1590 // either an index or a name must be provided
1591 if (!*pItm->wzIndex && !*pItm->wzName)
1592 ExitOnFailure(hr = E_FAIL, "A method must have either an index or a name associated, key: %S", pItm->wzKey);
1593
1594 // read properties
1595 if (CpiTableExists(cptComPlusMethodProperty))
1596 {
1597 hr = CpiPropertiesRead(vcsMethodPropertyQuery, pItm->wzKey, pdlMethodProperties, &pItm->pProperties, &pItm->iPropertyCount);
1598 ExitOnFailure(hr, "Failed to get method properties");
1599 }
1600
1601 // read roles
1602 if (CpiTableExists(cptComPlusRoleForMethod))
1603 {
1604 hr = RoleAssignmentsRead(vcsRoleForMethodQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1605 ExitOnFailure(hr, "Failed to get roles for method");
1606 }
1607
1608 if (pItm->iRoleInstallCount)
1609 pAsm->iRoleAssignmentsInstallCount++;
1610 if (pItm->iRoleUninstallCount)
1611 pAsm->iRoleAssignmentsUninstallCount++;
1612
1613 // add entry
1614 pIntf->iMethodCount++;
1615 if (pIntf->pMethods)
1616 pItm->pNext = pIntf->pMethods;
1617 pIntf->pMethods = pItm;
1618 pItm = NULL;
1619 }
1620
1621 if (E_NOMOREITEMS == hr)
1622 hr = S_OK;
1623
1624LExit:
1625 // clean up
1626 if (pItm)
1627 MethodsFreeList(pItm);
1628
1629 ReleaseStr(pwzData);
1630
1631 return hr;
1632}
1633
1634static HRESULT RoleAssignmentsRead(
1635 LPCWSTR pwzQuery,
1636 LPCWSTR pwzKey,
1637 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1638 CPISCHED_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 CPISCHED_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 = (CPISCHED_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_ROLE_ASSIGNMENT));
1681 if (!pItm)
1682 ExitFunction1(hr = E_OUTOFMEMORY);
1683
1684 // get component install state
1685 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
1686 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
1687
1688 // get key
1689 hr = WcaGetRecordString(hRec, raqKey, &pwzData);
1690 ExitOnFailure(hr, "Failed to get key");
1691 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1692
1693 // get application role
1694 hr = WcaGetRecordString(hRec, raqApplicationRole, &pwzData);
1695 ExitOnFailure(hr, "Failed to get application role");
1696
1697 hr = CpiApplicationRoleFindByKey(pAppRoleList, pwzData, &pItm->pApplicationRole);
1698 if (S_FALSE == hr)
1699 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1700 ExitOnFailure(hr, "Failed to find application, key: %S", pwzData);
1701
1702 // set references & increment counters
1703 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1704 {
1705 CpiApplicationRoleAddReferenceInstall(pItm->pApplicationRole);
1706 ++*piInstallCount;
1707 }
1708 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
1709 {
1710 CpiApplicationRoleAddReferenceUninstall(pItm->pApplicationRole);
1711 ++*piUninstallCount;
1712 }
1713
1714 // add entry
1715 if (*ppRoleList)
1716 pItm->pNext = *ppRoleList;
1717 *ppRoleList = pItm;
1718 pItm = NULL;
1719 }
1720
1721 if (E_NOMOREITEMS == hr)
1722 hr = S_OK;
1723
1724LExit:
1725 // clean up
1726 if (pItm)
1727 RoleAssignmentsFreeList(pItm);
1728
1729 ReleaseStr(pwzData);
1730
1731 return hr;
1732}
1733
1734static HRESULT AddAssemblyToActionData(
1735 CPI_ASSEMBLY* pItm,
1736 BOOL fInstall,
1737 int iActionType,
1738 int iActionCost,
1739 LPWSTR* ppwzActionData
1740 )
1741{
1742 HRESULT hr = S_OK;
1743
1744 // add action information to custom action data
1745 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
1746 ExitOnFailure(hr, "Failed to add action type to custom action data");
1747 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
1748 ExitOnFailure(hr, "Failed to add action cost to custom action data");
1749
1750 // add assembly information to custom action data
1751 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
1752 ExitOnFailure(hr, "Failed to add assembly key to custom action data");
1753 hr = WcaWriteStringToCaData(pItm->pwzAssemblyName, ppwzActionData);
1754 ExitOnFailure(hr, "Failed to add assembly name to custom action data");
1755 hr = WcaWriteStringToCaData(pItm->pwzDllPath, ppwzActionData);
1756 ExitOnFailure(hr, "Failed to add assembly dll path to custom action data");
1757 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pwzTlbPath : L"", ppwzActionData);
1758 ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data");
1759 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pwzPSDllPath : L"", ppwzActionData);
1760 ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data");
1761 hr = WcaWriteIntegerToCaData(pItm->iAttributes, ppwzActionData);
1762 ExitOnFailure(hr, "Failed to add assembly attributes to custom action data");
1763
1764 // add application information to custom action data
1765 hr = WcaWriteStringToCaData(pItm->pApplication ? pItm->pApplication->wzID : L"", ppwzActionData);
1766 ExitOnFailure(hr, "Failed to add application id to custom action data");
1767
1768 // add partition information to custom action data
1769 LPCWSTR pwzPartID = pItm->pApplication && pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"";
1770 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
1771 ExitOnFailure(hr, "Failed to add partition id to custom action data");
1772
1773 // add components to custom action data
1774 //
1775 // components are needed acording to the following table:
1776 //
1777 // Native .NET
1778 // --------------------------------------------
1779 // NoOp | No | No
1780 // Create | Yes | Yes
1781 // Remove | Yes | No
1782 //
1783 int iCompCount = (atCreate == iActionType || (atRemove == iActionType && 0 == (pItm->iAttributes & aaDotNetAssembly))) ? pItm->iComponentCount : 0;
1784 hr = WcaWriteIntegerToCaData(iCompCount, ppwzActionData);
1785 ExitOnFailure(hr, "Failed to add component count to custom action data, key: %S", pItm->wzKey);
1786
1787 if (iCompCount)
1788 {
1789 for (CPISCHED_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext)
1790 {
1791 hr = AddComponentToActionData(pComp, fInstall, atCreate == iActionType, FALSE, ppwzActionData);
1792 ExitOnFailure(hr, "Failed to add component to custom action data, component: %S", pComp->wzKey);
1793 }
1794 }
1795
1796 hr = S_OK;
1797
1798LExit:
1799 return hr;
1800}
1801
1802static HRESULT AddRoleAssignmentsToActionData(
1803 CPI_ASSEMBLY* pItm,
1804 BOOL fInstall,
1805 int iActionType,
1806 int iActionCost,
1807 LPWSTR* ppwzActionData
1808 )
1809{
1810 HRESULT hr = S_OK;
1811
1812 // add action information to custom action data
1813 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
1814 ExitOnFailure(hr, "Failed to add action type to custom action data");
1815 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
1816 ExitOnFailure(hr, "Failed to add action cost to custom action data");
1817
1818 // add assembly information to custom action data
1819 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
1820 ExitOnFailure(hr, "Failed to add assembly key to custom action data");
1821 hr = WcaWriteIntegerToCaData(fInstall ? pItm->iRoleAssignmentsInstallCount : pItm->iRoleAssignmentsUninstallCount, ppwzActionData);
1822 ExitOnFailure(hr, "Failed to add role assignments count to custom action data");
1823
1824 // add application information to custom action data
1825 hr = WcaWriteStringToCaData(pItm->pApplication ? pItm->pApplication->wzID : L"", ppwzActionData);
1826 ExitOnFailure(hr, "Failed to add application id to custom action data");
1827
1828 // add partition information to custom action data
1829 LPCWSTR pwzPartID = pItm->pApplication && pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"";
1830 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
1831 ExitOnFailure(hr, "Failed to add partition id to custom action data");
1832
1833 // add components to custom action data
1834 hr = WcaWriteIntegerToCaData(pItm->iComponentCount, ppwzActionData);
1835 ExitOnFailure(hr, "Failed to add component count to custom action data");
1836
1837 for (CPISCHED_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext)
1838 {
1839 hr = AddComponentToActionData(pComp, fInstall, FALSE, TRUE, ppwzActionData);
1840 ExitOnFailure(hr, "Failed to add component to custom action data, component: %S", pComp->wzKey);
1841 }
1842
1843 hr = S_OK;
1844
1845LExit:
1846 return hr;
1847}
1848
1849static HRESULT AddComponentToActionData(
1850 CPISCHED_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 (CPISCHED_INTERFACE* pIntf = pItm->pInterfaces; pIntf; pIntf = pIntf->pNext)
1879 {
1880 hr = AddInterfaceToActionData(pIntf, fInstall, fProps, fRoles, ppwzActionData);
1881 ExitOnFailure(hr, "Failed to add interface custom action data, interface: %S", pIntf->wzKey);
1882 }
1883 }
1884
1885 hr = S_OK;
1886
1887LExit:
1888 return hr;
1889}
1890
1891static HRESULT AddInterfaceToActionData(
1892 CPISCHED_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 (CPISCHED_METHOD* pMeth = pItm->pMethods; pMeth; pMeth = pMeth->pNext)
1918 {
1919 hr = AddMethodToActionData(pMeth, fInstall, fProps, fRoles, ppwzActionData);
1920 ExitOnFailure(hr, "Failed to add method custom action data, method: %S", pMeth->wzKey);
1921 }
1922
1923 hr = S_OK;
1924
1925LExit:
1926 return hr;
1927}
1928
1929static HRESULT AddMethodToActionData(
1930 CPISCHED_METHOD* pItm,
1931 BOOL fInstall,
1932 BOOL fProps,
1933 BOOL fRoles,
1934 LPWSTR* ppwzActionData
1935 )
1936{
1937 HRESULT hr = S_OK;
1938
1939 // add interface information to custom action data
1940 hr = WcaWriteStringToCaData(pItm->wzIndex, ppwzActionData);
1941 ExitOnFailure(hr, "Failed to add method index to custom action data");
1942
1943 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
1944 ExitOnFailure(hr, "Failed to add method name to custom action data");
1945
1946 // add properties to custom action data
1947 hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
1948 ExitOnFailure(hr, "Failed to add properties to custom action data");
1949
1950 // add roles to custom action data
1951 hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData);
1952 ExitOnFailure(hr, "Failed to add roles to custom action data");
1953
1954 hr = S_OK;
1955
1956LExit:
1957 return hr;
1958}
1959
1960static HRESULT AddRolesToActionData(
1961 int iRoleInstallCount,
1962 int iRoleUninstallCount,
1963 CPISCHED_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 (CPISCHED_ROLE_ASSIGNMENT* pRole = pRoleList; pRole; pRole = pRole->pNext)
1978 {
1979 // make sure the install state matches the create flag
1980 if (fInstall ? !WcaIsInstalling(pRole->isInstalled, pRole->isAction) : !WcaIsUninstalling(pRole->isInstalled, pRole->isAction))
1981 continue;
1982
1983 hr = WcaWriteStringToCaData(pRole->pApplicationRole->wzKey, ppwzActionData);
1984 ExitOnFailure(hr, "Failed to add key to custom action data, role: %S", pRole->wzKey);
1985
1986 hr = WcaWriteStringToCaData(pRole->pApplicationRole->wzName, ppwzActionData);
1987 ExitOnFailure(hr, "Failed to add role name to custom action data, role: %S", pRole->wzKey);
1988 }
1989 }
1990
1991 hr = S_OK;
1992
1993LExit:
1994 return hr;
1995}
1996
1997static HRESULT KeyPairFindByFirstKey(
1998 CPI_KEY_PAIR* pList,
1999 LPCWSTR pwzKey,
2000 CPI_KEY_PAIR** ppItm
2001 )
2002{
2003 for (; pList; pList = pList->pNext)
2004 {
2005 if (0 == lstrcmpW(pList->wzFirstKey, pwzKey))
2006 {
2007 *ppItm = pList;
2008 return S_OK;
2009 }
2010 }
2011
2012 return S_FALSE;
2013}
2014
2015static void AssemblyFree(
2016 CPI_ASSEMBLY* pItm
2017 )
2018{
2019 ReleaseStr(pItm->pwzAssemblyName);
2020 ReleaseStr(pItm->pwzDllPath);
2021 ReleaseStr(pItm->pwzTlbPath);
2022 ReleaseStr(pItm->pwzPSDllPath);
2023
2024 if (pItm->pComponents)
2025 ComponentsFreeList(pItm->pComponents);
2026
2027 ::HeapFree(::GetProcessHeap(), 0, pItm);
2028}
2029
2030static void KeyPairsFreeList(
2031 CPI_KEY_PAIR* pList
2032 )
2033{
2034 while (pList)
2035 {
2036 CPI_KEY_PAIR* pDelete = pList;
2037 pList = pList->pNext;
2038 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2039 }
2040}
2041
2042void ModuleListFree(
2043 CPI_MODULE_LIST* pList
2044 )
2045{
2046 CPI_MODULE* pItm = pList->pFirst;
2047
2048 while (pItm)
2049 {
2050 CPI_MODULE* pDelete = pItm;
2051 pItm = pItm->pNext;
2052 ModuleFree(pDelete);
2053 }
2054}
2055
2056static void ModuleFree(
2057 CPI_MODULE* pItm
2058 )
2059{
2060 ::HeapFree(::GetProcessHeap(), 0, pItm);
2061}
2062
2063static void ComponentsFreeList(
2064 CPISCHED_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 CPISCHED_COMPONENT* pDelete = pList;
2081 pList = pList->pNext;
2082 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2083 }
2084}
2085
2086static void InterfacesFreeList(
2087 CPISCHED_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 CPISCHED_INTERFACE* pDelete = pList;
2102 pList = pList->pNext;
2103 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2104 }
2105}
2106
2107static void MethodsFreeList(
2108 CPISCHED_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 CPISCHED_METHOD* pDelete = pList;
2120 pList = pList->pNext;
2121 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2122 }
2123}
2124
2125static void RoleAssignmentsFreeList(
2126 CPISCHED_ROLE_ASSIGNMENT* pList
2127 )
2128{
2129 while (pList)
2130 {
2131 CPISCHED_ROLE_ASSIGNMENT* pDelete = pList;
2132 pList = pList->pNext;
2133 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2134 }
2135}
diff --git a/src/ext/ComPlus/ca/cpasmsched.h b/src/ext/ComPlus/ca/cpasmsched.h
new file mode 100644
index 00000000..ddf4b6c0
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpasmsched.h
@@ -0,0 +1,168 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5enum eAssemblyAttributes
6{
7 aaEventClass = (1 << 0),
8 aaDotNetAssembly = (1 << 1),
9 aaPathFromGAC = (1 << 2),
10 aaRunInCommit = (1 << 3)
11};
12
13
14// structs
15
16struct CPISCHED_ROLE_ASSIGNMENT
17{
18 WCHAR wzKey[MAX_DARWIN_KEY + 1];
19
20 INSTALLSTATE isInstalled, isAction;
21
22 CPI_APPLICATION_ROLE* pApplicationRole;
23
24 CPISCHED_ROLE_ASSIGNMENT* pNext;
25};
26
27struct CPISCHED_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 CPISCHED_ROLE_ASSIGNMENT* pRoles;
39
40 CPISCHED_METHOD* pNext;
41};
42
43struct CPISCHED_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 CPISCHED_ROLE_ASSIGNMENT* pRoles;
54
55 int iMethodCount;
56 CPISCHED_METHOD* pMethods;
57
58 CPISCHED_INTERFACE* pNext;
59};
60
61struct CPISCHED_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 CPISCHED_ROLE_ASSIGNMENT* pRoles;
72
73 int iInterfaceCount;
74 CPISCHED_INTERFACE* pInterfaces;
75
76 ICatalogCollection* piSubsColl;
77
78 CPISCHED_COMPONENT* pNext;
79};
80
81struct CPI_ASSEMBLY
82{
83 WCHAR wzKey[MAX_DARWIN_KEY + 1];
84 WCHAR wzModule[MAX_DARWIN_KEY + 1];
85 LPWSTR pwzAssemblyName;
86 LPWSTR pwzDllPath;
87 LPWSTR pwzTlbPath;
88 LPWSTR pwzPSDllPath;
89 int iAttributes;
90
91 int iComponentCount;
92 CPISCHED_COMPONENT* pComponents;
93
94 BOOL fReferencedForInstall;
95 BOOL fReferencedForUninstall;
96 BOOL fIgnore;
97
98 int iRoleAssignmentsInstallCount;
99 int iRoleAssignmentsUninstallCount;
100
101 INSTALLSTATE isInstalled, isAction;
102
103 CPI_APPLICATION* pApplication;
104
105 CPI_ASSEMBLY* pPrev;
106 CPI_ASSEMBLY* pNext;
107};
108
109struct CPI_ASSEMBLY_LIST
110{
111 CPI_ASSEMBLY* pFirst;
112 CPI_ASSEMBLY* pLast;
113
114 int iInstallCount;
115 int iCommitCount;
116 int iUninstallCount;
117
118 int iRoleInstallCount;
119 int iRoleCommitCount;
120 int iRoleUninstallCount;
121};
122
123
124// function prototypes
125
126void CpiAssemblyListFree(
127 CPI_ASSEMBLY_LIST* pList
128 );
129HRESULT CpiAssembliesRead(
130 CPI_APPLICATION_LIST* pAppList,
131 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
132 CPI_ASSEMBLY_LIST* pAsmList
133 );
134HRESULT CpiAssembliesVerifyInstall(
135 CPI_ASSEMBLY_LIST* pList
136 );
137HRESULT CpiAssembliesVerifyUninstall(
138 CPI_ASSEMBLY_LIST* pList
139 );
140HRESULT CpiAssembliesInstall(
141 CPI_ASSEMBLY_LIST* pList,
142 int iRunMode,
143 LPWSTR* ppwzActionData,
144 int* piProgress
145 );
146HRESULT CpiAssembliesUninstall(
147 CPI_ASSEMBLY_LIST* pList,
148 int iRunMode,
149 LPWSTR* ppwzActionData,
150 int* piProgress
151 );
152HRESULT CpiRoleAssignmentsInstall(
153 CPI_ASSEMBLY_LIST* pList,
154 int iRunMode,
155 LPWSTR* ppwzActionData,
156 int* piProgress
157 );
158HRESULT CpiRoleAssignmentsUninstall(
159 CPI_ASSEMBLY_LIST* pList,
160 int iRunMode,
161 LPWSTR* ppwzActionData,
162 int* piProgress
163 );
164HRESULT CpiGetSubscriptionsCollForComponent(
165 CPI_ASSEMBLY* pAsm,
166 CPISCHED_COMPONENT* pComp,
167 ICatalogCollection** ppiSubsColl
168 );
diff --git a/src/ext/ComPlus/ca/cpcost.h b/src/ext/ComPlus/ca/cpcost.h
new file mode 100644
index 00000000..7a23e03b
--- /dev/null
+++ b/src/ext/ComPlus/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/ext/ComPlus/ca/cpexec.cpp b/src/ext/ComPlus/ca/cpexec.cpp
new file mode 100644
index 00000000..9b1691fc
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpexec.cpp
@@ -0,0 +1,681 @@
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 ComPlusPrepare - CUSTOM ACTION ENTRY POINT
7
8 Input: deferred CustomActionData - ComPlusPrepare
9********************************************************************/
10extern "C" UINT __stdcall ComPlusPrepare(MSIHANDLE hInstall)
11{
12 HRESULT hr = S_OK;
13 UINT er = ERROR_SUCCESS;
14
15 LPWSTR pwzCustomActionData = NULL;
16 LPWSTR pwzData = NULL;
17
18 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
19
20 // initialize
21 hr = WcaInitialize(hInstall, "ComPlusPrepare");
22 ExitOnFailure(hr, "Failed to initialize ComPlusPrepare");
23
24 // get custom action data
25 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
26 ExitOnFailure(hr, "Failed to get CustomActionData");
27 pwzData = pwzCustomActionData;
28
29 // create rollback file
30 hRollbackFile = ::CreateFileW(pwzData, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
31 if (INVALID_HANDLE_VALUE == hRollbackFile)
32 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to create rollback file, name: %S", pwzData);
33
34 hr = S_OK;
35
36LExit:
37 // clean up
38 ReleaseStr(pwzCustomActionData);
39
40 if (INVALID_HANDLE_VALUE != hRollbackFile)
41 ::CloseHandle(hRollbackFile);
42
43 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
44 return WcaFinalize(er);
45}
46
47/********************************************************************
48 ComPlusCleanup - CUSTOM ACTION ENTRY POINT
49
50 Input: deferred CustomActionData - ComPlusCleanup
51********************************************************************/
52extern "C" UINT __stdcall ComPlusCleanup(MSIHANDLE hInstall)
53{
54 HRESULT hr = S_OK;
55 UINT er = ERROR_SUCCESS;
56
57 LPWSTR pwzCustomActionData = NULL;
58 LPWSTR pwzData = NULL;
59
60 // initialize
61 hr = WcaInitialize(hInstall, "ComPlusCleanup");
62 ExitOnFailure(hr, "Failed to initialize ComPlusCleanup");
63
64 // get custom action data
65 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
66 ExitOnFailure(hr, "Failed to get CustomActionData");
67 pwzData = pwzCustomActionData;
68
69 // delete rollback file
70 if (!::DeleteFileW(pwzData))
71 {
72 // error, but not a showstopper
73 hr = HRESULT_FROM_WIN32(::GetLastError());
74 WcaLog(LOGMSG_STANDARD, "Failed to delete rollback file, hr: 0x%x, name: %S", hr, pwzData);
75 }
76
77 hr = S_OK;
78
79LExit:
80 // clean up
81 ReleaseStr(pwzCustomActionData);
82
83 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
84 return WcaFinalize(er);
85}
86
87/********************************************************************
88 ComPlusInstallExecute - CUSTOM ACTION ENTRY POINT
89
90 Input: deferred CustomActionData - ComPlusInstallExecute
91********************************************************************/
92extern "C" UINT __stdcall ComPlusInstallExecute(MSIHANDLE hInstall)
93{
94 HRESULT hr = S_OK;
95 UINT er = ERROR_SUCCESS;
96
97 LPWSTR pwzCustomActionData = NULL;
98 LPWSTR pwzData = NULL;
99 LPWSTR pwzRollbackFileName = NULL;
100
101 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
102
103 BOOL fInitializedCom = FALSE;
104
105 // initialize
106 hr = WcaInitialize(hInstall, "ComPlusInstallExecute");
107 ExitOnFailure(hr, "Failed to initialize ComPlusInstallExecute");
108
109 hr = ::CoInitialize(NULL);
110 ExitOnFailure(hr, "Failed to initialize COM");
111 fInitializedCom = TRUE;
112
113 CpiExecInitialize();
114
115 // get custom action data
116 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
117 ExitOnFailure(hr, "Failed to get CustomActionData");
118 pwzData = pwzCustomActionData;
119
120 // open rollback file
121 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
122 ExitOnFailure(hr, "Failed to read rollback file name");
123
124 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
125 if (INVALID_HANDLE_VALUE == hRollbackFile)
126 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
127
128 // create partitions
129 hr = CpiConfigurePartitions(&pwzData, hRollbackFile);
130 ExitOnFailure(hr, "Failed to create partitions");
131 if (S_FALSE == hr) ExitFunction();
132
133 // create users in partition roles
134 hr = CpiConfigureUsersInPartitionRoles(&pwzData, hRollbackFile);
135 ExitOnFailure(hr, "Failed to create users in partition roles");
136 if (S_FALSE == hr) ExitFunction();
137
138 // create partition users
139 hr = CpiConfigurePartitionUsers(&pwzData, hRollbackFile);
140 ExitOnFailure(hr, "Failed to add partition users");
141 if (S_FALSE == hr) ExitFunction();
142
143 // create applications
144 hr = CpiConfigureApplications(&pwzData, hRollbackFile);
145 ExitOnFailure(hr, "Failed to create applications");
146 if (S_FALSE == hr) ExitFunction();
147
148 // create application roles
149 hr = CpiConfigureApplicationRoles(&pwzData, hRollbackFile);
150 ExitOnFailure(hr, "Failed to create application roles");
151 if (S_FALSE == hr) ExitFunction();
152
153 // create users in application roles
154 hr = CpiConfigureUsersInApplicationRoles(&pwzData, hRollbackFile);
155 ExitOnFailure(hr, "Failed to create users in application roles");
156 if (S_FALSE == hr) ExitFunction();
157
158 // register assemblies
159 hr = CpiConfigureAssemblies(&pwzData, hRollbackFile);
160 ExitOnFailure(hr, "Failed to register assemblies");
161 if (S_FALSE == hr) ExitFunction();
162
163 // create role assignments
164 hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile);
165 ExitOnFailure(hr, "Failed to create role assignments");
166 if (S_FALSE == hr) ExitFunction();
167
168 // create subscriptions
169 hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile);
170 ExitOnFailure(hr, "Failed to create subscriptions");
171 if (S_FALSE == hr) ExitFunction();
172
173 hr = S_OK;
174
175LExit:
176 // clean up
177 ReleaseStr(pwzCustomActionData);
178 ReleaseStr(pwzRollbackFileName);
179
180 if (INVALID_HANDLE_VALUE != hRollbackFile)
181 ::CloseHandle(hRollbackFile);
182
183 // unitialize
184 CpiExecFinalize();
185
186 if (fInitializedCom)
187 ::CoUninitialize();
188
189 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
190 return WcaFinalize(er);
191}
192
193/********************************************************************
194 ComPlusInstallExecuteCommit - CUSTOM ACTION ENTRY POINT
195
196 Input: deferred CustomActionData - ComPlusInstallExecuteCommit
197********************************************************************/
198extern "C" UINT __stdcall ComPlusInstallExecuteCommit(MSIHANDLE hInstall)
199{
200 HRESULT hr = S_OK;
201 UINT er = ERROR_SUCCESS;
202
203 LPWSTR pwzCustomActionData = NULL;
204 LPWSTR pwzData = NULL;
205 LPWSTR pwzRollbackFileName = NULL;
206
207 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
208
209 BOOL fInitializedCom = FALSE;
210
211 // initialize
212 hr = WcaInitialize(hInstall, "ComPlusInstallExecuteCommit");
213 ExitOnFailure(hr, "Failed to initialize ComPlusInstallExecuteCommit");
214
215 hr = ::CoInitialize(NULL);
216 ExitOnFailure(hr, "Failed to initialize COM");
217 fInitializedCom = TRUE;
218
219 CpiExecInitialize();
220
221 // get custom action data
222 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
223 ExitOnFailure(hr, "Failed to get CustomActionData");
224 pwzData = pwzCustomActionData;
225
226 // open rollback file
227 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
228 ExitOnFailure(hr, "Failed to read rollback file name");
229
230 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
231 if (INVALID_HANDLE_VALUE == hRollbackFile)
232 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
233
234 if (INVALID_SET_FILE_POINTER == ::SetFilePointer(hRollbackFile, 0, NULL, FILE_END))
235 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set file pointer");
236
237 // register assemblies
238 hr = CpiConfigureAssemblies(&pwzData, hRollbackFile);
239 ExitOnFailure(hr, "Failed to register assemblies");
240 if (S_FALSE == hr) ExitFunction();
241
242 // create role assignments
243 hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile);
244 ExitOnFailure(hr, "Failed to create role assignments");
245 if (S_FALSE == hr) ExitFunction();
246
247 // create subscriptions
248 hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile);
249 ExitOnFailure(hr, "Failed to create subscriptions");
250 if (S_FALSE == hr) ExitFunction();
251
252 hr = S_OK;
253
254LExit:
255 // clean up
256 ReleaseStr(pwzCustomActionData);
257
258 if (INVALID_HANDLE_VALUE != hRollbackFile)
259 ::CloseHandle(hRollbackFile);
260
261 // unitialize
262 CpiExecFinalize();
263
264 if (fInitializedCom)
265 ::CoUninitialize();
266
267 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
268 return WcaFinalize(er);
269}
270
271/********************************************************************
272 ComPlusRollbackInstallExecute - CUSTOM ACTION ENTRY POINT
273
274 Input: deferred CustomActionData - ComPlusRollbackInstallExecute
275********************************************************************/
276extern "C" UINT __stdcall ComPlusRollbackInstallExecute(MSIHANDLE hInstall)
277{
278 HRESULT hr = S_OK;
279 UINT er = ERROR_SUCCESS;
280
281 LPWSTR pwzCustomActionData = NULL;
282 LPWSTR pwzData = NULL;
283 LPWSTR pwzRollbackFileName = NULL;
284
285 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
286
287 CPI_ROLLBACK_DATA* prdPartitions = NULL;
288 CPI_ROLLBACK_DATA* prdUsersInPartitionRoles = NULL;
289 CPI_ROLLBACK_DATA* prdPartitionUsers = NULL;
290 CPI_ROLLBACK_DATA* prdApplications = NULL;
291 CPI_ROLLBACK_DATA* prdApplicationRoles = NULL;
292 CPI_ROLLBACK_DATA* prdUsersApplicationRoles = NULL;
293 CPI_ROLLBACK_DATA* prdAssemblies = NULL;
294 CPI_ROLLBACK_DATA* prdRoleAssignments = NULL;
295 CPI_ROLLBACK_DATA* prdSubscriptions = NULL;
296
297 BOOL fInitializedCom = FALSE;
298
299 // initialize
300 hr = WcaInitialize(hInstall, "ComPlusRollbackInstallExecute");
301 ExitOnFailure(hr, "Failed to initialize ComPlusRollbackInstallExecute");
302
303 hr = ::CoInitialize(NULL);
304 ExitOnFailure(hr, "Failed to initialize COM");
305 fInitializedCom = TRUE;
306
307 CpiExecInitialize();
308
309 // get custom action data
310 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
311 ExitOnFailure(hr, "Failed to get CustomActionData");
312 pwzData = pwzCustomActionData;
313
314 // open rollback file
315 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
316 ExitOnFailure(hr, "Failed to read rollback file name");
317
318 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
319 if (INVALID_HANDLE_VALUE == hRollbackFile)
320 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
321
322 // read rollback data (execute)
323 hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitions);
324 ExitOnFailure(hr, "Failed to read partitions rollback data");
325 hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersInPartitionRoles);
326 ExitOnFailure(hr, "Failed to read users in partition roles rollback data");
327 hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitionUsers);
328 ExitOnFailure(hr, "Failed to read partition users rollback data");
329 hr = CpiReadRollbackDataList(hRollbackFile, &prdApplications);
330 ExitOnFailure(hr, "Failed to read applications rollback data");
331 hr = CpiReadRollbackDataList(hRollbackFile, &prdApplicationRoles);
332 ExitOnFailure(hr, "Failed to read application roles rollback data");
333 hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersApplicationRoles);
334 ExitOnFailure(hr, "Failed to read users in application roles rollback data");
335 hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies);
336 ExitOnFailure(hr, "Failed to read assemblies rollback data");
337 hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments);
338 ExitOnFailure(hr, "Failed to read role assignments rollback data");
339 hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions);
340 ExitOnFailure(hr, "Failed to read subscription rollback data");
341
342 // read rollback data (commit)
343 hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies);
344 ExitOnFailure(hr, "Failed to read assemblies rollback data (commit)");
345 hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments);
346 ExitOnFailure(hr, "Failed to read role assignments rollback data");
347 hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions);
348 ExitOnFailure(hr, "Failed to read subscription rollback data (commit)");
349
350 ::CloseHandle(hRollbackFile);
351 hRollbackFile = INVALID_HANDLE_VALUE;
352
353 // rollback create subscriptions
354 hr = CpiRollbackConfigureSubscriptions(&pwzData, prdSubscriptions);
355 ExitOnFailure(hr, "Failed to rollback create subscriptions");
356
357 // rollback create role assignments
358 hr = CpiRollbackConfigureRoleAssignments(&pwzData, prdRoleAssignments);
359 ExitOnFailure(hr, "Failed to rollback create role assignments");
360
361 // rollback register assemblies
362 hr = CpiRollbackConfigureAssemblies(&pwzData, prdAssemblies);
363 ExitOnFailure(hr, "Failed to rollback register assemblies");
364
365 // rollback create users in application roles
366 hr = CpiRollbackConfigureUsersInApplicationRoles(&pwzData, prdUsersApplicationRoles);
367 ExitOnFailure(hr, "Failed to rollback create users in application roles");
368
369 // rollback create application roles
370 hr = CpiRollbackConfigureApplicationRoles(&pwzData, prdApplicationRoles);
371 ExitOnFailure(hr, "Failed to rollback create application roles");
372
373 // rollback create applications
374 hr = CpiRollbackConfigureApplications(&pwzData, prdApplications);
375 ExitOnFailure(hr, "Failed to rollback create applications");
376
377 // rollback create partition users
378 hr = CpiRollbackConfigurePartitionUsers(&pwzData, prdPartitionUsers);
379 ExitOnFailure(hr, "Failed to rollback create partition users");
380
381 // rollback create users in partition roles
382 hr = CpiRollbackConfigureUsersInPartitionRoles(&pwzData, prdUsersInPartitionRoles);
383 ExitOnFailure(hr, "Failed to rollback create users in partition roles");
384
385 // rollback create partitions
386 hr = CpiRollbackConfigurePartitions(&pwzData, prdPartitions);
387 ExitOnFailure(hr, "Failed to rollback create partitions");
388
389 hr = S_OK;
390
391LExit:
392 // clean up
393 ReleaseStr(pwzCustomActionData);
394 ReleaseStr(pwzRollbackFileName);
395
396 if (INVALID_HANDLE_VALUE != hRollbackFile)
397 ::CloseHandle(hRollbackFile);
398
399 if (prdPartitions)
400 CpiFreeRollbackDataList(prdPartitions);
401 if (prdUsersInPartitionRoles)
402 CpiFreeRollbackDataList(prdUsersInPartitionRoles);
403 if (prdPartitionUsers)
404 CpiFreeRollbackDataList(prdPartitionUsers);
405 if (prdApplications)
406 CpiFreeRollbackDataList(prdApplications);
407 if (prdApplicationRoles)
408 CpiFreeRollbackDataList(prdApplicationRoles);
409 if (prdUsersApplicationRoles)
410 CpiFreeRollbackDataList(prdUsersApplicationRoles);
411 if (prdAssemblies)
412 CpiFreeRollbackDataList(prdAssemblies);
413 if (prdRoleAssignments)
414 CpiFreeRollbackDataList(prdRoleAssignments);
415 if (prdSubscriptions)
416 CpiFreeRollbackDataList(prdSubscriptions);
417
418 // unitialize
419 CpiExecFinalize();
420
421 if (fInitializedCom)
422 ::CoUninitialize();
423
424 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
425 return WcaFinalize(er);
426}
427
428/********************************************************************
429 ComPlusUninstallExecute - CUSTOM ACTION ENTRY POINT
430
431 Input: deferred CustomActionData - ComPlusUninstallExecute
432********************************************************************/
433extern "C" UINT __stdcall ComPlusUninstallExecute(MSIHANDLE hInstall)
434{
435 HRESULT hr = S_OK;
436 UINT er = ERROR_SUCCESS;
437
438 LPWSTR pwzCustomActionData = NULL;
439 LPWSTR pwzData = NULL;
440 LPWSTR pwzRollbackFileName = NULL;
441
442 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
443
444 BOOL fInitializedCom = FALSE;
445
446 // initialize
447 hr = WcaInitialize(hInstall, "ComPlusUninstallExecute");
448 ExitOnFailure(hr, "Failed to initialize ComPlusUninstallExecute");
449
450 hr = ::CoInitialize(NULL);
451 ExitOnFailure(hr, "Failed to initialize COM");
452 fInitializedCom = TRUE;
453
454 CpiExecInitialize();
455
456 // get custom action data
457 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
458 ExitOnFailure(hr, "Failed to get CustomActionData");
459 pwzData = pwzCustomActionData;
460
461 // open rollback file
462 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
463 ExitOnFailure(hr, "Failed to read rollback file name");
464
465 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
466 if (INVALID_HANDLE_VALUE == hRollbackFile)
467 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
468
469 // delete subscriptions
470 hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile);
471 ExitOnFailure(hr, "Failed to delete subscriptions");
472 if (S_FALSE == hr) ExitFunction();
473
474 // delete role assignments
475 hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile);
476 ExitOnFailure(hr, "Failed to delete role assignments");
477 if (S_FALSE == hr) ExitFunction();
478
479 // unregister assemblies
480 hr = CpiConfigureAssemblies(&pwzData, hRollbackFile);
481 ExitOnFailure(hr, "Failed to unregister assemblies");
482 if (S_FALSE == hr) ExitFunction();
483
484 // remove users in application roles
485 hr = CpiConfigureUsersInApplicationRoles(&pwzData, hRollbackFile);
486 ExitOnFailure(hr, "Failed to delete users in application roles");
487 if (S_FALSE == hr) ExitFunction();
488
489 // remove application roles
490 hr = CpiConfigureApplicationRoles(&pwzData, hRollbackFile);
491 ExitOnFailure(hr, "Failed to delete application roles");
492 if (S_FALSE == hr) ExitFunction();
493
494 // remove applications
495 hr = CpiConfigureApplications(&pwzData, hRollbackFile);
496 ExitOnFailure(hr, "Failed to remove applications");
497 if (S_FALSE == hr) ExitFunction();
498
499 // remove partition users
500 hr = CpiConfigurePartitionUsers(&pwzData, hRollbackFile);
501 ExitOnFailure(hr, "Failed to remove partition users");
502 if (S_FALSE == hr) ExitFunction();
503
504 // remove users in partition roles
505 hr = CpiConfigureUsersInPartitionRoles(&pwzData, hRollbackFile);
506 ExitOnFailure(hr, "Failed to delete users in partition roles");
507 if (S_FALSE == hr) ExitFunction();
508
509 // remove partitions
510 hr = CpiConfigurePartitions(&pwzData, hRollbackFile);
511 ExitOnFailure(hr, "Failed to delete partitions");
512 if (S_FALSE == hr) ExitFunction();
513
514 hr = S_OK;
515
516LExit:
517 // clean up
518 ReleaseStr(pwzCustomActionData);
519 ReleaseStr(pwzRollbackFileName);
520
521 if (INVALID_HANDLE_VALUE != hRollbackFile)
522 ::CloseHandle(hRollbackFile);
523
524 // unitialize
525 CpiExecFinalize();
526
527 if (fInitializedCom)
528 ::CoUninitialize();
529
530 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
531 return WcaFinalize(er);
532}
533
534/********************************************************************
535 ComPlusRollbackUninstallExecute - CUSTOM ACTION ENTRY POINT
536
537 Input: deferred CustomActionData - ComPlusRollbackUninstallExecute
538********************************************************************/
539extern "C" UINT __stdcall ComPlusRollbackUninstallExecute(MSIHANDLE hInstall)
540{
541 HRESULT hr = S_OK;
542 UINT er = ERROR_SUCCESS;
543
544 LPWSTR pwzCustomActionData = NULL;
545 LPWSTR pwzData = NULL;
546 LPWSTR pwzRollbackFileName = NULL;
547
548 HANDLE hRollbackFile = INVALID_HANDLE_VALUE;
549
550 CPI_ROLLBACK_DATA* prdPartitions = NULL;
551 CPI_ROLLBACK_DATA* prdUsersInPartitionRoles = NULL;
552 CPI_ROLLBACK_DATA* prdPartitionUsers = NULL;
553 CPI_ROLLBACK_DATA* prdApplications = NULL;
554 CPI_ROLLBACK_DATA* prdApplicationRoles = NULL;
555 CPI_ROLLBACK_DATA* prdUsersApplicationRoles = NULL;
556 CPI_ROLLBACK_DATA* prdAssemblies = NULL;
557 CPI_ROLLBACK_DATA* prdRoleAssignments = NULL;
558 CPI_ROLLBACK_DATA* prdSubscriptions = NULL;
559
560 BOOL fInitializedCom = FALSE;
561
562 // initialize
563 hr = WcaInitialize(hInstall, "ComPlusRollbackUninstallExecute");
564 ExitOnFailure(hr, "Failed to initialize ComPlusRollbackUninstallExecute");
565
566 hr = ::CoInitialize(NULL);
567 ExitOnFailure(hr, "Failed to initialize COM");
568 fInitializedCom = TRUE;
569
570 CpiExecInitialize();
571
572 // get custom action data
573 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
574 ExitOnFailure(hr, "Failed to get CustomActionData");
575 pwzData = pwzCustomActionData;
576
577 // open rollback file
578 hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName);
579 ExitOnFailure(hr, "Failed to read rollback file name");
580
581 hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
582 if (INVALID_HANDLE_VALUE == hRollbackFile)
583 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName);
584
585 // read rollback data
586 hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions);
587 ExitOnFailure(hr, "Failed to read subscription rollback data");
588 hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments);
589 ExitOnFailure(hr, "Failed to read role assignments rollback data");
590 hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies);
591 ExitOnFailure(hr, "Failed to read assemblies rollback data");
592 hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersApplicationRoles);
593 ExitOnFailure(hr, "Failed to read users in application roles rollback data");
594 hr = CpiReadRollbackDataList(hRollbackFile, &prdApplicationRoles);
595 ExitOnFailure(hr, "Failed to read application roles rollback data");
596 hr = CpiReadRollbackDataList(hRollbackFile, &prdApplications);
597 ExitOnFailure(hr, "Failed to read applications rollback data");
598 hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitionUsers);
599 ExitOnFailure(hr, "Failed to read partition users rollback data");
600 hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersInPartitionRoles);
601 ExitOnFailure(hr, "Failed to read users in partition roles rollback data");
602 hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitions);
603 ExitOnFailure(hr, "Failed to read partitions rollback data");
604
605 ::CloseHandle(hRollbackFile);
606 hRollbackFile = INVALID_HANDLE_VALUE;
607
608 // rollback remove partitions
609 hr = CpiRollbackConfigurePartitions(&pwzData, prdPartitions);
610 ExitOnFailure(hr, "Failed to rollback delete partitions");
611
612 // rollback remove users in partition roles
613 hr = CpiRollbackConfigureUsersInPartitionRoles(&pwzData, prdUsersInPartitionRoles);
614 ExitOnFailure(hr, "Failed to rollback delete users in partition roles");
615
616 // rollback remove partition users
617 hr = CpiRollbackConfigurePartitionUsers(&pwzData, prdPartitionUsers);
618 ExitOnFailure(hr, "Failed to rollback delete partition users");
619
620 // rollback remove applications
621 hr = CpiRollbackConfigureApplications(&pwzData, prdApplications);
622 ExitOnFailure(hr, "Failed to rollback delete applications");
623
624 // rollback remove application roles
625 hr = CpiRollbackConfigureApplicationRoles(&pwzData, prdApplicationRoles);
626 ExitOnFailure(hr, "Failed to rollback delete application roles");
627
628 // rollback remove users in application roles
629 hr = CpiRollbackConfigureUsersInApplicationRoles(&pwzData, prdUsersApplicationRoles);
630 ExitOnFailure(hr, "Failed to rollback delete users in application roles");
631
632 // rollback unregister assemblies
633 hr = CpiRollbackConfigureAssemblies(&pwzData, prdAssemblies);
634 ExitOnFailure(hr, "Failed to rollback unregister assemblies");
635
636 // rollback delete role assignments
637 hr = CpiRollbackConfigureRoleAssignments(&pwzData, prdAssemblies);
638 ExitOnFailure(hr, "Failed to rollback delete role assignments");
639
640 // rollback delete subscriptions
641 hr = CpiRollbackConfigureSubscriptions(&pwzData, prdSubscriptions);
642 ExitOnFailure(hr, "Failed to rollback delete subscriptions");
643
644 hr = S_OK;
645
646LExit:
647 // clean up
648 ReleaseStr(pwzCustomActionData);
649 ReleaseStr(pwzRollbackFileName);
650
651 if (INVALID_HANDLE_VALUE != hRollbackFile)
652 ::CloseHandle(hRollbackFile);
653
654 if (prdPartitions)
655 CpiFreeRollbackDataList(prdPartitions);
656 if (prdUsersInPartitionRoles)
657 CpiFreeRollbackDataList(prdUsersInPartitionRoles);
658 if (prdPartitionUsers)
659 CpiFreeRollbackDataList(prdPartitionUsers);
660 if (prdApplications)
661 CpiFreeRollbackDataList(prdApplications);
662 if (prdApplicationRoles)
663 CpiFreeRollbackDataList(prdApplicationRoles);
664 if (prdUsersApplicationRoles)
665 CpiFreeRollbackDataList(prdUsersApplicationRoles);
666 if (prdAssemblies)
667 CpiFreeRollbackDataList(prdAssemblies);
668 if (prdRoleAssignments)
669 CpiFreeRollbackDataList(prdRoleAssignments);
670 if (prdSubscriptions)
671 CpiFreeRollbackDataList(prdSubscriptions);
672
673 // unitialize
674 CpiExecFinalize();
675
676 if (fInitializedCom)
677 ::CoUninitialize();
678
679 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
680 return WcaFinalize(er);
681}
diff --git a/src/ext/ComPlus/ca/cppartexec.cpp b/src/ext/ComPlus/ca/cppartexec.cpp
new file mode 100644
index 00000000..673bdaf9
--- /dev/null
+++ b/src/ext/ComPlus/ca/cppartexec.cpp
@@ -0,0 +1,690 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_PARTITION_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzID;
14 LPWSTR pwzName;
15 CPI_PROPERTY* pPropList;
16};
17
18struct CPI_PARTITION_USER_ATTRIBUTES
19{
20 int iActionType;
21 int iActionCost;
22 LPWSTR pwzKey;
23 LPWSTR pwzAccount;
24 LPWSTR pwzPartID;
25};
26
27
28// prototypes for private helper functions
29
30static HRESULT ReadPartitionAttributes(
31 LPWSTR* ppwzData,
32 CPI_PARTITION_ATTRIBUTES* pAttrs
33 );
34static void FreePartitionAttributes(
35 CPI_PARTITION_ATTRIBUTES* pAttrs
36 );
37static HRESULT CreatePartition(
38 CPI_PARTITION_ATTRIBUTES* pAttrs
39 );
40static HRESULT RemovePartition(
41 CPI_PARTITION_ATTRIBUTES* pAttrs
42 );
43static HRESULT ReadPartitionUserAttributes(
44 LPWSTR* ppwzData,
45 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
46 );
47static void FreePartitionUserAttributes(
48 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
49 );
50static HRESULT CreatePartitionUser(
51 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
52 );
53static HRESULT RemovePartitionUser(
54 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
55 );
56
57
58// function definitions
59
60HRESULT CpiConfigurePartitions(
61 LPWSTR* ppwzData,
62 HANDLE hRollbackFile
63 )
64{
65 HRESULT hr = S_OK;
66
67 CPI_PARTITION_ATTRIBUTES attrs;
68 ::ZeroMemory(&attrs, sizeof(attrs));
69
70 // read action text
71 hr = CpiActionStartMessage(ppwzData, FALSE);
72 ExitOnFailure(hr, "Failed to send action start message");
73
74 // ger partition count
75 int iCnt = 0;
76 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
77 ExitOnFailure(hr, "Failed to read count");
78
79 // write count to rollback file
80 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
81 ExitOnFailure(hr, "Failed to write count to rollback file");
82
83 for (int i = 0; i < iCnt; i++)
84 {
85 // read partition attributes from CustomActionData
86 hr = ReadPartitionAttributes(ppwzData, &attrs);
87 ExitOnFailure(hr, "Failed to read attributes");
88
89 // progress message
90 hr = CpiActionDataMessage(1, attrs.pwzName);
91 ExitOnFailure(hr, "Failed to send progress messages");
92
93 if (S_FALSE == hr)
94 ExitFunction();
95
96 // write key to rollback file
97 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
98 ExitOnFailure(hr, "Failed to write key to rollback file");
99
100 // action
101 switch (attrs.iActionType)
102 {
103 case atCreate:
104 hr = CreatePartition(&attrs);
105 ExitOnFailure(hr, "Failed to create partition, key: %S", attrs.pwzKey);
106 break;
107 case atRemove:
108 hr = RemovePartition(&attrs);
109 ExitOnFailure(hr, "Failed to remove partition, key: %S", attrs.pwzKey);
110 break;
111 }
112
113 // write completion status to rollback file
114 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
115 ExitOnFailure(hr, "Failed to write completion status to rollback file");
116
117 // progress
118 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
119 ExitOnFailure(hr, "Failed to update progress");
120 }
121
122 hr = S_OK;
123
124LExit:
125 // clean up
126 FreePartitionAttributes(&attrs);
127
128 return hr;
129}
130
131HRESULT CpiRollbackConfigurePartitions(
132 LPWSTR* ppwzData,
133 CPI_ROLLBACK_DATA* pRollbackDataList
134 )
135{
136 HRESULT hr = S_OK;
137
138 int iRollbackStatus;
139
140 CPI_PARTITION_ATTRIBUTES attrs;
141 ::ZeroMemory(&attrs, sizeof(attrs));
142
143 // read action text
144 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
145 ExitOnFailure(hr, "Failed to send action start message");
146
147 // get count
148 int iCnt = 0;
149 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
150 ExitOnFailure(hr, "Failed to read count");
151
152 for (int i = 0; i < iCnt; i++)
153 {
154 // read partition attributes from CustomActionData
155 hr = ReadPartitionAttributes(ppwzData, &attrs);
156 ExitOnFailure(hr, "Failed to read attributes");
157
158 // rollback status
159 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
160
161 if (S_FALSE == hr)
162 continue; // not found, nothing to rollback
163
164 // progress message
165 hr = CpiActionDataMessage(1, attrs.pwzName);
166 ExitOnFailure(hr, "Failed to send progress messages");
167
168 if (S_FALSE == hr)
169 ExitFunction();
170
171 // action
172 switch (attrs.iActionType)
173 {
174 case atCreate:
175 hr = CreatePartition(&attrs);
176 if (FAILED(hr))
177 WcaLog(LOGMSG_STANDARD, "Failed to create partition, hr: 0x%x, key: %S", hr, attrs.pwzKey);
178 break;
179 case atRemove:
180 hr = RemovePartition(&attrs);
181 if (FAILED(hr))
182 WcaLog(LOGMSG_STANDARD, "Failed to remove partition, hr: 0x%x, key: %S", hr, attrs.pwzKey);
183 break;
184 }
185
186 // check rollback status
187 if (0 == iRollbackStatus)
188 continue; // operation did not complete, skip progress
189
190 // progress
191 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
192 ExitOnFailure(hr, "Failed to update progress");
193 }
194
195 hr = S_OK;
196
197LExit:
198 // clean up
199 FreePartitionAttributes(&attrs);
200
201 return hr;
202}
203
204HRESULT CpiConfigurePartitionUsers(
205 LPWSTR* ppwzData,
206 HANDLE hRollbackFile
207 )
208{
209 HRESULT hr = S_OK;
210
211 CPI_PARTITION_USER_ATTRIBUTES attrs;
212 ::ZeroMemory(&attrs, sizeof(attrs));
213
214 // read action text
215 hr = CpiActionStartMessage(ppwzData, FALSE);
216 ExitOnFailure(hr, "Failed to send action start message");
217
218 // ger partition count
219 int iCnt = 0;
220 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
221 ExitOnFailure(hr, "Failed to read count");
222
223 // write count to rollback file
224 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
225 ExitOnFailure(hr, "Failed to write count to rollback file");
226
227 for (int i = 0; i < iCnt; i++)
228 {
229 // read partition attributes from CustomActionData
230 hr = ReadPartitionUserAttributes(ppwzData, &attrs);
231 ExitOnFailure(hr, "Failed to read attributes");
232
233 // progress message
234 hr = CpiActionDataMessage(1, attrs.pwzAccount);
235 ExitOnFailure(hr, "Failed to send progress messages");
236
237 if (S_FALSE == hr)
238 ExitFunction();
239
240 // write key to rollback file
241 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
242 ExitOnFailure(hr, "Failed to write key to rollback file");
243
244 // action
245 switch (attrs.iActionType)
246 {
247 case atCreate:
248 hr = CreatePartitionUser(&attrs);
249 ExitOnFailure(hr, "Failed to create partition user, key: %S", attrs.pwzKey);
250 break;
251 case atRemove:
252 hr = RemovePartitionUser(&attrs);
253 ExitOnFailure(hr, "Failed to remove partition user, key: %S", attrs.pwzKey);
254 break;
255 }
256
257 // write completion status to rollback file
258 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
259 ExitOnFailure(hr, "Failed to write completion status to rollback file");
260
261 // progress
262 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
263 ExitOnFailure(hr, "Failed to update progress");
264 }
265
266 hr = S_OK;
267
268LExit:
269 // clean up
270 FreePartitionUserAttributes(&attrs);
271
272 return hr;
273}
274
275HRESULT CpiRollbackConfigurePartitionUsers(
276 LPWSTR* ppwzData,
277 CPI_ROLLBACK_DATA* pRollbackDataList
278 )
279{
280 HRESULT hr = S_OK;
281
282 int iRollbackStatus;
283
284 CPI_PARTITION_USER_ATTRIBUTES attrs;
285 ::ZeroMemory(&attrs, sizeof(attrs));
286
287 // read action text
288 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
289 ExitOnFailure(hr, "Failed to send action start message");
290
291 // get count
292 int iCnt = 0;
293 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
294 ExitOnFailure(hr, "Failed to read count");
295
296 for (int i = 0; i < iCnt; i++)
297 {
298 // read partition attributes from CustomActionData
299 hr = ReadPartitionUserAttributes(ppwzData, &attrs);
300 ExitOnFailure(hr, "Failed to read attributes");
301
302 // rollback status
303 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
304
305 if (S_FALSE == hr)
306 continue; // not found, nothing to rollback
307
308 // progress message
309 hr = CpiActionDataMessage(1, attrs.pwzAccount);
310 ExitOnFailure(hr, "Failed to send progress messages");
311
312 if (S_FALSE == hr)
313 ExitFunction();
314
315 // action
316 switch (attrs.iActionType)
317 {
318 case atCreate:
319 hr = CreatePartitionUser(&attrs);
320 ExitOnFailure(hr, "Failed to create partition user, key: %S", attrs.pwzKey);
321 break;
322 case atRemove:
323 hr = RemovePartitionUser(&attrs);
324 ExitOnFailure(hr, "Failed to remove partition user, key: %S", attrs.pwzKey);
325 break;
326 }
327
328 // check rollback status
329 if (0 == iRollbackStatus)
330 continue; // operation did not complete, skip progress
331
332 // progress
333 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
334 ExitOnFailure(hr, "Failed to update progress");
335 }
336
337 hr = S_OK;
338
339LExit:
340 // clean up
341 FreePartitionUserAttributes(&attrs);
342
343 return hr;
344}
345
346
347// helper function definitions
348
349static HRESULT ReadPartitionAttributes(
350 LPWSTR* ppwzData,
351 CPI_PARTITION_ATTRIBUTES* pAttrs
352 )
353{
354 HRESULT hr = S_OK;
355
356 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
357 ExitOnFailure(hr, "Failed to read action type");
358 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
359 ExitOnFailure(hr, "Failed to read action cost");
360 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
361 ExitOnFailure(hr, "Failed to read key");
362 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID);
363 ExitOnFailure(hr, "Failed to read id");
364 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
365 ExitOnFailure(hr, "Failed to read name");
366 hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList);
367 ExitOnFailure(hr, "Failed to read properties");
368
369 hr = S_OK;
370
371LExit:
372 return hr;
373}
374
375static void FreePartitionAttributes(
376 CPI_PARTITION_ATTRIBUTES* pAttrs
377 )
378{
379 ReleaseStr(pAttrs->pwzKey);
380 ReleaseStr(pAttrs->pwzID);
381 ReleaseStr(pAttrs->pwzName);
382
383 if (pAttrs->pPropList)
384 CpiFreePropertyList(pAttrs->pPropList);
385}
386
387static HRESULT CreatePartition(
388 CPI_PARTITION_ATTRIBUTES* pAttrs
389 )
390{
391 HRESULT hr = S_OK;
392
393 ICatalogCollection* piPartColl = NULL;
394 ICatalogObject* piPartObj = NULL;
395
396 long lChanges = 0;
397
398 // log
399 WcaLog(LOGMSG_VERBOSE, "Creating partition, key: %S", pAttrs->pwzKey);
400
401 // get partitions collection
402 hr = CpiExecGetPartitionsCollection(&piPartColl);
403 ExitOnFailure(hr, "Failed to get partitions collection");
404
405 // check if partition exists
406 hr = CpiFindCollectionObjectByStringKey(piPartColl, pAttrs->pwzID, &piPartObj);
407 ExitOnFailure(hr, "Failed to find partition");
408
409 if (S_FALSE == hr)
410 {
411 // create partition
412 hr = CpiAddCollectionObject(piPartColl, &piPartObj);
413 ExitOnFailure(hr, "Failed to add partition to collection");
414
415 hr = CpiPutCollectionObjectValue(piPartObj, L"ID", pAttrs->pwzID);
416 ExitOnFailure(hr, "Failed to set partition id property");
417
418 hr = CpiPutCollectionObjectValue(piPartObj, L"Name", pAttrs->pwzName);
419 ExitOnFailure(hr, "Failed to set partition name property");
420 }
421
422 // properties
423 hr = CpiPutCollectionObjectValues(piPartObj, pAttrs->pPropList);
424 ExitOnFailure(hr, "Failed to write properties");
425
426 // save changes
427 hr = piPartColl->SaveChanges(&lChanges);
428 if (COMADMIN_E_OBJECTERRORS == hr)
429 CpiLogCatalogErrorInfo();
430 ExitOnFailure(hr, "Failed to save changes");
431
432 // log
433 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
434
435 hr = S_OK;
436
437LExit:
438 // clean up
439 ReleaseObject(piPartColl);
440 ReleaseObject(piPartObj);
441
442 return hr;
443}
444
445static HRESULT RemovePartition(
446 CPI_PARTITION_ATTRIBUTES* pAttrs
447 )
448{
449 HRESULT hr = S_OK;
450
451 ICatalogCollection* piPartColl = NULL;
452
453 long lChanges = 0;
454
455 // log
456 WcaLog(LOGMSG_VERBOSE, "Removing partition, key: %S", pAttrs->pwzKey);
457
458 // get partitions collection
459 hr = CpiExecGetPartitionsCollection(&piPartColl);
460 ExitOnFailure(hr, "Failed to get partitions collection");
461
462 // remove
463 hr = CpiRemoveCollectionObject(piPartColl, pAttrs->pwzID, NULL, TRUE);
464 ExitOnFailure(hr, "Failed to remove partition");
465
466 if (S_FALSE == hr)
467 {
468 // partition not found
469 WcaLog(LOGMSG_VERBOSE, "Partition not found, nothing to delete, key: %S", pAttrs->pwzKey);
470 ExitFunction1(hr = S_OK);
471 }
472
473 // save changes
474 hr = piPartColl->SaveChanges(&lChanges);
475 if (COMADMIN_E_OBJECTERRORS == hr)
476 CpiLogCatalogErrorInfo();
477 ExitOnFailure(hr, "Failed to save changes");
478
479 // log
480 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
481
482 hr = S_OK;
483
484LExit:
485 // clean up
486 ReleaseObject(piPartColl);
487
488 return hr;
489}
490
491static HRESULT ReadPartitionUserAttributes(
492 LPWSTR* ppwzData,
493 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
494 )
495{
496 HRESULT hr = S_OK;
497
498 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
499 ExitOnFailure(hr, "Failed to read action type");
500 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
501 ExitOnFailure(hr, "Failed to read action cost");
502 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
503 ExitOnFailure(hr, "Failed to read key");
504 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount);
505 ExitOnFailure(hr, "Failed to read account name");
506 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
507 ExitOnFailure(hr, "Failed to read partition id");
508
509 hr = S_OK;
510
511LExit:
512 return hr;
513}
514
515static void FreePartitionUserAttributes(
516 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
517 )
518{
519 ReleaseStr(pAttrs->pwzKey);
520 ReleaseStr(pAttrs->pwzAccount);
521 ReleaseStr(pAttrs->pwzPartID);
522}
523
524static HRESULT CreatePartitionUser(
525 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
526 )
527{
528 HRESULT hr = S_OK;
529 UINT er = ERROR_SUCCESS;
530
531 ICatalogCollection* piUserColl = NULL;
532 ICatalogObject* piUserObj = NULL;
533
534 PSID pSid = NULL;
535 long lChanges = 0;
536
537 // log
538 WcaLog(LOGMSG_VERBOSE, "Setting default partition for user, key: %S", pAttrs->pwzKey);
539
540 // get partition users collection
541 hr = CpiGetPartitionUsersCollection(&piUserColl);
542 ExitOnFailure(hr, "Failed to get partition users collection");
543
544 // get SID for account
545 do {
546 er = ERROR_SUCCESS;
547 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
548 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
549 {
550 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
551 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
552 switch (er)
553 {
554 case IDABORT:
555 ExitFunction(); // exit with error code from CpiAccountNameToSid()
556 case IDRETRY:
557 break;
558 case IDIGNORE:
559 default:
560 ExitFunction1(hr = S_OK);
561 }
562 }
563 else
564 ExitOnFailure(hr, "Failed to get SID for account");
565 } while (IDRETRY == er);
566
567 // remove any existing entry
568 hr = CpiRemoveUserCollectionObject(piUserColl, pSid);
569 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
570 {
571 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
572 hr = S_FALSE;
573 }
574 else
575 ExitOnFailure(hr, "Failed to remove user");
576
577 if (S_OK == hr)
578 WcaLog(LOGMSG_VERBOSE, "Existing default partition for user was removed, key: %S", pAttrs->pwzKey);
579
580 // add partition user
581 hr = CpiAddCollectionObject(piUserColl, &piUserObj);
582 ExitOnFailure(hr, "Failed to add partition to collection");
583
584 hr = CpiPutCollectionObjectValue(piUserObj, L"AccountName", pAttrs->pwzAccount);
585 ExitOnFailure(hr, "Failed to set account name property");
586
587 hr = CpiPutCollectionObjectValue(piUserObj, L"DefaultPartitionID", pAttrs->pwzPartID);
588 ExitOnFailure(hr, "Failed to set default partition id property");
589
590 // save changes
591 hr = piUserColl->SaveChanges(&lChanges);
592 if (COMADMIN_E_OBJECTERRORS == hr)
593 CpiLogCatalogErrorInfo();
594 ExitOnFailure(hr, "Failed to save changes");
595
596 // log
597 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
598
599 hr = S_OK;
600
601LExit:
602 // clean up
603 ReleaseObject(piUserColl);
604 ReleaseObject(piUserObj);
605
606 if (pSid)
607 ::HeapFree(::GetProcessHeap(), 0, pSid);
608
609 return hr;
610}
611
612static HRESULT RemovePartitionUser(
613 CPI_PARTITION_USER_ATTRIBUTES* pAttrs
614 )
615{
616 HRESULT hr = S_OK;
617 UINT er = ERROR_SUCCESS;
618
619 ICatalogCollection* piUserColl = NULL;
620
621 PSID pSid = NULL;
622 long lChanges = 0;
623
624 // log
625 WcaLog(LOGMSG_VERBOSE, "Removing default partition for user, key: %S", pAttrs->pwzKey);
626
627 // get partition users collection
628 hr = CpiGetPartitionUsersCollection(&piUserColl);
629 ExitOnFailure(hr, "Failed to get partition users collection");
630
631 // get SID for account
632 do {
633 er = ERROR_SUCCESS;
634 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
635 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
636 {
637 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
638 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
639 switch (er)
640 {
641 case IDABORT:
642 ExitFunction(); // exit with error code from CpiAccountNameToSid()
643 case IDRETRY:
644 break;
645 case IDIGNORE:
646 default:
647 ExitFunction1(hr = S_OK);
648 }
649 }
650 else
651 ExitOnFailure(hr, "Failed to get SID for account");
652 } while (IDRETRY == er);
653
654 // remove
655 hr = CpiRemoveUserCollectionObject(piUserColl, pSid);
656 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
657 {
658 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
659 hr = S_FALSE;
660 }
661 else
662 ExitOnFailure(hr, "Failed to remove user");
663
664 if (S_FALSE == hr)
665 {
666 // user not found
667 WcaLog(LOGMSG_VERBOSE, "Default partition for user not found, nothing to delete, key: %S", pAttrs->pwzKey);
668 ExitFunction1(hr = S_OK);
669 }
670
671 // save changes
672 hr = piUserColl->SaveChanges(&lChanges);
673 if (COMADMIN_E_OBJECTERRORS == hr)
674 CpiLogCatalogErrorInfo();
675 ExitOnFailure(hr, "Failed to save changes");
676
677 // log
678 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
679
680 hr = S_OK;
681
682LExit:
683 // clean up
684 ReleaseObject(piUserColl);
685
686 if (pSid)
687 ::HeapFree(::GetProcessHeap(), 0, pSid);
688
689 return hr;
690}
diff --git a/src/ext/ComPlus/ca/cppartexec.h b/src/ext/ComPlus/ca/cppartexec.h
new file mode 100644
index 00000000..132a9f5a
--- /dev/null
+++ b/src/ext/ComPlus/ca/cppartexec.h
@@ -0,0 +1,20 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigurePartitions(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigurePartitions(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
13HRESULT CpiConfigurePartitionUsers(
14 LPWSTR* ppwzData,
15 HANDLE hRollbackFile
16 );
17HRESULT CpiRollbackConfigurePartitionUsers(
18 LPWSTR* ppwzData,
19 CPI_ROLLBACK_DATA* pRollbackDataList
20 );
diff --git a/src/ext/ComPlus/ca/cppartroleexec.cpp b/src/ext/ComPlus/ca/cppartroleexec.cpp
new file mode 100644
index 00000000..4a503c79
--- /dev/null
+++ b/src/ext/ComPlus/ca/cppartroleexec.cpp
@@ -0,0 +1,397 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzRoleName;
14 LPWSTR pwzAccount;
15 LPWSTR pwzPartID;
16};
17
18
19// prototypes for private helper functions
20
21static HRESULT ReadUserInPartitionRoleAttributes(
22 LPWSTR* ppwzData,
23 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
24 );
25static void FreeUserInPartitionRoleAttributes(
26 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
27 );
28static HRESULT CreateUserInPartitionRole(
29 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
30 );
31static HRESULT RemoveUserInPartitionRole(
32 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
33 );
34
35
36// function definitions
37
38HRESULT CpiConfigureUsersInPartitionRoles(
39 LPWSTR* ppwzData,
40 HANDLE hRollbackFile
41 )
42{
43 HRESULT hr = S_OK;
44
45 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES attrs;
46 ::ZeroMemory(&attrs, sizeof(attrs));
47
48 // read action text
49 hr = CpiActionStartMessage(ppwzData, FALSE);
50 ExitOnFailure(hr, "Failed to send action start message");
51
52 // ger count
53 int iCnt = 0;
54 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
55 ExitOnFailure(hr, "Failed to read count");
56
57 // write count to rollback file
58 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
59 ExitOnFailure(hr, "Failed to write count to rollback file");
60
61 for (int i = 0; i < iCnt; i++)
62 {
63 // read attributes from CustomActionData
64 hr = ReadUserInPartitionRoleAttributes(ppwzData, &attrs);
65 ExitOnFailure(hr, "Failed to read attributes");
66
67 // progress message
68 hr = CpiActionDataMessage(1, attrs.pwzRoleName);
69 ExitOnFailure(hr, "Failed to send progress messages");
70
71 if (S_FALSE == hr)
72 ExitFunction();
73
74 // write key to rollback file
75 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
76 ExitOnFailure(hr, "Failed to write key to rollback file");
77
78 // action
79 switch (attrs.iActionType)
80 {
81 case atCreate:
82 hr = CreateUserInPartitionRole(&attrs);
83 ExitOnFailure(hr, "Failed to add user to partition role, key: %S", attrs.pwzKey);
84 break;
85 case atRemove:
86 hr = RemoveUserInPartitionRole(&attrs);
87 ExitOnFailure(hr, "Failed to remove user from partition role, key: %S", attrs.pwzKey);
88 break;
89 }
90
91 // write completion status to rollback file
92 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
93 ExitOnFailure(hr, "Failed to write completion status to rollback file");
94
95 // progress
96 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
97 ExitOnFailure(hr, "Failed to update progress");
98 }
99
100 hr = S_OK;
101
102LExit:
103 // clean up
104 FreeUserInPartitionRoleAttributes(&attrs);
105
106 return hr;
107}
108
109HRESULT CpiRollbackConfigureUsersInPartitionRoles(
110 LPWSTR* ppwzData,
111 CPI_ROLLBACK_DATA* pRollbackDataList
112 )
113{
114 HRESULT hr = S_OK;
115
116 int iRollbackStatus;
117
118 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES attrs;
119 ::ZeroMemory(&attrs, sizeof(attrs));
120
121 // read action text
122 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
123 ExitOnFailure(hr, "Failed to send action start message");
124
125 // get count
126 int iCnt = 0;
127 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
128 ExitOnFailure(hr, "Failed to read count");
129
130 for (int i = 0; i < iCnt; i++)
131 {
132 // read attributes from CustomActionData
133 hr = ReadUserInPartitionRoleAttributes(ppwzData, &attrs);
134 ExitOnFailure(hr, "Failed to read attributes");
135
136 // rollback status
137 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
138
139 if (S_FALSE == hr)
140 continue; // not found, nothing to rollback
141
142 // progress message
143 hr = CpiActionDataMessage(1, attrs.pwzRoleName);
144 ExitOnFailure(hr, "Failed to send progress messages");
145
146 if (S_FALSE == hr)
147 ExitFunction();
148
149 // action
150 switch (attrs.iActionType)
151 {
152 case atCreate:
153 hr = CreateUserInPartitionRole(&attrs);
154 if (FAILED(hr))
155 WcaLog(LOGMSG_STANDARD, "Failed to add user to partition role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
156 break;
157 case atRemove:
158 hr = RemoveUserInPartitionRole(&attrs);
159 if (FAILED(hr))
160 WcaLog(LOGMSG_STANDARD, "Failed to remove user from partition role, hr: 0x%x, key: %S", hr, attrs.pwzKey);
161 break;
162 }
163
164 // check rollback status
165 if (0 == iRollbackStatus)
166 continue; // operation did not complete, skip progress
167
168 // progress
169 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
170 ExitOnFailure(hr, "Failed to update progress");
171 }
172
173 hr = S_OK;
174
175LExit:
176 // clean up
177 FreeUserInPartitionRoleAttributes(&attrs);
178
179 return hr;
180}
181
182
183// helper function definitions
184
185static HRESULT ReadUserInPartitionRoleAttributes(
186 LPWSTR* ppwzData,
187 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
188 )
189{
190 HRESULT hr = S_OK;
191
192 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
193 ExitOnFailure(hr, "Failed to read action type");
194 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
195 ExitOnFailure(hr, "Failed to read action cost");
196 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
197 ExitOnFailure(hr, "Failed to read key");
198 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzRoleName);
199 ExitOnFailure(hr, "Failed to read role name");
200 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount);
201 ExitOnFailure(hr, "Failed to read account name");
202 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
203 ExitOnFailure(hr, "Failed to read partition id");
204
205 hr = S_OK;
206
207LExit:
208 return hr;
209}
210
211static void FreeUserInPartitionRoleAttributes(
212 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
213 )
214{
215 ReleaseStr(pAttrs->pwzKey);
216 ReleaseStr(pAttrs->pwzRoleName);
217 ReleaseStr(pAttrs->pwzAccount);
218 ReleaseStr(pAttrs->pwzPartID);
219}
220
221static HRESULT CreateUserInPartitionRole(
222 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
223 )
224{
225 HRESULT hr = S_OK;
226 UINT er = ERROR_SUCCESS;
227
228 ICatalogCollection* piUsrInRoleColl = NULL;
229 ICatalogObject* piUsrInRoleObj = NULL;
230
231 PSID pSid = NULL;
232 long lChanges = 0;
233
234 // log
235 WcaLog(LOGMSG_VERBOSE, "Adding user to partition role, key: %S", pAttrs->pwzKey);
236
237 // get users in partition role collection
238 hr = CpiGetUsersInPartitionRoleCollection(pAttrs->pwzPartID, pAttrs->pwzRoleName, &piUsrInRoleColl);
239 if (S_FALSE == hr)
240 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
241 ExitOnFailure(hr, "Failed to get users in partition role collection");
242
243 // get SID for account
244 do {
245 er = ERROR_SUCCESS;
246 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
247 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
248 {
249 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
250 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
251 switch (er)
252 {
253 case IDABORT:
254 ExitFunction(); // exit with error code from CpiAccountNameToSid()
255 case IDRETRY:
256 break;
257 case IDIGNORE:
258 default:
259 ExitFunction1(hr = S_OK);
260 }
261 }
262 else
263 ExitOnFailure(hr, "Failed to get SID for account");
264 } while (IDRETRY == er);
265
266 // find any existing entry
267 hr = CpiFindUserCollectionObject(piUsrInRoleColl, pSid, NULL);
268 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
269 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
270 else
271 ExitOnFailure(hr, "Failed to find user in partition role");
272
273 if (S_OK == hr)
274 {
275 WcaLog(LOGMSG_VERBOSE, "User already assigned to partition role, key: %S", pAttrs->pwzKey);
276 ExitFunction(); // exit with hr = S_OK
277 }
278
279 // convert SID back to account name
280 hr = CpiSidToAccountName(pSid, &pAttrs->pwzAccount);
281 ExitOnFailure(hr, "Failed to convert SID to account name");
282
283 // add user
284 hr = CpiAddCollectionObject(piUsrInRoleColl, &piUsrInRoleObj);
285 ExitOnFailure(hr, "Failed to add user in role to collection");
286
287 hr = CpiPutCollectionObjectValue(piUsrInRoleObj, L"User", pAttrs->pwzAccount);
288 ExitOnFailure(hr, "Failed to set role name property");
289
290 // save changes
291 hr = piUsrInRoleColl->SaveChanges(&lChanges);
292 if (COMADMIN_E_OBJECTERRORS == hr)
293 CpiLogCatalogErrorInfo();
294 ExitOnFailure(hr, "Failed to save changes");
295
296 // log
297 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
298
299 hr = S_OK;
300
301LExit:
302 // clean up
303 ReleaseObject(piUsrInRoleColl);
304 ReleaseObject(piUsrInRoleObj);
305
306 if (pSid)
307 ::HeapFree(::GetProcessHeap(), 0, pSid);
308
309 return hr;
310}
311
312static HRESULT RemoveUserInPartitionRole(
313 CPI_USER_IN_PARTITION_ROLE_ATTRIBUTES* pAttrs
314 )
315{
316 HRESULT hr = S_OK;
317 UINT er = ERROR_SUCCESS;
318
319 ICatalogCollection* piUsrInRoleColl = NULL;
320
321 PSID pSid = NULL;
322 long lChanges = 0;
323
324 // log
325 WcaLog(LOGMSG_VERBOSE, "Removing user from partition role, key: %S", pAttrs->pwzKey);
326
327 // get users in partition role collection
328 hr = CpiGetUsersInPartitionRoleCollection(pAttrs->pwzPartID, pAttrs->pwzRoleName, &piUsrInRoleColl);
329 ExitOnFailure(hr, "Failed to get users in partition role collection");
330
331 if (S_FALSE == hr)
332 {
333 // users in role collection not found
334 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve users in partition role collection, nothing to delete, key: %S", pAttrs->pwzKey);
335 ExitFunction1(hr = S_OK);
336 }
337
338 // get SID for account
339 do {
340 er = ERROR_SUCCESS;
341 hr = CpiAccountNameToSid(pAttrs->pwzAccount, &pSid);
342 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr && !::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
343 {
344 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pAttrs->pwzAccount);
345 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
346 switch (er)
347 {
348 case IDABORT:
349 ExitFunction(); // exit with error code from CpiAccountNameToSid()
350 case IDRETRY:
351 break;
352 case IDIGNORE:
353 default:
354 ExitFunction1(hr = S_OK);
355 }
356 }
357 else
358 ExitOnFailure(hr, "Failed to get SID for account");
359 } while (IDRETRY == er);
360
361 // remove
362 hr = CpiRemoveUserCollectionObject(piUsrInRoleColl, pSid);
363 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr || HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED) == hr)
364 {
365 WcaLog(LOGMSG_STANDARD, "Failed to lookup account names, hr: 0x%x", hr);
366 hr = S_FALSE;
367 }
368 else
369 ExitOnFailure(hr, "Failed to remove user");
370
371 if (S_FALSE == hr)
372 {
373 // role not found
374 WcaLog(LOGMSG_VERBOSE, "User not found for partition role, nothing to delete, key: %S", pAttrs->pwzKey);
375 ExitFunction1(hr = S_OK);
376 }
377
378 // save changes
379 hr = piUsrInRoleColl->SaveChanges(&lChanges);
380 if (COMADMIN_E_OBJECTERRORS == hr)
381 CpiLogCatalogErrorInfo();
382 ExitOnFailure(hr, "Failed to save changes");
383
384 // log
385 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
386
387 hr = S_OK;
388
389LExit:
390 // clean up
391 ReleaseObject(piUsrInRoleColl);
392
393 if (pSid)
394 ::HeapFree(::GetProcessHeap(), 0, pSid);
395
396 return hr;
397}
diff --git a/src/ext/ComPlus/ca/cppartroleexec.h b/src/ext/ComPlus/ca/cppartroleexec.h
new file mode 100644
index 00000000..0ec47dad
--- /dev/null
+++ b/src/ext/ComPlus/ca/cppartroleexec.h
@@ -0,0 +1,12 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureUsersInPartitionRoles(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureUsersInPartitionRoles(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
diff --git a/src/ext/ComPlus/ca/cppartrolesched.cpp b/src/ext/ComPlus/ca/cppartrolesched.cpp
new file mode 100644
index 00000000..a988f8e3
--- /dev/null
+++ b/src/ext/ComPlus/ca/cppartrolesched.cpp
@@ -0,0 +1,421 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsPartitionRoleQuery =
9 L"SELECT `PartitionRole`, `Partition_`, `Component_`, `Name` FROM `ComPlusPartitionRole`";
10enum ePartitionRoleQuery { prqPartitionRole = 1, prqPartition, prqComponent, prqName };
11
12LPCWSTR vcsUserInPartitionRoleQuery =
13 L"SELECT `UserInPartitionRole`, `PartitionRole_`, `ComPlusUserInPartitionRole`.`Component_`, `Domain`, `Name` FROM `ComPlusUserInPartitionRole`, `User` WHERE `User_` = `User`";
14LPCWSTR vcsGroupInPartitionRoleQuery =
15 L"SELECT `GroupInPartitionRole`, `PartitionRole_`, `ComPlusGroupInPartitionRole`.`Component_`, `Domain`, `Name` FROM `ComPlusGroupInPartitionRole`, `Group` WHERE `Group_` = `Group`";
16enum eTrusteeInPartitionRoleQuery { tiprqUserInPartitionRole = 1, tiprqPartitionRole, tiprqComponent, tiprqDomain, tiprqName };
17
18
19// prototypes for private helper functions
20
21static HRESULT TrusteesInPartitionRolesRead(
22 LPCWSTR pwzQuery,
23 CPI_PARTITION_ROLE_LIST* pPartRoleList,
24 CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList
25 );
26static void FreePartitionRole(
27 CPI_PARTITION_ROLE* pItm
28 );
29static void FreeUserInPartitionRole(
30 CPI_USER_IN_PARTITION_ROLE* pItm
31 );
32static HRESULT AddUserInPartitionRoleToActionData(
33 CPI_USER_IN_PARTITION_ROLE* pItm,
34 int iActionType,
35 int iActionCost,
36 LPWSTR* ppwzActionData
37 );
38
39
40// function definitions
41
42void CpiPartitionRoleListFree(
43 CPI_PARTITION_ROLE_LIST* pList
44 )
45{
46 CPI_PARTITION_ROLE* pItm = pList->pFirst;
47
48 while (pItm)
49 {
50 CPI_PARTITION_ROLE* pDelete = pItm;
51 pItm = pItm->pNext;
52 FreePartitionRole(pDelete);
53 }
54}
55
56HRESULT CpiPartitionRolesRead(
57 CPI_PARTITION_LIST* pPartList,
58 CPI_PARTITION_ROLE_LIST* pPartRoleList
59 )
60{
61 HRESULT hr = S_OK;
62 PMSIHANDLE hView, hRec;
63 CPI_PARTITION_ROLE* pItm = NULL;
64 LPWSTR pwzData = NULL;
65
66 // loop through all application roles
67 hr = WcaOpenExecuteView(vcsPartitionRoleQuery, &hView);
68 ExitOnFailure(hr, "Failed to execute view on ComPlusPartitionRole table");
69
70 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
71 {
72 // create entry
73 pItm = (CPI_PARTITION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION_ROLE));
74 if (!pItm)
75 ExitFunction1(hr = E_OUTOFMEMORY);
76
77 // get key
78 hr = WcaGetRecordString(hRec, prqPartitionRole, &pwzData);
79 ExitOnFailure(hr, "Failed to get key");
80 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
81
82 // get partition
83 hr = WcaGetRecordString(hRec, prqPartition, &pwzData);
84 ExitOnFailure(hr, "Failed to get application");
85
86 hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition);
87 if (S_FALSE == hr)
88 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
89 ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData);
90
91 // get name
92 hr = WcaGetRecordFormattedString(hRec, prqName, &pwzData);
93 ExitOnFailure(hr, "Failed to get name");
94 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
95
96 // add entry
97 if (pPartRoleList->pFirst)
98 pItm->pNext = pPartRoleList->pFirst;
99 pPartRoleList->pFirst = pItm;
100 pItm = NULL;
101 }
102
103 if (E_NOMOREITEMS == hr)
104 hr = S_OK;
105
106LExit:
107 // clean up
108 if (pItm)
109 FreePartitionRole(pItm);
110
111 ReleaseStr(pwzData);
112
113 return hr;
114}
115
116HRESULT CpiPartitionRoleFindByKey(
117 CPI_PARTITION_ROLE_LIST* pList,
118 LPCWSTR pwzKey,
119 CPI_PARTITION_ROLE** ppPartRole
120 )
121{
122 for (CPI_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
123 {
124 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
125 {
126 *ppPartRole = pItm;
127 return S_OK;
128 }
129 }
130
131 return E_FAIL;
132}
133
134void CpiUserInPartitionRoleListFree(
135 CPI_USER_IN_PARTITION_ROLE_LIST* pList
136 )
137{
138 CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst;
139
140 while (pItm)
141 {
142 CPI_USER_IN_PARTITION_ROLE* pDelete = pItm;
143 pItm = pItm->pNext;
144 FreeUserInPartitionRole(pDelete);
145 }
146}
147
148HRESULT CpiUsersInPartitionRolesRead(
149 CPI_PARTITION_ROLE_LIST* pPartRoleList,
150 CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList
151 )
152{
153 HRESULT hr = S_OK;
154
155 // read users in partition roles
156 if (CpiTableExists(cptComPlusUserInPartitionRole))
157 {
158 hr = TrusteesInPartitionRolesRead(vcsUserInPartitionRoleQuery, pPartRoleList, pUsrInPartRoleList);
159 ExitOnFailure(hr, "Failed to read users in partition roles");
160 }
161
162 // read groups in partition roles
163 if (CpiTableExists(cptComPlusGroupInPartitionRole))
164 {
165 hr = TrusteesInPartitionRolesRead(vcsGroupInPartitionRoleQuery, pPartRoleList, pUsrInPartRoleList);
166 ExitOnFailure(hr, "Failed to read groups in partition roles");
167 }
168
169 hr = S_OK;
170
171LExit:
172 return hr;
173}
174
175HRESULT CpiUsersInPartitionRolesInstall(
176 CPI_USER_IN_PARTITION_ROLE_LIST* pList,
177 int iRunMode,
178 LPWSTR* ppwzActionData,
179 int* piProgress
180 )
181{
182 HRESULT hr = S_OK;
183
184 int iActionType;
185
186 // add action text
187 hr = CpiAddActionTextToActionData(L"AddUsersToComPlusPartitionRoles", ppwzActionData);
188 ExitOnFailure(hr, "Failed to add action text to custom action data");
189
190 // add count to action data
191 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
192 ExitOnFailure(hr, "Failed to add count to custom action data");
193
194 // add roles to custom action data
195 for (CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
196 {
197 // roles that are being installed only
198 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
199 continue;
200
201 // action type
202 if (rmRollback == iRunMode)
203 {
204 if (CpiIsInstalled(pItm->isInstalled))
205 iActionType = atNoOp;
206 else
207 iActionType = atRemove;
208 }
209 else
210 iActionType = atCreate;
211
212 // add to action data
213 hr = AddUserInPartitionRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_CREATE, ppwzActionData);
214 ExitOnFailure(hr, "Failed to add user in partition role to custom action data, key: %S", pItm->wzKey);
215 }
216
217 // add progress tics
218 if (piProgress)
219 *piProgress += COST_USER_IN_APPLICATION_ROLE_CREATE * pList->iInstallCount;
220
221 hr = S_OK;
222
223LExit:
224 return hr;
225}
226
227HRESULT CpiUsersInPartitionRolesUninstall(
228 CPI_USER_IN_PARTITION_ROLE_LIST* pList,
229 int iRunMode,
230 LPWSTR* ppwzActionData,
231 int* piProgress
232 )
233{
234 HRESULT hr = S_OK;
235
236 int iActionType;
237
238 // add action text
239 hr = CpiAddActionTextToActionData(L"RemoveUsersFromComPlusPartRoles", ppwzActionData);
240 ExitOnFailure(hr, "Failed to add action text to custom action data");
241
242 // add count to action data
243 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
244 ExitOnFailure(hr, "Failed to add count to custom action data");
245
246 // add roles to custom action data
247 for (CPI_USER_IN_PARTITION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
248 {
249 // roles that are being uninstalled only
250 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
251 continue;
252
253 // action type
254 if (rmRollback == iRunMode)
255 iActionType = atCreate;
256 else
257 iActionType = atRemove;
258
259 // add to action data
260 hr = AddUserInPartitionRoleToActionData(pItm, iActionType, COST_USER_IN_APPLICATION_ROLE_DELETE, ppwzActionData);
261 ExitOnFailure(hr, "Failed to add user in partition role to custom action data, key: %S", pItm->wzKey);
262 }
263
264 // add progress tics
265 if (piProgress)
266 *piProgress += COST_USER_IN_APPLICATION_ROLE_DELETE * pList->iUninstallCount;
267
268 hr = S_OK;
269
270LExit:
271 return hr;
272}
273
274
275// helper function definitions
276
277static HRESULT TrusteesInPartitionRolesRead(
278 LPCWSTR pwzQuery,
279 CPI_PARTITION_ROLE_LIST* pPartRoleList,
280 CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList
281 )
282{
283 HRESULT hr = S_OK;
284 UINT er = ERROR_SUCCESS;
285
286 PMSIHANDLE hView, hRec;
287
288 CPI_USER_IN_PARTITION_ROLE* pItm = NULL;
289 LPWSTR pwzData = NULL;
290 LPWSTR pwzDomain = NULL;
291 LPWSTR pwzName = NULL;
292 BOOL fMatchingArchitecture = FALSE;
293
294 // loop through all application roles
295 hr = WcaOpenExecuteView(pwzQuery, &hView);
296 ExitOnFailure(hr, "Failed to execute view on table");
297
298 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
299 {
300 // get component
301 hr = WcaGetRecordString(hRec, tiprqComponent, &pwzData);
302 ExitOnFailure(hr, "Failed to get component");
303
304 // check if the component is our processor architecture
305 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
306 ExitOnFailure(hr, "Failed to get component architecture.");
307
308 if (!fMatchingArchitecture)
309 {
310 continue; // not the same architecture, ignore
311 }
312
313 // create entry
314 pItm = (CPI_USER_IN_PARTITION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_USER_IN_PARTITION_ROLE));
315 if (!pItm)
316 ExitFunction1(hr = E_OUTOFMEMORY);
317
318 // get component install state
319 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
320 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
321
322 // get key
323 hr = WcaGetRecordString(hRec, tiprqUserInPartitionRole, &pwzData);
324 ExitOnFailure(hr, "Failed to get key");
325 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
326
327 // get partition role
328 hr = WcaGetRecordString(hRec, tiprqPartitionRole, &pwzData);
329 ExitOnFailure(hr, "Failed to get partition role");
330
331 hr = CpiPartitionRoleFindByKey(pPartRoleList, pwzData, &pItm->pPartitionRole);
332 ExitOnFailure(hr, "Failed to find partition role, key: %S", pwzData);
333
334 // get user domain
335 hr = WcaGetRecordFormattedString(hRec, tiprqDomain, &pwzDomain);
336 ExitOnFailure(hr, "Failed to get domain");
337
338 // get user name
339 hr = WcaGetRecordFormattedString(hRec, tiprqName, &pwzName);
340 ExitOnFailure(hr, "Failed to get name");
341
342 // build account name
343 hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount);
344 ExitOnFailure(hr, "Failed to build account name");
345
346 // increment counters
347 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
348 pUsrInPartRoleList->iInstallCount++;
349 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
350 pUsrInPartRoleList->iUninstallCount++;
351
352 // add entry
353 if (pUsrInPartRoleList->pFirst)
354 pItm->pNext = pUsrInPartRoleList->pFirst;
355 pUsrInPartRoleList->pFirst = pItm;
356 pItm = NULL;
357 }
358
359 if (E_NOMOREITEMS == hr)
360 hr = S_OK;
361
362LExit:
363 // clean up
364 if (pItm)
365 FreeUserInPartitionRole(pItm);
366
367 ReleaseStr(pwzData);
368 ReleaseStr(pwzDomain);
369 ReleaseStr(pwzName);
370
371 return hr;
372}
373
374static void FreePartitionRole(
375 CPI_PARTITION_ROLE* pItm
376 )
377{
378 ::HeapFree(::GetProcessHeap(), 0, pItm);
379}
380
381static void FreeUserInPartitionRole(
382 CPI_USER_IN_PARTITION_ROLE* pItm
383 )
384{
385 ReleaseStr(pItm->pwzAccount);
386
387 ::HeapFree(::GetProcessHeap(), 0, pItm);
388}
389
390static HRESULT AddUserInPartitionRoleToActionData(
391 CPI_USER_IN_PARTITION_ROLE* pItm,
392 int iActionType,
393 int iActionCost,
394 LPWSTR* ppwzActionData
395 )
396{
397 HRESULT hr = S_OK;
398
399 // add action information to custom action data
400 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
401 ExitOnFailure(hr, "Failed to add action type to custom action data");
402 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
403 ExitOnFailure(hr, "Failed to add action cost to custom action data");
404
405 // add application role information to custom action data
406 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
407 ExitOnFailure(hr, "Failed to add key to custom action data");
408 hr = WcaWriteStringToCaData(pItm->pPartitionRole->wzName, ppwzActionData);
409 ExitOnFailure(hr, "Failed to add role name to custom action data");
410 hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData);
411 ExitOnFailure(hr, "Failed to add user account to custom action data");
412
413 // add partition information to custom action data
414 hr = WcaWriteStringToCaData(pItm->pPartitionRole->pPartition->wzID, ppwzActionData);
415 ExitOnFailure(hr, "Failed to add partition id to custom action data");
416
417 hr = S_OK;
418
419LExit:
420 return hr;
421}
diff --git a/src/ext/ComPlus/ca/cppartrolesched.h b/src/ext/ComPlus/ca/cppartrolesched.h
new file mode 100644
index 00000000..ff1275d9
--- /dev/null
+++ b/src/ext/ComPlus/ca/cppartrolesched.h
@@ -0,0 +1,76 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_PARTITION_ROLE
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
9
10 CPI_PARTITION* pPartition;
11
12 ICatalogCollection* piUsersColl;
13
14 CPI_PARTITION_ROLE* pNext;
15};
16
17struct CPI_PARTITION_ROLE_LIST
18{
19 CPI_PARTITION_ROLE* pFirst;
20};
21
22struct CPI_USER_IN_PARTITION_ROLE
23{
24 WCHAR wzKey[MAX_DARWIN_KEY + 1];
25 LPWSTR pwzAccount;
26
27 INSTALLSTATE isInstalled, isAction;
28
29 CPI_PARTITION_ROLE* pPartitionRole;
30
31 CPI_USER_IN_PARTITION_ROLE* pNext;
32};
33
34struct CPI_USER_IN_PARTITION_ROLE_LIST
35{
36 CPI_USER_IN_PARTITION_ROLE* pFirst;
37
38 int iInstallCount;
39 int iUninstallCount;
40};
41
42
43// function prototypes
44
45void CpiPartitionRoleListFree(
46 CPI_PARTITION_ROLE_LIST* pList
47 );
48HRESULT CpiPartitionRolesRead(
49 CPI_PARTITION_LIST* pPartList,
50 CPI_PARTITION_ROLE_LIST* pPartRoleList
51 );
52HRESULT CpiPartitionRoleFindByKey(
53 CPI_PARTITION_ROLE_LIST* pList,
54 LPCWSTR pwzKey,
55 CPI_PARTITION_ROLE** ppPartRole
56 );
57
58void CpiUserInPartitionRoleListFree(
59 CPI_USER_IN_PARTITION_ROLE_LIST* pList
60 );
61HRESULT CpiUsersInPartitionRolesRead(
62 CPI_PARTITION_ROLE_LIST* pPartRoleList,
63 CPI_USER_IN_PARTITION_ROLE_LIST* pUsrInPartRoleList
64 );
65HRESULT CpiUsersInPartitionRolesInstall(
66 CPI_USER_IN_PARTITION_ROLE_LIST* pList,
67 int iRunMode,
68 LPWSTR* ppwzActionData,
69 int* piProgress
70 );
71HRESULT CpiUsersInPartitionRolesUninstall(
72 CPI_USER_IN_PARTITION_ROLE_LIST* pList,
73 int iRunMode,
74 LPWSTR* ppwzActionData,
75 int* piProgress
76 );
diff --git a/src/ext/ComPlus/ca/cppartsched.cpp b/src/ext/ComPlus/ca/cppartsched.cpp
new file mode 100644
index 00000000..7cd98791
--- /dev/null
+++ b/src/ext/ComPlus/ca/cppartsched.cpp
@@ -0,0 +1,912 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsPartitionQuery =
9 L"SELECT `Partition`, `Component_`, `Id`, `Name` FROM `ComPlusPartition`";
10enum ePartitionQuery { pqPartition = 1, pqComponent, pqID, pqName };
11
12LPCWSTR vcsPartitionPropertyQuery =
13 L"SELECT `Name`, `Value` FROM `ComPlusPartitionProperty` WHERE `Partition_` = ?";
14
15LPCWSTR vcsPartitionUserQuery =
16 L"SELECT `PartitionUser`, `Partition_`, `ComPlusPartitionUser`.`Component_`, `Domain`, `Name` FROM `ComPlusPartitionUser`, `User` WHERE `User_` = `User`";
17enum ePartitionUserQuery { puqPartitionUser = 1, puqPartition, puqComponent, puqDomain, puqName };
18
19
20// property definitions
21
22CPI_PROPERTY_DEFINITION pdlPartitionProperties[] =
23{
24 {L"Changeable", cpptBoolean, 502},
25 {L"Deleteable", cpptBoolean, 502},
26 {L"Description", cpptString, 502},
27 {NULL, cpptNone, 0}
28};
29
30
31// prototypes for private helper functions
32
33static void FreePartition(
34 CPI_PARTITION* pItm
35 );
36static void FreePartitionUser(
37 CPI_PARTITION_USER* pItm
38 );
39static HRESULT AddPartitionToActionData(
40 CPI_PARTITION* pItm,
41 int iActionType,
42 int iActionCost,
43 LPWSTR* ppwzActionData
44 );
45static HRESULT AddPartitionUserToActionData(
46 CPI_PARTITION_USER* pItm,
47 int iActionType,
48 int iActionCost,
49 LPWSTR* ppwzActionData
50 );
51
52
53// function definitions
54
55void CpiPartitionListFree(
56 CPI_PARTITION_LIST* pList
57 )
58{
59 CPI_PARTITION* pItm = pList->pFirst;
60
61 while (pItm)
62 {
63 CPI_PARTITION* pDelete = pItm;
64 pItm = pItm->pNext;
65 FreePartition(pDelete);
66 }
67}
68
69HRESULT CpiPartitionsRead(
70 CPI_PARTITION_LIST* pPartList
71 )
72{
73 HRESULT hr = S_OK;
74 UINT er = ERROR_SUCCESS;
75
76 PMSIHANDLE hView, hRec;
77
78 CPI_PARTITION* pItm = NULL;
79 LPWSTR pwzData = NULL;
80 BOOL fMatchingArchitecture = FALSE;
81
82 // loop through all partitions
83 hr = WcaOpenExecuteView(vcsPartitionQuery, &hView);
84 ExitOnFailure(hr, "Failed to execute view on ComPlusPartition table");
85
86 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
87 {
88 // get component
89 hr = WcaGetRecordString(hRec, pqComponent, &pwzData);
90 ExitOnFailure(hr, "Failed to get component");
91
92 // check if the component is our processor architecture
93 if (pwzData && *pwzData)
94 {
95 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
96 ExitOnFailure(hr, "Failed to get component architecture.");
97
98 if (!fMatchingArchitecture)
99 {
100 continue; // not the same architecture, ignore
101 }
102 }
103
104 // create entry
105 pItm = (CPI_PARTITION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION));
106 if (!pItm)
107 ExitFunction1(hr = E_OUTOFMEMORY);
108
109 // get component install state
110 if (pwzData && *pwzData)
111 {
112 pItm->fHasComponent = TRUE;
113
114 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
115 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
116 }
117
118 // get key
119 hr = WcaGetRecordString(hRec, pqPartition, &pwzData);
120 ExitOnFailure(hr, "Failed to get key");
121 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
122
123 // get id
124 hr = WcaGetRecordFormattedString(hRec, pqID, &pwzData);
125 ExitOnFailure(hr, "Failed to get id");
126
127 if (pwzData && *pwzData)
128 {
129 hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID));
130 ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData);
131 }
132
133 // get name
134 hr = WcaGetRecordFormattedString(hRec, pqName, &pwzData);
135 ExitOnFailure(hr, "Failed to get name");
136 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
137
138 // if partition is a locater, either an id or a name must be provided
139 if (!pItm->fHasComponent && !*pItm->wzID && !*pItm->wzName)
140 ExitOnFailure(hr = E_FAIL, "A partition locater must have either an id or a name associated, key: %S", pItm->wzKey);
141
142 // if partition is not a locater, an name must be provided
143 if (pItm->fHasComponent && !*pItm->wzName)
144 ExitOnFailure(hr = E_FAIL, "A partition must have a name associated, key: %S", pItm->wzKey);
145
146 // get properties
147 if (CpiTableExists(cptComPlusPartitionProperty) && pItm->fHasComponent)
148 {
149 hr = CpiPropertiesRead(vcsPartitionPropertyQuery, pItm->wzKey, pdlPartitionProperties, &pItm->pProperties, &pItm->iPropertyCount);
150 ExitOnFailure(hr, "Failed to get properties");
151 }
152
153 // increment counters
154 if (pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))
155 pPartList->iInstallCount++;
156 if (pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
157 pPartList->iUninstallCount++;
158
159 // add entry
160 if (pPartList->pFirst)
161 pItm->pNext = pPartList->pFirst;
162 pPartList->pFirst = pItm;
163 pItm = NULL;
164 }
165
166 if (E_NOMOREITEMS == hr)
167 hr = S_OK;
168
169LExit:
170 // clean up
171 if (pItm)
172 FreePartition(pItm);
173
174 ReleaseStr(pwzData);
175
176 return hr;
177}
178
179HRESULT CpiPartitionsVerifyInstall(
180 CPI_PARTITION_LIST* pList
181 )
182{
183 HRESULT hr = S_OK;
184 UINT er = ERROR_SUCCESS;
185
186 ICatalogCollection* piPartColl = NULL;
187 ICatalogObject* piPartObj = NULL;
188
189 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
190 {
191 // referenced locaters or partitions that are being installed
192 if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)))
193 continue;
194
195 // if the partition is referensed and is not a locater, it must be installed
196 if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
197 MessageExitOnFailure(hr = E_FAIL, msierrComPlusPartitionDependency, "A partition is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
198
199 // get partitions collection
200 if (!piPartColl)
201 {
202 hr = CpiSchedGetPartitionsCollection(&piPartColl);
203 ExitOnFailure(hr, "Failed to get partitions collection");
204 }
205
206 // partition is supposed to exist
207 if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled))
208 {
209 // get collection object for partition
210 hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj);
211 ExitOnFailure(hr, "Failed to find collection object for partition");
212
213 // if the partition was found
214 if (S_OK == hr)
215 {
216 // if we don't have an id, copy id from object
217 if (!*pItm->wzID)
218 {
219 hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID));
220 ExitOnFailure(hr, "Failed to get id");
221 }
222 }
223
224 // if the partition was not found
225 else
226 {
227 // if the application is a locater, this is an error
228 if (!pItm->fHasComponent)
229 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusPartitionNotFound, "A partition required by this installation was not found, key: %S", pItm->wzKey);
230
231 // create a new id if one is missing
232 if (!*pItm->wzID)
233 {
234 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
235 ExitOnFailure(hr, "Failed to create id");
236 }
237 }
238 }
239
240 // partition is supposed to be created
241 else
242 {
243 // check for conflicts
244 do {
245 if (*pItm->wzID)
246 {
247 // find partitions with conflicting id
248 hr = CpiFindCollectionObject(piPartColl, pItm->wzID, NULL, &piPartObj);
249 ExitOnFailure(hr, "Failed to find collection object for partition");
250
251 if (S_FALSE == hr)
252 {
253 // find partitions with conflicting name
254 hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj);
255 ExitOnFailure(hr, "Failed to find collection object for partition");
256
257 if (S_OK == hr)
258 // "A partition with a conflictiong name exists. retry cancel"
259 er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
260 else
261 break; // no conflicting entry found, break loop
262 }
263 else
264 // "A partition with a conflicting id exists. abort retry ignore"
265 er = WcaErrorMessage(msierrComPlusPartitionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
266 }
267 else
268 {
269 // find partitions with conflicting name
270 hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj);
271 ExitOnFailure(hr, "Failed to find collection object for partition");
272
273 if (S_OK == hr)
274 // "A partition with a conflictiong name exists. abort retry ignore"
275 er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
276 else
277 break; // no conflicting entry found, break loop
278 }
279
280 switch (er)
281 {
282 case IDCANCEL:
283 case IDABORT:
284 ExitOnFailure(hr = E_FAIL, "A partition with a conflictiong name or id exists, key: %S", pItm->wzKey);
285 break;
286 case IDRETRY:
287 break;
288 case IDIGNORE:
289 default:
290 // if we don't have an id, copy id from object
291 if (!*pItm->wzID)
292 {
293 hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID));
294 ExitOnFailure(hr, "Failed to get id");
295 }
296 hr = S_FALSE; // indicate that this is not a conflict
297 }
298 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
299
300 // create a new id if one is missing
301 if (!*pItm->wzID)
302 {
303 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
304 ExitOnFailure(hr, "Failed to create id");
305 }
306 }
307
308 // clean up
309 ReleaseNullObject(piPartObj);
310 }
311
312 hr = S_OK;
313
314LExit:
315 // clean up
316 ReleaseObject(piPartColl);
317 ReleaseObject(piPartObj);
318
319 return hr;
320}
321
322HRESULT CpiPartitionsVerifyUninstall(
323 CPI_PARTITION_LIST* pList
324 )
325{
326 HRESULT hr = S_OK;
327 ICatalogCollection* piPartColl = NULL;
328 ICatalogObject* piPartObj = NULL;
329
330 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
331 {
332 // referenced locaters or partitions that are being uninstalled
333 if (!pItm->fReferencedForUninstall && !(pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction)))
334 continue;
335
336 // get partitions collection
337 if (!piPartColl)
338 {
339 hr = CpiSchedGetPartitionsCollection(&piPartColl);
340 ExitOnFailure(hr, "Failed to get partitions collection");
341 }
342
343 // get collection object for partition
344 hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj);
345 ExitOnFailure(hr, "Failed to find collection object for partition");
346
347 // if the partition was found
348 if (S_OK == hr)
349 {
350 // if we don't have an id, copy id from object
351 if (!*pItm->wzID)
352 {
353 hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID));
354 ExitOnFailure(hr, "Failed to get id");
355 }
356 }
357
358 // if the partition was not found
359 else
360 {
361 pItm->fObjectNotFound = TRUE;
362 if (pItm->fHasComponent)
363 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
364 }
365
366 // clean up
367 ReleaseNullObject(piPartObj);
368 }
369
370 hr = S_OK;
371
372LExit:
373 // clean up
374 ReleaseObject(piPartColl);
375 ReleaseObject(piPartObj);
376
377 return hr;
378}
379
380void CpiPartitionAddReferenceInstall(
381 CPI_PARTITION* pItm
382 )
383{
384 pItm->fReferencedForInstall = TRUE;
385}
386
387void CpiPartitionAddReferenceUninstall(
388 CPI_PARTITION* pItm
389 )
390{
391 pItm->fReferencedForUninstall = TRUE;
392}
393
394HRESULT CpiPartitionsInstall(
395 CPI_PARTITION_LIST* pList,
396 int iRunMode,
397 LPWSTR* ppwzActionData,
398 int* piProgress
399 )
400{
401 HRESULT hr = S_OK;
402
403 int iActionType;
404
405 // add action text
406 hr = CpiAddActionTextToActionData(L"CreateComPlusPartitions", ppwzActionData);
407 ExitOnFailure(hr, "Failed to add action text to custom action data");
408
409 // add partition count to action data
410 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
411 ExitOnFailure(hr, "Failed to add count to custom action data");
412
413 // add applications to custom action data
414 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
415 {
416 // partitions that are being installed only
417 if (!pItm->fHasComponent || !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
418 continue;
419
420 // action type
421 if (rmRollback == iRunMode)
422 {
423 if (CpiIsInstalled(pItm->isInstalled))
424 iActionType = atNoOp;
425 else
426 iActionType = atRemove;
427 }
428 else
429 iActionType = atCreate;
430
431 // add to action data
432 hr = AddPartitionToActionData(pItm, iActionType, COST_PARTITION_CREATE, ppwzActionData);
433 ExitOnFailure(hr, "Failed to add partition to custom action data, key: %S", pItm->wzKey);
434 }
435
436 // add progress tics
437 if (piProgress)
438 *piProgress += COST_PARTITION_CREATE * pList->iInstallCount;
439
440 hr = S_OK;
441
442LExit:
443 return hr;
444}
445
446HRESULT CpiPartitionsUninstall(
447 CPI_PARTITION_LIST* pList,
448 int iRunMode,
449 LPWSTR* ppwzActionData,
450 int* piProgress
451 )
452{
453 HRESULT hr = S_OK;
454
455 int iActionType;
456
457 // add action text
458 hr = CpiAddActionTextToActionData(L"RemoveComPlusPartitions", ppwzActionData);
459 ExitOnFailure(hr, "Failed to add action text to custom action data");
460
461 // add partition count to action data
462 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
463 ExitOnFailure(hr, "Failed to add count to custom action data");
464
465 // add partitions to custom action data
466 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
467 {
468 // partitions that are being uninstalled only
469 if (!pItm->fHasComponent || pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
470 continue;
471
472 // action type
473 if (rmRollback == iRunMode)
474 iActionType = atCreate;
475 else
476 iActionType = atRemove;
477
478 // add to action data
479 hr = AddPartitionToActionData(pItm, iActionType, COST_PARTITION_DELETE, ppwzActionData);
480 ExitOnFailure(hr, "Failed to add partition to custom action data, key:", pItm->wzKey);
481 }
482
483 // add progress tics
484 if (piProgress)
485 *piProgress += COST_PARTITION_DELETE * pList->iUninstallCount;
486
487 hr = S_OK;
488
489LExit:
490 return hr;
491}
492
493HRESULT CpiPartitionFindByKey(
494 CPI_PARTITION_LIST* pList,
495 LPCWSTR wzKey,
496 CPI_PARTITION** ppItm
497 )
498{
499 for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
500 {
501 if (0 == lstrcmpW(pItm->wzKey, wzKey))
502 {
503 *ppItm = pItm;
504 return S_OK;
505 }
506 }
507
508 return S_FALSE;
509}
510
511HRESULT CpiGetApplicationsCollForPartition(
512 CPI_PARTITION* pPart,
513 ICatalogCollection** ppiAppColl
514 )
515{
516 HRESULT hr = S_OK;
517
518 ICatalogCollection* piPartColl = NULL;
519 ICatalogObject* piPartObj = NULL;
520
521 // if a previous attempt to locate the collection object failed
522 if (pPart->fObjectNotFound)
523 ExitFunction1(hr = S_FALSE);
524
525 // get applications collection
526 if (!pPart->piApplicationsColl)
527 {
528 // get partitions collection from catalog
529 hr = CpiSchedGetPartitionsCollection(&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 = CpiSchedGetCatalogCollection(piPartColl, piPartObj, L"Applications", &pPart->piApplicationsColl);
544 ExitOnFailure(hr, "Failed to get applications collection");
545 }
546
547 // return value
548 *ppiAppColl = pPart->piApplicationsColl;
549 (*ppiAppColl)->AddRef();
550
551 hr = S_OK;
552
553LExit:
554 // clean up
555 ReleaseObject(piPartColl);
556 ReleaseObject(piPartObj);
557
558 return hr;
559}
560
561HRESULT CpiGetRolesCollForPartition(
562 CPI_PARTITION* pPart,
563 ICatalogCollection** ppiRolesColl
564 )
565{
566 HRESULT hr = S_OK;
567
568 ICatalogCollection* piPartColl = NULL;
569 ICatalogObject* piPartObj = NULL;
570
571 // if a previous attempt to locate the collection object failed
572 if (pPart->fObjectNotFound)
573 ExitFunction1(hr = S_FALSE);
574
575 // get applications collection
576 if (!pPart->piRolesColl)
577 {
578 // get partitions collection from catalog
579 hr = CpiSchedGetPartitionsCollection(&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 = CpiSchedGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", &pPart->piRolesColl);
591 ExitOnFailure(hr, "Failed to get roles collection");
592 }
593
594 // return value
595 *ppiRolesColl = pPart->piRolesColl;
596 (*ppiRolesColl)->AddRef();
597
598 hr = S_OK;
599
600LExit:
601 // clean up
602 ReleaseObject(piPartColl);
603 ReleaseObject(piPartObj);
604
605 return hr;
606}
607
608void CpiPartitionUserListFree(
609 CPI_PARTITION_USER_LIST* pList
610 )
611{
612 CPI_PARTITION_USER* pItm = pList->pFirst;
613
614 while (pItm)
615 {
616 CPI_PARTITION_USER* pDelete = pItm;
617 pItm = pItm->pNext;
618 FreePartitionUser(pDelete);
619 }
620}
621
622HRESULT CpiPartitionUsersRead(
623 CPI_PARTITION_LIST* pPartList,
624 CPI_PARTITION_USER_LIST* pPartUsrList
625 )
626{
627 HRESULT hr = S_OK;
628 UINT er = ERROR_SUCCESS;
629
630 PMSIHANDLE hView, hRec;
631
632 CPI_PARTITION_USER* pItm = NULL;
633 LPWSTR pwzData = NULL;
634 LPWSTR pwzDomain = NULL;
635 LPWSTR pwzName = NULL;
636 BOOL fMatchingArchitecture = FALSE;
637
638 // loop through all partition users
639 hr = WcaOpenExecuteView(vcsPartitionUserQuery, &hView);
640 ExitOnFailure(hr, "Failed to execute view on ComPlusPartitionUser table");
641
642 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
643 {
644 // get component
645 hr = WcaGetRecordString(hRec, puqComponent, &pwzData);
646 ExitOnFailure(hr, "Failed to get component");
647
648 // check if the component is our processor architecture
649 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
650 ExitOnFailure(hr, "Failed to get component architecture.");
651
652 if (!fMatchingArchitecture)
653 {
654 continue; // not the same architecture, ignore
655 }
656
657 // create entry
658 pItm = (CPI_PARTITION_USER*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION_USER));
659 if (!pItm)
660 ExitFunction1(hr = E_OUTOFMEMORY);
661
662 // get component install state
663 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
664 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
665
666 // get key
667 hr = WcaGetRecordString(hRec, puqPartitionUser, &pwzData);
668 ExitOnFailure(hr, "Failed to get key");
669 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
670
671 // get partition
672 hr = WcaGetRecordString(hRec, puqPartition, &pwzData);
673 ExitOnFailure(hr, "Failed to get partition");
674
675 hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition);
676 if (S_FALSE == hr)
677 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
678 ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData);
679
680 // get user domain
681 hr = WcaGetRecordFormattedString(hRec, puqDomain, &pwzDomain);
682 ExitOnFailure(hr, "Failed to get user domain");
683
684 // get user name
685 hr = WcaGetRecordFormattedString(hRec, puqName, &pwzName);
686 ExitOnFailure(hr, "Failed to get user name");
687
688 // build account name
689 hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount);
690 ExitOnFailure(hr, "Failed to build account name");
691
692 // set references & increment counters
693 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
694 {
695 pItm->pPartition->fReferencedForInstall = TRUE;
696 pPartUsrList->iInstallCount++;
697 }
698 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
699 {
700 pItm->pPartition->fReferencedForUninstall = TRUE;
701 pPartUsrList->iUninstallCount++;
702 }
703
704 // add entry
705 if (pPartUsrList->pFirst)
706 pItm->pNext = pPartUsrList->pFirst;
707 pPartUsrList->pFirst = pItm;
708 pItm = NULL;
709 }
710
711 if (E_NOMOREITEMS == hr)
712 hr = S_OK;
713
714LExit:
715 // clean up
716 if (pItm)
717 FreePartitionUser(pItm);
718
719 ReleaseStr(pwzData);
720 ReleaseStr(pwzDomain);
721 ReleaseStr(pwzName);
722
723 return hr;
724}
725
726HRESULT CpiPartitionUsersInstall(
727 CPI_PARTITION_USER_LIST* pList,
728 int iRunMode,
729 LPWSTR* ppwzActionData,
730 int* piProgress
731 )
732{
733 HRESULT hr = S_OK;
734
735 int iActionType;
736
737 // add action text
738 hr = CpiAddActionTextToActionData(L"AddComPlusPartitionUsers", ppwzActionData);
739 ExitOnFailure(hr, "Failed to add action text to custom action data");
740
741 // add partition count to action data
742 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
743 ExitOnFailure(hr, "Failed to add count to custom action data");
744
745 // add applications to custom action data
746 for (CPI_PARTITION_USER* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
747 {
748 // partitions that are being installed only
749 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
750 continue;
751
752 // action type
753 if (rmRollback == iRunMode)
754 {
755 if (CpiIsInstalled(pItm->isInstalled))
756 iActionType = atNoOp;
757 else
758 iActionType = atRemove;
759 }
760 else
761 iActionType = atCreate;
762
763 // add to action data
764 hr = AddPartitionUserToActionData(pItm, iActionType, COST_PARTITION_USER_CREATE, ppwzActionData);
765 ExitOnFailure(hr, "Failed to add partition user to custom action data, key: %S", pItm->wzKey);
766 }
767
768 // add progress tics
769 if (piProgress)
770 *piProgress += COST_PARTITION_USER_CREATE * pList->iInstallCount;
771
772 hr = S_OK;
773
774LExit:
775 return hr;
776}
777
778HRESULT CpiPartitionUsersUninstall(
779 CPI_PARTITION_USER_LIST* pList,
780 int iRunMode,
781 LPWSTR* ppwzActionData,
782 int* piProgress
783 )
784{
785 HRESULT hr = S_OK;
786
787 int iActionType;
788
789 // add action text
790 hr = CpiAddActionTextToActionData(L"RemoveComPlusPartitionUsers", ppwzActionData);
791 ExitOnFailure(hr, "Failed to add action text to custom action data");
792
793 // add partition count to action data
794 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
795 ExitOnFailure(hr, "Failed to add count to custom action data");
796
797 // add partitions to custom action data
798 for (CPI_PARTITION_USER* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
799 {
800 // partitions that are being uninstalled only
801 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
802 continue;
803
804 // action type
805 if (rmRollback == iRunMode)
806 iActionType = atCreate;
807 else
808 iActionType = atRemove;
809
810 // add to action data
811 hr = AddPartitionUserToActionData(pItm, iActionType, COST_PARTITION_USER_DELETE, ppwzActionData);
812 ExitOnFailure(hr, "Failed to add partition user to custom action data, key: %S", pItm->wzKey);
813 }
814
815 // add progress tics
816 if (piProgress)
817 *piProgress += COST_PARTITION_USER_DELETE * pList->iUninstallCount;
818
819 hr = S_OK;
820
821LExit:
822 return hr;
823}
824
825
826// helper function definitions
827
828static void FreePartition(
829 CPI_PARTITION* pItm
830 )
831{
832 if (pItm->pProperties)
833 CpiPropertiesFreeList(pItm->pProperties);
834
835 ReleaseObject(pItm->piApplicationsColl);
836 ReleaseObject(pItm->piRolesColl);
837
838 ::HeapFree(::GetProcessHeap(), 0, pItm);
839}
840
841static void FreePartitionUser(
842 CPI_PARTITION_USER* pItm
843 )
844{
845 ReleaseStr(pItm->pwzAccount);
846
847 ::HeapFree(::GetProcessHeap(), 0, pItm);
848}
849
850static HRESULT AddPartitionToActionData(
851 CPI_PARTITION* pItm,
852 int iActionType,
853 int iActionCost,
854 LPWSTR* ppwzActionData
855 )
856{
857 HRESULT hr = S_OK;
858
859 // add action information to custom action data
860 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
861 ExitOnFailure(hr, "Failed to add action type to custom action data");
862 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
863 ExitOnFailure(hr, "Failed to add action cost to custom action data");
864
865 // add partition information to custom action data
866 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
867 ExitOnFailure(hr, "Failed to add partition key to custom action data");
868 hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
869 ExitOnFailure(hr, "Failed to add partition id to custom action data");
870 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
871 ExitOnFailure(hr, "Failed to add partition name to custom action data");
872
873 // add properties to custom action data
874 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
875 ExitOnFailure(hr, "Failed to add properties to custom action data");
876
877 hr = S_OK;
878
879LExit:
880 return hr;
881}
882
883static HRESULT AddPartitionUserToActionData(
884 CPI_PARTITION_USER* pItm,
885 int iActionType,
886 int iActionCost,
887 LPWSTR* ppwzActionData
888 )
889{
890 HRESULT hr = S_OK;
891
892 // add action information to custom action data
893 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
894 ExitOnFailure(hr, "Failed to add action type to custom action data");
895 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
896 ExitOnFailure(hr, "Failed to add action cost to custom action data");
897
898 // add partition user information to custom action data
899 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
900 ExitOnFailure(hr, "Failed to add partition user key to custom action data");
901 hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData);
902 ExitOnFailure(hr, "Failed to add user account to custom action data");
903
904 // add partition information to custom action data
905 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pPartition->wzID : L"", ppwzActionData);
906 ExitOnFailure(hr, "Failed to add partition id to custom action data");
907
908 hr = S_OK;
909
910LExit:
911 return hr;
912}
diff --git a/src/ext/ComPlus/ca/cppartsched.h b/src/ext/ComPlus/ca/cppartsched.h
new file mode 100644
index 00000000..55085912
--- /dev/null
+++ b/src/ext/ComPlus/ca/cppartsched.h
@@ -0,0 +1,125 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_PARTITION
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzID[CPI_MAX_GUID + 1];
9 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
10
11 int iPropertyCount;
12 CPI_PROPERTY* pProperties;
13
14 BOOL fHasComponent;
15 BOOL fReferencedForInstall;
16 BOOL fReferencedForUninstall;
17 BOOL fObjectNotFound;
18
19 INSTALLSTATE isInstalled, isAction;
20
21 ICatalogCollection* piApplicationsColl;
22 ICatalogCollection* piRolesColl;
23
24 CPI_PARTITION* pNext;
25};
26
27struct CPI_PARTITION_LIST
28{
29 CPI_PARTITION* pFirst;
30
31 int iInstallCount;
32 int iUninstallCount;
33};
34
35struct CPI_PARTITION_USER
36{
37 WCHAR wzKey[MAX_DARWIN_KEY + 1];
38 LPWSTR pwzAccount;
39
40 BOOL fNoFind;
41
42 INSTALLSTATE isInstalled, isAction;
43
44 CPI_PARTITION* pPartition;
45
46 CPI_PARTITION_USER* pNext;
47};
48
49struct CPI_PARTITION_USER_LIST
50{
51 CPI_PARTITION_USER* pFirst;
52
53 int iInstallCount;
54 int iUninstallCount;
55};
56
57
58// function prototypes
59
60void CpiPartitionListFree(
61 CPI_PARTITION_LIST* pList
62 );
63HRESULT CpiPartitionsRead(
64 CPI_PARTITION_LIST* pPartList
65 );
66HRESULT CpiPartitionsVerifyInstall(
67 CPI_PARTITION_LIST* pList
68 );
69HRESULT CpiPartitionsVerifyUninstall(
70 CPI_PARTITION_LIST* pList
71 );
72void CpiPartitionAddReferenceInstall(
73 CPI_PARTITION* pItm
74 );
75void CpiPartitionAddReferenceUninstall(
76 CPI_PARTITION* pItm
77 );
78HRESULT CpiPartitionsInstall(
79 CPI_PARTITION_LIST* pList,
80 int iRunMode,
81 LPWSTR* ppwzActionData,
82 int* piProgress
83 );
84HRESULT CpiPartitionsUninstall(
85 CPI_PARTITION_LIST* pList,
86 int iRunMode,
87 LPWSTR* ppwzActionData,
88 int* piProgress
89 );
90HRESULT CpiPartitionFindByKey(
91 CPI_PARTITION_LIST* pList,
92 LPCWSTR wzKey,
93 CPI_PARTITION** ppItm
94 );
95HRESULT CpiGetApplicationsCollForPartition(
96 CPI_PARTITION* pPart,
97 ICatalogCollection** ppiAppColl
98 );
99HRESULT CpiGetPartitionUsersCollection(
100 CPI_PARTITION* pPart,
101 ICatalogCollection** ppiPartUsrColl
102 );
103HRESULT CpiGetRolesCollForPartition(
104 CPI_PARTITION* pPart,
105 ICatalogCollection** ppiRolesColl
106 );
107void CpiPartitionUserListFree(
108 CPI_PARTITION_USER_LIST* pList
109 );
110HRESULT CpiPartitionUsersRead(
111 CPI_PARTITION_LIST* pPartList,
112 CPI_PARTITION_USER_LIST* pPartUsrList
113 );
114HRESULT CpiPartitionUsersInstall(
115 CPI_PARTITION_USER_LIST* pList,
116 int iRunMode,
117 LPWSTR* ppwzActionData,
118 int* piProgress
119 );
120HRESULT CpiPartitionUsersUninstall(
121 CPI_PARTITION_USER_LIST* pList,
122 int iRunMode,
123 LPWSTR* ppwzActionData,
124 int* piProgress
125 );
diff --git a/src/ext/ComPlus/ca/cpsched.cpp b/src/ext/ComPlus/ca/cpsched.cpp
new file mode 100644
index 00000000..ebc547ae
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpsched.cpp
@@ -0,0 +1,566 @@
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 ConfigureComPlusInstall - CUSTOM ACTION ENTRY POINT for installing COM+ components
34
35********************************************************************/
36extern "C" UINT __stdcall ConfigureComPlusInstall(MSIHANDLE hInstall)
37{
38 HRESULT hr = S_OK;
39 UINT er = ERROR_SUCCESS;
40
41 BOOL fInitializedCom = FALSE;
42
43 ICOMAdminCatalog* piCatalog = NULL;
44
45 CPI_PARTITION_LIST partList;
46 CPI_PARTITION_ROLE_LIST partRoleList;
47 CPI_USER_IN_PARTITION_ROLE_LIST usrInPartRoleList;
48 CPI_PARTITION_USER_LIST partUsrList;
49 CPI_APPLICATION_LIST appList;
50 CPI_APPLICATION_ROLE_LIST appRoleList;
51 CPI_USER_IN_APPLICATION_ROLE_LIST usrInAppRoleList;
52 CPI_ASSEMBLY_LIST asmList;
53 CPI_SUBSCRIPTION_LIST subList;
54
55 LPWSTR pwzRollbackFileName = NULL;
56 LPWSTR pwzActionData = NULL;
57 LPWSTR pwzRollbackActionData = NULL;
58 LPWSTR pwzCommitActionData = NULL;
59
60 int iVersionNT = 0;
61 int iProgress = 0;
62 int iCommitProgress = 0;
63
64 ::ZeroMemory(&partList, sizeof(CPI_PARTITION_LIST));
65 ::ZeroMemory(&partRoleList, sizeof(CPI_PARTITION_ROLE_LIST));
66 ::ZeroMemory(&usrInPartRoleList, sizeof(CPI_USER_IN_PARTITION_ROLE_LIST));
67 ::ZeroMemory(&partUsrList, sizeof(CPI_PARTITION_USER_LIST));
68 ::ZeroMemory(&appList, sizeof(CPI_APPLICATION_LIST));
69 ::ZeroMemory(&appRoleList, sizeof(CPI_APPLICATION_ROLE_LIST));
70 ::ZeroMemory(&usrInAppRoleList, sizeof(CPI_USER_IN_APPLICATION_ROLE_LIST));
71 ::ZeroMemory(&asmList, sizeof(CPI_ASSEMBLY_LIST));
72 ::ZeroMemory(&subList, sizeof(CPI_SUBSCRIPTION_LIST));
73
74 // initialize
75 hr = WcaInitialize(hInstall, "ConfigureComPlusInstall");
76 ExitOnFailure(hr, "Failed to initialize");
77
78 hr = ::CoInitialize(NULL);
79 ExitOnFailure(hr, "Failed to initialize COM");
80 fInitializedCom = TRUE;
81
82 CpiSchedInitialize();
83
84 // check for the prerequsite tables
85 if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly))
86 {
87 WcaLog(LOGMSG_VERBOSE, "skipping install COM+ CustomAction, no ComPlusPartition, ComPlusApplication or ComPlusAssembly table present");
88 ExitFunction1(hr = S_FALSE);
89 }
90
91 // make sure we can access the COM+ admin catalog
92 do {
93 hr = CpiSchedGetAdminCatalog(&piCatalog);
94 if (FAILED(hr))
95 {
96 WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog");
97 er = WcaErrorMessage(msierrComPlusCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
98 switch (er)
99 {
100 case IDABORT:
101 ExitFunction(); // exit with hr from CpiGetAdminCatalog() to kick off a rollback
102 case IDRETRY:
103 hr = S_FALSE;
104 break;
105 case IDIGNORE:
106 default:
107 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
108 }
109 }
110 } while (S_FALSE == hr);
111
112 // get NT version
113 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
114 ExitOnFailure(hr, "Failed to get VersionNT property");
115
116 // read elements
117 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartition))
118 {
119 hr = CpiPartitionsRead(&partList);
120 MessageExitOnFailure(hr, msierrComPlusPartitionReadFailed, "Failed to read ComPlusPartitions table");
121 }
122
123 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionRole))
124 {
125 hr = CpiPartitionRolesRead(&partList, &partRoleList);
126 MessageExitOnFailure(hr, msierrComPlusPartitionRoleReadFailed, "Failed to read ComPlusPartitionRole table");
127 }
128
129 if (502 <= iVersionNT && (CpiTableExists(cptComPlusUserInPartitionRole) || CpiTableExists(cptComPlusGroupInPartitionRole)))
130 {
131 hr = CpiUsersInPartitionRolesRead(&partRoleList, &usrInPartRoleList);
132 MessageExitOnFailure(hr, msierrComPlusUserInPartitionRoleReadFailed, "Failed to read ComPlusUserInPartitionRole table");
133 }
134
135 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionUser))
136 {
137 hr = CpiPartitionUsersRead(&partList, &partUsrList);
138 MessageExitOnFailure(hr, msierrComPlusPartitionUserReadFailed, "Failed to read ComPlusPartitionUser table");
139 }
140
141 if (CpiTableExists(cptComPlusApplication))
142 {
143 hr = CpiApplicationsRead(&partList, &appList);
144 MessageExitOnFailure(hr, msierrComPlusApplicationReadFailed, "Failed to read ComPlusApplication table");
145 }
146
147 if (CpiTableExists(cptComPlusApplicationRole))
148 {
149 hr = CpiApplicationRolesRead(&appList, &appRoleList);
150 MessageExitOnFailure(hr, msierrComPlusApplicationRoleReadFailed, "Failed to read ComPlusApplicationRole table");
151 }
152
153 if (CpiTableExists(cptComPlusUserInApplicationRole) || CpiTableExists(cptComPlusGroupInApplicationRole))
154 {
155 hr = CpiUsersInApplicationRolesRead(&appRoleList, &usrInAppRoleList);
156 MessageExitOnFailure(hr, msierrComPlusUserInApplicationRoleReadFailed, "Failed to read ComPlusUserInApplicationRole table");
157 }
158
159 if (CpiTableExists(cptComPlusAssembly))
160 {
161 hr = CpiAssembliesRead(&appList, &appRoleList, &asmList);
162 MessageExitOnFailure(hr, msierrComPlusAssembliesReadFailed, "Failed to read ComPlusAssembly table");
163 }
164
165 if (CpiTableExists(cptComPlusSubscription))
166 {
167 hr = CpiSubscriptionsRead(&asmList, &subList);
168 MessageExitOnFailure(hr, msierrComPlusSubscriptionReadFailed, "Failed to read ComPlusSubscription table");
169 }
170
171 // verify elements
172 hr = CpiPartitionsVerifyInstall(&partList);
173 ExitOnFailure(hr, "Failed to verify partitions");
174
175 hr = CpiApplicationsVerifyInstall(&appList);
176 ExitOnFailure(hr, "Failed to verify applications");
177
178 hr = CpiApplicationRolesVerifyInstall(&appRoleList);
179 ExitOnFailure(hr, "Failed to verify application roles");
180
181 hr = CpiAssembliesVerifyInstall(&asmList);
182 ExitOnFailure(hr, "Failed to verify assemblies");
183
184 if (subList.iInstallCount)
185 {
186 hr = CpiSubscriptionsVerifyInstall(&subList);
187 ExitOnFailure(hr, "Failed to verify subscriptions");
188 }
189
190 // schedule
191 if (partList.iInstallCount || appList.iInstallCount || usrInAppRoleList.iInstallCount ||
192 appRoleList.iInstallCount || asmList.iInstallCount || asmList.iRoleInstallCount || subList.iInstallCount)
193 {
194 // create rollback file name
195 hr = CpiGetTempFileName(&pwzRollbackFileName);
196 ExitOnFailure(hr, "Failed to get rollback file name");
197
198 // schedule rollback prepare custom action
199 hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLPREPARE, pwzRollbackFileName, 0);
200 ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallPrepare");
201
202 // schedule prepare custom action
203 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLPREPARE, pwzRollbackFileName, 0);
204 ExitOnFailure(hr, "Failed to schedule ComPlusInstallPrepare");
205
206 // schedule rollback custom action
207 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzRollbackActionData);
208 ExitOnFailure(hr, "Failed to add rollback file name to rollback custom action data");
209
210 hr = CpiSubscriptionsInstall(&subList, rmRollback, &pwzRollbackActionData, NULL);
211 ExitOnFailure(hr, "Failed to install subscriptions");
212 hr = CpiRoleAssignmentsInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
213 ExitOnFailure(hr, "Failed to install assemblies");
214 hr = CpiAssembliesInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
215 ExitOnFailure(hr, "Failed to install assemblies");
216 hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmRollback, &pwzRollbackActionData, NULL);
217 ExitOnFailure(hr, "Failed to install users in application roles");
218 hr = CpiApplicationRolesInstall(&appRoleList, rmRollback, &pwzRollbackActionData, NULL);
219 ExitOnFailure(hr, "Failed to install application roles");
220 hr = CpiApplicationsInstall(&appList, rmRollback, &pwzRollbackActionData, NULL);
221 ExitOnFailure(hr, "Failed to install applications");
222 hr = CpiPartitionUsersInstall(&partUsrList, rmRollback, &pwzRollbackActionData, NULL);
223 ExitOnFailure(hr, "Failed to install partition users");
224 hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmRollback, &pwzRollbackActionData, NULL);
225 ExitOnFailure(hr, "Failed to install users in partition roles");
226 hr = CpiPartitionsInstall(&partList, rmRollback, &pwzRollbackActionData, NULL);
227 ExitOnFailure(hr, "Failed to install partitions");
228
229 hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLEXECUTE, pwzRollbackActionData, 0);
230 ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallExecute");
231
232 // schedule install custom action
233 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzActionData);
234 ExitOnFailure(hr, "Failed to add rollback file name to custom action data");
235
236 hr = CpiPartitionsInstall(&partList, rmDeferred, &pwzActionData, &iProgress);
237 ExitOnFailure(hr, "Failed to install partitions");
238 hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmDeferred, &pwzActionData, &iProgress);
239 ExitOnFailure(hr, "Failed to install users in partition roles");
240 hr = CpiPartitionUsersInstall(&partUsrList, rmDeferred, &pwzActionData, &iProgress);
241 ExitOnFailure(hr, "Failed to install partition users");
242 hr = CpiApplicationsInstall(&appList, rmDeferred, &pwzActionData, &iProgress);
243 ExitOnFailure(hr, "Failed to install applications");
244 hr = CpiApplicationRolesInstall(&appRoleList, rmDeferred, &pwzActionData, &iProgress);
245 ExitOnFailure(hr, "Failed to install application roles");
246 hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmDeferred, &pwzActionData, &iProgress);
247 ExitOnFailure(hr, "Failed to install users in application roles");
248 hr = CpiAssembliesInstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
249 ExitOnFailure(hr, "Failed to install assemblies");
250 hr = CpiRoleAssignmentsInstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
251 ExitOnFailure(hr, "Failed to install assemblies");
252 hr = CpiSubscriptionsInstall(&subList, rmDeferred, &pwzActionData, &iProgress);
253 ExitOnFailure(hr, "Failed to install subscriptions");
254
255 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTE, pwzActionData, iProgress);
256 ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecute");
257
258 // schedule install commit custom action
259 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzCommitActionData);
260 ExitOnFailure(hr, "Failed to add rollback file name to commit custom action data");
261
262 hr = CpiAssembliesInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress);
263 ExitOnFailure(hr, "Failed to install assemblies");
264 hr = CpiRoleAssignmentsInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress);
265 ExitOnFailure(hr, "Failed to install assemblies");
266 hr = CpiSubscriptionsInstall(&subList, rmCommit, &pwzCommitActionData, &iCommitProgress);
267 ExitOnFailure(hr, "Failed to install subscriptions");
268
269 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTECOMMIT, pwzCommitActionData, iCommitProgress);
270 ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecuteCommit");
271
272 // schedule commit custom action
273 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLCOMMIT, pwzRollbackFileName, 0);
274 ExitOnFailure(hr, "Failed to schedule ComPlusInstallCommit");
275 }
276
277 hr = S_OK;
278
279LExit:
280 // clean up
281 ReleaseObject(piCatalog);
282
283 ReleaseStr(pwzRollbackFileName);
284 ReleaseStr(pwzActionData);
285 ReleaseStr(pwzRollbackActionData);
286 ReleaseStr(pwzCommitActionData);
287
288 CpiPartitionListFree(&partList);
289 CpiPartitionRoleListFree(&partRoleList);
290 CpiUserInPartitionRoleListFree(&usrInPartRoleList);
291 CpiPartitionUserListFree(&partUsrList);
292 CpiApplicationListFree(&appList);
293 CpiApplicationRoleListFree(&appRoleList);
294 CpiUserInApplicationRoleListFree(&usrInAppRoleList);
295 CpiAssemblyListFree(&asmList);
296 CpiSubscriptionListFree(&subList);
297
298 // unitialize
299 CpiSchedFinalize();
300
301 if (fInitializedCom)
302 ::CoUninitialize();
303
304 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
305 return WcaFinalize(er);
306}
307
308
309/********************************************************************
310 ConfigureComPlusUninstall - CUSTOM ACTION ENTRY POINT for uninstalling COM+ components
311
312********************************************************************/
313extern "C" UINT __stdcall ConfigureComPlusUninstall(MSIHANDLE hInstall)
314{
315 HRESULT hr = S_OK;
316 UINT er = ERROR_SUCCESS;
317
318 BOOL fInitializedCom = FALSE;
319
320 ICOMAdminCatalog* piCatalog = NULL;
321
322 CPI_PARTITION_LIST partList;
323 CPI_PARTITION_ROLE_LIST partRoleList;
324 CPI_USER_IN_PARTITION_ROLE_LIST usrInPartRoleList;
325 CPI_PARTITION_USER_LIST partUsrList;
326 CPI_APPLICATION_LIST appList;
327 CPI_APPLICATION_ROLE_LIST appRoleList;
328 CPI_USER_IN_APPLICATION_ROLE_LIST usrInAppRoleList;
329 CPI_ASSEMBLY_LIST asmList;
330 CPI_SUBSCRIPTION_LIST subList;
331
332 LPWSTR pwzRollbackFileName = NULL;
333 LPWSTR pwzActionData = NULL;
334 LPWSTR pwzRollbackActionData = NULL;
335
336 int iVersionNT = 0;
337 int iProgress = 0;
338
339 ::ZeroMemory(&partList, sizeof(CPI_PARTITION_LIST));
340 ::ZeroMemory(&partRoleList, sizeof(CPI_PARTITION_ROLE_LIST));
341 ::ZeroMemory(&usrInPartRoleList, sizeof(CPI_USER_IN_PARTITION_ROLE_LIST));
342 ::ZeroMemory(&partUsrList, sizeof(CPI_PARTITION_USER_LIST));
343 ::ZeroMemory(&appList, sizeof(CPI_APPLICATION_LIST));
344 ::ZeroMemory(&appRoleList, sizeof(CPI_APPLICATION_ROLE_LIST));
345 ::ZeroMemory(&usrInAppRoleList, sizeof(CPI_USER_IN_APPLICATION_ROLE_LIST));
346 ::ZeroMemory(&asmList, sizeof(CPI_ASSEMBLY_LIST));
347 ::ZeroMemory(&subList, sizeof(CPI_SUBSCRIPTION_LIST));
348
349 // initialize
350 hr = WcaInitialize(hInstall, "ConfigureComPlusUninstall");
351 ExitOnFailure(hr, "Failed to initialize");
352
353 hr = ::CoInitialize(NULL);
354 ExitOnFailure(hr, "Failed to initialize COM");
355 fInitializedCom = TRUE;
356
357 CpiSchedInitialize();
358
359 // check for the prerequsite tables
360 if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly))
361 {
362 WcaLog(LOGMSG_VERBOSE, "skipping uninstall COM+ CustomAction, no ComPlusPartition, ComPlusApplication or ComPlusAssembly table present");
363 ExitFunction1(hr = S_FALSE);
364 }
365
366 // make sure we can access the COM+ admin catalog
367 do {
368 hr = CpiSchedGetAdminCatalog(&piCatalog);
369 if (FAILED(hr))
370 {
371 WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog");
372 er = WcaErrorMessage(msierrComPlusCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
373 switch (er)
374 {
375 case IDABORT:
376 ExitFunction(); // exit with hr from CpiGetAdminCatalog() to kick off a rollback
377 case IDRETRY:
378 hr = S_FALSE;
379 break;
380 case IDIGNORE:
381 default:
382 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
383 }
384 }
385 } while (S_FALSE == hr);
386
387 // get NT version
388 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
389 ExitOnFailure(hr, "Failed to get VersionNT property");
390
391 // read elements
392 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartition))
393 {
394 hr = CpiPartitionsRead(&partList);
395 MessageExitOnFailure(hr, msierrComPlusPartitionReadFailed, "Failed to read ComPlusPartitions table");
396 }
397
398 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionRole))
399 {
400 hr = CpiPartitionRolesRead(&partList, &partRoleList);
401 MessageExitOnFailure(hr, msierrComPlusPartitionRoleReadFailed, "Failed to read ComPlusPartitionRole table");
402 }
403
404 if (502 <= iVersionNT && (CpiTableExists(cptComPlusUserInPartitionRole) || CpiTableExists(cptComPlusGroupInPartitionRole)))
405 {
406 hr = CpiUsersInPartitionRolesRead(&partRoleList, &usrInPartRoleList);
407 MessageExitOnFailure(hr, msierrComPlusUserInPartitionRoleReadFailed, "Failed to read ComPlusUserInPartitionRole table");
408 }
409
410 if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionUser))
411 {
412 hr = CpiPartitionUsersRead(&partList, &partUsrList);
413 MessageExitOnFailure(hr, msierrComPlusPartitionUserReadFailed, "Failed to read ComPlusPartitionUser table");
414 }
415
416 if (CpiTableExists(cptComPlusApplication))
417 {
418 hr = CpiApplicationsRead(&partList, &appList);
419 MessageExitOnFailure(hr, msierrComPlusApplicationReadFailed, "Failed to read ComPlusApplication table");
420 }
421
422 if (CpiTableExists(cptComPlusApplicationRole))
423 {
424 hr = CpiApplicationRolesRead(&appList, &appRoleList);
425 MessageExitOnFailure(hr, msierrComPlusApplicationRoleReadFailed, "Failed to read ComPlusApplicationRole table");
426 }
427
428 if (CpiTableExists(cptComPlusUserInApplicationRole) || CpiTableExists(cptComPlusGroupInApplicationRole))
429 {
430 hr = CpiUsersInApplicationRolesRead(&appRoleList, &usrInAppRoleList);
431 MessageExitOnFailure(hr, msierrComPlusUserInApplicationRoleReadFailed, "Failed to read ComPlusUserInApplicationRole table");
432 }
433
434 if (CpiTableExists(cptComPlusAssembly))
435 {
436 hr = CpiAssembliesRead(&appList, &appRoleList, &asmList);
437 MessageExitOnFailure(hr, msierrComPlusAssembliesReadFailed, "Failed to read ComPlusAssembly table");
438 }
439
440 if (CpiTableExists(cptComPlusSubscription))
441 {
442 hr = CpiSubscriptionsRead(&asmList, &subList);
443 MessageExitOnFailure(hr, msierrComPlusSubscriptionReadFailed, "Failed to read ComPlusSubscription table");
444 }
445
446 // verify elements
447 hr = CpiPartitionsVerifyUninstall(&partList);
448 ExitOnFailure(hr, "Failed to verify partitions");
449
450 hr = CpiApplicationsVerifyUninstall(&appList);
451 ExitOnFailure(hr, "Failed to verify applications");
452
453 hr = CpiApplicationRolesVerifyUninstall(&appRoleList);
454 ExitOnFailure(hr, "Failed to verify application roles");
455
456 hr = CpiAssembliesVerifyUninstall(&asmList);
457 ExitOnFailure(hr, "Failed to verify assemblies");
458
459 if (subList.iUninstallCount)
460 {
461 hr = CpiSubscriptionsVerifyUninstall(&subList);
462 ExitOnFailure(hr, "Failed to verify subscriptions");
463 }
464
465 // schedule
466 if (partList.iUninstallCount || appList.iUninstallCount || appRoleList.iUninstallCount ||
467 usrInAppRoleList.iUninstallCount || asmList.iUninstallCount || asmList.iRoleUninstallCount || subList.iUninstallCount)
468 {
469 // create rollback file name
470 hr = CpiGetTempFileName(&pwzRollbackFileName);
471 ExitOnFailure(hr, "Failed to get rollback file name");
472
473 // schedule rollback prepare custom action
474 hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLPREPARE, pwzRollbackFileName, 0);
475 ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallPrepare");
476
477 // schedule prepare custom action
478 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLPREPARE, pwzRollbackFileName, 0);
479 ExitOnFailure(hr, "Failed to schedule ComPlusInstallPrepare");
480
481 // schedule rollback custom action
482 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzRollbackActionData);
483 ExitOnFailure(hr, "Failed to add rollback file name to rollback custom action data");
484
485 hr = CpiPartitionsUninstall(&partList, rmRollback, &pwzRollbackActionData, NULL);
486 ExitOnFailure(hr, "Failed to uninstall partitions");
487 hr = CpiUsersInPartitionRolesUninstall(&usrInPartRoleList, rmRollback, &pwzRollbackActionData, NULL);
488 ExitOnFailure(hr, "Failed to uninstall users in partition roles");
489 hr = CpiPartitionUsersUninstall(&partUsrList, rmRollback, &pwzRollbackActionData, NULL);
490 ExitOnFailure(hr, "Failed to uninstall partition users");
491 hr = CpiApplicationsUninstall(&appList, rmRollback, &pwzRollbackActionData, NULL);
492 ExitOnFailure(hr, "Failed to uninstall applications");
493 hr = CpiApplicationRolesUninstall(&appRoleList, rmRollback, &pwzRollbackActionData, NULL);
494 ExitOnFailure(hr, "Failed to uninstall application roles");
495 hr = CpiUsersInApplicationRolesUninstall(&usrInAppRoleList, rmRollback, &pwzRollbackActionData, NULL);
496 ExitOnFailure(hr, "Failed to uninstall users in application roles");
497 hr = CpiAssembliesUninstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
498 ExitOnFailure(hr, "Failed to uninstall assemblies");
499 hr = CpiRoleAssignmentsUninstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
500 ExitOnFailure(hr, "Failed to uninstall assemblies");
501 hr = CpiSubscriptionsUninstall(&subList, rmRollback, &pwzRollbackActionData, NULL);
502 ExitOnFailure(hr, "Failed to uninstall subscriptions");
503
504 hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKUNINSTALLEXECUTE, pwzRollbackActionData, 0);
505 ExitOnFailure(hr, "Failed to schedule ComPlusRollbackUninstallExecute");
506
507 // schedule install custom action
508 hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzActionData);
509 ExitOnFailure(hr, "Failed to add rollback file name to custom action data");
510
511 hr = CpiSubscriptionsUninstall(&subList, rmDeferred, &pwzActionData, &iProgress);
512 ExitOnFailure(hr, "Failed to uninstall subscriptions");
513 hr = CpiRoleAssignmentsUninstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
514 ExitOnFailure(hr, "Failed to uninstall assemblies");
515 hr = CpiAssembliesUninstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
516 ExitOnFailure(hr, "Failed to uninstall assemblies");
517 hr = CpiUsersInApplicationRolesUninstall(&usrInAppRoleList, rmDeferred, &pwzActionData, &iProgress);
518 ExitOnFailure(hr, "Failed to uninstall users in application roles");
519 hr = CpiApplicationRolesUninstall(&appRoleList, rmDeferred, &pwzActionData, &iProgress);
520 ExitOnFailure(hr, "Failed to uninstall application roles");
521 hr = CpiApplicationsUninstall(&appList, rmDeferred, &pwzActionData, &iProgress);
522 ExitOnFailure(hr, "Failed to uninstall applications");
523 hr = CpiPartitionUsersUninstall(&partUsrList, rmDeferred, &pwzActionData, &iProgress);
524 ExitOnFailure(hr, "Failed to uninstall partition users");
525 hr = CpiUsersInPartitionRolesUninstall(&usrInPartRoleList, rmDeferred, &pwzActionData, &iProgress);
526 ExitOnFailure(hr, "Failed to uninstall users in partition roles");
527 hr = CpiPartitionsUninstall(&partList, rmDeferred, &pwzActionData, &iProgress);
528 ExitOnFailure(hr, "Failed to uninstall partitions");
529
530 hr = WcaDoDeferredAction(CP_COMPLUSUNINSTALLEXECUTE, pwzActionData, iProgress);
531 ExitOnFailure(hr, "Failed to schedule ComPlusUninstallExecute");
532
533 // schedule commit custom action
534 hr = WcaDoDeferredAction(CP_COMPLUSINSTALLCOMMIT, pwzRollbackFileName, 0);
535 ExitOnFailure(hr, "Failed to schedule ComPlusInstallCommit");
536 }
537
538 hr = S_OK;
539
540LExit:
541 // clean up
542 ReleaseObject(piCatalog);
543
544 ReleaseStr(pwzRollbackFileName);
545 ReleaseStr(pwzActionData);
546 ReleaseStr(pwzRollbackActionData);
547
548 CpiPartitionListFree(&partList);
549 CpiPartitionRoleListFree(&partRoleList);
550 CpiUserInPartitionRoleListFree(&usrInPartRoleList);
551 CpiPartitionUserListFree(&partUsrList);
552 CpiApplicationListFree(&appList);
553 CpiApplicationRoleListFree(&appRoleList);
554 CpiUserInApplicationRoleListFree(&usrInAppRoleList);
555 CpiAssemblyListFree(&asmList);
556 CpiSubscriptionListFree(&subList);
557
558 // unitialize
559 CpiSchedFinalize();
560
561 if (fInitializedCom)
562 ::CoUninitialize();
563
564 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
565 return WcaFinalize(er);
566}
diff --git a/src/ext/ComPlus/ca/cpsubsexec.cpp b/src/ext/ComPlus/ca/cpsubsexec.cpp
new file mode 100644
index 00000000..bbcf9853
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpsubsexec.cpp
@@ -0,0 +1,411 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_SUBSCRIPTION_ATTRIBUTES
9{
10 int iActionType;
11 int iActionCost;
12 LPWSTR pwzKey;
13 LPWSTR pwzID;
14 LPWSTR pwzName;
15 LPWSTR pwzEventCLSID;
16 LPWSTR pwzPublisherID;
17 LPWSTR pwzCompCLSID;
18 LPWSTR pwzAppID;
19 LPWSTR pwzPartID;
20 CPI_PROPERTY* pPropList;
21};
22
23
24// prototypes for private helper functions
25
26static HRESULT ReadSubscriptionAttributes(
27 LPWSTR* ppwzData,
28 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
29 );
30static void FreeSubscriptionAttributes(
31 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
32 );
33static HRESULT CreateSubscription(
34 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
35 );
36static HRESULT RemoveSubscription(
37 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
38 );
39
40
41// function definitions
42
43HRESULT CpiConfigureSubscriptions(
44 LPWSTR* ppwzData,
45 HANDLE hRollbackFile
46 )
47{
48 HRESULT hr = S_OK;
49
50 CPI_SUBSCRIPTION_ATTRIBUTES attrs;
51 ::ZeroMemory(&attrs, sizeof(attrs));
52
53 // read action text
54 hr = CpiActionStartMessage(ppwzData, FALSE);
55 ExitOnFailure(hr, "Failed to send action start message");
56
57 // ger count
58 int iCnt = 0;
59 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
60 ExitOnFailure(hr, "Failed to read count");
61
62 // write count to rollback file
63 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
64 ExitOnFailure(hr, "Failed to write count to rollback file");
65
66 for (int i = 0; i < iCnt; i++)
67 {
68 // read attributes from CustomActionData
69 hr = ReadSubscriptionAttributes(ppwzData, &attrs);
70 ExitOnFailure(hr, "Failed to read attributes");
71
72 // progress message
73 hr = CpiActionDataMessage(1, attrs.pwzName);
74 ExitOnFailure(hr, "Failed to send progress messages");
75
76 if (S_FALSE == hr)
77 ExitFunction();
78
79 // write key to rollback file
80 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
81 ExitOnFailure(hr, "Failed to write key to rollback file");
82
83 // action
84 switch (attrs.iActionType)
85 {
86 case atCreate:
87 hr = CreateSubscription(&attrs);
88 ExitOnFailure(hr, "Failed to create subscription, key: %S", attrs.pwzKey);
89 break;
90 case atRemove:
91 hr = RemoveSubscription(&attrs);
92 ExitOnFailure(hr, "Failed to remove subscription, key: %S", attrs.pwzKey);
93 break;
94 }
95
96 // write completion status to rollback file
97 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
98 ExitOnFailure(hr, "Failed to write completion status to rollback file");
99
100 // progress
101 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
102 ExitOnFailure(hr, "Failed to update progress");
103 }
104
105 hr = S_OK;
106
107LExit:
108 // clean up
109 FreeSubscriptionAttributes(&attrs);
110
111 return hr;
112}
113
114HRESULT CpiRollbackConfigureSubscriptions(
115 LPWSTR* ppwzData,
116 CPI_ROLLBACK_DATA* pRollbackDataList
117 )
118{
119 HRESULT hr = S_OK;
120
121 int iRollbackStatus;
122
123 CPI_SUBSCRIPTION_ATTRIBUTES attrs;
124 ::ZeroMemory(&attrs, sizeof(attrs));
125
126 // read action text
127 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
128 ExitOnFailure(hr, "Failed to send action start message");
129
130 // ger count
131 int iCnt = 0;
132 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
133 ExitOnFailure(hr, "Failed to read count");
134
135 for (int i = 0; i < iCnt; i++)
136 {
137 // read attributes from CustomActionData
138 hr = ReadSubscriptionAttributes(ppwzData, &attrs);
139 ExitOnFailure(hr, "Failed to read attributes");
140
141 // rollback status
142 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
143
144 if (S_FALSE == hr)
145 continue; // not found, nothing to rollback
146
147 // progress message
148 hr = CpiActionDataMessage(1, attrs.pwzName);
149 ExitOnFailure(hr, "Failed to send progress messages");
150
151 if (S_FALSE == hr)
152 ExitFunction();
153
154 // action
155 switch (attrs.iActionType)
156 {
157 case atCreate:
158 hr = CreateSubscription(&attrs);
159 if (FAILED(hr))
160 WcaLog(LOGMSG_STANDARD, "Failed to create subscription, hr: 0x%x, key: %S", hr, attrs.pwzKey);
161 break;
162 case atRemove:
163 hr = RemoveSubscription(&attrs);
164 if (FAILED(hr))
165 WcaLog(LOGMSG_STANDARD, "Failed to remove subscription, hr: 0x%x, key: %S", hr, attrs.pwzKey);
166 break;
167 }
168
169 // check rollback status
170 if (0 == iRollbackStatus)
171 continue; // operation did not complete, skip progress
172
173 // progress
174 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
175 ExitOnFailure(hr, "Failed to update progress");
176 }
177
178 hr = S_OK;
179
180LExit:
181 // clean up
182 FreeSubscriptionAttributes(&attrs);
183
184 return hr;
185}
186
187
188// helper function definitions
189
190static HRESULT ReadSubscriptionAttributes(
191 LPWSTR* ppwzData,
192 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
193 )
194{
195 HRESULT hr = S_OK;
196
197 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
198 ExitOnFailure(hr, "Failed to read action type");
199 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
200 ExitOnFailure(hr, "Failed to read action cost");
201 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
202 ExitOnFailure(hr, "Failed to read key");
203 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzID);
204 ExitOnFailure(hr, "Failed to read id");
205 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
206 ExitOnFailure(hr, "Failed to read name");
207 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzEventCLSID);
208 ExitOnFailure(hr, "Failed to read event clsid");
209 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPublisherID);
210 ExitOnFailure(hr, "Failed to read publisher id");
211 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzCompCLSID);
212 ExitOnFailure(hr, "Failed to read component clsid");
213 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
214 ExitOnFailure(hr, "Failed to read application id");
215 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
216 ExitOnFailure(hr, "Failed to read partition id");
217
218 hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList);
219 ExitOnFailure(hr, "Failed to read properties");
220
221 hr = S_OK;
222
223LExit:
224 return hr;
225}
226
227static void FreeSubscriptionAttributes(
228 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
229 )
230{
231 ReleaseStr(pAttrs->pwzKey);
232 ReleaseStr(pAttrs->pwzID);
233 ReleaseStr(pAttrs->pwzName);
234 ReleaseStr(pAttrs->pwzEventCLSID);
235 ReleaseStr(pAttrs->pwzPublisherID);
236 ReleaseStr(pAttrs->pwzCompCLSID);
237 ReleaseStr(pAttrs->pwzAppID);
238 ReleaseStr(pAttrs->pwzPartID);
239
240 if (pAttrs->pPropList)
241 CpiFreePropertyList(pAttrs->pPropList);
242}
243
244static HRESULT CreateSubscription(
245 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
246 )
247{
248 HRESULT hr = S_OK;
249 UINT er = ERROR_SUCCESS;
250
251 ICatalogCollection* piSubsColl = NULL;
252 ICatalogObject* piSubsObj = NULL;
253
254 PSID pSid = NULL;
255 long lChanges = 0;
256
257 // log
258 WcaLog(LOGMSG_VERBOSE, "Creating subscription, key: %S", pAttrs->pwzKey);
259
260 // get subscriptions collection
261 hr = CpiGetSubscriptionsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzCompCLSID, &piSubsColl);
262 if (S_FALSE == hr)
263 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
264 ExitOnFailure(hr, "Failed to get subscriptions collection");
265
266 // check if subscription exists
267 hr = CpiFindCollectionObjectByStringKey(piSubsColl, pAttrs->pwzID, &piSubsObj);
268 ExitOnFailure(hr, "Failed to find subscription");
269
270 if (S_FALSE == hr)
271 {
272 // create subscription
273 hr = CpiAddCollectionObject(piSubsColl, &piSubsObj);
274 ExitOnFailure(hr, "Failed to add subscription to collection");
275
276 hr = CpiPutCollectionObjectValue(piSubsObj, L"ID", pAttrs->pwzID);
277 ExitOnFailure(hr, "Failed to set subscription id property");
278
279 hr = CpiPutCollectionObjectValue(piSubsObj, L"Name", pAttrs->pwzName);
280 ExitOnFailure(hr, "Failed to set subscription name property");
281
282 if (pAttrs->pwzEventCLSID && *pAttrs->pwzEventCLSID)
283 {
284 hr = CpiPutCollectionObjectValue(piSubsObj, L"EventCLSID", pAttrs->pwzEventCLSID);
285 ExitOnFailure(hr, "Failed to set role event clsid property");
286 }
287
288 if (pAttrs->pwzPublisherID && *pAttrs->pwzPublisherID)
289 {
290 hr = CpiPutCollectionObjectValue(piSubsObj, L"PublisherID", pAttrs->pwzPublisherID);
291 ExitOnFailure(hr, "Failed to set role publisher id property");
292 }
293 }
294
295 // properties
296 for (CPI_PROPERTY* pItm = pAttrs->pPropList; pItm; pItm = pItm->pNext)
297 {
298 // UserName property
299 if (0 == lstrcmpW(pItm->wzName, L"UserName"))
300 {
301 // get SID for account
302 do {
303 er = ERROR_SUCCESS;
304 hr = CpiAccountNameToSid(pItm->pwzValue, &pSid);
305 if (!::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK))
306 {
307 if (HRESULT_FROM_WIN32(ERROR_NONE_MAPPED) == hr)
308 {
309 WcaLog(LOGMSG_STANDARD, "Failed to lookup account name, hr: 0x%x, account: '%S'", hr, pItm->pwzValue);
310 er = WcaErrorMessage(msierrComPlusFailedLookupNames, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
311 switch (er)
312 {
313 case IDABORT:
314 ExitFunction(); // exit with error code from CpiAccountNameToSid()
315 case IDRETRY:
316 break;
317 case IDIGNORE:
318 default:
319 hr = S_FALSE;
320 }
321 }
322 else
323 ExitOnFailure(hr, "Failed to get SID for account, account: '%S'", pItm->pwzValue);
324 }
325 else if (FAILED(hr))
326 {
327 WcaLog(LOGMSG_STANDARD, "Failed to get SID for account, hr: 0x%x, account: '%S'", hr, pItm->pwzValue);
328 hr = S_FALSE;
329 }
330 } while (IDRETRY == er);
331
332 if (S_FALSE == hr)
333 continue;
334
335 // convert SID back to account name
336 hr = CpiSidToAccountName(pSid, &pItm->pwzValue);
337 ExitOnFailure(hr, "Failed to convert SID to account name");
338 }
339
340 // set property
341 hr = CpiPutCollectionObjectValue(piSubsObj, pItm->wzName, pItm->pwzValue);
342 ExitOnFailure(hr, "Failed to set object property value, name: %S", pItm->wzName);
343 }
344
345 // save changes
346 hr = piSubsColl->SaveChanges(&lChanges);
347 if (COMADMIN_E_OBJECTERRORS == hr)
348 CpiLogCatalogErrorInfo();
349 ExitOnFailure(hr, "Failed to save changes");
350
351 // log
352 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
353
354 hr = S_OK;
355
356LExit:
357 // clean up
358 ReleaseObject(piSubsColl);
359 ReleaseObject(piSubsObj);
360
361 if (pSid)
362 ::HeapFree(::GetProcessHeap(), 0, pSid);
363
364 return hr;
365}
366
367static HRESULT RemoveSubscription(
368 CPI_SUBSCRIPTION_ATTRIBUTES* pAttrs
369 )
370{
371 HRESULT hr = S_OK;
372
373 ICatalogCollection* piSubsColl = NULL;
374
375 long lChanges = 0;
376
377 // log
378 WcaLog(LOGMSG_VERBOSE, "Removing subscription, key: %S", pAttrs->pwzKey);
379
380 // get subscriptions collection
381 hr = CpiGetSubscriptionsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pwzCompCLSID, &piSubsColl);
382 ExitOnFailure(hr, "Failed to get subscriptions collection");
383
384 if (S_FALSE == hr)
385 {
386 // subscription not found
387 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve subscriptions collection, nothing to delete, key: %S", pAttrs->pwzKey);
388 ExitFunction1(hr = S_OK);
389 }
390
391 // remove
392 hr = CpiRemoveCollectionObject(piSubsColl, pAttrs->pwzID, NULL, FALSE);
393 ExitOnFailure(hr, "Failed to remove subscriptions");
394
395 // save changes
396 hr = piSubsColl->SaveChanges(&lChanges);
397 if (COMADMIN_E_OBJECTERRORS == hr)
398 CpiLogCatalogErrorInfo();
399 ExitOnFailure(hr, "Failed to save changes");
400
401 // log
402 WcaLog(LOGMSG_VERBOSE, "%d changes saved to catalog, key: %S", lChanges, pAttrs->pwzKey);
403
404 hr = S_OK;
405
406LExit:
407 // clean up
408 ReleaseObject(piSubsColl);
409
410 return hr;
411}
diff --git a/src/ext/ComPlus/ca/cpsubsexec.h b/src/ext/ComPlus/ca/cpsubsexec.h
new file mode 100644
index 00000000..2f4d3c75
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpsubsexec.h
@@ -0,0 +1,12 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5HRESULT CpiConfigureSubscriptions(
6 LPWSTR* ppwzData,
7 HANDLE hRollbackFile
8 );
9HRESULT CpiRollbackConfigureSubscriptions(
10 LPWSTR* ppwzData,
11 CPI_ROLLBACK_DATA* pRollbackDataList
12 );
diff --git a/src/ext/ComPlus/ca/cpsubssched.cpp b/src/ext/ComPlus/ca/cpsubssched.cpp
new file mode 100644
index 00000000..df15fd03
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpsubssched.cpp
@@ -0,0 +1,606 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsSubscriptionQuery =
9 L"SELECT `Subscription`, `ComPlusComponent_`, `Component_`, `Id`, `Name`, `EventCLSID`, `PublisherID` FROM `ComPlusSubscription`";
10enum eSubscriptionQuery { sqSubscription = 1, sqComPlusComponent, sqComponent, sqID, sqName, sqEventCLSID, sqPublisherID };
11
12LPCWSTR vcsSubscriptionPropertyQuery =
13 L"SELECT `Name`, `Value` FROM `ComPlusSubscriptionProperty` WHERE `Subscription_` = ?";
14
15
16// property definitions
17
18CPI_PROPERTY_DEFINITION pdlSubscriptionProperties[] =
19{
20 {L"Description", cpptString, 500},
21 {L"Enabled", cpptBoolean, 500},
22 {L"EventClassPartitionID", cpptString, 502},
23 {L"FilterCriteria", cpptString, 500},
24 {L"InterfaceID", cpptString, 500},
25 {L"MachineName", cpptString, 500},
26 {L"MethodName", cpptString, 500},
27 {L"PerUser", cpptBoolean, 500},
28 {L"Queued", cpptBoolean, 500},
29 {L"SubscriberMoniker", cpptString, 500},
30 {L"UserName", cpptUser, 500},
31 {NULL, cpptNone, 0}
32};
33
34
35// prototypes for private helper functions
36
37static void FreeSubscription(
38 CPI_SUBSCRIPTION* pItm
39 );
40static HRESULT FindObjectForSubscription(
41 CPI_SUBSCRIPTION* pItm,
42 BOOL fFindId,
43 BOOL fFindName,
44 ICatalogObject** ppiSubsObj
45 );
46static HRESULT AddSubscriptionToActionData(
47 CPI_SUBSCRIPTION* pItm,
48 int iActionType,
49 int iActionCost,
50 LPWSTR* ppwzActionData
51 );
52static HRESULT ComponentFindByKey(
53 CPI_ASSEMBLY_LIST* pAsmList,
54 LPCWSTR pwzKey,
55 CPI_ASSEMBLY** ppAsmItm,
56 CPISCHED_COMPONENT** ppCompItm
57 );
58
59
60// function definitions
61
62void CpiSubscriptionListFree(
63 CPI_SUBSCRIPTION_LIST* pList
64 )
65{
66 CPI_SUBSCRIPTION* pItm = pList->pFirst;
67
68 while (pItm)
69 {
70 CPI_SUBSCRIPTION* pDelete = pItm;
71 pItm = pItm->pNext;
72 FreeSubscription(pDelete);
73 }
74}
75
76HRESULT CpiSubscriptionsRead(
77 CPI_ASSEMBLY_LIST* pAsmList,
78 CPI_SUBSCRIPTION_LIST* pSubList
79 )
80{
81 HRESULT hr = S_OK;
82 UINT er = ERROR_SUCCESS;
83
84 PMSIHANDLE hView, hRec;
85
86 CPI_SUBSCRIPTION* pItm = NULL;
87 LPWSTR pwzData = NULL;
88 BOOL fMatchingArchitecture = FALSE;
89
90 // loop through all applications
91 hr = WcaOpenExecuteView(vcsSubscriptionQuery, &hView);
92 ExitOnFailure(hr, "Failed to execute view on ComPlusSubscription table");
93
94 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
95 {
96 // get component
97 hr = WcaGetRecordString(hRec, sqComponent, &pwzData);
98 ExitOnFailure(hr, "Failed to get component");
99
100 // check if the component is our processor architecture
101 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
102 ExitOnFailure(hr, "Failed to get component architecture.");
103
104 if (!fMatchingArchitecture)
105 {
106 continue; // not the same architecture, ignore
107 }
108
109 // create entry
110 pItm = (CPI_SUBSCRIPTION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_SUBSCRIPTION));
111 if (!pItm)
112 ExitFunction1(hr = E_OUTOFMEMORY);
113
114 // get component install state
115 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
116 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
117
118 // get key
119 hr = WcaGetRecordString(hRec, sqSubscription, &pwzData);
120 ExitOnFailure(hr, "Failed to get key");
121 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
122
123 // get com+ component
124 hr = WcaGetRecordString(hRec, sqComPlusComponent, &pwzData);
125 ExitOnFailure(hr, "Failed to get COM+ component");
126
127 hr = ComponentFindByKey(pAsmList, pwzData, &pItm->pAssembly, &pItm->pComponent);
128
129 if (S_FALSE == hr)
130 {
131 // component not found
132 ExitOnFailure(hr = E_FAIL, "Failed to find component, key: %S", pwzData);
133 }
134
135 // get id
136 hr = WcaGetRecordFormattedString(hRec, sqID, &pwzData);
137 ExitOnFailure(hr, "Failed to get id");
138
139 if (pwzData && *pwzData)
140 {
141 hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID));
142 ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData);
143 }
144
145 // get name
146 hr = WcaGetRecordFormattedString(hRec, sqName, &pwzData);
147 ExitOnFailure(hr, "Failed to get name");
148 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
149
150 // get event clsid
151 hr = WcaGetRecordFormattedString(hRec, sqEventCLSID, &pwzData);
152 ExitOnFailure(hr, "Failed to get event clsid");
153 StringCchCopyW(pItm->wzEventCLSID, countof(pItm->wzEventCLSID), pwzData);
154
155 // get publisher id
156 hr = WcaGetRecordFormattedString(hRec, sqPublisherID, &pwzData);
157 ExitOnFailure(hr, "Failed to get publisher id");
158 StringCchCopyW(pItm->wzPublisherID, countof(pItm->wzPublisherID), pwzData);
159
160 // get properties
161 if (CpiTableExists(cptComPlusSubscriptionProperty))
162 {
163 hr = CpiPropertiesRead(vcsSubscriptionPropertyQuery, pItm->wzKey, pdlSubscriptionProperties, &pItm->pProperties, &pItm->iPropertyCount);
164 ExitOnFailure(hr, "Failed to get subscription properties");
165 }
166
167 // set references & increment counters
168 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
169 {
170 CpiApplicationAddReferenceInstall(pItm->pAssembly->pApplication);
171 pItm->pAssembly->fReferencedForInstall = TRUE;
172 pSubList->iInstallCount++;
173 if (pItm->pAssembly->iAttributes & aaRunInCommit)
174 pSubList->iCommitCount++;
175 }
176 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
177 {
178 CpiApplicationAddReferenceUninstall(pItm->pAssembly->pApplication);
179 pItm->pAssembly->fReferencedForUninstall = TRUE;
180 pSubList->iUninstallCount++;
181 }
182
183 // add entry
184 if (pSubList->pFirst)
185 pItm->pNext = pSubList->pFirst;
186 pSubList->pFirst = pItm;
187 pItm = NULL;
188 }
189
190 if (E_NOMOREITEMS == hr)
191 hr = S_OK;
192
193LExit:
194 // clean up
195 if (pItm)
196 FreeSubscription(pItm);
197
198 ReleaseStr(pwzData);
199
200 return hr;
201}
202
203HRESULT CpiSubscriptionsVerifyInstall(
204 CPI_SUBSCRIPTION_LIST* pList
205 )
206{
207 HRESULT hr = S_OK;
208 UINT er = ERROR_SUCCESS;
209
210 ICatalogObject* piSubsObj = NULL;
211
212 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
213 {
214 // subscriptions that are being installed
215 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
216 continue;
217
218 // subscription is supposed to exist
219 if (CpiIsInstalled(pItm->isInstalled))
220 {
221 // if we don't have an id
222 if (!*pItm->wzID)
223 {
224 // find subscriptions with conflicting name
225 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
226 ExitOnFailure(hr, "Failed to find collection object for subscription");
227
228 // if the subscription was found
229 if (S_OK == hr)
230 {
231 // get id from subscription object
232 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
233 ExitOnFailure(hr, "Failed to get id");
234 }
235
236 // if the subscription was not found
237 else
238 {
239 // create a new id
240 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
241 ExitOnFailure(hr, "Failed to create id");
242 }
243 }
244 }
245
246 // subscription is supposed to be created
247 else
248 {
249 // check for conflicts
250 do {
251 if (*pItm->wzID)
252 {
253 // find subscriptions with conflicting id
254 hr = FindObjectForSubscription(pItm, TRUE, FALSE, &piSubsObj);
255 ExitOnFailure(hr, "Failed to find collection object for subscription");
256
257 if (S_FALSE == hr)
258 {
259 // find subscriptions with conflicting name
260 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
261 ExitOnFailure(hr, "Failed to find collection object for subscription");
262
263 if (S_OK == hr)
264 // "A subscription with a conflictiong name exists. retry cancel"
265 er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
266 else
267 break; // no conflicting entry found, break loop
268 }
269 else
270 // "A subscription with a conflicting id exists. abort retry ignore"
271 er = WcaErrorMessage(msierrComPlusSubscriptionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
272 }
273 else
274 {
275 // find subscriptions with conflicting name
276 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
277 ExitOnFailure(hr, "Failed to find collection object for subscription");
278
279 if (S_OK == hr)
280 // "A subscription with a conflictiong name exists. abort retry ignore"
281 er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
282 else
283 break; // no conflicting entry found, break loop
284 }
285
286 switch (er)
287 {
288 case IDCANCEL:
289 case IDABORT:
290 ExitOnFailure(hr = E_FAIL, "A subscription with a conflictiong name or id exists, key: %S", pItm->wzKey);
291 break;
292 case IDRETRY:
293 break;
294 case IDIGNORE:
295 default:
296 // if we don't have an id, copy id from object
297 if (!*pItm->wzID)
298 {
299 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
300 ExitOnFailure(hr, "Failed to get id");
301 }
302 hr = S_FALSE; // indicate that this is not a conflict
303 }
304 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
305
306 // create a new id if one is missing
307 if (!*pItm->wzID)
308 {
309 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
310 ExitOnFailure(hr, "Failed to create id");
311 }
312 }
313
314 // clean up
315 ReleaseNullObject(piSubsObj);
316 }
317
318 hr = S_OK;
319
320LExit:
321 // clean up
322 ReleaseObject(piSubsObj);
323
324 return hr;
325}
326
327HRESULT CpiSubscriptionsVerifyUninstall(
328 CPI_SUBSCRIPTION_LIST* pList
329 )
330{
331 HRESULT hr = S_OK;
332 ICatalogObject* piSubsObj = NULL;
333
334 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
335 {
336 // subscriptions that are being installed
337 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
338 continue;
339
340 // find subscriptions with conflicting name
341 hr = FindObjectForSubscription(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piSubsObj);
342 ExitOnFailure(hr, "Failed to find collection object for subscription");
343
344 // if the subscription was found
345 if (S_OK == hr)
346 {
347 // if we don't have an id, copy id from object
348 if (!*pItm->wzID)
349 {
350 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
351 ExitOnFailure(hr, "Failed to get id");
352 }
353 }
354
355 // if the subscription was not found
356 else
357 {
358 pItm->fObjectNotFound = TRUE;
359 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
360 }
361
362 // clean up
363 ReleaseNullObject(piSubsObj);
364 }
365
366 hr = S_OK;
367
368LExit:
369 // clean up
370 ReleaseObject(piSubsObj);
371
372 return hr;
373}
374
375HRESULT CpiSubscriptionsInstall(
376 CPI_SUBSCRIPTION_LIST* pList,
377 int iRunMode,
378 LPWSTR* ppwzActionData,
379 int* piProgress
380 )
381{
382 HRESULT hr = S_OK;
383
384 int iActionType;
385 int iCount = 0;
386
387 // add action text
388 hr = CpiAddActionTextToActionData(L"CreateSubscrComPlusComponents", ppwzActionData);
389 ExitOnFailure(hr, "Failed to add action text to custom action data");
390
391 // subscription count
392 switch (iRunMode)
393 {
394 case rmDeferred:
395 iCount = pList->iInstallCount - pList->iCommitCount;
396 break;
397 case rmCommit:
398 iCount = pList->iCommitCount;
399 break;
400 case rmRollback:
401 iCount = pList->iInstallCount;
402 break;
403 }
404
405 // add subscription count to action data
406 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
407 ExitOnFailure(hr, "Failed to add count to custom action data");
408
409 // add assemblies to custom action data in forward order
410 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
411 {
412 // roles that are being installed only
413 if ((rmCommit == iRunMode && !(pItm->pAssembly->iAttributes & aaRunInCommit)) ||
414 (rmDeferred == iRunMode && (pItm->pAssembly->iAttributes & aaRunInCommit)) ||
415 !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
416 continue;
417
418 // action type
419 if (rmRollback == iRunMode)
420 {
421 if (CpiIsInstalled(pItm->isInstalled))
422 iActionType = atNoOp;
423 else
424 iActionType = atRemove;
425 }
426 else
427 iActionType = atCreate;
428
429 // add to action data
430 hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_CREATE, ppwzActionData);
431 ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey);
432 }
433
434 // add progress tics
435 if (piProgress)
436 *piProgress += COST_SUBSCRIPTION_CREATE * pList->iInstallCount;
437
438 hr = S_OK;
439
440LExit:
441 return hr;
442}
443
444HRESULT CpiSubscriptionsUninstall(
445 CPI_SUBSCRIPTION_LIST* pList,
446 int iRunMode,
447 LPWSTR* ppwzActionData,
448 int* piProgress
449 )
450{
451 HRESULT hr = S_OK;
452
453 int iActionType;
454
455 // add action text
456 hr = CpiAddActionTextToActionData(L"RemoveSubscrComPlusComponents", ppwzActionData);
457 ExitOnFailure(hr, "Failed to add action text to custom action data");
458
459 // add subscription count to action data
460 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
461 ExitOnFailure(hr, "Failed to add count to custom action data");
462
463 // add assemblies to custom action data in reverse order
464 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
465 {
466 // roles that are being uninstalled only
467 if (pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
468 continue;
469
470 // action type
471 if (rmRollback == iRunMode)
472 iActionType = atCreate;
473 else
474 iActionType = atRemove;
475
476 // add to action data
477 hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_DELETE, ppwzActionData);
478 ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey);
479 }
480
481 // add progress tics
482 if (piProgress)
483 *piProgress += COST_SUBSCRIPTION_DELETE * pList->iUninstallCount;
484
485 hr = S_OK;
486
487LExit:
488 return hr;
489}
490
491
492// helper function definitions
493
494static void FreeSubscription(
495 CPI_SUBSCRIPTION* pItm
496 )
497{
498 if (pItm->pProperties)
499 CpiPropertiesFreeList(pItm->pProperties);
500
501 ::HeapFree(::GetProcessHeap(), 0, pItm);
502}
503
504static HRESULT FindObjectForSubscription(
505 CPI_SUBSCRIPTION* pItm,
506 BOOL fFindId,
507 BOOL fFindName,
508 ICatalogObject** ppiSubsObj
509 )
510{
511 HRESULT hr = S_OK;
512
513 ICatalogCollection* piSubsColl = NULL;
514
515 // get applications collection
516 hr = CpiGetSubscriptionsCollForComponent(pItm->pAssembly, pItm->pComponent, &piSubsColl);
517 ExitOnFailure(hr, "Failed to get collection");
518
519 if (S_FALSE == hr)
520 ExitFunction(); // exit with hr = S_FALSE
521
522 // find application object
523 hr = CpiFindCollectionObject(piSubsColl, fFindId ? pItm->wzID : NULL, fFindName ? pItm->wzName : NULL, ppiSubsObj);
524 ExitOnFailure(hr, "Failed to find object");
525
526 // exit with hr from CpiFindCollectionObject()
527
528LExit:
529 // clean up
530 ReleaseObject(piSubsColl);
531
532 return hr;
533}
534
535static HRESULT AddSubscriptionToActionData(
536 CPI_SUBSCRIPTION* pItm,
537 int iActionType,
538 int iActionCost,
539 LPWSTR* ppwzActionData
540 )
541{
542 HRESULT hr = S_OK;
543
544 // add action information to custom action data
545 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
546 ExitOnFailure(hr, "Failed to add action type to custom action data");
547 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
548 ExitOnFailure(hr, "Failed to add action cost to custom action data");
549
550 // add application role information to custom action data
551 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
552 ExitOnFailure(hr, "Failed to add subscription key to custom action data");
553 hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
554 ExitOnFailure(hr, "Failed to add subscription id to custom action data");
555 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
556 ExitOnFailure(hr, "Failed to add subscription name to custom action data");
557 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzEventCLSID : L"", ppwzActionData);
558 ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data");
559 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzPublisherID : L"", ppwzActionData);
560 ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data");
561
562 // add component information to custom action data
563 hr = WcaWriteStringToCaData(pItm->pComponent->wzCLSID, ppwzActionData);
564 ExitOnFailure(hr, "Failed to add application id to custom action data");
565
566 // add application information to custom action data
567 hr = WcaWriteStringToCaData(pItm->pAssembly->pApplication->wzID, ppwzActionData);
568 ExitOnFailure(hr, "Failed to add application id to custom action data");
569
570 // add partition information to custom action data
571 LPCWSTR pwzPartID = pItm->pAssembly->pApplication->pPartition ? pItm->pAssembly->pApplication->pPartition->wzID : L"";
572 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
573 ExitOnFailure(hr, "Failed to add partition id to custom action data");
574
575 // add properties to custom action data
576 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
577 ExitOnFailure(hr, "Failed to add properties to custom action data");
578
579 hr = S_OK;
580
581LExit:
582 return hr;
583}
584
585static HRESULT ComponentFindByKey(
586 CPI_ASSEMBLY_LIST* pAsmList,
587 LPCWSTR pwzKey,
588 CPI_ASSEMBLY** ppAsmItm,
589 CPISCHED_COMPONENT** ppCompItm
590 )
591{
592 for (CPI_ASSEMBLY* pAsmItm = pAsmList->pFirst; pAsmItm; pAsmItm = pAsmItm->pNext)
593 {
594 for (CPISCHED_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/ext/ComPlus/ca/cpsubssched.h b/src/ext/ComPlus/ca/cpsubssched.h
new file mode 100644
index 00000000..83ff1af8
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpsubssched.h
@@ -0,0 +1,62 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5struct CPI_SUBSCRIPTION
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzID[CPI_MAX_GUID + 1];
9 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
10 WCHAR wzEventCLSID[CPI_MAX_GUID + 1];
11 WCHAR wzPublisherID[CPI_MAX_GUID + 1];
12
13 BOOL fObjectNotFound;
14
15 int iPropertyCount;
16 CPI_PROPERTY* pProperties;
17
18 INSTALLSTATE isInstalled, isAction;
19
20 CPI_ASSEMBLY* pAssembly;
21 CPISCHED_COMPONENT* pComponent;
22
23 CPI_SUBSCRIPTION* pNext;
24};
25
26struct CPI_SUBSCRIPTION_LIST
27{
28 CPI_SUBSCRIPTION* pFirst;
29
30 int iInstallCount;
31 int iCommitCount;
32 int iUninstallCount;
33};
34
35
36// function prototypes
37
38void CpiSubscriptionListFree(
39 CPI_SUBSCRIPTION_LIST* pList
40 );
41HRESULT CpiSubscriptionsRead(
42 CPI_ASSEMBLY_LIST* pAsmList,
43 CPI_SUBSCRIPTION_LIST* pSubList
44 );
45HRESULT CpiSubscriptionsVerifyInstall(
46 CPI_SUBSCRIPTION_LIST* pList
47 );
48HRESULT CpiSubscriptionsVerifyUninstall(
49 CPI_SUBSCRIPTION_LIST* pList
50 );
51HRESULT CpiSubscriptionsInstall(
52 CPI_SUBSCRIPTION_LIST* pList,
53 int iRunMode,
54 LPWSTR* ppwzActionData,
55 int* piProgress
56 );
57HRESULT CpiSubscriptionsUninstall(
58 CPI_SUBSCRIPTION_LIST* pList,
59 int iRunMode,
60 LPWSTR* ppwzActionData,
61 int* piProgress
62 );
diff --git a/src/ext/ComPlus/ca/cputilexec.cpp b/src/ext/ComPlus/ca/cputilexec.cpp
new file mode 100644
index 00000000..1c2c8b93
--- /dev/null
+++ b/src/ext/ComPlus/ca/cputilexec.cpp
@@ -0,0 +1,1881 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct CPI_WELLKNOWN_SID
9{
10 LPCWSTR pwzName;
11 SID_IDENTIFIER_AUTHORITY iaIdentifierAuthority;
12 BYTE nSubAuthorityCount;
13 DWORD dwSubAuthority[8];
14};
15
16
17// well known SIDs
18
19CPI_WELLKNOWN_SID wsWellKnownSids[] = {
20 {L"\\Everyone", SECURITY_WORLD_SID_AUTHORITY, 1, {SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0}},
21 {L"\\Administrators", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0}},
22 {L"\\LocalSystem", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0}},
23 {L"\\LocalService", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}},
24 {L"\\NetworkService", SECURITY_NT_AUTHORITY, 1, {SECURITY_NETWORK_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}},
25 {L"\\AuthenticatedUser", SECURITY_NT_AUTHORITY, 1, {SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0}},
26 {L"\\Guests", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0, 0, 0, 0, 0, 0}},
27 {L"\\Users", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0}},
28 {L"\\CREATOR OWNER", SECURITY_NT_AUTHORITY, 1, {SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, 0}},
29 {NULL, SECURITY_NULL_SID_AUTHORITY, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
30};
31
32
33// prototypes for private helper functions
34
35static HRESULT FindUserCollectionObjectIndex(
36 ICatalogCollection* piColl,
37 PSID pSid,
38 int* pi
39 );
40static HRESULT CreateSidFromDomainRidPair(
41 PSID pDomainSid,
42 DWORD dwRid,
43 PSID* ppSid
44 );
45static HRESULT InitLsaUnicodeString(
46 PLSA_UNICODE_STRING plusStr,
47 LPCWSTR pwzStr,
48 DWORD dwLen
49 );
50static void FreeLsaUnicodeString(
51 PLSA_UNICODE_STRING plusStr
52 );
53static HRESULT WriteFileAll(
54 HANDLE hFile,
55 PBYTE pbBuffer,
56 DWORD dwBufferLength
57 );
58static HRESULT ReadFileAll(
59 HANDLE hFile,
60 PBYTE pbBuffer,
61 DWORD dwBufferLength
62 );
63
64
65// variables
66
67static ICOMAdminCatalog* gpiCatalog;
68
69
70// function definitions
71
72void CpiExecInitialize()
73{
74 // collections
75 gpiCatalog = NULL;
76}
77
78void CpiExecFinalize()
79{
80 // collections
81 ReleaseObject(gpiCatalog);
82}
83
84HRESULT CpiActionStartMessage(
85 LPWSTR* ppwzActionData,
86 BOOL fSuppress
87 )
88{
89 HRESULT hr = S_OK;
90 UINT er = ERROR_SUCCESS;
91
92 PMSIHANDLE hRec;
93
94 LPWSTR pwzData = NULL;
95
96 // create record
97 hRec = ::MsiCreateRecord(3);
98 ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record");
99
100 // action name
101 hr = WcaReadStringFromCaData(ppwzActionData, &pwzData);
102 ExitOnFailure(hr, "Failed to action name");
103
104 er = ::MsiRecordSetStringW(hRec, 1, pwzData);
105 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set action name");
106
107 // description
108 hr = WcaReadStringFromCaData(ppwzActionData, &pwzData);
109 ExitOnFailure(hr, "Failed to description");
110
111 er = ::MsiRecordSetStringW(hRec, 2, pwzData);
112 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set description");
113
114 // template
115 hr = WcaReadStringFromCaData(ppwzActionData, &pwzData);
116 ExitOnFailure(hr, "Failed to template");
117
118 er = ::MsiRecordSetStringW(hRec, 3, pwzData);
119 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set template");
120
121 // message
122 if (!fSuppress)
123 {
124 er = WcaProcessMessage(INSTALLMESSAGE_ACTIONSTART, hRec);
125 if (0 == er || IDOK == er || IDYES == er)
126 {
127 hr = S_OK;
128 }
129 else if (IDABORT == er || IDCANCEL == er)
130 {
131 WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit
132 hr = S_FALSE;
133 }
134 else
135 hr = E_UNEXPECTED;
136 }
137
138LExit:
139 // clean up
140 ReleaseStr(pwzData);
141
142 return hr;
143}
144
145HRESULT CpiActionDataMessage(
146 DWORD cArgs,
147 ...
148 )
149{
150 HRESULT hr = S_OK;
151 UINT er = ERROR_SUCCESS;
152
153 PMSIHANDLE hRec;
154 va_list args;
155
156 // record
157 hRec = ::MsiCreateRecord(cArgs);
158 ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record");
159
160 va_start(args, cArgs);
161 for (DWORD i = 1; i <= cArgs; i++)
162 {
163 LPCWSTR pwzArg = va_arg(args, WCHAR*);
164 if (pwzArg && *pwzArg)
165 {
166 er = ::MsiRecordSetStringW(hRec, i, pwzArg);
167 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set record field string");
168 }
169 }
170 va_end(args);
171
172 // message
173 er = WcaProcessMessage(INSTALLMESSAGE_ACTIONDATA, hRec);
174 if (0 == er || IDOK == er || IDYES == er)
175 {
176 hr = S_OK;
177 }
178 else if (IDABORT == er || IDCANCEL == er)
179 {
180 WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit
181 hr = S_FALSE;
182 }
183 else
184 hr = E_UNEXPECTED;
185
186LExit:
187 return hr;
188}
189
190HRESULT CpiExecGetAdminCatalog(
191 ICOMAdminCatalog** ppiCatalog
192 )
193{
194 HRESULT hr = S_OK;
195
196 if (!gpiCatalog)
197 {
198 // get collection
199 hr = ::CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_ALL, IID_ICOMAdminCatalog, (void**)&gpiCatalog);
200 ExitOnFailure(hr, "Failed to create COM+ admin catalog object");
201 }
202
203 // return value
204 gpiCatalog->AddRef();
205 *ppiCatalog = gpiCatalog;
206
207 hr = S_OK;
208
209LExit:
210 return hr;
211}
212
213HRESULT CpiLogCatalogErrorInfo()
214{
215 HRESULT hr = S_OK;
216
217 ICOMAdminCatalog* piCatalog = NULL;
218 ICatalogCollection* piErrColl = NULL;
219 IDispatch* piDisp = NULL;
220 ICatalogObject* piObj = NULL;
221
222 LPWSTR pwzName = NULL;
223 LPWSTR pwzErrorCode = NULL;
224 LPWSTR pwzMajorRef = NULL;
225 LPWSTR pwzMinorRef = NULL;
226
227 // get catalog
228 hr = CpiExecGetAdminCatalog(&piCatalog);
229 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
230
231 // get error info collection
232 hr = CpiExecGetCatalogCollection(L"ErrorInfo", &piErrColl);
233 ExitOnFailure(hr, "Failed to get error info collection");
234
235 // loop objects
236 long lCnt;
237 hr = piErrColl->get_Count(&lCnt);
238 ExitOnFailure(hr, "Failed to get to number of items in collection");
239
240 for (long i = 0; i < lCnt; i++)
241 {
242 // get ICatalogObject interface
243 hr = piErrColl->get_Item(i, &piDisp);
244 ExitOnFailure(hr, "Failed to get item from partitions collection");
245
246 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
247 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
248
249 // get properties
250 hr = CpiGetCollectionObjectValue(piObj, L"Name", &pwzName);
251 ExitOnFailure(hr, "Failed to get name");
252 hr = CpiGetCollectionObjectValue(piObj, L"ErrorCode", &pwzErrorCode);
253 ExitOnFailure(hr, "Failed to get error code");
254 hr = CpiGetCollectionObjectValue(piObj, L"MajorRef", &pwzMajorRef);
255 ExitOnFailure(hr, "Failed to get major ref");
256 hr = CpiGetCollectionObjectValue(piObj, L"MinorRef", &pwzMinorRef);
257 ExitOnFailure(hr, "Failed to get minor ref");
258
259 // write to log
260 WcaLog(LOGMSG_STANDARD, "ErrorInfo: Name='%S', ErrorCode='%S', MajorRef='%S', MinorRef='%S'",
261 pwzName, pwzErrorCode, pwzMajorRef, pwzMinorRef);
262
263 // clean up
264 ReleaseNullObject(piDisp);
265 ReleaseNullObject(piObj);
266 }
267
268 hr = S_OK;
269
270LExit:
271 // clean up
272 ReleaseObject(piCatalog);
273 ReleaseObject(piErrColl);
274 ReleaseObject(piDisp);
275 ReleaseObject(piObj);
276
277 ReleaseStr(pwzName);
278 ReleaseStr(pwzErrorCode);
279 ReleaseStr(pwzMajorRef);
280 ReleaseStr(pwzMinorRef);
281
282 return hr;
283}
284
285HRESULT CpiExecGetCatalogCollection(
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 = CpiExecGetAdminCatalog(&piCatalog);
303 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
304
305 // get collecton from catalog
306 hr = piCatalog->GetCollection(bstrName, &piDisp);
307 ExitOnFailure(hr, "Failed to get collection");
308
309 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
310 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
311
312 // populate collection
313 hr = (*ppiColl)->Populate();
314 if (COMADMIN_E_OBJECTERRORS == hr)
315 CpiLogCatalogErrorInfo();
316 ExitOnFailure(hr, "Failed to populate collection");
317
318 hr = S_OK;
319
320LExit:
321 // clean up
322 ReleaseObject(piCatalog);
323 ReleaseObject(piDisp);
324 ReleaseBSTR(bstrName);
325
326 return hr;
327}
328
329HRESULT CpiExecGetCatalogCollection(
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 = CpiExecGetAdminCatalog(&piCatalog);
352 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
353
354 // get key
355 hr = piObj->get_Key(&vtKey);
356 ExitOnFailure(hr, "Failed to get object key");
357
358 // get collecton from catalog
359 hr = piColl->GetCollection(bstrName, vtKey, &piDisp);
360 ExitOnFailure(hr, "Failed to get collection");
361
362 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
363 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
364
365 // populate collection
366 hr = (*ppiColl)->Populate();
367 if (COMADMIN_E_OBJECTERRORS == hr)
368 CpiLogCatalogErrorInfo();
369 ExitOnFailure(hr, "Failed to populate collection");
370
371 hr = S_OK;
372
373LExit:
374 // clean up
375 ReleaseObject(piCatalog);
376 ReleaseObject(piDisp);
377 ReleaseBSTR(bstrName);
378 ::VariantClear(&vtKey);
379
380 return hr;
381}
382
383HRESULT CpiAddCollectionObject(
384 ICatalogCollection* piColl,
385 ICatalogObject** ppiObj
386 )
387{
388 HRESULT hr = S_OK;
389
390 IDispatch* piDisp = NULL;
391
392 hr = piColl->Add(&piDisp);
393 ExitOnFailure(hr, "Failed to add object to collection");
394
395 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)ppiObj);
396 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
397
398 hr = S_OK;
399
400LExit:
401 // clean up
402 ReleaseObject(piDisp);
403
404 return hr;
405}
406
407HRESULT CpiPutCollectionObjectValue(
408 ICatalogObject* piObj,
409 LPCWSTR pwzPropName,
410 LPCWSTR pwzValue
411 )
412{
413 HRESULT hr = S_OK;
414
415 BSTR bstrPropName = NULL;
416
417 VARIANT vtVal;
418 ::VariantInit(&vtVal);
419
420 // allocate property name string
421 bstrPropName = ::SysAllocString(pwzPropName);
422 ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate property name string");
423
424 // prepare value variant
425 vtVal.vt = VT_BSTR;
426 vtVal.bstrVal = ::SysAllocString(pwzValue);
427 ExitOnNull(vtVal.bstrVal, hr, E_OUTOFMEMORY, "Failed to allocate property value string");
428
429 // put value
430 hr = piObj->put_Value(bstrPropName, vtVal);
431 ExitOnFailure(hr, "Failed to put property value");
432
433 hr = S_OK;
434
435LExit:
436 // clean up
437 ReleaseBSTR(bstrPropName);
438 ::VariantClear(&vtVal);
439
440 return hr;
441}
442
443HRESULT CpiPutCollectionObjectValues(
444 ICatalogObject* piObj,
445 CPI_PROPERTY* pPropList
446 )
447{
448 HRESULT hr = S_OK;
449
450 for (CPI_PROPERTY* pItm = pPropList; pItm; pItm = pItm->pNext)
451 {
452 // set property
453 hr = CpiPutCollectionObjectValue(piObj, pItm->wzName, pItm->pwzValue);
454 ExitOnFailure(hr, "Failed to set object property value, name: %S", pItm->wzName);
455 }
456
457 hr = S_OK;
458
459LExit:
460 return hr;
461}
462
463HRESULT CpiGetCollectionObjectValue(
464 ICatalogObject* piObj,
465 LPCWSTR szPropName,
466 LPWSTR* ppwzValue
467 )
468{
469 HRESULT hr = S_OK;
470
471 BSTR bstrPropName = NULL;
472
473 VARIANT vtVal;
474 ::VariantInit(&vtVal);
475
476 // allocate property name string
477 bstrPropName = ::SysAllocString(szPropName);
478 ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate property name string");
479
480 // get value
481 hr = piObj->get_Value(bstrPropName, &vtVal);
482 ExitOnFailure(hr, "Failed to get property value");
483
484 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
485 ExitOnFailure(hr, "Failed to change variant type");
486
487 hr = StrAllocString(ppwzValue, vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal));
488 ExitOnFailure(hr, "Failed to allocate memory for value string");
489
490 hr = S_OK;
491
492LExit:
493 // clean up
494 ReleaseBSTR(bstrPropName);
495 ::VariantClear(&vtVal);
496
497 return hr;
498}
499
500HRESULT CpiResetObjectProperty(
501 ICatalogCollection* piColl,
502 ICatalogObject* piObj,
503 LPCWSTR pwzPropName
504 )
505{
506 HRESULT hr = S_OK;
507
508 BSTR bstrPropName = NULL;
509
510 long lChanges = 0;
511
512 VARIANT vtVal;
513 ::VariantInit(&vtVal);
514
515 // allocate property name string
516 bstrPropName = ::SysAllocString(pwzPropName);
517 ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate deleteable property name string");
518
519 // get value
520 hr = piObj->get_Value(bstrPropName, &vtVal);
521 ExitOnFailure(hr, "Failed to get deleteable property value");
522
523 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BOOL);
524 ExitOnFailure(hr, "Failed to change variant type");
525
526 // if the deleteable property is set
527 if (VARIANT_FALSE == vtVal.boolVal)
528 {
529 // clear property
530 vtVal.boolVal = VARIANT_TRUE;
531
532 hr = piObj->put_Value(bstrPropName, vtVal);
533 ExitOnFailure(hr, "Failed to get property value");
534
535 // save changes
536 hr = piColl->SaveChanges(&lChanges);
537 if (COMADMIN_E_OBJECTERRORS == hr)
538 CpiLogCatalogErrorInfo();
539 ExitOnFailure(hr, "Failed to save changes");
540 }
541
542 hr = S_OK;
543
544LExit:
545 // clean up
546 ReleaseBSTR(bstrPropName);
547 ::VariantClear(&vtVal);
548
549 return hr;
550}
551
552HRESULT CpiRemoveCollectionObject(
553 ICatalogCollection* piColl,
554 LPCWSTR pwzID,
555 LPCWSTR pwzName,
556 BOOL fResetDeleteable
557 )
558{
559 HRESULT hr = S_OK;
560
561 IDispatch* piDisp = NULL;
562 ICatalogObject* piObj = NULL;
563
564 BOOL fMatch = FALSE;
565
566 VARIANT vtVal;
567 ::VariantInit(&vtVal);
568
569 long lCnt;
570 hr = piColl->get_Count(&lCnt);
571 ExitOnFailure(hr, "Failed to get to number of items in collection");
572
573 for (long i = 0; i < lCnt; i++)
574 {
575 // get ICatalogObject interface
576 hr = piColl->get_Item(i, &piDisp);
577 ExitOnFailure(hr, "Failed to get object from collection");
578
579 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
580 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
581
582 // compare id
583 if (pwzID && *pwzID)
584 {
585 hr = piObj->get_Key(&vtVal);
586 ExitOnFailure(hr, "Failed to get key");
587
588 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
589 ExitOnFailure(hr, "Failed to change variant type");
590
591 if (0 == lstrcmpiW(vtVal.bstrVal, pwzID))
592 fMatch = TRUE;
593
594 ::VariantClear(&vtVal);
595 }
596
597 // compare name
598 if (pwzName && *pwzName)
599 {
600 hr = piObj->get_Name(&vtVal);
601 ExitOnFailure(hr, "Failed to get name");
602
603 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
604 ExitOnFailure(hr, "Failed to change variant type");
605
606 if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
607 fMatch = TRUE;
608
609 ::VariantClear(&vtVal);
610 }
611
612 // if it's a match, remove it
613 if (fMatch)
614 {
615 if (fResetDeleteable)
616 {
617 // reset deleteable property, if set
618 hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable");
619 ExitOnFailure(hr, "Failed to reset deleteable property");
620 }
621
622 hr = piColl->Remove(i);
623 ExitOnFailure(hr, "Failed to remove item from collection");
624 break;
625 }
626
627 // release interface pointers
628 ReleaseNullObject(piDisp);
629 ReleaseNullObject(piObj);
630 }
631
632 hr = S_OK;
633
634LExit:
635 // clean up
636 ReleaseObject(piDisp);
637 ReleaseObject(piObj);
638
639 ::VariantClear(&vtVal);
640
641 return hr;
642}
643
644HRESULT CpiRemoveUserCollectionObject(
645 ICatalogCollection* piColl,
646 PSID pSid
647 )
648{
649 HRESULT hr = S_OK;
650
651 int i = 0;
652
653 // find index
654 hr = FindUserCollectionObjectIndex(piColl, pSid, &i);
655 ExitOnFailure(hr, "Failed to find user collection index");
656
657 if (S_FALSE == hr)
658 ExitFunction(); // not found, exit with hr = S_FALSE
659
660 // remove object
661 hr = piColl->Remove(i);
662 ExitOnFailure(hr, "Failed to remove object from collection");
663
664 hr = S_OK;
665
666LExit:
667 return hr;
668}
669
670HRESULT CpiFindCollectionObjectByStringKey(
671 ICatalogCollection* piColl,
672 LPCWSTR pwzKey,
673 ICatalogObject** ppiObj
674 )
675{
676 HRESULT hr = S_OK;
677
678 IDispatch* piDisp = NULL;
679 ICatalogObject* piObj = NULL;
680
681 VARIANT vtVal;
682 ::VariantInit(&vtVal);
683
684 long lCnt;
685 hr = piColl->get_Count(&lCnt);
686 ExitOnFailure(hr, "Failed to get to number of items in collection");
687
688 for (long i = 0; i < lCnt; i++)
689 {
690 // get ICatalogObject interface
691 hr = piColl->get_Item(i, &piDisp);
692 ExitOnFailure(hr, "Failed to get object from collection");
693
694 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
695 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
696
697 // compare key
698 hr = piObj->get_Key(&vtVal);
699 ExitOnFailure(hr, "Failed to get key");
700
701 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
702 ExitOnFailure(hr, "Failed to change variant type");
703
704 if (0 == lstrcmpiW(vtVal.bstrVal, pwzKey))
705 {
706 if (ppiObj)
707 {
708 *ppiObj = piObj;
709 piObj = NULL;
710 }
711 ExitFunction1(hr = S_OK);
712 }
713
714 // clean up
715 ReleaseNullObject(piDisp);
716 ReleaseNullObject(piObj);
717
718 ::VariantClear(&vtVal);
719 }
720
721 hr = S_FALSE;
722
723LExit:
724 // clean up
725 ReleaseObject(piDisp);
726 ReleaseObject(piObj);
727
728 ::VariantClear(&vtVal);
729
730 return hr;
731}
732
733HRESULT CpiFindCollectionObjectByIntegerKey(
734 ICatalogCollection* piColl,
735 long lKey,
736 ICatalogObject** ppiObj
737 )
738{
739 HRESULT hr = S_OK;
740
741 IDispatch* piDisp = NULL;
742 ICatalogObject* piObj = NULL;
743
744 VARIANT vtVal;
745 ::VariantInit(&vtVal);
746
747 long lCnt;
748 hr = piColl->get_Count(&lCnt);
749 ExitOnFailure(hr, "Failed to get to number of items in collection");
750
751 for (long i = 0; i < lCnt; i++)
752 {
753 // get ICatalogObject interface
754 hr = piColl->get_Item(i, &piDisp);
755 ExitOnFailure(hr, "Failed to get object from collection");
756
757 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
758 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
759
760 // compare key
761 hr = piObj->get_Key(&vtVal);
762 ExitOnFailure(hr, "Failed to get key");
763
764 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_I4);
765 ExitOnFailure(hr, "Failed to change variant type");
766
767 if (vtVal.lVal == lKey)
768 {
769 if (ppiObj)
770 {
771 *ppiObj = piObj;
772 piObj = NULL;
773 }
774 ExitFunction1(hr = S_OK);
775 }
776
777 // clean up
778 ReleaseNullObject(piDisp);
779 ReleaseNullObject(piObj);
780
781 ::VariantClear(&vtVal);
782 }
783
784 hr = S_FALSE;
785
786LExit:
787 // clean up
788 ReleaseObject(piDisp);
789 ReleaseObject(piObj);
790
791 ::VariantClear(&vtVal);
792
793 return hr;
794}
795
796HRESULT CpiFindCollectionObjectByName(
797 ICatalogCollection* piColl,
798 LPCWSTR pwzName,
799 ICatalogObject** ppiObj
800 )
801{
802 HRESULT hr = S_OK;
803
804 IDispatch* piDisp = NULL;
805 ICatalogObject* piObj = NULL;
806
807 VARIANT vtVal;
808 ::VariantInit(&vtVal);
809
810 long lCnt;
811 hr = piColl->get_Count(&lCnt);
812 ExitOnFailure(hr, "Failed to get to number of items in collection");
813
814 for (long i = 0; i < lCnt; i++)
815 {
816 // get ICatalogObject interface
817 hr = piColl->get_Item(i, &piDisp);
818 ExitOnFailure(hr, "Failed to get object from collection");
819
820 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
821 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
822
823 // compare key
824 hr = piObj->get_Name(&vtVal);
825 ExitOnFailure(hr, "Failed to get key");
826
827 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
828 ExitOnFailure(hr, "Failed to change variant type");
829
830 if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
831 {
832 if (ppiObj)
833 {
834 *ppiObj = piObj;
835 piObj = NULL;
836 }
837 ExitFunction1(hr = S_OK);
838 }
839
840 // clean up
841 ReleaseNullObject(piDisp);
842 ReleaseNullObject(piObj);
843
844 ::VariantClear(&vtVal);
845 }
846
847 hr = S_FALSE;
848
849LExit:
850 // clean up
851 ReleaseObject(piDisp);
852 ReleaseObject(piObj);
853
854 ::VariantClear(&vtVal);
855
856 return hr;
857}
858
859HRESULT CpiFindUserCollectionObject(
860 ICatalogCollection* piColl,
861 PSID pSid,
862 ICatalogObject** ppiObj
863 )
864{
865 HRESULT hr = S_OK;
866
867 int i = 0;
868
869 IDispatch* piDisp = NULL;
870
871 // find index
872 hr = FindUserCollectionObjectIndex(piColl, pSid, &i);
873 ExitOnFailure(hr, "Failed to find user collection index");
874
875 if (S_FALSE == hr)
876 ExitFunction(); // not found, exit with hr = S_FALSE
877
878 // get object
879 if (ppiObj)
880 {
881 hr = piColl->get_Item(i, &piDisp);
882 ExitOnFailure(hr, "Failed to get object from collection");
883
884 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)ppiObj);
885 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
886 }
887
888 hr = S_OK;
889
890LExit:
891 // clean up
892 ReleaseObject(piDisp);
893
894 return hr;
895}
896
897HRESULT CpiExecGetPartitionsCollection(
898 ICatalogCollection** ppiPartColl
899 )
900{
901 HRESULT hr = S_OK;
902
903 // get collection
904 hr = CpiExecGetCatalogCollection(L"Partitions", ppiPartColl);
905 ExitOnFailure(hr, "Failed to get catalog collection");
906
907 hr = S_OK;
908
909LExit:
910 return hr;
911}
912
913HRESULT CpiGetPartitionRolesCollection(
914 LPCWSTR pwzPartID,
915 ICatalogCollection** ppiRolesColl
916 )
917{
918 HRESULT hr = S_OK;
919
920 ICatalogCollection* piPartColl = NULL;
921 ICatalogObject* piPartObj = NULL;
922
923 // get partitions collection
924 hr = CpiExecGetPartitionsCollection(&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 = CpiExecGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", ppiRolesColl);
939 ExitOnFailure(hr, "Failed to get catalog collection");
940
941 hr = S_OK;
942
943LExit:
944 // clean up
945 ReleaseObject(piPartColl);
946 ReleaseObject(piPartObj);
947
948 return hr;
949}
950
951HRESULT CpiGetUsersInPartitionRoleCollection(
952 LPCWSTR pwzPartID,
953 LPCWSTR pwzRoleName,
954 ICatalogCollection** ppiUsrInRoleColl
955 )
956{
957 HRESULT hr = S_OK;
958
959 ICatalogCollection* piRoleColl = NULL;
960 ICatalogObject* piRoleObj = NULL;
961
962 // get roles collection
963 hr = CpiGetPartitionRolesCollection(pwzPartID, &piRoleColl);
964 ExitOnFailure(hr, "Failed to get roles collection");
965
966 if (S_FALSE == hr)
967 ExitFunction(); // partition roles collection not found, exit with hr = S_FALSE
968
969 // find object
970 hr = CpiFindCollectionObjectByName(piRoleColl, pwzRoleName, &piRoleObj);
971 ExitOnFailure(hr, "Failed to find collection object");
972
973 if (S_FALSE == hr)
974 ExitFunction(); // user not found, exit with hr = S_FALSE
975
976 // get roles collection
977 hr = CpiExecGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInPartitionRole", ppiUsrInRoleColl);
978 ExitOnFailure(hr, "Failed to get catalog collection");
979
980 hr = S_OK;
981
982LExit:
983 // clean up
984 ReleaseObject(piRoleColl);
985 ReleaseObject(piRoleObj);
986
987 return hr;
988}
989
990HRESULT CpiGetPartitionUsersCollection(
991 ICatalogCollection** ppiUserColl
992 )
993{
994 HRESULT hr = S_OK;
995
996 // get roles collection
997 hr = CpiExecGetCatalogCollection(L"PartitionUsers", ppiUserColl);
998 ExitOnFailure(hr, "Failed to get catalog collection");
999
1000 hr = S_OK;
1001
1002LExit:
1003 return hr;
1004}
1005
1006HRESULT CpiExecGetApplicationsCollection(
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 = CpiExecGetAdminCatalog(&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 = CpiExecGetPartitionsCollection(&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 = CpiExecGetCatalogCollection(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 = CpiExecGetCatalogCollection(L"Applications", ppiAppColl);
1065 ExitOnFailure(hr, "Failed to get catalog collection");
1066 }
1067
1068 hr = S_OK;
1069
1070LExit:
1071 // clean up
1072 ReleaseObject(piCatalog);
1073 ReleaseObject(piCatalog2);
1074 ReleaseBSTR(bstrGlobPartID);
1075
1076 ReleaseObject(piPartColl);
1077 ReleaseObject(piPartObj);
1078
1079 return hr;
1080}
1081
1082HRESULT CpiGetRolesCollection(
1083 LPCWSTR pwzPartID,
1084 LPCWSTR pwzAppID,
1085 ICatalogCollection** ppiRolesColl
1086 )
1087{
1088 HRESULT hr = S_OK;
1089
1090 ICatalogCollection* piAppColl = NULL;
1091 ICatalogObject* piAppObj = NULL;
1092
1093 // get applications collection
1094 hr = CpiExecGetApplicationsCollection(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 = CpiExecGetCatalogCollection(piAppColl, piAppObj, L"Roles", ppiRolesColl);
1109 ExitOnFailure(hr, "Failed to catalog collection");
1110
1111 hr = S_OK;
1112
1113LExit:
1114 // clean up
1115 ReleaseObject(piAppColl);
1116 ReleaseObject(piAppObj);
1117
1118 return hr;
1119}
1120
1121HRESULT CpiGetUsersInRoleCollection(
1122 LPCWSTR pwzPartID,
1123 LPCWSTR pwzAppID,
1124 LPCWSTR pwzRoleName,
1125 ICatalogCollection** ppiUsrInRoleColl
1126 )
1127{
1128 HRESULT hr = S_OK;
1129
1130 ICatalogCollection* piRoleColl = NULL;
1131 ICatalogObject* piRoleObj = NULL;
1132
1133 // get roles collection
1134 hr = CpiGetRolesCollection(pwzPartID, pwzAppID, &piRoleColl);
1135 ExitOnFailure(hr, "Failed to get roles collection");
1136
1137 if (S_FALSE == hr)
1138 ExitFunction(); // roles collection not found, exit with hr = S_FALSE
1139
1140 // find object
1141 hr = CpiFindCollectionObjectByName(piRoleColl, pwzRoleName, &piRoleObj);
1142 ExitOnFailure(hr, "Failed to find collection object");
1143
1144 if (S_FALSE == hr)
1145 ExitFunction(); // role not found, exit with hr = S_FALSE
1146
1147 // get roles collection
1148 hr = CpiExecGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", ppiUsrInRoleColl);
1149 ExitOnFailure(hr, "Failed to get catalog collection");
1150
1151 hr = S_OK;
1152
1153LExit:
1154 // clean up
1155 ReleaseObject(piRoleColl);
1156 ReleaseObject(piRoleObj);
1157
1158 return hr;
1159}
1160
1161HRESULT CpiGetComponentsCollection(
1162 LPCWSTR pwzPartID,
1163 LPCWSTR pwzAppID,
1164 ICatalogCollection** ppiCompsColl
1165 )
1166{
1167 HRESULT hr = S_OK;
1168
1169 ICatalogCollection* piAppColl = NULL;
1170 ICatalogObject* piAppObj = NULL;
1171
1172 // get applications collection
1173 hr = CpiExecGetApplicationsCollection(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 = CpiExecGetCatalogCollection(piAppColl, piAppObj, L"Components", ppiCompsColl);
1188 ExitOnFailure(hr, "Failed to get catalog collection");
1189
1190 hr = S_OK;
1191
1192LExit:
1193 // clean up
1194 ReleaseObject(piAppColl);
1195 ReleaseObject(piAppObj);
1196
1197 return hr;
1198}
1199
1200HRESULT CpiGetInterfacesCollection(
1201 ICatalogCollection* piCompColl,
1202 ICatalogObject* piCompObj,
1203 ICatalogCollection** ppiIntfColl
1204 )
1205{
1206 HRESULT hr = S_OK;
1207
1208 // get interfaces collection
1209 hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, L"InterfacesForComponent", ppiIntfColl);
1210 ExitOnFailure(hr, "Failed to get catalog collection");
1211
1212 hr = S_OK;
1213
1214LExit:
1215 return hr;
1216}
1217
1218HRESULT CpiGetMethodsCollection(
1219 ICatalogCollection* piIntfColl,
1220 ICatalogObject* piIntfObj,
1221 ICatalogCollection** ppiMethColl
1222 )
1223{
1224 HRESULT hr = S_OK;
1225
1226 // get interfaces collection
1227 hr = CpiExecGetCatalogCollection(piIntfColl, piIntfObj, L"MethodsForInterface", ppiMethColl);
1228 ExitOnFailure(hr, "Failed to get catalog collection");
1229
1230 hr = S_OK;
1231
1232LExit:
1233 return hr;
1234}
1235
1236HRESULT CpiGetSubscriptionsCollection(
1237 LPCWSTR pwzPartID,
1238 LPCWSTR pwzAppID,
1239 LPCWSTR pwzCompCLSID,
1240 ICatalogCollection** ppiSubsColl
1241 )
1242{
1243 HRESULT hr = S_OK;
1244
1245 ICatalogCollection* piCompColl = NULL;
1246 ICatalogObject* piCompObj = NULL;
1247
1248 // get components collection
1249 hr = CpiGetComponentsCollection(pwzPartID, pwzAppID, &piCompColl);
1250 ExitOnFailure(hr, "Failed to get components collection");
1251
1252 if (S_FALSE == hr)
1253 ExitFunction(); // components collection not found, exit with hr = S_FALSE
1254
1255 // find object
1256 hr = CpiFindCollectionObjectByStringKey(piCompColl, pwzCompCLSID, &piCompObj);
1257 ExitOnFailure(hr, "Failed to find collection object");
1258
1259 if (S_FALSE == hr)
1260 ExitFunction(); // component not found, exit with hr = S_FALSE
1261
1262 // get subscriptions collection
1263 hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", ppiSubsColl);
1264 ExitOnFailure(hr, "Failed to get catalog collection");
1265
1266 hr = S_OK;
1267
1268LExit:
1269 // clean up
1270 ReleaseObject(piCompColl);
1271 ReleaseObject(piCompObj);
1272
1273 return hr;
1274}
1275
1276HRESULT CpiReadPropertyList(
1277 LPWSTR* ppwzData,
1278 CPI_PROPERTY** ppPropList
1279 )
1280{
1281 HRESULT hr = S_OK;
1282
1283 CPI_PROPERTY* pItm = NULL;
1284 LPWSTR pwzName = NULL;
1285
1286 // clear list if it already contains items
1287 if (*ppPropList)
1288 CpiFreePropertyList(*ppPropList);
1289 *ppPropList = NULL;
1290
1291 // read property count
1292 int iPropCnt = 0;
1293 hr = WcaReadIntegerFromCaData(ppwzData, &iPropCnt);
1294 ExitOnFailure(hr, "Failed to read property count");
1295
1296 for (int i = 0; i < iPropCnt; i++)
1297 {
1298 // allocate new element
1299 pItm = (CPI_PROPERTY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PROPERTY));
1300 if (!pItm)
1301 ExitFunction1(hr = E_OUTOFMEMORY);
1302
1303 // Name
1304 hr = WcaReadStringFromCaData(ppwzData, &pwzName);
1305 ExitOnFailure(hr, "Failed to read name");
1306 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzName);
1307
1308 // Value
1309 hr = WcaReadStringFromCaData(ppwzData, &pItm->pwzValue);
1310 ExitOnFailure(hr, "Failed to read property value");
1311
1312 // add to list
1313 if (*ppPropList)
1314 pItm->pNext = *ppPropList;
1315 *ppPropList = pItm;
1316 pItm = NULL;
1317 }
1318
1319 hr = S_OK;
1320
1321LExit:
1322 // clean up
1323 ReleaseStr(pwzName);
1324
1325 if (pItm)
1326 CpiFreePropertyList(pItm);
1327
1328 return hr;
1329}
1330
1331void CpiFreePropertyList(
1332 CPI_PROPERTY* pList
1333 )
1334{
1335 while (pList)
1336 {
1337 ReleaseStr(pList->pwzValue);
1338
1339 CPI_PROPERTY* pDelete = pList;
1340 pList = pList->pNext;
1341 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1342 }
1343}
1344
1345HRESULT CpiWriteKeyToRollbackFile(
1346 HANDLE hFile,
1347 LPCWSTR pwzKey
1348 )
1349{
1350 HRESULT hr = S_OK;
1351
1352 WCHAR wzKey[MAX_DARWIN_KEY + 1];
1353 ::ZeroMemory(wzKey, sizeof(wzKey));
1354 hr = StringCchCopyW(wzKey, countof(wzKey), pwzKey);
1355 ExitOnFailure(hr, "Failed to copy key");
1356
1357 hr = WriteFileAll(hFile, (PBYTE)wzKey, MAX_DARWIN_KEY * sizeof(WCHAR));
1358 ExitOnFailure(hr, "Failed to write buffer");
1359
1360 FlushFileBuffers(hFile);
1361
1362 hr = S_OK;
1363
1364LExit:
1365 return hr;
1366}
1367
1368HRESULT CpiWriteIntegerToRollbackFile(
1369 HANDLE hFile,
1370 int i
1371 )
1372{
1373 HRESULT hr = S_OK;
1374
1375 hr = WriteFileAll(hFile, (PBYTE)&i, sizeof(int));
1376 ExitOnFailure(hr, "Failed to write buffer");
1377
1378 FlushFileBuffers(hFile);
1379
1380 hr = S_OK;
1381
1382LExit:
1383 return hr;
1384}
1385
1386HRESULT CpiReadRollbackDataList(
1387 HANDLE hFile,
1388 CPI_ROLLBACK_DATA** pprdList
1389 )
1390{
1391 HRESULT hr = S_OK;
1392
1393 int iCount;
1394
1395 CPI_ROLLBACK_DATA* pItm = NULL;
1396
1397 // read count
1398 hr = ReadFileAll(hFile, (PBYTE)&iCount, sizeof(int));
1399 if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
1400 ExitFunction1(hr = S_OK); // EOF reached, nothing left to read
1401 ExitOnFailure(hr, "Failed to read count");
1402
1403 for (int i = 0; i < iCount; i++)
1404 {
1405 // allocate new element
1406 pItm = (CPI_ROLLBACK_DATA*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLLBACK_DATA));
1407 if (!pItm)
1408 ExitFunction1(hr = E_OUTOFMEMORY);
1409
1410 // read from file
1411 hr = ReadFileAll(hFile, (PBYTE)pItm->wzKey, MAX_DARWIN_KEY * sizeof(WCHAR));
1412 if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
1413 break; // EOF reached, nothing left to read
1414 ExitOnFailure(hr, "Failed to read key");
1415
1416 hr = ReadFileAll(hFile, (PBYTE)&pItm->iStatus, sizeof(int));
1417 if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
1418 pItm->iStatus = 0; // EOF reached, the operation was interupted; set status to zero
1419 else
1420 ExitOnFailure(hr, "Failed to read status");
1421
1422 // add to list
1423 if (*pprdList)
1424 pItm->pNext = *pprdList;
1425 *pprdList = pItm;
1426 pItm = NULL;
1427 }
1428
1429 hr = S_OK;
1430
1431LExit:
1432 // clean up
1433 if (pItm)
1434 CpiFreeRollbackDataList(pItm);
1435
1436 return hr;
1437}
1438
1439void CpiFreeRollbackDataList(
1440 CPI_ROLLBACK_DATA* pList
1441 )
1442{
1443 while (pList)
1444 {
1445 CPI_ROLLBACK_DATA* pDelete = pList;
1446 pList = pList->pNext;
1447 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1448 }
1449}
1450
1451HRESULT CpiFindRollbackStatus(
1452 CPI_ROLLBACK_DATA* pList,
1453 LPCWSTR pwzKey,
1454 int* piStatus
1455 )
1456{
1457 HRESULT hr = S_OK;
1458
1459 for (; pList; pList = pList->pNext)
1460 {
1461 if (0 == lstrcmpW(pList->wzKey, pwzKey))
1462 {
1463 *piStatus = pList->iStatus;
1464 ExitFunction1(hr = S_OK);
1465 }
1466 }
1467
1468 hr = S_FALSE;
1469
1470LExit:
1471 return hr;
1472}
1473
1474HRESULT CpiAccountNameToSid(
1475 LPCWSTR pwzAccountName,
1476 PSID* ppSid
1477 )
1478{
1479 HRESULT hr = S_OK;
1480 UINT er = ERROR_SUCCESS;
1481 NTSTATUS st = 0;
1482
1483 PSID pSid = NULL;
1484 LSA_OBJECT_ATTRIBUTES loaAttributes;
1485 LSA_HANDLE lsahPolicy = NULL;
1486 LSA_UNICODE_STRING lusName;
1487 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
1488 PLSA_TRANSLATED_SID pltsSid = NULL;
1489
1490 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
1491 ::ZeroMemory(&lusName, sizeof(lusName));
1492
1493 // identify well known SIDs
1494 for (CPI_WELLKNOWN_SID* pWS = wsWellKnownSids; pWS->pwzName; pWS++)
1495 {
1496 if (0 == lstrcmpiW(pwzAccountName, pWS->pwzName))
1497 {
1498 // allocate SID buffer
1499 pSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, ::GetSidLengthRequired(pWS->nSubAuthorityCount));
1500 ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID");
1501
1502 // initialize SID
1503 ::InitializeSid(pSid, &pWS->iaIdentifierAuthority, pWS->nSubAuthorityCount);
1504
1505 // copy sub autorities
1506 for (DWORD i = 0; i < pWS->nSubAuthorityCount; i++)
1507 *::GetSidSubAuthority(pSid, i) = pWS->dwSubAuthority[i];
1508
1509 break;
1510 }
1511 }
1512
1513 // lookup name
1514 if (!pSid)
1515 {
1516 // open policy handle
1517 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
1518 er = ::LsaNtStatusToWinError(st);
1519 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
1520
1521 // create account name lsa unicode string
1522 hr = InitLsaUnicodeString(&lusName, pwzAccountName, (DWORD)wcslen(pwzAccountName));
1523 ExitOnFailure(hr, "Failed to initialize account name string");
1524
1525 // lookup name
1526 st = ::LsaLookupNames(lsahPolicy, 1, &lusName, &plrdsDomains, &pltsSid);
1527 er = ::LsaNtStatusToWinError(st);
1528 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names");
1529
1530 if (SidTypeDomain == pltsSid->Use)
1531 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported");
1532
1533 // convert sid
1534 hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pSid);
1535 ExitOnFailure(hr, "Failed to convert SID");
1536 }
1537
1538 *ppSid = pSid;
1539 pSid = NULL;
1540
1541 hr = S_OK;
1542
1543LExit:
1544 // clean up
1545 if (pSid)
1546 ::HeapFree(::GetProcessHeap(), 0, pSid);
1547 if (lsahPolicy)
1548 ::LsaClose(lsahPolicy);
1549 if (plrdsDomains)
1550 ::LsaFreeMemory(plrdsDomains);
1551 if (pltsSid)
1552 ::LsaFreeMemory(pltsSid);
1553 FreeLsaUnicodeString(&lusName);
1554
1555 return hr;
1556}
1557
1558HRESULT CpiSidToAccountName(
1559 PSID pSid,
1560 LPWSTR* ppwzAccountName
1561 )
1562{
1563 HRESULT hr = S_OK;
1564 UINT er = ERROR_SUCCESS;
1565 NTSTATUS st = 0;
1566
1567 LSA_OBJECT_ATTRIBUTES loaAttributes;
1568 LSA_HANDLE lsahPolicy = NULL;
1569 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
1570 PLSA_TRANSLATED_NAME pltnName = NULL;
1571
1572 LPWSTR pwzDomain = NULL;
1573 LPWSTR pwzName = NULL;
1574
1575 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
1576
1577 // open policy handle
1578 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
1579 er = ::LsaNtStatusToWinError(st);
1580 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
1581
1582 // lookup SID
1583 st = ::LsaLookupSids(lsahPolicy, 1, &pSid, &plrdsDomains, &pltnName);
1584 er = ::LsaNtStatusToWinError(st);
1585 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed lookup SID");
1586
1587 if (SidTypeDomain == pltnName->Use)
1588 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported");
1589
1590 // format account name string
1591 if (SidTypeWellKnownGroup != pltnName->Use)
1592 {
1593 PLSA_UNICODE_STRING plusDomain = &plrdsDomains->Domains[pltnName->DomainIndex].Name;
1594 hr = StrAllocString(&pwzDomain, plusDomain->Buffer, plusDomain->Length / sizeof(WCHAR));
1595 ExitOnFailure(hr, "Failed to allocate name string");
1596 }
1597
1598 hr = StrAllocString(&pwzName, pltnName->Name.Buffer, pltnName->Name.Length / sizeof(WCHAR));
1599 ExitOnFailure(hr, "Failed to allocate domain string");
1600
1601 hr = StrAllocFormatted(ppwzAccountName, L"%s\\%s", pwzDomain ? pwzDomain : L"", pwzName);
1602 ExitOnFailure(hr, "Failed to format account name string");
1603
1604 hr = S_OK;
1605
1606LExit:
1607 // clean up
1608 if (lsahPolicy)
1609 ::LsaClose(lsahPolicy);
1610 if (plrdsDomains)
1611 ::LsaFreeMemory(plrdsDomains);
1612 if (pltnName)
1613 ::LsaFreeMemory(pltnName);
1614
1615 ReleaseStr(pwzDomain);
1616 ReleaseStr(pwzName);
1617
1618 return hr;
1619}
1620
1621// helper function definitions
1622
1623static HRESULT FindUserCollectionObjectIndex(
1624 ICatalogCollection* piColl,
1625 PSID pSid,
1626 int* pi
1627 )
1628{
1629 HRESULT hr = S_OK;
1630 UINT er = ERROR_SUCCESS;
1631 NTSTATUS st = 0;
1632
1633 long i = 0;
1634 long lCollCnt = 0;
1635
1636 LSA_OBJECT_ATTRIBUTES loaAttributes;
1637 LSA_HANDLE lsahPolicy = NULL;
1638 PLSA_UNICODE_STRING plusNames = NULL;
1639 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
1640 PLSA_TRANSLATED_SID pltsSids = NULL;
1641
1642 IDispatch* piDisp = NULL;
1643 ICatalogObject* piObj = NULL;
1644 VARIANT vtVal;
1645
1646 PSID pTmpSid = NULL;
1647
1648 PLSA_TRANSLATED_SID pltsSid;
1649
1650 ::VariantInit(&vtVal);
1651 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
1652
1653 // open policy handle
1654 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
1655 er = ::LsaNtStatusToWinError(st);
1656 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
1657
1658 // get number of elements in collection
1659 hr = piColl->get_Count(&lCollCnt);
1660 ExitOnFailure(hr, "Failed to get to number of objects in collection");
1661
1662 if (0 == lCollCnt)
1663 ExitFunction1(hr = S_FALSE); // not found
1664
1665 // allocate name buffer
1666 plusNames = (PLSA_UNICODE_STRING)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LSA_UNICODE_STRING) * lCollCnt);
1667 ExitOnNull(plusNames, hr, E_OUTOFMEMORY, "Failed to allocate names buffer");
1668
1669 // get accounts in collection
1670 for (i = 0; i < lCollCnt; i++)
1671 {
1672 // get ICatalogObject interface
1673 hr = piColl->get_Item(i, &piDisp);
1674 ExitOnFailure(hr, "Failed to get object from collection");
1675
1676 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
1677 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
1678
1679 // get value
1680 hr = piObj->get_Key(&vtVal);
1681 ExitOnFailure(hr, "Failed to get key");
1682
1683 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
1684 ExitOnFailure(hr, "Failed to change variant type");
1685
1686 // copy account name string
1687 hr = InitLsaUnicodeString(&plusNames[i], vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal));
1688 ExitOnFailure(hr, "Failed to initialize account name string");
1689
1690 // clean up
1691 ReleaseNullObject(piDisp);
1692 ReleaseNullObject(piObj);
1693 ::VariantClear(&vtVal);
1694 }
1695
1696 // lookup names
1697 st = ::LsaLookupNames(lsahPolicy, lCollCnt, plusNames, &plrdsDomains, &pltsSids);
1698 er = ::LsaNtStatusToWinError(st);
1699 if (ERROR_NONE_MAPPED != er && ERROR_SOME_NOT_MAPPED != er)
1700 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names");
1701
1702 // compare SIDs
1703 for (i = 0; i < lCollCnt; i++)
1704 {
1705 // get SID
1706 pltsSid = &pltsSids[i];
1707 if (SidTypeDomain == pltsSid->Use || SidTypeInvalid == pltsSid->Use || SidTypeUnknown == pltsSid->Use)
1708 continue; // ignore...
1709
1710 hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pTmpSid);
1711 ExitOnFailure(hr, "Failed to convert SID");
1712
1713 // compare SIDs
1714 if (::EqualSid(pSid, pTmpSid))
1715 {
1716 *pi = i;
1717 ExitFunction1(hr = S_OK);
1718 }
1719 }
1720
1721 if (ERROR_NONE_MAPPED == er || ERROR_SOME_NOT_MAPPED == er)
1722 hr = HRESULT_FROM_WIN32(er);
1723 else
1724 hr = S_FALSE; // not found
1725
1726LExit:
1727 // clean up
1728 ReleaseObject(piDisp);
1729 ReleaseObject(piObj);
1730 ::VariantClear(&vtVal);
1731
1732 if (plusNames)
1733 {
1734 for (i = 0; i < lCollCnt; i++)
1735 FreeLsaUnicodeString(&plusNames[i]);
1736 ::HeapFree(::GetProcessHeap(), 0, plusNames);
1737 }
1738
1739 if (lsahPolicy)
1740 ::LsaClose(lsahPolicy);
1741 if (plrdsDomains)
1742 ::LsaFreeMemory(plrdsDomains);
1743 if (pltsSids)
1744 ::LsaFreeMemory(pltsSids);
1745
1746 if (pTmpSid)
1747 ::HeapFree(::GetProcessHeap(), 0, pTmpSid);
1748
1749 return hr;
1750}
1751
1752static HRESULT CreateSidFromDomainRidPair(
1753 PSID pDomainSid,
1754 DWORD dwRid,
1755 PSID* ppSid
1756 )
1757{
1758 HRESULT hr = S_OK;
1759 PSID pSid = NULL;
1760
1761 // get domain SID sub authority count
1762 UCHAR ucSubAuthorityCount = *::GetSidSubAuthorityCount(pDomainSid);
1763
1764 // allocate SID buffer
1765 DWORD dwLengthRequired = ::GetSidLengthRequired(ucSubAuthorityCount + (UCHAR)1);
1766 if (*ppSid)
1767 {
1768 SIZE_T ccb = ::HeapSize(::GetProcessHeap(), 0, *ppSid);
1769 if (-1 == ccb)
1770 ExitOnFailure(hr = E_FAIL, "Failed to get size of SID buffer");
1771
1772 if (ccb < dwLengthRequired)
1773 {
1774 pSid = (PSID)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, *ppSid, dwLengthRequired);
1775 ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for SID, len: %d", dwLengthRequired);
1776 *ppSid = pSid;
1777 }
1778 }
1779 else
1780 {
1781 *ppSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwLengthRequired);
1782 ExitOnNull(*ppSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID, len: %d", dwLengthRequired);
1783 }
1784
1785 ::InitializeSid(*ppSid, ::GetSidIdentifierAuthority(pDomainSid), ucSubAuthorityCount + (UCHAR)1);
1786
1787 // copy sub autorities
1788 DWORD i = 0;
1789 for (; i < ucSubAuthorityCount; i++)
1790 *::GetSidSubAuthority(*ppSid, i) = *::GetSidSubAuthority(pDomainSid, i);
1791 *::GetSidSubAuthority(*ppSid, i) = dwRid;
1792
1793 hr = S_OK;
1794
1795LExit:
1796 return hr;
1797}
1798
1799static HRESULT InitLsaUnicodeString(
1800 PLSA_UNICODE_STRING plusStr,
1801 LPCWSTR pwzStr,
1802 DWORD dwLen
1803 )
1804{
1805 HRESULT hr = S_OK;
1806
1807 plusStr->Length = (USHORT)dwLen * sizeof(WCHAR);
1808 plusStr->MaximumLength = (USHORT)(dwLen + 1) * sizeof(WCHAR);
1809
1810 plusStr->Buffer = (WCHAR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * (dwLen + 1));
1811 ExitOnNull(plusStr->Buffer, hr, E_OUTOFMEMORY, "Failed to allocate account name string");
1812
1813 hr = StringCchCopyW(plusStr->Buffer, dwLen + 1, pwzStr);
1814 ExitOnFailure(hr, "Failed to copy buffer");
1815
1816 hr = S_OK;
1817
1818LExit:
1819 return hr;
1820}
1821
1822static void FreeLsaUnicodeString(
1823 PLSA_UNICODE_STRING plusStr
1824 )
1825{
1826 if (plusStr->Buffer)
1827 ::HeapFree(::GetProcessHeap(), 0, plusStr->Buffer);
1828}
1829
1830static HRESULT WriteFileAll(
1831 HANDLE hFile,
1832 PBYTE pbBuffer,
1833 DWORD dwBufferLength
1834 )
1835{
1836 HRESULT hr = S_OK;
1837
1838 DWORD dwBytesWritten;
1839
1840 while (dwBufferLength)
1841 {
1842 if (!::WriteFile(hFile, pbBuffer, dwBufferLength, &dwBytesWritten, NULL))
1843 ExitFunction1(hr = HRESULT_FROM_WIN32(::GetLastError()));
1844
1845 dwBufferLength -= dwBytesWritten;
1846 pbBuffer += dwBytesWritten;
1847 }
1848
1849 hr = S_OK;
1850
1851LExit:
1852 return hr;
1853}
1854
1855static HRESULT ReadFileAll(
1856 HANDLE hFile,
1857 PBYTE pbBuffer,
1858 DWORD dwBufferLength
1859 )
1860{
1861 HRESULT hr = S_OK;
1862
1863 DWORD dwBytesRead;
1864
1865 while (dwBufferLength)
1866 {
1867 if (!::ReadFile(hFile, pbBuffer, dwBufferLength, &dwBytesRead, NULL))
1868 ExitFunction1(hr = HRESULT_FROM_WIN32(::GetLastError()));
1869
1870 if (0 == dwBytesRead)
1871 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF));
1872
1873 dwBufferLength -= dwBytesRead;
1874 pbBuffer += dwBytesRead;
1875 }
1876
1877 hr = S_OK;
1878
1879LExit:
1880 return hr;
1881}
diff --git a/src/ext/ComPlus/ca/cputilexec.h b/src/ext/ComPlus/ca/cputilexec.h
new file mode 100644
index 00000000..b900883d
--- /dev/null
+++ b/src/ext/ComPlus/ca/cputilexec.h
@@ -0,0 +1,193 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#define CPI_MAX_GUID 38
6
7enum eActionType { atNoOp = 0, atCreate, atRemove };
8
9
10// structs
11
12struct CPI_PROPERTY
13{
14 WCHAR wzName[MAX_DARWIN_KEY + 1];
15 LPWSTR pwzValue;
16
17 CPI_PROPERTY* pNext;
18};
19
20struct CPI_ROLLBACK_DATA
21{
22 WCHAR wzKey[MAX_DARWIN_KEY + 1];
23 int iStatus;
24
25 CPI_ROLLBACK_DATA* pNext;
26};
27
28
29// function prototypes
30
31void CpiExecInitialize();
32void CpiExecFinalize();
33HRESULT CpiActionStartMessage(
34 LPWSTR* ppwzActionData,
35 BOOL fSuppress
36 );
37HRESULT CpiActionDataMessage(
38 DWORD cArgs,
39 ...
40 );
41HRESULT CpiExecGetAdminCatalog(
42 ICOMAdminCatalog** ppiCatalog
43 );
44HRESULT CpiLogCatalogErrorInfo();
45HRESULT CpiExecGetCatalogCollection(
46 LPCWSTR pwzName,
47 ICatalogCollection** ppiColl
48 );
49HRESULT CpiExecGetCatalogCollection(
50 ICatalogCollection* piColl,
51 ICatalogObject* piObj,
52 LPCWSTR pwzName,
53 ICatalogCollection** ppiColl
54 );
55HRESULT CpiAddCollectionObject(
56 ICatalogCollection* piColl,
57 ICatalogObject** ppiObj
58 );
59HRESULT CpiPutCollectionObjectValue(
60 ICatalogObject* piObj,
61 LPCWSTR pwzPropName,
62 LPCWSTR pwzValue
63 );
64HRESULT CpiPutCollectionObjectValues(
65 ICatalogObject* piObj,
66 CPI_PROPERTY* pPropList
67 );
68HRESULT CpiGetCollectionObjectValue(
69 ICatalogObject* piObj,
70 LPCWSTR szPropName,
71 LPWSTR* ppwzValue
72 );
73HRESULT CpiResetObjectProperty(
74 ICatalogCollection* piColl,
75 ICatalogObject* piObj,
76 LPCWSTR pwzPropName
77 );
78HRESULT CpiRemoveCollectionObject(
79 ICatalogCollection* piColl,
80 LPCWSTR pwzID,
81 LPCWSTR pwzName,
82 BOOL fResetDeleteable
83 );
84HRESULT CpiRemoveUserCollectionObject(
85 ICatalogCollection* piColl,
86 PSID pSid
87 );
88HRESULT CpiFindCollectionObjectByStringKey(
89 ICatalogCollection* piColl,
90 LPCWSTR pwzKey,
91 ICatalogObject** ppiObj
92 );
93HRESULT CpiFindCollectionObjectByIntegerKey(
94 ICatalogCollection* piColl,
95 long lKey,
96 ICatalogObject** ppiObj
97 );
98HRESULT CpiFindCollectionObjectByName(
99 ICatalogCollection* piColl,
100 LPCWSTR pwzName,
101 ICatalogObject** ppiObj
102 );
103HRESULT CpiFindUserCollectionObject(
104 ICatalogCollection* piColl,
105 PSID pSid,
106 ICatalogObject** ppiObj
107 );
108HRESULT CpiExecGetPartitionsCollection(
109 ICatalogCollection** ppiPartColl
110 );
111HRESULT CpiGetPartitionRolesCollection(
112 LPCWSTR pwzPartID,
113 ICatalogCollection** ppiRolesColl
114 );
115HRESULT CpiGetUsersInPartitionRoleCollection(
116 LPCWSTR pwzPartID,
117 LPCWSTR pwzRoleName,
118 ICatalogCollection** ppiUsrInRoleColl
119 );
120HRESULT CpiGetPartitionUsersCollection(
121 ICatalogCollection** ppiUserColl
122 );
123HRESULT CpiExecGetApplicationsCollection(
124 LPCWSTR pwzPartID,
125 ICatalogCollection** ppiAppColl
126 );
127HRESULT CpiGetRolesCollection(
128 LPCWSTR pwzPartID,
129 LPCWSTR pwzAppID,
130 ICatalogCollection** ppiRolesColl
131 );
132HRESULT CpiGetUsersInRoleCollection(
133 LPCWSTR pwzPartID,
134 LPCWSTR pwzAppID,
135 LPCWSTR pwzRoleName,
136 ICatalogCollection** ppiUsrInRoleColl
137 );
138HRESULT CpiGetComponentsCollection(
139 LPCWSTR pwzPartID,
140 LPCWSTR pwzAppID,
141 ICatalogCollection** ppiCompsColl
142 );
143HRESULT CpiGetInterfacesCollection(
144 ICatalogCollection* piCompColl,
145 ICatalogObject* piCompObj,
146 ICatalogCollection** ppiIntfColl
147 );
148HRESULT CpiGetMethodsCollection(
149 ICatalogCollection* piIntfColl,
150 ICatalogObject* piIntfObj,
151 ICatalogCollection** ppiMethColl
152 );
153HRESULT CpiGetSubscriptionsCollection(
154 LPCWSTR pwzPartID,
155 LPCWSTR pwzAppID,
156 LPCWSTR pwzCompCLSID,
157 ICatalogCollection** ppiCompsColl
158 );
159HRESULT CpiReadPropertyList(
160 LPWSTR* ppwzData,
161 CPI_PROPERTY** ppPropList
162 );
163void CpiFreePropertyList(
164 CPI_PROPERTY* pList
165 );
166HRESULT CpiWriteKeyToRollbackFile(
167 HANDLE hFile,
168 LPCWSTR pwzKey
169 );
170HRESULT CpiWriteIntegerToRollbackFile(
171 HANDLE hFile,
172 int i
173 );
174HRESULT CpiReadRollbackDataList(
175 HANDLE hFile,
176 CPI_ROLLBACK_DATA** pprdList
177 );
178void CpiFreeRollbackDataList(
179 CPI_ROLLBACK_DATA* pList
180 );
181HRESULT CpiFindRollbackStatus(
182 CPI_ROLLBACK_DATA* pList,
183 LPCWSTR pwzKey,
184 int* piStatus
185 );
186HRESULT CpiAccountNameToSid(
187 LPCWSTR pwzAccountName,
188 PSID* ppSid
189 );
190HRESULT CpiSidToAccountName(
191 PSID pSid,
192 LPWSTR* ppwzAccountName
193 );
diff --git a/src/ext/ComPlus/ca/cputilsched.cpp b/src/ext/ComPlus/ca/cputilsched.cpp
new file mode 100644
index 00000000..1a958c56
--- /dev/null
+++ b/src/ext/ComPlus/ca/cputilsched.cpp
@@ -0,0 +1,885 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsActionTextQuery =
9 L"SELECT `Description`, `Template` FROM `ActionText` WHERE `Action` = ?";
10enum eActionTextQuery { atqDescription = 1, atqTemplate };
11
12LPCWSTR vcsComponentAttributesQuery =
13 L"SELECT `Attributes` FROM `Component` WHERE `Component` = ?";
14enum eComponentAttributesQuery { caqAttributes = 1 };
15
16LPCWSTR vcsUserQuery = L"SELECT `Domain`, `Name` FROM `User` WHERE `User` = ?";
17enum eUserQuery { uqDomain = 1, uqName };
18
19enum ePropertyQuery { pqName = 1, pqValue };
20
21
22// prototypes for private helper functions
23
24static HRESULT FindPropertyDefinition(
25 CPI_PROPERTY_DEFINITION* pPropDefList,
26 LPCWSTR pwzName,
27 CPI_PROPERTY_DEFINITION** ppPropDef
28 );
29static HRESULT GetUserAccountName(
30 LPCWSTR pwzKey,
31 LPWSTR* ppwzAccount
32 );
33
34
35// variables
36
37static ICOMAdminCatalog* gpiCatalog;
38static ICatalogCollection* gpiPartColl;
39static ICatalogCollection* gpiAppColl;
40
41static int giTables;
42
43
44// function definitions
45
46void CpiSchedInitialize()
47{
48 // collections
49 gpiCatalog = NULL;
50 gpiPartColl = NULL;
51 gpiAppColl = NULL;
52
53 // tables
54 giTables = 0;
55
56 if (S_OK == WcaTableExists(L"ComPlusPartition")) giTables |= cptComPlusPartition;
57 if (S_OK == WcaTableExists(L"ComPlusPartitionProperty")) giTables |= cptComPlusPartitionProperty;
58 if (S_OK == WcaTableExists(L"ComPlusPartitionRole")) giTables |= cptComPlusPartitionRole;
59 if (S_OK == WcaTableExists(L"ComPlusUserInPartitionRole")) giTables |= cptComPlusUserInPartitionRole;
60 if (S_OK == WcaTableExists(L"ComPlusGroupInPartitionRole")) giTables |= cptComPlusGroupInPartitionRole;
61 if (S_OK == WcaTableExists(L"ComPlusPartitionUser")) giTables |= cptComPlusPartitionUser;
62 if (S_OK == WcaTableExists(L"ComPlusApplication")) giTables |= cptComPlusApplication;
63 if (S_OK == WcaTableExists(L"ComPlusApplicationProperty")) giTables |= cptComPlusApplicationProperty;
64 if (S_OK == WcaTableExists(L"ComPlusApplicationRole")) giTables |= cptComPlusApplicationRole;
65 if (S_OK == WcaTableExists(L"ComPlusApplicationRoleProperty")) giTables |= cptComPlusApplicationRoleProperty;
66 if (S_OK == WcaTableExists(L"ComPlusUserInApplicationRole")) giTables |= cptComPlusUserInApplicationRole;
67 if (S_OK == WcaTableExists(L"ComPlusGroupInApplicationRole")) giTables |= cptComPlusGroupInApplicationRole;
68 if (S_OK == WcaTableExists(L"ComPlusAssembly")) giTables |= cptComPlusAssembly;
69 if (S_OK == WcaTableExists(L"ComPlusAssemblyDependency")) giTables |= cptComPlusAssemblyDependency;
70 if (S_OK == WcaTableExists(L"ComPlusComponent")) giTables |= cptComPlusComponent;
71 if (S_OK == WcaTableExists(L"ComPlusComponentProperty")) giTables |= cptComPlusComponentProperty;
72 if (S_OK == WcaTableExists(L"ComPlusRoleForComponent")) giTables |= cptComPlusRoleForComponent;
73 if (S_OK == WcaTableExists(L"ComPlusInterface")) giTables |= cptComPlusInterface;
74 if (S_OK == WcaTableExists(L"ComPlusInterfaceProperty")) giTables |= cptComPlusInterfaceProperty;
75 if (S_OK == WcaTableExists(L"ComPlusRoleForInterface")) giTables |= cptComPlusRoleForInterface;
76 if (S_OK == WcaTableExists(L"ComPlusMethod")) giTables |= cptComPlusMethod;
77 if (S_OK == WcaTableExists(L"ComPlusMethodProperty")) giTables |= cptComPlusMethodProperty;
78 if (S_OK == WcaTableExists(L"ComPlusRoleForMethod")) giTables |= cptComPlusRoleForMethod;
79 if (S_OK == WcaTableExists(L"ComPlusSubscription")) giTables |= cptComPlusSubscription;
80 if (S_OK == WcaTableExists(L"ComPlusSubscriptionProperty")) giTables |= cptComPlusSubscriptionProperty;
81}
82
83void CpiSchedFinalize()
84{
85 // collections
86 ReleaseObject(gpiCatalog);
87 ReleaseObject(gpiPartColl);
88 ReleaseObject(gpiAppColl);
89}
90
91BOOL CpiTableExists(
92 int iTable
93 )
94{
95 return (giTables & iTable) == iTable;
96}
97
98HRESULT CpiSchedGetAdminCatalog(
99 ICOMAdminCatalog** ppiCatalog
100 )
101{
102 HRESULT hr = S_OK;
103
104 if (!gpiCatalog)
105 {
106 // get collection
107 hr = ::CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_ALL, IID_ICOMAdminCatalog, (void**)&gpiCatalog);
108 ExitOnFailure(hr, "Failed to create COM+ admin catalog object");
109 }
110
111 // return value
112 gpiCatalog->AddRef();
113 *ppiCatalog = gpiCatalog;
114
115 hr = S_OK;
116
117LExit:
118 return hr;
119}
120
121HRESULT CpiSchedGetCatalogCollection(
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 = CpiSchedGetAdminCatalog(&piCatalog);
138 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
139
140 // get collecton from catalog
141 hr = piCatalog->GetCollection(bstrName, &piDisp);
142 ExitOnFailure(hr, "Failed to get collection");
143
144 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
145 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
146
147 // populate collection
148 hr = (*ppiColl)->Populate();
149 ExitOnFailure(hr, "Failed to populate collection");
150
151 hr = S_OK;
152
153LExit:
154 // clean up
155 ReleaseObject(piCatalog);
156 ReleaseObject(piDisp);
157 ReleaseBSTR(bstrName);
158
159 return hr;
160}
161
162HRESULT CpiSchedGetCatalogCollection(
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 = CpiSchedGetAdminCatalog(&piCatalog);
184 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
185
186 // get key
187 hr = piObj->get_Key(&vtKey);
188 ExitOnFailure(hr, "Failed to get object key");
189
190 // get collecton from catalog
191 hr = piColl->GetCollection(bstrName, vtKey, &piDisp);
192 ExitOnFailure(hr, "Failed to get collection");
193
194 hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl);
195 ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface");
196
197 // populate collection
198 hr = (*ppiColl)->Populate();
199 ExitOnFailure(hr, "Failed to populate collection");
200
201 hr = S_OK;
202
203LExit:
204 // clean up
205 ReleaseObject(piCatalog);
206 ReleaseObject(piDisp);
207 ReleaseBSTR(bstrName);
208 ::VariantClear(&vtKey);
209
210 return hr;
211}
212
213HRESULT CpiGetKeyForObject(
214 ICatalogObject* piObj,
215 LPWSTR pwzKey,
216 SIZE_T cchKey
217 )
218{
219 HRESULT hr = S_OK;
220
221 VARIANT vtKey;
222 ::VariantInit(&vtKey);
223
224 // get key
225 hr = piObj->get_Key(&vtKey);
226 ExitOnFailure(hr, "Failed to get key");
227
228 // change variant type
229 hr = ::VariantChangeType(&vtKey, &vtKey, 0, VT_BSTR);
230 ExitOnFailure(hr, "Failed to change variant type");
231
232 // copy key
233 hr = StringCchCopyW(pwzKey, cchKey, vtKey.bstrVal);
234 ExitOnFailure(hr, "Failed to copy key");
235
236 hr = S_OK;
237
238LExit:
239 // clean up
240 ::VariantClear(&vtKey);
241
242 return hr;
243}
244
245HRESULT CpiFindCollectionObject(
246 ICatalogCollection* piColl,
247 LPCWSTR pwzID,
248 LPCWSTR pwzName,
249 ICatalogObject** ppiObj
250 )
251{
252 HRESULT hr = S_OK;
253
254 IDispatch* piDisp = NULL;
255 ICatalogObject* piObj = NULL;
256
257 VARIANT vtVal;
258 ::VariantInit(&vtVal);
259
260 long lCnt;
261 hr = piColl->get_Count(&lCnt);
262 ExitOnFailure(hr, "Failed to get to number of items in collection");
263
264 for (long i = 0; i < lCnt; i++)
265 {
266 // get ICatalogObject interface
267 hr = piColl->get_Item(i, &piDisp);
268 ExitOnFailure(hr, "Failed to get object from collection");
269
270 hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
271 ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");
272
273 // compare id
274 if (pwzID && *pwzID)
275 {
276 hr = piObj->get_Key(&vtVal);
277 ExitOnFailure(hr, "Failed to get key");
278
279 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
280 ExitOnFailure(hr, "Failed to change variant type");
281
282 if (0 == lstrcmpiW(vtVal.bstrVal, pwzID))
283 {
284 if (ppiObj)
285 {
286 *ppiObj = piObj;
287 piObj = NULL;
288 }
289 ExitFunction1(hr = S_OK);
290 }
291
292 ::VariantClear(&vtVal);
293 }
294
295 // compare name
296 if (pwzName && *pwzName)
297 {
298 hr = piObj->get_Name(&vtVal);
299 ExitOnFailure(hr, "Failed to get name");
300
301 hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
302 ExitOnFailure(hr, "Failed to change variant type");
303
304 if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
305 {
306 if (ppiObj)
307 {
308 *ppiObj = piObj;
309 piObj = NULL;
310 }
311 ExitFunction1(hr = S_OK);
312 }
313
314 ::VariantClear(&vtVal);
315 }
316
317 // release interface pointers
318 ReleaseNullObject(piDisp);
319 ReleaseNullObject(piObj);
320 }
321
322 hr = S_FALSE;
323
324LExit:
325 // clean up
326 ReleaseObject(piDisp);
327 ReleaseObject(piObj);
328
329 ::VariantClear(&vtVal);
330
331 return hr;
332}
333
334HRESULT CpiSchedGetPartitionsCollection(
335 ICatalogCollection** ppiPartColl
336 )
337{
338 HRESULT hr = S_OK;
339
340 if (!gpiPartColl)
341 {
342 // get collection
343 hr = CpiSchedGetCatalogCollection(L"Partitions", &gpiPartColl);
344 ExitOnFailure(hr, "Failed to get partitions collection");
345 }
346
347 // return value
348 gpiPartColl->AddRef();
349 *ppiPartColl = gpiPartColl;
350
351 hr = S_OK;
352
353LExit:
354 return hr;
355}
356
357HRESULT CpiSchedGetApplicationsCollection(
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 = CpiSchedGetAdminCatalog(&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 = CpiSchedGetPartitionsCollection(&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 = CpiSchedGetCatalogCollection(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 = CpiSchedGetCatalogCollection(L"Applications", &gpiAppColl);
408 ExitOnFailure(hr, "Failed to get applications collection");
409 }
410 }
411
412 // return value
413 gpiAppColl->AddRef();
414 *ppiAppColl = gpiAppColl;
415
416 hr = S_OK;
417
418LExit:
419 // clean up
420 ReleaseObject(piCatalog);
421 ReleaseObject(piCatalog2);
422 ReleaseObject(piPartColl);
423 ReleaseObject(piPartObj);
424 ReleaseBSTR(bstrGlobPartID);
425
426 return hr;
427}
428
429HRESULT CpiAddActionTextToActionData(
430 LPCWSTR pwzAction,
431 LPWSTR* ppwzActionData
432 )
433{
434 HRESULT hr = S_OK;
435
436 PMSIHANDLE hView, hRecKey, hRec;
437
438 LPWSTR pwzDescription = NULL;
439 LPWSTR pwzTemplate = NULL;
440
441 if (S_OK == WcaTableExists(L"ActionText"))
442 {
443 // create parameter record
444 hRecKey = ::MsiCreateRecord(1);
445 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
446 hr = WcaSetRecordString(hRecKey, 1, pwzAction);
447 ExitOnFailure(hr, "Failed to set record string");
448
449 // open view
450 hr = WcaOpenView(vcsActionTextQuery, &hView);
451 ExitOnFailure(hr, "Failed to open view on ActionText table");
452 hr = WcaExecuteView(hView, hRecKey);
453 ExitOnFailure(hr, "Failed to execute view on ActionText table");
454
455 // fetch record
456 hr = WcaFetchSingleRecord(hView, &hRec);
457 if (S_FALSE != hr)
458 {
459 ExitOnFailure(hr, "Failed to fetch action text record");
460
461 // get description
462 hr = WcaGetRecordString(hRec, atqDescription, &pwzDescription);
463 ExitOnFailure(hr, "Failed to get description");
464
465 // get template
466 hr = WcaGetRecordString(hRec, atqTemplate, &pwzTemplate);
467 ExitOnFailure(hr, "Failed to get template");
468 }
469 }
470
471 // add action name to action data
472 hr = WcaWriteStringToCaData(pwzAction, ppwzActionData);
473 ExitOnFailure(hr, "Failed to add action name to custom action data");
474
475 // add description to action data
476 hr = WcaWriteStringToCaData(pwzDescription ? pwzDescription : L"", ppwzActionData);
477 ExitOnFailure(hr, "Failed to add description to custom action data");
478
479 // add template to action data
480 hr = WcaWriteStringToCaData(pwzTemplate ? pwzTemplate : L"", ppwzActionData);
481 ExitOnFailure(hr, "Failed to add template to custom action data");
482
483 hr = S_OK;
484
485LExit:
486 // clean up
487 ReleaseStr(pwzDescription);
488 ReleaseStr(pwzTemplate);
489
490 return hr;
491}
492
493HRESULT CpiVerifyComponentArchitecure(
494 LPCWSTR pwzComponent,
495 BOOL* pfMatchingArchitecture
496 )
497{
498 HRESULT hr = S_OK;
499
500 PMSIHANDLE hView, hRecKey, hRec;
501
502 int iAttributes = 0;
503
504 if (S_OK == WcaTableExists(L"Component"))
505 {
506 // create parameter record
507 hRecKey = ::MsiCreateRecord(1);
508 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
509 hr = WcaSetRecordString(hRecKey, 1, pwzComponent);
510 ExitOnFailure(hr, "Failed to set record string");
511
512 // open view
513 hr = WcaOpenView(vcsComponentAttributesQuery, &hView);
514 ExitOnFailure(hr, "Failed to open view on ActionText table");
515 hr = WcaExecuteView(hView, hRecKey);
516 ExitOnFailure(hr, "Failed to execute view on ActionText table");
517
518 // fetch record
519 hr = WcaFetchSingleRecord(hView, &hRec);
520 if (S_FALSE != hr)
521 {
522 ExitOnFailure(hr, "Failed to fetch component record");
523
524 hr = WcaGetRecordInteger(hRec, caqAttributes, &iAttributes);
525 ExitOnFailure(hr, "Failed to get component attributes");
526 }
527 }
528
529 // return values
530#ifdef _WIN64
531 *pfMatchingArchitecture = 256 == (iAttributes & 256);
532#else
533 *pfMatchingArchitecture = 256 != (iAttributes & 256);
534#endif
535
536 hr = S_OK;
537
538LExit:
539 return hr;
540}
541
542HRESULT CpiPropertiesRead(
543 LPCWSTR pwzQuery,
544 LPCWSTR pwzKey,
545 CPI_PROPERTY_DEFINITION* pPropDefList,
546 CPI_PROPERTY** ppPropList,
547 int* piCount
548 )
549{
550 HRESULT hr = S_OK;
551
552 PMSIHANDLE hView, hRecKey, hRec;
553
554 CPI_PROPERTY* pItm = NULL;
555 LPWSTR pwzData = NULL;
556
557 int iVersionNT = 0;
558
559 CPI_PROPERTY_DEFINITION* pPropDef;
560
561 *piCount = 0;
562
563 // get NT version
564 hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
565 ExitOnFailure(hr, "Failed to set record string");
566
567 // create parameter record
568 hRecKey = ::MsiCreateRecord(1);
569 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
570 hr = WcaSetRecordString(hRecKey, 1, pwzKey);
571 ExitOnFailure(hr, "Failed to set record string");
572
573 // open view
574 hr = WcaOpenView(pwzQuery, &hView);
575 ExitOnFailure(hr, "Failed to open view on property table");
576 hr = WcaExecuteView(hView, hRecKey);
577 ExitOnFailure(hr, "Failed to execute view on property table");
578
579 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
580 {
581 // create entry
582 pItm = (CPI_PROPERTY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PROPERTY));
583 if (!pItm)
584 ExitFunction1(hr = E_OUTOFMEMORY);
585
586 // get name
587 hr = WcaGetRecordString(hRec, pqName, &pwzData);
588 ExitOnFailure(hr, "Failed to get name");
589 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
590
591 // get value
592 hr = WcaGetRecordFormattedString(hRec, pqValue, &pItm->pwzValue);
593 ExitOnFailure(hr, "Failed to get value");
594
595 // find property definition
596 hr = FindPropertyDefinition(pPropDefList, pItm->wzName, &pPropDef);
597 ExitOnFailure(hr, "Failed to find property definition");
598
599 if (S_FALSE == hr)
600 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Unknown property, key: %S, property: %S", pwzKey, pItm->wzName);
601
602 // check version, ignore if catalog version is too low
603 if (iVersionNT < pPropDef->iMinVersionNT)
604 {
605 WcaLog(LOGMSG_VERBOSE, "Skipping property since NT version is too low, key: %S, property: %S", pwzKey, pItm->wzName);
606 CpiPropertiesFreeList(pItm);
607 pItm = NULL;
608 continue;
609 }
610
611 // if the property is a user, replace the User table key with a user account name
612 if (cpptUser == pPropDef->iType)
613 {
614 hr = GetUserAccountName(pItm->pwzValue, &pItm->pwzValue);
615 ExitOnFailure(hr, "Failed to get user account name");
616 }
617
618 // add entry
619 ++*piCount;
620 if (*ppPropList)
621 pItm->pNext = *ppPropList;
622 *ppPropList = pItm;
623 pItm = NULL;
624 }
625
626 if (E_NOMOREITEMS == hr)
627 hr = S_OK;
628
629LExit:
630 // clean up
631 if (pItm)
632 CpiPropertiesFreeList(pItm);
633
634 ReleaseStr(pwzData);
635
636 return hr;
637}
638
639void CpiPropertiesFreeList(
640 CPI_PROPERTY* pList
641 )
642{
643 while (pList)
644 {
645 ReleaseStr(pList->pwzValue);
646
647 CPI_PROPERTY* pDelete = pList;
648 pList = pList->pNext;
649 ::HeapFree(::GetProcessHeap(), 0, pDelete);
650 }
651}
652
653HRESULT CpiAddPropertiesToActionData(
654 int iPropCount,
655 CPI_PROPERTY* pPropList,
656 LPWSTR* ppwzActionData
657 )
658{
659 HRESULT hr = S_OK;
660
661 hr = WcaWriteIntegerToCaData(iPropCount, ppwzActionData);
662 ExitOnFailure(hr, "Failed to add count to custom action data");
663
664 if (iPropCount) // count might be 0 event thought there are elements in the list
665 {
666 for (CPI_PROPERTY* pProp = pPropList; pProp; pProp = pProp->pNext)
667 {
668 hr = WcaWriteStringToCaData(pProp->wzName, ppwzActionData);
669 ExitOnFailure(hr, "Failed to add property name to custom action data, name: %S", pProp->wzName);
670
671 hr = WcaWriteStringToCaData(pProp->pwzValue, ppwzActionData);
672 ExitOnFailure(hr, "Failed to add property value to custom action data, name: %S", pProp->wzName);
673 }
674 }
675
676 hr = S_OK;
677
678LExit:
679 return hr;
680}
681
682HRESULT CpiBuildAccountName(
683 LPCWSTR pwzDomain,
684 LPCWSTR pwzName,
685 LPWSTR* ppwzAccount
686 )
687{
688 HRESULT hr = S_OK;
689
690 WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1];
691 ::ZeroMemory(wzComputerName, sizeof(wzComputerName));
692
693 // if domain is '.', get computer name
694 if (0 == lstrcmpW(pwzDomain, L"."))
695 {
696 DWORD dwSize = countof(wzComputerName);
697 if (!::GetComputerNameW(wzComputerName, &dwSize))
698 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get computer name");
699 }
700
701 // build account name
702 hr = StrAllocFormatted(ppwzAccount, L"%s\\%s", *wzComputerName ? wzComputerName : pwzDomain, pwzName);
703 ExitOnFailure(hr, "Failed to build domain user name");
704
705 hr = S_OK;
706
707LExit:
708 return hr;
709}
710
711HRESULT CpiGetTempFileName(
712 LPWSTR* ppwzTempFile
713 )
714{
715 HRESULT hr = S_OK;
716
717 // get temp path
718 WCHAR wzTempPath[MAX_PATH];
719 DWORD dw = ::GetTempPathW(countof(wzTempPath), wzTempPath);
720 if (countof(wzTempPath) <= dw)
721 ExitOnFailure(hr = E_FAIL, "TEMP directory path too long");
722
723 // get unique number
724 LARGE_INTEGER liCount;
725 if (!::QueryPerformanceCounter(&liCount))
726 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to query performance counter");
727
728 // create temp file name
729 hr = StrAllocFormatted(ppwzTempFile, L"%sCPI%I64X.tmp", wzTempPath, liCount.QuadPart);
730 ExitOnFailure(hr, "Failed to create temp file name string");
731
732 hr = S_OK;
733
734LExit:
735 return hr;
736}
737
738HRESULT CpiCreateId(
739 LPWSTR pwzDest,
740 SIZE_T cchDest
741 )
742{
743 HRESULT hr = S_OK;
744
745 GUID guid;
746
747 // create new guid
748 hr = ::CoCreateGuid(&guid);
749 ExitOnFailure(hr, "Failed to create new guid");
750
751 // convert guid to string
752 if (0 == ::StringFromGUID2(guid, pwzDest, (int)cchDest))
753 ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string");
754
755 hr = S_OK;
756
757LExit:
758 return hr;
759}
760
761BOOL CpiIsInstalled(
762 INSTALLSTATE isInstalled
763 )
764{
765 return INSTALLSTATE_LOCAL == isInstalled || INSTALLSTATE_SOURCE == isInstalled;
766}
767
768BOOL CpiWillBeInstalled(
769 INSTALLSTATE isInstalled,
770 INSTALLSTATE isAction
771 )
772{
773 return WcaIsInstalling(isInstalled, isAction) ||
774 (CpiIsInstalled(isInstalled) && !WcaIsUninstalling(isInstalled, isAction));
775}
776
777HRESULT PcaGuidToRegFormat(
778 LPWSTR pwzGuid,
779 LPWSTR pwzDest,
780 SIZE_T cchDest
781 )
782{
783 HRESULT hr = S_OK;
784
785 GUID guid = GUID_NULL;
786 int cch = 0;
787
788 WCHAR wz[39];
789 ::ZeroMemory(wz, sizeof(wz));
790
791 cch = lstrlenW(pwzGuid);
792
793 if (38 == cch && L'{' == pwzGuid[0] && L'}' == pwzGuid[37])
794 StringCchCopyW(wz, countof(wz), pwzGuid);
795 else if (36 == cch)
796 StringCchPrintfW(wz, countof(wz), L"{%s}", pwzGuid);
797 else
798 ExitFunction1(hr = E_INVALIDARG);
799
800 // convert string to guid
801 hr = ::CLSIDFromString(wz, &guid);
802 ExitOnFailure(hr, "Failed to parse guid string");
803
804 // convert guid to string
805 if (0 == ::StringFromGUID2(guid, pwzDest, (int)cchDest))
806 ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string");
807
808 hr = S_OK;
809
810LExit:
811 return hr;
812}
813
814
815// helper function definitions
816
817static HRESULT FindPropertyDefinition(
818 CPI_PROPERTY_DEFINITION* pPropDefList,
819 LPCWSTR pwzName,
820 CPI_PROPERTY_DEFINITION** ppPropDef
821 )
822{
823 for (CPI_PROPERTY_DEFINITION* pItm = pPropDefList; pItm->pwzName; pItm++)
824 {
825 if (0 == lstrcmpW(pItm->pwzName, pwzName))
826 {
827 *ppPropDef = pItm;
828 return S_OK;
829 }
830 }
831
832 return S_FALSE;
833}
834
835static HRESULT GetUserAccountName(
836 LPCWSTR pwzKey,
837 LPWSTR* ppwzAccount
838 )
839{
840 HRESULT hr = S_OK;
841
842 PMSIHANDLE hView, hRecKey, hRec;
843
844 LPWSTR pwzDomain = NULL;
845 LPWSTR pwzName = NULL;
846
847 // create parameter record
848 hRecKey = ::MsiCreateRecord(1);
849 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
850 hr = WcaSetRecordString(hRecKey, 1, pwzKey);
851 ExitOnFailure(hr, "Failed to set record string");
852
853 // open view
854 hr = WcaOpenView(vcsUserQuery, &hView);
855 ExitOnFailure(hr, "Failed to open view on User table");
856 hr = WcaExecuteView(hView, hRecKey);
857 ExitOnFailure(hr, "Failed to execute view on User table");
858
859 // fetch record
860 hr = WcaFetchSingleRecord(hView, &hRec);
861 if (S_FALSE == hr)
862 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "User not found, key: %S", pwzKey);
863 ExitOnFailure(hr, "Failed to fetch user record");
864
865 // get user domain
866 hr = WcaGetRecordFormattedString(hRec, uqDomain, &pwzDomain);
867 ExitOnFailure(hr, "Failed to get domain");
868
869 // get user name
870 hr = WcaGetRecordFormattedString(hRec, uqName, &pwzName);
871 ExitOnFailure(hr, "Failed to get name");
872
873 // build account name
874 hr = CpiBuildAccountName(pwzDomain, pwzName, ppwzAccount);
875 ExitOnFailure(hr, "Failed to build account name");
876
877 hr = S_OK;
878
879LExit:
880 // clean up
881 ReleaseStr(pwzDomain);
882 ReleaseStr(pwzName);
883
884 return hr;
885}
diff --git a/src/ext/ComPlus/ca/cputilsched.h b/src/ext/ComPlus/ca/cputilsched.h
new file mode 100644
index 00000000..1f315576
--- /dev/null
+++ b/src/ext/ComPlus/ca/cputilsched.h
@@ -0,0 +1,132 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5enum eRunMode { rmDeferred = 1, rmCommit, rmRollback };
6
7enum eComPlusPropertyType { cpptNone = 0, cpptBoolean, cpptInteger, cpptString, cpptUser };
8
9enum eComPlusTables
10{
11 cptComPlusPartition = (1 << 0),
12 cptComPlusPartitionProperty = (1 << 1),
13 cptComPlusPartitionRole = (1 << 2),
14 cptComPlusUserInPartitionRole = (1 << 3),
15 cptComPlusGroupInPartitionRole = (1 << 4),
16 cptComPlusPartitionUser = (1 << 5),
17 cptComPlusApplication = (1 << 6),
18 cptComPlusApplicationProperty = (1 << 7),
19 cptComPlusApplicationRole = (1 << 8),
20 cptComPlusApplicationRoleProperty = (1 << 9),
21 cptComPlusUserInApplicationRole = (1 << 10),
22 cptComPlusGroupInApplicationRole = (1 << 11),
23 cptComPlusAssembly = (1 << 12),
24 cptComPlusAssemblyDependency = (1 << 13),
25 cptComPlusComponent = (1 << 14),
26 cptComPlusComponentProperty = (1 << 15),
27 cptComPlusRoleForComponent = (1 << 16),
28 cptComPlusInterface = (1 << 17),
29 cptComPlusInterfaceProperty = (1 << 18),
30 cptComPlusRoleForInterface = (1 << 19),
31 cptComPlusMethod = (1 << 20),
32 cptComPlusMethodProperty = (1 << 21),
33 cptComPlusRoleForMethod = (1 << 22),
34 cptComPlusSubscription = (1 << 23),
35 cptComPlusSubscriptionProperty = (1 << 24)
36};
37
38
39// structs
40
41struct CPI_PROPERTY_DEFINITION
42{
43 LPCWSTR pwzName;
44 int iType;
45 int iMinVersionNT;
46};
47
48
49// function prototypes
50
51void CpiSchedInitialize();
52void CpiSchedFinalize();
53BOOL CpiTableExists(
54 int iTable
55 );
56HRESULT CpiSchedGetAdminCatalog(
57 ICOMAdminCatalog** ppiCatalog
58 );
59HRESULT CpiSchedGetCatalogCollection(
60 LPCWSTR pwzName,
61 ICatalogCollection** ppiColl
62 );
63HRESULT CpiSchedGetCatalogCollection(
64 ICatalogCollection* piColl,
65 ICatalogObject* piObj,
66 LPCWSTR pwzName,
67 ICatalogCollection** ppiColl
68 );
69HRESULT CpiGetKeyForObject(
70 ICatalogObject* piObj,
71 LPWSTR pwzKey,
72 SIZE_T cchKey
73 );
74HRESULT CpiFindCollectionObject(
75 ICatalogCollection* piColl,
76 LPCWSTR pwzID,
77 LPCWSTR pwzName,
78 ICatalogObject** ppiObj
79 );
80HRESULT CpiSchedGetPartitionsCollection(
81 ICatalogCollection** ppiPartColl
82 );
83HRESULT CpiSchedGetApplicationsCollection(
84 ICatalogCollection** ppiAppColl
85 );
86HRESULT CpiAddActionTextToActionData(
87 LPCWSTR pwzAction,
88 LPWSTR* ppwzActionData
89 );
90HRESULT CpiVerifyComponentArchitecure(
91 LPCWSTR pwzComponent,
92 BOOL* pfMatchingArchitecture
93 );
94HRESULT CpiPropertiesRead(
95 LPCWSTR pwzQuery,
96 LPCWSTR pwzKey,
97 CPI_PROPERTY_DEFINITION* pPropDefList,
98 CPI_PROPERTY** ppPropList,
99 int* piCount
100 );
101void CpiPropertiesFreeList(
102 CPI_PROPERTY* pList
103 );
104HRESULT CpiAddPropertiesToActionData(
105 int iPropCount,
106 CPI_PROPERTY* pPropList,
107 LPWSTR* ppwzActionData
108 );
109HRESULT CpiBuildAccountName(
110 LPCWSTR pwzDomain,
111 LPCWSTR pwzName,
112 LPWSTR* ppwzAccount
113 );
114HRESULT CpiGetTempFileName(
115 LPWSTR* ppwzTempFile
116 );
117HRESULT CpiCreateId(
118 LPWSTR pwzDest,
119 SIZE_T cchDest
120 );
121BOOL CpiIsInstalled(
122 INSTALLSTATE isInstalled
123 );
124BOOL CpiWillBeInstalled(
125 INSTALLSTATE isInstalled,
126 INSTALLSTATE isAction
127 );
128HRESULT PcaGuidToRegFormat(
129 LPWSTR pwzGuid,
130 LPWSTR pwzDest,
131 SIZE_T cchDest
132 );
diff --git a/src/ext/ComPlus/ca/custommsierrors.h b/src/ext/ComPlus/ca/custommsierrors.h
new file mode 100644
index 00000000..219df698
--- /dev/null
+++ b/src/ext/ComPlus/ca/custommsierrors.h
@@ -0,0 +1,29 @@
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 msierrComPlusCannotConnect 28001
6#define msierrComPlusPartitionReadFailed 28002
7#define msierrComPlusPartitionRoleReadFailed 28003
8#define msierrComPlusUserInPartitionRoleReadFailed 28004
9#define msierrComPlusPartitionUserReadFailed 28005
10#define msierrComPlusApplicationReadFailed 28006
11#define msierrComPlusApplicationRoleReadFailed 28007
12#define msierrComPlusUserInApplicationRoleReadFailed 28008
13#define msierrComPlusAssembliesReadFailed 28009
14#define msierrComPlusSubscriptionReadFailed 28010
15#define msierrComPlusPartitionDependency 28011
16#define msierrComPlusPartitionNotFound 28012
17#define msierrComPlusPartitionIdConflict 28013
18#define msierrComPlusPartitionNameConflict 28014
19#define msierrComPlusApplicationDependency 28015
20#define msierrComPlusApplicationNotFound 28016
21#define msierrComPlusApplicationIdConflict 28017
22#define msierrComPlusApplicationNameConflict 28018
23#define msierrComPlusApplicationRoleDependency 28019
24#define msierrComPlusApplicationRoleNotFound 28020
25#define msierrComPlusApplicationRoleConflict 28021
26#define msierrComPlusAssemblyDependency 28022
27#define msierrComPlusSubscriptionIdConflict 28023
28#define msierrComPlusSubscriptionNameConflict 28024
29#define msierrComPlusFailedLookupNames 28025
diff --git a/src/ext/ComPlus/ca/dllmain.cpp b/src/ext/ComPlus/ca/dllmain.cpp
new file mode 100644
index 00000000..7d299feb
--- /dev/null
+++ b/src/ext/ComPlus/ca/dllmain.cpp
@@ -0,0 +1,27 @@
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/********************************************************************
6DllMain - standard entry point for all WiX custom actions.
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInstance,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInstance);
18 ::DisableThreadLibraryCalls(hInstance);
19 break;
20
21 case DLL_PROCESS_DETACH:
22 WcaGlobalFinalize();
23 break;
24 }
25
26 return TRUE;
27}
diff --git a/src/ext/ComPlus/ca/packages.config b/src/ext/ComPlus/ca/packages.config
new file mode 100644
index 00000000..e3dc0e43
--- /dev/null
+++ b/src/ext/ComPlus/ca/packages.config
@@ -0,0 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="WixToolset.DUtil" version="4.0.30" targetFramework="native" />
4 <package id="WixToolset.WcaUtil" version="4.0.16" targetFramework="native" />
5</packages> \ No newline at end of file
diff --git a/src/ext/ComPlus/ca/precomp.h b/src/ext/ComPlus/ca/precomp.h
new file mode 100644
index 00000000..74c328d2
--- /dev/null
+++ b/src/ext/ComPlus/ca/precomp.h
@@ -0,0 +1,33 @@
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#include <windows.h>
6#include <msiquery.h>
7#include <strsafe.h>
8#include <comadmin.h>
9#include <ntsecapi.h>
10#include <aclapi.h>
11
12#include "wcautil.h"
13#include "memutil.h"
14#include "strutil.h"
15#include "wiutil.h"
16
17#include "CustomMsiErrors.h"
18
19#include "cpcost.h"
20#include "cputilexec.h"
21#include "cppartexec.h"
22#include "cppartroleexec.h"
23#include "cpappexec.h"
24#include "cpapproleexec.h"
25#include "cpasmexec.h"
26#include "cpsubsexec.h"
27#include "cputilsched.h"
28#include "cppartsched.h"
29#include "cppartrolesched.h"
30#include "cpappsched.h"
31#include "cpapprolesched.h"
32#include "cpasmsched.h"
33#include "cpsubssched.h"