aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2019-01-19 19:19:15 -0600
committerSean Hall <r.sean.hall@gmail.com>2019-01-19 19:19:15 -0600
commita12b13c36d1da707cf541595cf5f38338f37cc68 (patch)
tree8dc9b00c7bcad590a21f09e5cf494d740832d25f /src
parented56e28bad640bb3164929a66ad45150a577adbf (diff)
downloadwix-a12b13c36d1da707cf541595cf5f38338f37cc68.tar.gz
wix-a12b13c36d1da707cf541595cf5f38338f37cc68.tar.bz2
wix-a12b13c36d1da707cf541595cf5f38338f37cc68.zip
Import code from old v4 repo
Diffstat (limited to 'src')
-rw-r--r--src/ca/mqcost.h9
-rw-r--r--src/ca/mqexec.cpp214
-rw-r--r--src/ca/mqqueueexec.cpp927
-rw-r--r--src/ca/mqqueueexec.h30
-rw-r--r--src/ca/mqqueuesched.cpp582
-rw-r--r--src/ca/mqqueuesched.h92
-rw-r--r--src/ca/mqsched.cpp219
-rw-r--r--src/ca/mqutilexec.cpp380
-rw-r--r--src/ca/mqutilexec.h23
-rw-r--r--src/ca/mqutilsched.cpp43
-rw-r--r--src/ca/mqutilsched.h9
-rw-r--r--src/wixext/MsmqCompiler.cs536
-rw-r--r--src/wixext/MsmqDecompiler.cs303
-rw-r--r--src/wixext/MsmqExtensionData.cs64
-rw-r--r--src/wixext/WixMsmqExtension.csproj49
-rw-r--r--src/wixext/messages.xml77
-rw-r--r--src/wixext/msmq.xsd121
-rw-r--r--src/wixext/tables.xml54
-rw-r--r--src/wixlib/MsmqExtension.wixproj24
-rw-r--r--src/wixlib/MsmqExtension.wxs31
-rw-r--r--src/wixlib/en-us.wxl10
-rw-r--r--src/wixlib/ja-jp.wxl10
22 files changed, 3807 insertions, 0 deletions
diff --git a/src/ca/mqcost.h b/src/ca/mqcost.h
new file mode 100644
index 00000000..a40b7437
--- /dev/null
+++ b/src/ca/mqcost.h
@@ -0,0 +1,9 @@
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_MESSAGE_QUEUE_CREATE 10000
6#define COST_MESSAGE_QUEUE_DELETE 10000
7
8#define COST_MESSAGE_QUEUE_PERMISSION_ADD 10000
9#define COST_MESSAGE_QUEUE_PERMISSION_REMOVE 10000
diff --git a/src/ca/mqexec.cpp b/src/ca/mqexec.cpp
new file mode 100644
index 00000000..bac54f31
--- /dev/null
+++ b/src/ca/mqexec.cpp
@@ -0,0 +1,214 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5/********************************************************************
6 DllMain - standard entry point for all WiX CustomActions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInst,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInst);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
27
28/********************************************************************
29 MessageQueuingExecuteInstall - CUSTOM ACTION ENTRY POINT
30
31 Input: deferred CustomActionData - MessageQueuingExecuteInstall
32********************************************************************/
33extern "C" UINT __stdcall MessageQueuingExecuteInstall(MSIHANDLE hInstall)
34{
35 HRESULT hr = S_OK;
36 UINT er = ERROR_SUCCESS;
37
38 LPWSTR pwzCustomActionData = NULL;
39 LPWSTR pwzData = NULL;
40
41 // initialize
42 hr = WcaInitialize(hInstall, "MessageQueuingExecuteInstall");
43 ExitOnFailure(hr, "Failed to initialize MessageQueuingExecuteInstall");
44
45 hr = MqiInitialize();
46 ExitOnFailure(hr, "Failed to initialize");
47
48 // get custom action data
49 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
50 ExitOnFailure(hr, "Failed to get CustomActionData");
51 pwzData = pwzCustomActionData;
52
53 // create message queues
54 hr = MqiCreateMessageQueues(&pwzData);
55 ExitOnFailure(hr, "Failed to create message queues");
56 if (S_FALSE == hr) ExitFunction();
57
58 // add message queue permissions
59 hr = MqiAddMessageQueuePermissions(&pwzData);
60 ExitOnFailure(hr, "Failed to add message queue permissions");
61 if (S_FALSE == hr) ExitFunction();
62
63 hr = S_OK;
64
65LExit:
66 // clean up
67 ReleaseStr(pwzCustomActionData);
68
69 // uninitialize
70 MqiUninitialize();
71
72 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
73 return WcaFinalize(er);
74}
75
76/********************************************************************
77 MessageQueuingRollbackInstall - CUSTOM ACTION ENTRY POINT
78
79 Input: deferred CustomActionData - MessageQueuingRollbackInstall
80********************************************************************/
81extern "C" UINT __stdcall MessageQueuingRollbackInstall(MSIHANDLE hInstall)
82{
83 HRESULT hr = S_OK;
84 UINT er = ERROR_SUCCESS;
85
86 LPWSTR pwzCustomActionData = NULL;
87 LPWSTR pwzData = NULL;
88
89 // initialize
90 hr = WcaInitialize(hInstall, "MessageQueuingRollbackInstall");
91 ExitOnFailure(hr, "Failed to initialize MessageQueuingRollbackInstall");
92
93 hr = MqiInitialize();
94 ExitOnFailure(hr, "Failed to initialize");
95
96 // get custom action data
97 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
98 ExitOnFailure(hr, "Failed to get CustomActionData");
99 pwzData = pwzCustomActionData;
100
101 // add message queue permissions
102 hr = MqiRollbackAddMessageQueuePermissions(&pwzData);
103 ExitOnFailure(hr, "Failed to rollback add message queue permissions");
104
105 // create message queues
106 hr = MqiRollbackCreateMessageQueues(&pwzData);
107 ExitOnFailure(hr, "Failed to rollback create message queues");
108
109 hr = S_OK;
110
111LExit:
112 // clean up
113 ReleaseStr(pwzCustomActionData);
114
115 // uninitialize
116 MqiUninitialize();
117
118 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
119 return WcaFinalize(er);
120}
121
122/********************************************************************
123 MessageQueuingExecuteUninstall - CUSTOM ACTION ENTRY POINT
124
125 Input: deferred CustomActionData - MessageQueuingExecuteUninstall
126********************************************************************/
127extern "C" UINT __stdcall MessageQueuingExecuteUninstall(MSIHANDLE hInstall)
128{
129 HRESULT hr = S_OK;
130 UINT er = ERROR_SUCCESS;
131
132 LPWSTR pwzCustomActionData = NULL;
133 LPWSTR pwzData = NULL;
134
135 // initialize
136 hr = WcaInitialize(hInstall, "MessageQueuingExecuteUninstall");
137 ExitOnFailure(hr, "Failed to initialize MessageQueuingExecuteUninstall");
138
139 hr = MqiInitialize();
140 ExitOnFailure(hr, "Failed to initialize");
141
142 // get custom action data
143 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
144 ExitOnFailure(hr, "Failed to get CustomActionData");
145 pwzData = pwzCustomActionData;
146
147 // remove message queue permissions
148 hr = MqiRemoveMessageQueuePermissions(&pwzData);
149 ExitOnFailure(hr, "Failed to remove message queue permissions");
150 if (S_FALSE == hr) ExitFunction();
151
152 // delete message queues
153 hr = MqiDeleteMessageQueues(&pwzData);
154 ExitOnFailure(hr, "Failed to delete message queues");
155 if (S_FALSE == hr) ExitFunction();
156
157 hr = S_OK;
158
159LExit:
160 // clean up
161 ReleaseStr(pwzCustomActionData);
162
163 // uninitialize
164 MqiUninitialize();
165
166 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
167 return WcaFinalize(er);
168}
169
170/********************************************************************
171 MessageQueuingRollbackUninstall - CUSTOM ACTION ENTRY POINT
172
173 Input: deferred CustomActionData - MessageQueuingRollbackUninstall
174********************************************************************/
175extern "C" UINT __stdcall MessageQueuingRollbackUninstall(MSIHANDLE hInstall)
176{
177 HRESULT hr = S_OK;
178 UINT er = ERROR_SUCCESS;
179
180 LPWSTR pwzCustomActionData = NULL;
181 LPWSTR pwzData = NULL;
182
183 // initialize
184 hr = WcaInitialize(hInstall, "MessageQueuingRollbackUninstall");
185 ExitOnFailure(hr, "Failed to initialize MessageQueuingRollbackUninstall");
186
187 hr = MqiInitialize();
188 ExitOnFailure(hr, "Failed to initialize");
189
190 // get custom action data
191 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
192 ExitOnFailure(hr, "Failed to get CustomActionData");
193 pwzData = pwzCustomActionData;
194
195 // delete message queues
196 hr = MqiRollbackDeleteMessageQueues(&pwzData);
197 ExitOnFailure(hr, "Failed to delete message queues");
198
199 // remove message queue permissions
200 hr = MqiRollbackRemoveMessageQueuePermissions(&pwzData);
201 ExitOnFailure(hr, "Failed to remove message queue permissions");
202
203 hr = S_OK;
204
205LExit:
206 // clean up
207 ReleaseStr(pwzCustomActionData);
208
209 // uninitialize
210 MqiUninitialize();
211
212 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
213 return WcaFinalize(er);
214}
diff --git a/src/ca/mqqueueexec.cpp b/src/ca/mqqueueexec.cpp
new file mode 100644
index 00000000..f5b99da7
--- /dev/null
+++ b/src/ca/mqqueueexec.cpp
@@ -0,0 +1,927 @@
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 typedefs
7
8typedef HRESULT (__stdcall *MQCreateQueueFunc)(PSECURITY_DESCRIPTOR, MQQUEUEPROPS*, LPWSTR, LPDWORD);
9typedef HRESULT (__stdcall *MQDeleteQueueFunc)(LPCWSTR);
10typedef HRESULT (__stdcall *MQPathNameToFormatNameFunc)(LPCWSTR, LPWSTR, LPDWORD);
11typedef HRESULT (__stdcall *MQGetQueueSecurityFunc)(LPCWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
12typedef HRESULT (__stdcall *MQSetQueueSecurityFunc)(LPCWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR);
13
14
15// private enums
16
17enum eMessageQueueAttributes
18{
19 mqaAuthenticate = (1 << 0),
20 mqaJournal = (1 << 1),
21 mqaTransactional = (1 << 2)
22};
23
24enum eMessageQueuePrivacyLevel
25{
26 mqplNone = 0,
27 mqplOptional = 1,
28 mqplBody = 2
29};
30
31enum eMessageQueuePermission
32{
33 mqpDeleteMessage = (1 << 0),
34 mqpPeekMessage = (1 << 1),
35 mqpWriteMessage = (1 << 2),
36 mqpDeleteJournalMessage = (1 << 3),
37 mqpSetQueueProperties = (1 << 4),
38 mqpGetQueueProperties = (1 << 5),
39 mqpDeleteQueue = (1 << 6),
40 mqpGetQueuePermissions = (1 << 7),
41 mqpChangeQueuePermissions = (1 << 8),
42 mqpTakeQueueOwnership = (1 << 9),
43 mqpReceiveMessage = (1 << 10),
44 mqpReceiveJournalMessage = (1 << 11),
45 mqpQueueGenericRead = (1 << 12),
46 mqpQueueGenericWrite = (1 << 13),
47 mqpQueueGenericExecute = (1 << 14),
48 mqpQueueGenericAll = (1 << 15)
49};
50
51
52// private structs
53
54struct MQI_MESSAGE_QUEUE_ATTRIBUTES
55{
56 LPWSTR pwzKey;
57 int iBasePriority;
58 int iJournalQuota;
59 LPWSTR pwzLabel;
60 LPWSTR pwzMulticastAddress;
61 LPWSTR pwzPathName;
62 int iPrivLevel;
63 int iQuota;
64 LPWSTR pwzServiceTypeGuid;
65 int iAttributes;
66};
67
68struct MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES
69{
70 LPWSTR pwzKey;
71 LPWSTR pwzPathName;
72 LPWSTR pwzDomain;
73 LPWSTR pwzName;
74 int iPermissions;
75};
76
77
78// prototypes for private helper functions
79
80static HRESULT ReadMessageQueueAttributes(
81 LPWSTR* ppwzData,
82 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
83 );
84static void FreeMessageQueueAttributes(
85 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
86 );
87static HRESULT ReadMessageQueuePermissionAttributes(
88 LPWSTR* ppwzData,
89 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs
90 );
91static void FreeMessageQueuePermissionAttributes(
92 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs
93 );
94static HRESULT CreateMessageQueue(
95 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
96 );
97static HRESULT DeleteMessageQueue(
98 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
99 );
100static HRESULT SetMessageQueuePermissions(
101 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs,
102 BOOL fRevoke
103 );
104static void SetAccessPermissions(
105 int iPermissions,
106 LPDWORD pgrfAccessPermissions
107 );
108
109
110// private variables
111
112static HMODULE ghMQRT;
113static MQCreateQueueFunc gpfnMQCreateQueue;
114static MQDeleteQueueFunc gpfnMQDeleteQueue;
115static MQPathNameToFormatNameFunc gpfnMQPathNameToFormatName;
116static MQGetQueueSecurityFunc gpfnMQGetQueueSecurity;
117static MQSetQueueSecurityFunc gpfnMQSetQueueSecurity;
118
119
120// function definitions
121
122HRESULT MqiInitialize()
123{
124 HRESULT hr = S_OK;
125
126 // load mqrt.dll
127 ghMQRT = ::LoadLibraryW(L"mqrt.dll");
128 ExitOnNull(ghMQRT, hr, E_FAIL, "Failed to load mqrt.dll");
129
130 // get MQCreateQueue function address
131 gpfnMQCreateQueue = (MQCreateQueueFunc)::GetProcAddress(ghMQRT, "MQCreateQueue");
132 ExitOnNull(gpfnMQCreateQueue, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQCreateQueue() function");
133
134 // get MQDeleteQueue function address
135 gpfnMQDeleteQueue = (MQDeleteQueueFunc)::GetProcAddress(ghMQRT, "MQDeleteQueue");
136 ExitOnNull(gpfnMQDeleteQueue, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQDeleteQueue() function");
137
138 // get MQPathNameToFormatName function address
139 gpfnMQPathNameToFormatName = (MQPathNameToFormatNameFunc)::GetProcAddress(ghMQRT, "MQPathNameToFormatName");
140 ExitOnNull(gpfnMQPathNameToFormatName, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQPathNameToFormatName() function");
141
142 // get MQGetQueueSecurity function address
143 gpfnMQGetQueueSecurity = (MQGetQueueSecurityFunc)::GetProcAddress(ghMQRT, "MQGetQueueSecurity");
144 ExitOnNull(gpfnMQGetQueueSecurity, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQGetQueueSecurity() function");
145
146 // get MQSetQueueSecurity function address
147 gpfnMQSetQueueSecurity = (MQSetQueueSecurityFunc)::GetProcAddress(ghMQRT, "MQSetQueueSecurity");
148 ExitOnNull(gpfnMQSetQueueSecurity, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQSetQueueSecurity() function");
149
150 hr = S_OK;
151
152LExit:
153 return hr;
154}
155
156void MqiUninitialize()
157{
158 if (ghMQRT)
159 ::FreeLibrary(ghMQRT);
160}
161
162HRESULT MqiCreateMessageQueues(
163 LPWSTR* ppwzData
164 )
165{
166 HRESULT hr = S_OK;
167
168 int iCnt = 0;
169
170 MQI_MESSAGE_QUEUE_ATTRIBUTES attrs;
171 ::ZeroMemory(&attrs, sizeof(attrs));
172
173 // ger count
174 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
175 ExitOnFailure(hr, "Failed to read count");
176
177 for (int i = 0; i < iCnt; i++)
178 {
179 // read attributes from CustomActionData
180 hr = ReadMessageQueueAttributes(ppwzData, &attrs);
181 ExitOnFailure(hr, "Failed to read attributes");
182
183 // progress message
184 hr = PcaActionDataMessage(1, attrs.pwzPathName);
185 ExitOnFailure(hr, "Failed to send progress messages, key: %S", attrs.pwzKey);
186
187 // create message queue
188 hr = CreateMessageQueue(&attrs);
189 ExitOnFailure(hr, "Failed to create message queue, key: %S", attrs.pwzKey);
190
191 // progress tics
192 hr = WcaProgressMessage(COST_MESSAGE_QUEUE_CREATE, FALSE);
193 ExitOnFailure(hr, "Failed to update progress");
194 }
195
196 hr = S_OK;
197
198LExit:
199 // clean up
200 FreeMessageQueueAttributes(&attrs);
201
202 return hr;
203}
204
205HRESULT MqiRollbackCreateMessageQueues(
206 LPWSTR* ppwzData
207 )
208{
209 HRESULT hr = S_OK;
210
211 int iCnt = 0;
212
213 MQI_MESSAGE_QUEUE_ATTRIBUTES attrs;
214 ::ZeroMemory(&attrs, sizeof(attrs));
215
216 // ger count
217 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
218 ExitOnFailure(hr, "Failed to read count");
219
220 for (int i = 0; i < iCnt; i++)
221 {
222 // read attributes from CustomActionData
223 hr = ReadMessageQueueAttributes(ppwzData, &attrs);
224 ExitOnFailure(hr, "Failed to read attributes");
225
226 // create message queue
227 hr = DeleteMessageQueue(&attrs);
228 if (FAILED(hr))
229 WcaLog(LOGMSG_STANDARD, "Failed to delete message queue, hr: 0x%x, key: %S", hr, attrs.pwzKey);
230 }
231
232 hr = S_OK;
233
234LExit:
235 // clean up
236 FreeMessageQueueAttributes(&attrs);
237
238 return hr;
239}
240
241HRESULT MqiDeleteMessageQueues(
242 LPWSTR* ppwzData
243 )
244{
245 HRESULT hr = S_OK;
246
247 int iCnt = 0;
248
249 MQI_MESSAGE_QUEUE_ATTRIBUTES attrs;
250 ::ZeroMemory(&attrs, sizeof(attrs));
251
252 // ger count
253 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
254 ExitOnFailure(hr, "Failed to read count");
255
256 for (int i = 0; i < iCnt; i++)
257 {
258 // read attributes from CustomActionData
259 hr = ReadMessageQueueAttributes(ppwzData, &attrs);
260 ExitOnFailure(hr, "Failed to read attributes");
261
262 // progress message
263 hr = PcaActionDataMessage(1, attrs.pwzPathName);
264 ExitOnFailure(hr, "Failed to send progress messages, key: %S", attrs.pwzKey);
265
266 // create message queue
267 hr = DeleteMessageQueue(&attrs);
268 if (FAILED(hr))
269 {
270 WcaLog(LOGMSG_STANDARD, "Failed to delete queue, hr: 0x%x, key: %S", hr, attrs.pwzKey);
271 continue;
272 }
273
274 // progress tics
275 hr = WcaProgressMessage(COST_MESSAGE_QUEUE_DELETE, FALSE);
276 ExitOnFailure(hr, "Failed to update progress");
277 }
278
279 hr = S_OK;
280
281LExit:
282 // clean up
283 FreeMessageQueueAttributes(&attrs);
284
285 return hr;
286}
287
288HRESULT MqiRollbackDeleteMessageQueues(
289 LPWSTR* ppwzData
290 )
291{
292 HRESULT hr = S_OK;
293
294 int iCnt = 0;
295
296 MQI_MESSAGE_QUEUE_ATTRIBUTES attrs;
297 ::ZeroMemory(&attrs, sizeof(attrs));
298
299 // ger count
300 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
301 ExitOnFailure(hr, "Failed to read count");
302
303 for (int i = 0; i < iCnt; i++)
304 {
305 // read attributes from CustomActionData
306 hr = ReadMessageQueueAttributes(ppwzData, &attrs);
307 ExitOnFailure(hr, "Failed to read attributes");
308
309 // create message queue
310 hr = CreateMessageQueue(&attrs);
311 if (FAILED(hr))
312 WcaLog(LOGMSG_STANDARD, "Failed to create message queue, hr: 0x%x, key: %S", hr, attrs.pwzKey);
313 }
314
315 hr = S_OK;
316
317LExit:
318 // clean up
319 FreeMessageQueueAttributes(&attrs);
320
321 return hr;
322}
323
324HRESULT MqiAddMessageQueuePermissions(
325 LPWSTR* ppwzData
326 )
327{
328 HRESULT hr = S_OK;
329
330 int iCnt = 0;
331
332 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs;
333 ::ZeroMemory(&attrs, sizeof(attrs));
334
335 // ger count
336 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
337 ExitOnFailure(hr, "Failed to read count");
338
339 for (int i = 0; i < iCnt; i++)
340 {
341 // read attributes from CustomActionData
342 hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs);
343 ExitOnFailure(hr, "Failed to read attributes");
344
345 // progress message
346 hr = PcaActionDataMessage(1, attrs.pwzPathName);
347 ExitOnFailure(hr, "Failed to send progress messages");
348
349 // add message queue permission
350 hr = SetMessageQueuePermissions(&attrs, FALSE);
351 ExitOnFailure(hr, "Failed to add message queue permission");
352
353 // progress tics
354 hr = WcaProgressMessage(COST_MESSAGE_QUEUE_PERMISSION_ADD, FALSE);
355 ExitOnFailure(hr, "Failed to update progress");
356 }
357
358 hr = S_OK;
359
360LExit:
361 // clean up
362 FreeMessageQueuePermissionAttributes(&attrs);
363
364 return hr;
365}
366
367HRESULT MqiRollbackAddMessageQueuePermissions(
368 LPWSTR* ppwzData
369 )
370{
371 HRESULT hr = S_OK;
372
373 int iCnt = 0;
374
375 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs;
376 ::ZeroMemory(&attrs, sizeof(attrs));
377
378 // ger count
379 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
380 ExitOnFailure(hr, "Failed to read count");
381
382 for (int i = 0; i < iCnt; i++)
383 {
384 // read attributes from CustomActionData
385 hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs);
386 ExitOnFailure(hr, "Failed to read attributes");
387
388 // add message queue permission
389 hr = SetMessageQueuePermissions(&attrs, TRUE);
390 if (FAILED(hr))
391 WcaLog(LOGMSG_STANDARD, "Failed to rollback add message queue permission, hr: 0x%x, key: %S", hr, attrs.pwzKey);
392 }
393
394 hr = S_OK;
395
396LExit:
397 // clean up
398 FreeMessageQueuePermissionAttributes(&attrs);
399
400 return hr;
401}
402
403HRESULT MqiRemoveMessageQueuePermissions(
404 LPWSTR* ppwzData
405 )
406{
407 HRESULT hr = S_OK;
408
409 int iCnt = 0;
410
411 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs;
412 ::ZeroMemory(&attrs, sizeof(attrs));
413
414 // ger count
415 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
416 ExitOnFailure(hr, "Failed to read count");
417
418 for (int i = 0; i < iCnt; i++)
419 {
420 // read attributes from CustomActionData
421 hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs);
422 ExitOnFailure(hr, "Failed to read attributes");
423
424 // progress message
425 hr = PcaActionDataMessage(1, attrs.pwzPathName);
426 ExitOnFailure(hr, "Failed to send progress messages");
427
428 // add message queue permission
429 hr = SetMessageQueuePermissions(&attrs, TRUE);
430 ExitOnFailure(hr, "Failed to remove message queue permission");
431
432 // progress tics
433 hr = WcaProgressMessage(COST_MESSAGE_QUEUE_PERMISSION_ADD, FALSE);
434 ExitOnFailure(hr, "Failed to update progress");
435 }
436
437 hr = S_OK;
438
439LExit:
440 // clean up
441 FreeMessageQueuePermissionAttributes(&attrs);
442
443 return hr;
444}
445
446HRESULT MqiRollbackRemoveMessageQueuePermissions(
447 LPWSTR* ppwzData
448 )
449{
450 HRESULT hr = S_OK;
451
452 int iCnt = 0;
453
454 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs;
455 ::ZeroMemory(&attrs, sizeof(attrs));
456
457 // ger count
458 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
459 ExitOnFailure(hr, "Failed to read count");
460
461 for (int i = 0; i < iCnt; i++)
462 {
463 // read attributes from CustomActionData
464 hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs);
465 ExitOnFailure(hr, "Failed to read attributes");
466
467 // add message queue permission
468 hr = SetMessageQueuePermissions(&attrs, FALSE);
469 if (FAILED(hr))
470 WcaLog(LOGMSG_STANDARD, "Failed to rollback remove message queue permission, hr: 0x%x, key: %S", hr, attrs.pwzKey);
471 }
472
473 hr = S_OK;
474
475LExit:
476 // clean up
477 FreeMessageQueuePermissionAttributes(&attrs);
478
479 return hr;
480}
481
482
483// helper function definitions
484
485static HRESULT ReadMessageQueueAttributes(
486 LPWSTR* ppwzData,
487 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
488 )
489{
490 HRESULT hr = S_OK;
491
492 // read message queue information from custom action data
493 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
494 ExitOnFailure(hr, "Failed to read key from custom action data");
495 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iBasePriority);
496 ExitOnFailure(hr, "Failed to read base priority from custom action data");
497 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iJournalQuota);
498 ExitOnFailure(hr, "Failed to read journal quota from custom action data");
499 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzLabel);
500 ExitOnFailure(hr, "Failed to read label from custom action data");
501 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzMulticastAddress);
502 ExitOnFailure(hr, "Failed to read multicast address from custom action data");
503 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPathName);
504 ExitOnFailure(hr, "Failed to read path name from custom action data");
505 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iPrivLevel);
506 ExitOnFailure(hr, "Failed to read privacy level from custom action data");
507 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iQuota);
508 ExitOnFailure(hr, "Failed to read quota from custom action data");
509 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzServiceTypeGuid);
510 ExitOnFailure(hr, "Failed to read service type guid from custom action data");
511 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iAttributes);
512 ExitOnFailure(hr, "Failed to read attributes from custom action data");
513
514 hr = S_OK;
515
516LExit:
517 return hr;
518}
519
520static void FreeMessageQueueAttributes(
521 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
522 )
523{
524 ReleaseStr(pAttrs->pwzKey);
525 ReleaseStr(pAttrs->pwzLabel);
526 ReleaseStr(pAttrs->pwzMulticastAddress);
527 ReleaseStr(pAttrs->pwzPathName);
528 ReleaseStr(pAttrs->pwzServiceTypeGuid);
529}
530
531static HRESULT ReadMessageQueuePermissionAttributes(
532 LPWSTR* ppwzData,
533 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs
534 )
535{
536 HRESULT hr = S_OK;
537
538 // read message queue permission information from custom action data
539 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
540 ExitOnFailure(hr, "Failed to read key from custom action data");
541 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPathName);
542 ExitOnFailure(hr, "Failed to read path name from custom action data");
543 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzDomain);
544 ExitOnFailure(hr, "Failed to read domain from custom action data");
545 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
546 ExitOnFailure(hr, "Failed to read name from custom action data");
547 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iPermissions);
548 ExitOnFailure(hr, "Failed to read permissions from custom action data");
549
550 hr = S_OK;
551
552LExit:
553 return hr;
554}
555
556static void FreeMessageQueuePermissionAttributes(
557 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs
558 )
559{
560 ReleaseStr(pAttrs->pwzKey);
561 ReleaseStr(pAttrs->pwzPathName);
562 ReleaseStr(pAttrs->pwzDomain);
563 ReleaseStr(pAttrs->pwzName);
564}
565
566static HRESULT CreateMessageQueue(
567 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
568 )
569{
570 HRESULT hr = S_OK;
571
572 SECURITY_DESCRIPTOR sd;
573 PSID pOwner = NULL;
574 DWORD cbDacl = 0;
575 PACL pDacl = NULL;
576 QUEUEPROPID aPropID[11];
577 MQPROPVARIANT aPropVar[11];
578 MQQUEUEPROPS props;
579
580 GUID guidType;
581
582 DWORD dwFormatNameLength = 0;
583
584 ::ZeroMemory(&sd, sizeof(sd));
585 ::ZeroMemory(aPropID, sizeof(aPropID));
586 ::ZeroMemory(aPropVar, sizeof(aPropVar));
587 ::ZeroMemory(&props, sizeof(props));
588 ::ZeroMemory(&guidType, sizeof(guidType));
589
590 // initialize security descriptor
591 if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
592 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize security descriptor");
593
594 // set security descriptor owner
595 hr = PcaAccountNameToSid(L"\\Administrators", &pOwner);
596 ExitOnFailure(hr, "Failed to get sid for account name");
597
598 if (!::SetSecurityDescriptorOwner(&sd, pOwner, FALSE))
599 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set security descriptor owner");
600
601 // set security descriptor DACL
602 cbDacl = sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + ::GetLengthSid(pOwner);
603 pDacl = (PACL)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, cbDacl);
604 ExitOnNull(pDacl, hr, E_OUTOFMEMORY, "Failed to allocate buffer for DACL");
605
606 if (!::InitializeAcl(pDacl, cbDacl, ACL_REVISION))
607 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize DACL");
608
609 if (!::AddAccessAllowedAce(pDacl, ACL_REVISION, MQSEC_QUEUE_GENERIC_ALL, pOwner))
610 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to add ACE to DACL");
611
612 if (!::SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE))
613 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set security descriptor DACL");
614
615 // set property values
616 props.aPropID = aPropID;
617 props.aPropVar = aPropVar;
618
619 aPropID[0] = PROPID_Q_LABEL;
620 aPropVar[0].vt = VT_LPWSTR;
621 aPropVar[0].pwszVal = pAttrs->pwzLabel;
622
623 aPropID[1] = PROPID_Q_PATHNAME;
624 aPropVar[1].vt = VT_LPWSTR;
625 aPropVar[1].pwszVal = pAttrs->pwzPathName;
626
627 aPropID[2] = PROPID_Q_AUTHENTICATE;
628 aPropVar[2].vt = VT_UI1;
629 aPropVar[2].bVal = mqaAuthenticate == (pAttrs->iAttributes & mqaAuthenticate);
630
631 aPropID[3] = PROPID_Q_JOURNAL;
632 aPropVar[3].vt = VT_UI1;
633 aPropVar[3].bVal = mqaJournal == (pAttrs->iAttributes & mqaJournal);
634
635 aPropID[4] = PROPID_Q_TRANSACTION;
636 aPropVar[4].vt = VT_UI1;
637 aPropVar[4].bVal = mqaTransactional == (pAttrs->iAttributes & mqaTransactional);
638
639 props.cProp = 5;
640
641 if (MSI_NULL_INTEGER != pAttrs->iBasePriority)
642 {
643 aPropID[props.cProp] = PROPID_Q_BASEPRIORITY;
644 aPropVar[props.cProp].vt = VT_I2;
645 aPropVar[props.cProp].iVal = (SHORT)pAttrs->iBasePriority;
646 props.cProp++;
647 }
648
649 if (MSI_NULL_INTEGER != pAttrs->iJournalQuota)
650 {
651 aPropID[props.cProp] = PROPID_Q_JOURNAL_QUOTA;
652 aPropVar[props.cProp].vt = VT_UI4;
653 aPropVar[props.cProp].ulVal = (ULONG)pAttrs->iJournalQuota;
654 props.cProp++;
655 }
656
657 if (*pAttrs->pwzMulticastAddress)
658 {
659 aPropID[props.cProp] = PROPID_Q_MULTICAST_ADDRESS;
660 aPropVar[props.cProp].vt = VT_LPWSTR;
661 aPropVar[props.cProp].pwszVal = pAttrs->pwzMulticastAddress;
662 props.cProp++;
663 }
664
665 if (MSI_NULL_INTEGER != pAttrs->iPrivLevel)
666 {
667 aPropID[props.cProp] = PROPID_Q_PRIV_LEVEL;
668 aPropVar[props.cProp].vt = VT_UI4;
669 switch (pAttrs->iPrivLevel)
670 {
671 case mqplNone:
672 aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_NONE;
673 break;
674 case mqplBody:
675 aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_BODY;
676 break;
677 case mqplOptional:
678 aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_OPTIONAL;
679 break;
680 }
681 props.cProp++;
682 }
683
684 if (MSI_NULL_INTEGER != pAttrs->iQuota)
685 {
686 aPropID[props.cProp] = PROPID_Q_QUOTA;
687 aPropVar[props.cProp].vt = VT_UI4;
688 aPropVar[props.cProp].ulVal = (ULONG)pAttrs->iQuota;
689 props.cProp++;
690 }
691
692 if (*pAttrs->pwzServiceTypeGuid)
693 {
694 // parse guid string
695 hr = PcaGuidFromString(pAttrs->pwzServiceTypeGuid, &guidType);
696 ExitOnFailure(hr, "Failed to parse service type GUID string");
697
698 aPropID[props.cProp] = PROPID_Q_TYPE;
699 aPropVar[props.cProp].vt = VT_CLSID;
700 aPropVar[props.cProp].puuid = &guidType;
701 props.cProp++;
702 }
703
704 // create message queue
705 hr = gpfnMQCreateQueue(&sd, &props, NULL, &dwFormatNameLength);
706 ExitOnFailure(hr, "Failed to create message queue");
707
708 // log
709 WcaLog(LOGMSG_VERBOSE, "Message queue created, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName);
710
711 hr = S_OK;
712
713LExit:
714 // clean up
715 if (pOwner)
716 ::HeapFree(::GetProcessHeap(), 0, pOwner);
717 if (pDacl)
718 ::HeapFree(::GetProcessHeap(), 0, pDacl);
719
720 return hr;
721}
722
723static HRESULT DeleteMessageQueue(
724 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
725 )
726{
727 HRESULT hr = S_OK;
728
729 LPWSTR pwzFormatName = NULL;
730 DWORD dwCount = 128;
731
732 // get format name
733 hr = StrAlloc(&pwzFormatName, dwCount);
734 ExitOnFailure(hr, "Failed to allocate format name string");
735 do {
736 hr = gpfnMQPathNameToFormatName(pAttrs->pwzPathName, pwzFormatName, &dwCount);
737 switch (hr)
738 {
739 case MQ_ERROR_QUEUE_NOT_FOUND:
740 ExitFunction1(hr = S_OK); // nothing to delete
741 case MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL:
742 hr = StrAlloc(&pwzFormatName, dwCount);
743 ExitOnFailure(hr, "Failed to reallocate format name string");
744 hr = S_FALSE; // retry
745 break;
746 default:
747 ExitOnFailure(hr, "Failed to get format name");
748 hr = S_OK;
749 }
750 } while (S_FALSE == hr);
751
752 // delete queue
753 hr = gpfnMQDeleteQueue(pwzFormatName);
754 ExitOnFailure(hr, "Failed to delete queue");
755
756 // log
757 WcaLog(LOGMSG_VERBOSE, "Message queue deleted, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName);
758
759 hr = S_OK;
760
761LExit:
762 // clean up
763 ReleaseStr(pwzFormatName);
764
765 return hr;
766}
767
768static HRESULT SetMessageQueuePermissions(
769 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs,
770 BOOL fRevoke
771 )
772{
773 HRESULT hr = S_OK;
774 DWORD er = ERROR_SUCCESS;
775
776 DWORD dw = 0;
777
778 LPWSTR pwzAccount = NULL;
779 LPWSTR pwzFormatName = NULL;
780
781 PSECURITY_DESCRIPTOR psd = NULL;
782 PSECURITY_DESCRIPTOR ptsd = NULL;
783
784 PACL pAclExisting = NULL;
785 PACL pAclNew = NULL;
786 BOOL fDaclPresent = FALSE;
787 BOOL fDaclDefaulted = FALSE;
788
789 PSID psid = NULL;
790
791 EXPLICIT_ACCESSW ea;
792 SECURITY_DESCRIPTOR sdNew;
793
794 ::ZeroMemory(&ea, sizeof(ea));
795 ::ZeroMemory(&sdNew, sizeof(sdNew));
796
797 // get format name
798 dw = 128;
799 hr = StrAlloc(&pwzFormatName, dw);
800 ExitOnFailure(hr, "Failed to allocate format name string");
801 do {
802 hr = gpfnMQPathNameToFormatName(pAttrs->pwzPathName, pwzFormatName, &dw);
803 if (MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL == hr)
804 {
805 hr = StrAlloc(&pwzFormatName, dw);
806 ExitOnFailure(hr, "Failed to reallocate format name string");
807 hr = S_FALSE; // retry
808 }
809 else
810 {
811 ExitOnFailure(hr, "Failed to get format name");
812 hr = S_OK;
813 }
814 } while (S_FALSE == hr);
815
816 // get queue security information
817 dw = 256;
818 psd = (PSECURITY_DESCRIPTOR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dw);
819 ExitOnNull(psd, hr, E_OUTOFMEMORY, "Failed to allocate buffer for security descriptor");
820 do {
821 hr = gpfnMQGetQueueSecurity(pwzFormatName, DACL_SECURITY_INFORMATION, psd, dw, &dw);
822 if (MQ_ERROR_SECURITY_DESCRIPTOR_TOO_SMALL == hr)
823 {
824 ptsd = (PSECURITY_DESCRIPTOR)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, psd, dw);
825 ExitOnNull(ptsd, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for security descriptor");
826 psd = ptsd;
827 hr = S_FALSE; // retry
828 }
829 else
830 {
831 ExitOnFailure(hr, "Failed to get queue security information");
832 hr = S_OK;
833 }
834 } while (S_FALSE == hr);
835
836 // get dacl
837 if (!::GetSecurityDescriptorDacl(psd, &fDaclPresent, &pAclExisting, &fDaclDefaulted))
838 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get DACL for security descriptor");
839 if (!fDaclPresent || !pAclExisting)
840 ExitOnFailure(hr = E_ACCESSDENIED, "Failed to get DACL for security descriptor, access denied");
841
842 // build account name string
843 hr = PcaBuildAccountName(pAttrs->pwzDomain, pAttrs->pwzName, &pwzAccount);
844 ExitOnFailure(hr, "Failed to build account name string");
845
846 // get sid for account name
847 hr = PcaAccountNameToSid(pwzAccount, &psid);
848 ExitOnFailure(hr, "Failed to get SID for account name");
849
850 // set acl entry
851 SetAccessPermissions(pAttrs->iPermissions, &ea.grfAccessPermissions);
852 ea.grfAccessMode = fRevoke ? REVOKE_ACCESS : SET_ACCESS;
853 ea.grfInheritance = NO_INHERITANCE;
854 ::BuildTrusteeWithSidW(&ea.Trustee, psid);
855
856 er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew);
857 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set ACL entry");
858
859 // create new security descriptor
860 if (!::InitializeSecurityDescriptor(&sdNew, SECURITY_DESCRIPTOR_REVISION))
861 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize security descriptor");
862
863 if (!::SetSecurityDescriptorDacl(&sdNew, TRUE, pAclNew, FALSE))
864 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set DACL for security descriptor");
865
866 // set queue security information
867 hr = gpfnMQSetQueueSecurity(pwzFormatName, DACL_SECURITY_INFORMATION, &sdNew);
868 ExitOnFailure(hr, "Failed to set queue security information");
869
870 // log
871 WcaLog(LOGMSG_VERBOSE, "Permission set for message queue, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName);
872
873 hr = S_OK;
874
875LExit:
876 // clean up
877 ReleaseStr(pwzFormatName);
878 ReleaseStr(pwzAccount);
879
880 if (psd)
881 ::HeapFree(::GetProcessHeap(), 0, psd);
882 if (psid)
883 ::HeapFree(::GetProcessHeap(), 0, psid);
884 if (pAclNew)
885 ::LocalFree(pAclNew);
886
887 return hr;
888}
889
890static void SetAccessPermissions(
891 int iPermissions,
892 LPDWORD pgrfAccessPermissions
893 )
894{
895 if (iPermissions & mqpDeleteMessage)
896 *pgrfAccessPermissions |= MQSEC_DELETE_MESSAGE;
897 if (iPermissions & mqpPeekMessage)
898 *pgrfAccessPermissions |= MQSEC_PEEK_MESSAGE;
899 if (iPermissions & mqpWriteMessage)
900 *pgrfAccessPermissions |= MQSEC_WRITE_MESSAGE;
901 if (iPermissions & mqpDeleteJournalMessage)
902 *pgrfAccessPermissions |= MQSEC_DELETE_JOURNAL_MESSAGE;
903 if (iPermissions & mqpSetQueueProperties)
904 *pgrfAccessPermissions |= MQSEC_SET_QUEUE_PROPERTIES;
905 if (iPermissions & mqpGetQueueProperties)
906 *pgrfAccessPermissions |= MQSEC_GET_QUEUE_PROPERTIES;
907 if (iPermissions & mqpDeleteQueue)
908 *pgrfAccessPermissions |= MQSEC_DELETE_QUEUE;
909 if (iPermissions & mqpGetQueuePermissions)
910 *pgrfAccessPermissions |= MQSEC_GET_QUEUE_PERMISSIONS;
911 if (iPermissions & mqpChangeQueuePermissions)
912 *pgrfAccessPermissions |= MQSEC_CHANGE_QUEUE_PERMISSIONS;
913 if (iPermissions & mqpTakeQueueOwnership)
914 *pgrfAccessPermissions |= MQSEC_TAKE_QUEUE_OWNERSHIP;
915 if (iPermissions & mqpReceiveMessage)
916 *pgrfAccessPermissions |= MQSEC_RECEIVE_MESSAGE;
917 if (iPermissions & mqpReceiveJournalMessage)
918 *pgrfAccessPermissions |= MQSEC_RECEIVE_JOURNAL_MESSAGE;
919 if (iPermissions & mqpQueueGenericRead)
920 *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_READ;
921 if (iPermissions & mqpQueueGenericWrite)
922 *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_WRITE;
923 if (iPermissions & mqpQueueGenericExecute)
924 *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_EXECUTE;
925 if (iPermissions & mqpQueueGenericAll)
926 *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_ALL;
927}
diff --git a/src/ca/mqqueueexec.h b/src/ca/mqqueueexec.h
new file mode 100644
index 00000000..37ceea50
--- /dev/null
+++ b/src/ca/mqqueueexec.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
5HRESULT MqiInitialize();
6void MqiUninitialize();
7HRESULT MqiCreateMessageQueues(
8 LPWSTR* ppwzData
9 );
10HRESULT MqiRollbackCreateMessageQueues(
11 LPWSTR* ppwzData
12 );
13HRESULT MqiDeleteMessageQueues(
14 LPWSTR* ppwzData
15 );
16HRESULT MqiRollbackDeleteMessageQueues(
17 LPWSTR* ppwzData
18 );
19HRESULT MqiAddMessageQueuePermissions(
20 LPWSTR* ppwzData
21 );
22HRESULT MqiRollbackAddMessageQueuePermissions(
23 LPWSTR* ppwzData
24 );
25HRESULT MqiRemoveMessageQueuePermissions(
26 LPWSTR* ppwzData
27 );
28HRESULT MqiRollbackRemoveMessageQueuePermissions(
29 LPWSTR* ppwzData
30 );
diff --git a/src/ca/mqqueuesched.cpp b/src/ca/mqqueuesched.cpp
new file mode 100644
index 00000000..4f40a4aa
--- /dev/null
+++ b/src/ca/mqqueuesched.cpp
@@ -0,0 +1,582 @@
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 vcsMessageQueueQuery =
9 L"SELECT `MessageQueue`, `Component_`, `BasePriority`, `JournalQuota`, `Label`, `MulticastAddress`, `PathName`, `PrivLevel`, `Quota`, `ServiceTypeGuid`, `Attributes` FROM `MessageQueue`";
10enum eMessageQueueQuery { mqqMessageQueue = 1, mqqComponent, mqqBasePriority, mqqJournalQuota, mqqLabel, mqqMulticastAddress, mqqPathName, mqqPrivLevel, mqqQuota, mqqServiceTypeGuid, mqqAttributes };
11
12LPCWSTR vcsMessageQueueUserPermissionQuery =
13 L"SELECT `MessageQueueUserPermission`, `MessageQueue_`, `MessageQueueUserPermission`.`Component_`, `Domain`, `Name`, `Permissions` FROM `MessageQueueUserPermission`, `User` WHERE `User_` = `User`";
14LPCWSTR vcsMessageQueueGroupPermissionQuery =
15 L"SELECT `MessageQueueGroupPermission`, `MessageQueue_`, `MessageQueueGroupPermission`.`Component_`, `Domain`, `Name`, `Permissions` FROM `MessageQueueGroupPermission`, `Group` WHERE `Group_` = `Group`";
16enum eMessageQueuePermissionQuery { mqpqMessageQueuePermission = 1, mqpqMessageQueue, mqpqComponent, mqpqDomain, mqpqName, mqpqPermissions };
17
18
19// prototypes for private helper functions
20
21static HRESULT MqiMessageQueueFindByKey(
22 MQI_MESSAGE_QUEUE_LIST* pList,
23 LPCWSTR pwzKey,
24 MQI_MESSAGE_QUEUE** ppItm
25 );
26static HRESULT AddMessageQueueToActionData(
27 MQI_MESSAGE_QUEUE* pItm,
28 LPWSTR* ppwzActionData
29 );
30static HRESULT MessageQueueTrusteePermissionsRead(
31 LPCWSTR pwzQuery,
32 MQI_MESSAGE_QUEUE_LIST* pMessageQueueList,
33 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
34 );
35static HRESULT AddMessageQueuePermissionToActionData(
36 MQI_MESSAGE_QUEUE_PERMISSION* pItm,
37 LPWSTR* ppwzActionData
38 );
39
40
41// private typedefs
42
43typedef HRESULT (__stdcall *MQPathNameToFormatNameFunc)(LPCWSTR, LPWSTR, LPDWORD);
44
45
46// private variables
47
48static HMODULE ghMQRT;
49static MQPathNameToFormatNameFunc gpfnMQPathNameToFormatName;
50
51
52// function definitions
53
54HRESULT MqiInitialize()
55{
56 HRESULT hr = S_OK;
57
58 // load mqrt.dll
59 ghMQRT = ::LoadLibraryW(L"mqrt.dll");
60 if (!ghMQRT)
61 {
62 ExitFunction1(hr = S_FALSE);
63 }
64
65 // get MQPathNameToFormatName function address
66 gpfnMQPathNameToFormatName = (MQPathNameToFormatNameFunc)::GetProcAddress(ghMQRT, "MQPathNameToFormatName");
67 ExitOnNullWithLastError(gpfnMQPathNameToFormatName, hr, "Failed get address for MQPathNameToFormatName() function");
68
69 hr = S_OK;
70
71LExit:
72 return hr;
73}
74
75void MqiUninitialize()
76{
77 if (ghMQRT)
78 {
79 ::FreeLibrary(ghMQRT);
80 }
81}
82
83HRESULT MqiMessageQueueRead(
84 MQI_MESSAGE_QUEUE_LIST* pList
85 )
86{
87 HRESULT hr = S_OK;
88 UINT er = ERROR_SUCCESS;
89
90 PMSIHANDLE hView, hRec;
91
92 MQI_MESSAGE_QUEUE* pItm = NULL;
93 LPWSTR pwzData = NULL;
94
95 // loop through all partitions
96 hr = WcaOpenExecuteView(vcsMessageQueueQuery, &hView);
97 ExitOnFailure(hr, "Failed to execute view on MessageQueue table");
98
99 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
100 {
101 // create entry
102 pItm = (MQI_MESSAGE_QUEUE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MQI_MESSAGE_QUEUE));
103 if (!pItm)
104 ExitFunction1(hr = E_OUTOFMEMORY);
105
106 // get key
107 hr = WcaGetRecordString(hRec, mqqMessageQueue, &pwzData);
108 ExitOnFailure(hr, "Failed to get key");
109 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
110
111 // get component install state
112 hr = WcaGetRecordString(hRec, mqqComponent, &pwzData);
113 ExitOnFailure(hr, "Failed to get component");
114
115 // get component install state
116 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
117 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
118
119 // get base priority
120 hr = WcaGetRecordInteger(hRec, mqqBasePriority, &pItm->iBasePriority);
121 ExitOnFailure(hr, "Failed to get base priority");
122
123 // get journal quota
124 hr = WcaGetRecordInteger(hRec, mqqJournalQuota, &pItm->iJournalQuota);
125 ExitOnFailure(hr, "Failed to get journal quota");
126
127 // get label
128 hr = WcaGetRecordFormattedString(hRec, mqqLabel, &pwzData);
129 ExitOnFailure(hr, "Failed to get label");
130 StringCchCopyW(pItm->wzLabel, countof(pItm->wzLabel), pwzData);
131
132 // get multicast address
133 hr = WcaGetRecordFormattedString(hRec, mqqMulticastAddress, &pwzData);
134 ExitOnFailure(hr, "Failed to get multicast address");
135 StringCchCopyW(pItm->wzMulticastAddress, countof(pItm->wzMulticastAddress), pwzData);
136
137 // get path name
138 hr = WcaGetRecordFormattedString(hRec, mqqPathName, &pwzData);
139 ExitOnFailure(hr, "Failed to get path name");
140 StringCchCopyW(pItm->wzPathName, countof(pItm->wzPathName), pwzData);
141
142 // get privacy level
143 hr = WcaGetRecordInteger(hRec, mqqPrivLevel, &pItm->iPrivLevel);
144 ExitOnFailure(hr, "Failed to get privacy level");
145
146 // get quota
147 hr = WcaGetRecordInteger(hRec, mqqQuota, &pItm->iQuota);
148 ExitOnFailure(hr, "Failed to get quota");
149
150 // get service type guid
151 hr = WcaGetRecordFormattedString(hRec, mqqServiceTypeGuid, &pwzData);
152 ExitOnFailure(hr, "Failed to get service type guid");
153 StringCchCopyW(pItm->wzServiceTypeGuid, countof(pItm->wzServiceTypeGuid), pwzData);
154
155 // get attributes
156 hr = WcaGetRecordInteger(hRec, mqqAttributes, &pItm->iAttributes);
157 ExitOnFailure(hr, "Failed to get attributes");
158
159 // increment counters
160 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
161 pList->iInstallCount++;
162 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
163 pList->iUninstallCount++;
164
165 // add entry
166 pItm->pNext = pList->pFirst;
167 pList->pFirst = pItm;
168 pItm = NULL;
169 }
170
171 if (E_NOMOREITEMS == hr)
172 hr = S_OK;
173
174LExit:
175 // clean up
176 if (pItm)
177 ::HeapFree(::GetProcessHeap(), 0, pItm);
178
179 ReleaseStr(pwzData);
180
181 return hr;
182}
183
184HRESULT MqiMessageQueueVerify(
185 MQI_MESSAGE_QUEUE_LIST* pList
186 )
187{
188 HRESULT hr = S_OK;
189 LPWSTR pwzFormatName = NULL;
190 DWORD dwCount = 128;
191
192 for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
193 {
194 // queues that are being installed only
195 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
196 continue;
197
198 // get format name
199 hr = StrAlloc(&pwzFormatName, dwCount);
200 ExitOnFailure(hr, "Failed to allocate format name string");
201 do {
202 hr = gpfnMQPathNameToFormatName(pItm->wzPathName, pwzFormatName, &dwCount);
203 switch (hr)
204 {
205 case MQ_ERROR_QUEUE_NOT_FOUND:
206 break; // break
207 case MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL:
208 hr = StrAlloc(&pwzFormatName, dwCount);
209 ExitOnFailure(hr, "Failed to reallocate format name string");
210 hr = S_FALSE; // retry
211 break;
212 default:
213 ExitOnFailure(hr, "Failed to get format name");
214 hr = S_OK;
215 }
216 } while (S_FALSE == hr);
217
218 if (MQ_ERROR_QUEUE_NOT_FOUND == hr)
219 {
220 continue;
221 }
222 pItm->fExists = TRUE;
223 pList->iInstallCount--;
224
225 // clean up
226 ReleaseNullStr(pwzFormatName);
227 }
228
229 hr = S_OK;
230
231LExit:
232 ReleaseStr(pwzFormatName);
233 return hr;
234}
235
236HRESULT MqiMessageQueueInstall(
237 MQI_MESSAGE_QUEUE_LIST* pList,
238 BOOL fRollback,
239 LPWSTR* ppwzActionData
240 )
241{
242 HRESULT hr = S_OK;
243
244 // add count to action data
245 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
246 ExitOnFailure(hr, "Failed to add count to custom action data");
247
248 for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
249 {
250 // queues that are being installed only
251 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
252 continue;
253
254 // if the queue exists we should not try to create it
255 if (pItm->fExists && !fRollback)
256 {
257 continue;
258 }
259
260 // add message queue to action data
261 hr = AddMessageQueueToActionData(pItm, ppwzActionData);
262 ExitOnFailure(hr, "Failed to add message queue to action data");
263 }
264
265 hr = S_OK;
266
267LExit:
268 return hr;
269}
270
271HRESULT MqiMessageQueueUninstall(
272 MQI_MESSAGE_QUEUE_LIST* pList,
273 BOOL fRollback,
274 LPWSTR* ppwzActionData
275 )
276{
277 HRESULT hr = S_OK;
278
279 // add count to action data
280 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
281 ExitOnFailure(hr, "Failed to add count to custom action data");
282
283 for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
284 {
285 // queues that are being uninstalled only
286 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
287 continue;
288
289 // if we did not create the queue we should not try to delete it
290 if (pItm->fExists && fRollback)
291 {
292 continue;
293 }
294
295 // add message queue to action data
296 hr = AddMessageQueueToActionData(pItm, ppwzActionData);
297 ExitOnFailure(hr, "Failed to add message queue to action data");
298 }
299
300 hr = S_OK;
301
302LExit:
303 return hr;
304}
305
306void MqiMessageQueueFreeList(
307 MQI_MESSAGE_QUEUE_LIST* pList
308 )
309{
310 MQI_MESSAGE_QUEUE* pItm = pList->pFirst;
311 while (pItm)
312 {
313 MQI_MESSAGE_QUEUE* pDelete = pItm;
314 pItm = pItm->pNext;
315 ::HeapFree(::GetProcessHeap(), 0, pDelete);
316 }
317}
318
319HRESULT MqiMessageQueuePermissionRead(
320 MQI_MESSAGE_QUEUE_LIST* pMessageQueueList,
321 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
322 )
323{
324 HRESULT hr = S_OK;
325
326 // read message queue user permissions
327 if (S_OK == WcaTableExists(L"MessageQueueUserPermission"))
328 {
329 hr = MessageQueueTrusteePermissionsRead(vcsMessageQueueUserPermissionQuery, pMessageQueueList, pList);
330 ExitOnFailure(hr, "Failed to read message queue user permissions");
331 }
332
333 // read message queue group permissions
334 if (S_OK == WcaTableExists(L"MessageQueueGroupPermission"))
335 {
336 hr = MessageQueueTrusteePermissionsRead(vcsMessageQueueGroupPermissionQuery, pMessageQueueList, pList);
337 ExitOnFailure(hr, "Failed to read message queue group permissions");
338 }
339
340 hr = S_OK;
341
342LExit:
343 return hr;
344}
345
346HRESULT MqiMessageQueuePermissionInstall(
347 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList,
348 LPWSTR* ppwzActionData
349 )
350{
351 HRESULT hr = S_OK;
352
353 // add count to action data
354 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
355 ExitOnFailure(hr, "Failed to add count to custom action data");
356
357 for (MQI_MESSAGE_QUEUE_PERMISSION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
358 {
359 // queue permissions that are being installed only
360 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
361 continue;
362
363 // add message queue permission to action data
364 hr = AddMessageQueuePermissionToActionData(pItm, ppwzActionData);
365 ExitOnFailure(hr, "Failed to add message queue permission to action data");
366 }
367
368 hr = S_OK;
369
370LExit:
371 return hr;
372}
373
374HRESULT MqiMessageQueuePermissionUninstall(
375 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList,
376 LPWSTR* ppwzActionData
377 )
378{
379 HRESULT hr = S_OK;
380
381 // add count to action data
382 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
383 ExitOnFailure(hr, "Failed to add count to custom action data");
384
385 for (MQI_MESSAGE_QUEUE_PERMISSION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
386 {
387 // queue permissions that are being uninstalled only
388 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
389 continue;
390
391 // add message queue permission to action data
392 hr = AddMessageQueuePermissionToActionData(pItm, ppwzActionData);
393 ExitOnFailure(hr, "Failed to add message queue permission to action data");
394 }
395
396 hr = S_OK;
397
398LExit:
399 return hr;
400}
401
402void MqiMessageQueuePermissionFreeList(
403 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
404 )
405{
406 MQI_MESSAGE_QUEUE_PERMISSION* pItm = pList->pFirst;
407 while (pItm)
408 {
409 MQI_MESSAGE_QUEUE_PERMISSION* pDelete = pItm;
410 pItm = pItm->pNext;
411 ::HeapFree(::GetProcessHeap(), 0, pDelete);
412 }
413}
414
415
416// helper function definitions
417
418static HRESULT MqiMessageQueueFindByKey(
419 MQI_MESSAGE_QUEUE_LIST* pList,
420 LPCWSTR pwzKey,
421 MQI_MESSAGE_QUEUE** ppItm
422 )
423{
424 for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
425 {
426 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
427 {
428 *ppItm = pItm;
429 return S_OK;
430 }
431 }
432
433 return S_FALSE;
434}
435
436static HRESULT AddMessageQueueToActionData(
437 MQI_MESSAGE_QUEUE* pItm,
438 LPWSTR* ppwzActionData
439 )
440{
441 HRESULT hr = S_OK;
442
443 // add message queue information to custom action data
444 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
445 ExitOnFailure(hr, "Failed to add key to custom action data");
446 hr = WcaWriteIntegerToCaData(pItm->iBasePriority, ppwzActionData);
447 ExitOnFailure(hr, "Failed to add base priority to custom action data");
448 hr = WcaWriteIntegerToCaData(pItm->iJournalQuota, ppwzActionData);
449 ExitOnFailure(hr, "Failed to add journal quota to custom action data");
450 hr = WcaWriteStringToCaData(pItm->wzLabel, ppwzActionData);
451 ExitOnFailure(hr, "Failed to add label to custom action data");
452 hr = WcaWriteStringToCaData(pItm->wzMulticastAddress, ppwzActionData);
453 ExitOnFailure(hr, "Failed to add multicast address to custom action data");
454 hr = WcaWriteStringToCaData(pItm->wzPathName, ppwzActionData);
455 ExitOnFailure(hr, "Failed to add path name to custom action data");
456 hr = WcaWriteIntegerToCaData(pItm->iPrivLevel, ppwzActionData);
457 ExitOnFailure(hr, "Failed to add privacy level to custom action data");
458 hr = WcaWriteIntegerToCaData(pItm->iQuota, ppwzActionData);
459 ExitOnFailure(hr, "Failed to add quota to custom action data");
460 hr = WcaWriteStringToCaData(pItm->wzServiceTypeGuid, ppwzActionData);
461 ExitOnFailure(hr, "Failed to add service type guid to custom action data");
462 hr = WcaWriteIntegerToCaData(pItm->iAttributes, ppwzActionData);
463 ExitOnFailure(hr, "Failed to add attributes to custom action data");
464
465 hr = S_OK;
466
467LExit:
468 return hr;
469}
470
471static HRESULT MessageQueueTrusteePermissionsRead(
472 LPCWSTR pwzQuery,
473 MQI_MESSAGE_QUEUE_LIST* pMessageQueueList,
474 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
475 )
476{
477 HRESULT hr = S_OK;
478 UINT er = ERROR_SUCCESS;
479
480 PMSIHANDLE hView, hRec;
481
482 LPWSTR pwzData = NULL;
483
484 MQI_MESSAGE_QUEUE_PERMISSION* pItm = NULL;
485
486 // loop through all application roles
487 hr = WcaOpenExecuteView(pwzQuery, &hView);
488 ExitOnFailure(hr, "Failed to execute view on table");
489
490 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
491 {
492 // create entry
493 pItm = (MQI_MESSAGE_QUEUE_PERMISSION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MQI_MESSAGE_QUEUE_PERMISSION));
494 if (!pItm)
495 ExitFunction1(hr = E_OUTOFMEMORY);
496
497 // get key
498 hr = WcaGetRecordString(hRec, mqpqMessageQueuePermission, &pwzData);
499 ExitOnFailure(hr, "Failed to get key");
500 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
501
502 // get component
503 hr = WcaGetRecordString(hRec, mqpqComponent, &pwzData);
504 ExitOnFailure(hr, "Failed to get component");
505
506 // get component install state
507 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
508 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
509
510 // get message queue
511 hr = WcaGetRecordString(hRec, mqpqMessageQueue, &pwzData);
512 ExitOnFailure(hr, "Failed to get application role");
513
514 hr = MqiMessageQueueFindByKey(pMessageQueueList, pwzData, &pItm->pMessageQueue);
515 if (S_FALSE == hr)
516 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
517 ExitOnFailure(hr, "Failed to find message queue, key: %S", pwzData);
518
519 // get user domain
520 hr = WcaGetRecordFormattedString(hRec, mqpqDomain, &pwzData);
521 ExitOnFailure(hr, "Failed to get domain");
522 StringCchCopyW(pItm->wzDomain, countof(pItm->wzDomain), pwzData);
523
524 // get user name
525 hr = WcaGetRecordFormattedString(hRec, mqpqName, &pwzData);
526 ExitOnFailure(hr, "Failed to get name");
527 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
528
529 // get permissions
530 hr = WcaGetRecordInteger(hRec, mqpqPermissions, &pItm->iPermissions);
531 ExitOnFailure(hr, "Failed to get permissions");
532
533 // set references & increment counters
534 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
535 pList->iInstallCount++;
536 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
537 pList->iUninstallCount++;
538
539 // add entry
540 if (pList->pFirst)
541 pItm->pNext = pList->pFirst;
542 pList->pFirst = pItm;
543 pItm = NULL;
544 }
545
546 if (E_NOMOREITEMS == hr)
547 hr = S_OK;
548
549LExit:
550 // clean up
551 ReleaseStr(pwzData);
552
553 if (pItm)
554 ::HeapFree(::GetProcessHeap(), 0, pItm);
555
556 return hr;
557}
558
559static HRESULT AddMessageQueuePermissionToActionData(
560 MQI_MESSAGE_QUEUE_PERMISSION* pItm,
561 LPWSTR* ppwzActionData
562 )
563{
564 HRESULT hr = S_OK;
565
566 // add message queue information to custom action data
567 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
568 ExitOnFailure(hr, "Failed to add key to custom action data");
569 hr = WcaWriteStringToCaData(pItm->pMessageQueue->wzPathName, ppwzActionData);
570 ExitOnFailure(hr, "Failed to add path name to custom action data");
571 hr = WcaWriteStringToCaData(pItm->wzDomain, ppwzActionData);
572 ExitOnFailure(hr, "Failed to add domain to custom action data");
573 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
574 ExitOnFailure(hr, "Failed to add name to custom action data");
575 hr = WcaWriteIntegerToCaData(pItm->iPermissions, ppwzActionData);
576 ExitOnFailure(hr, "Failed to add permissions to custom action data");
577
578 hr = S_OK;
579
580LExit:
581 return hr;
582}
diff --git a/src/ca/mqqueuesched.h b/src/ca/mqqueuesched.h
new file mode 100644
index 00000000..b063ca28
--- /dev/null
+++ b/src/ca/mqqueuesched.h
@@ -0,0 +1,92 @@
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 MQI_MESSAGE_QUEUE
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 int iBasePriority;
9 int iJournalQuota;
10 WCHAR wzLabel[MAX_DARWIN_COLUMN + 1];
11 WCHAR wzMulticastAddress[MAX_DARWIN_COLUMN + 1];
12 WCHAR wzPathName[MAX_DARWIN_COLUMN + 1];
13 int iPrivLevel;
14 int iQuota;
15 WCHAR wzServiceTypeGuid[MAX_DARWIN_COLUMN + 1];
16 int iAttributes;
17
18 INSTALLSTATE isInstalled, isAction;
19 BOOL fExists;
20
21 MQI_MESSAGE_QUEUE* pNext;
22};
23
24struct MQI_MESSAGE_QUEUE_LIST
25{
26 MQI_MESSAGE_QUEUE* pFirst;
27
28 int iInstallCount;
29 int iUninstallCount;
30};
31
32struct MQI_MESSAGE_QUEUE_PERMISSION
33{
34 WCHAR wzKey[MAX_DARWIN_KEY + 1];
35 WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
36 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
37 int iPermissions;
38
39 MQI_MESSAGE_QUEUE* pMessageQueue;
40
41 INSTALLSTATE isInstalled, isAction;
42
43 MQI_MESSAGE_QUEUE_PERMISSION* pNext;
44};
45
46struct MQI_MESSAGE_QUEUE_PERMISSION_LIST
47{
48 MQI_MESSAGE_QUEUE_PERMISSION* pFirst;
49
50 int iInstallCount;
51 int iUninstallCount;
52};
53
54
55// function prototypes
56
57HRESULT MqiInitialize();
58void MqiUninitialize();
59HRESULT MqiMessageQueueRead(
60 MQI_MESSAGE_QUEUE_LIST* pList
61 );
62HRESULT MqiMessageQueueVerify(
63 MQI_MESSAGE_QUEUE_LIST* pList
64 );
65HRESULT MqiMessageQueueInstall(
66 MQI_MESSAGE_QUEUE_LIST* pList,
67 BOOL fRollback,
68 LPWSTR* ppwzActionData
69 );
70HRESULT MqiMessageQueueUninstall(
71 MQI_MESSAGE_QUEUE_LIST* pList,
72 BOOL fRollback,
73 LPWSTR* ppwzActionData
74 );
75void MqiMessageQueueFreeList(
76 MQI_MESSAGE_QUEUE_LIST* pList
77 );
78HRESULT MqiMessageQueuePermissionRead(
79 MQI_MESSAGE_QUEUE_LIST* pMessageQueueList,
80 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
81 );
82HRESULT MqiMessageQueuePermissionInstall(
83 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList,
84 LPWSTR* ppwzActionData
85 );
86HRESULT MqiMessageQueuePermissionUninstall(
87 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList,
88 LPWSTR* ppwzActionData
89 );
90void MqiMessageQueuePermissionFreeList(
91 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
92 );
diff --git a/src/ca/mqsched.cpp b/src/ca/mqsched.cpp
new file mode 100644
index 00000000..cefce853
--- /dev/null
+++ b/src/ca/mqsched.cpp
@@ -0,0 +1,219 @@
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/********************************************************************
7 DllMain - standard entry point for all WiX CustomActions
8
9********************************************************************/
10extern "C" BOOL WINAPI DllMain(
11 IN HINSTANCE hInst,
12 IN ULONG ulReason,
13 IN LPVOID)
14{
15 switch(ulReason)
16 {
17 case DLL_PROCESS_ATTACH:
18 WcaGlobalInitialize(hInst);
19 break;
20
21 case DLL_PROCESS_DETACH:
22 WcaGlobalFinalize();
23 break;
24 }
25
26 return TRUE;
27}
28
29/********************************************************************
30 MessageQueuingInstall - CUSTOM ACTION ENTRY POINT for installing MSMQ message queues
31
32********************************************************************/
33extern "C" UINT __stdcall MessageQueuingInstall(MSIHANDLE hInstall)
34{
35 HRESULT hr = S_OK;
36 UINT er = ERROR_SUCCESS;
37
38 MQI_MESSAGE_QUEUE_LIST lstMessageQueues;
39 MQI_MESSAGE_QUEUE_PERMISSION_LIST lstMessageQueuePermissions;
40
41 int iCost = 0;
42 LPWSTR pwzRollbackActionData = NULL;
43 LPWSTR pwzExecuteActionData = NULL;
44
45 ::ZeroMemory(&lstMessageQueues, sizeof(lstMessageQueues));
46 ::ZeroMemory(&lstMessageQueuePermissions, sizeof(lstMessageQueuePermissions));
47
48 // initialize
49 hr = WcaInitialize(hInstall, "MessageQueuingInstall");
50 ExitOnFailure(hr, "Failed to initialize");
51
52 do
53 {
54 hr = MqiInitialize();
55 if (S_FALSE == hr)
56 {
57 WcaLog(LOGMSG_STANDARD, "Failed to load mqrt.dll.");
58 er = WcaErrorMessage(msierrMsmqCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
59 switch (er)
60 {
61 case IDABORT:
62 ExitFunction1(hr = E_FAIL); // bail with error
63 case IDRETRY:
64 break; // retry
65 case IDIGNORE: __fallthrough;
66 default:
67 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
68 }
69 }
70 ExitOnFailure(hr, "Failed to initialize MSMQ.");
71 } while (S_FALSE == hr);
72
73 // read message queues
74 hr = MqiMessageQueueRead(&lstMessageQueues);
75 ExitOnFailure(hr, "Failed to read MessageQueue table");
76
77 // read message queue permissions
78 hr = MqiMessageQueuePermissionRead(&lstMessageQueues, &lstMessageQueuePermissions);
79 ExitOnFailure(hr, "Failed to read message queue permissions");
80
81 // verify message queue elementes
82 hr = MqiMessageQueueVerify(&lstMessageQueues);
83 ExitOnFailure(hr, "Failed to verify message queue elements.");
84
85 if (lstMessageQueues.iInstallCount || lstMessageQueuePermissions.iInstallCount)
86 {
87 // schedule rollback action
88 hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzRollbackActionData);
89 ExitOnFailure(hr, "Failed to add message queue permissions to rollback action data");
90
91 hr = MqiMessageQueueInstall(&lstMessageQueues, TRUE, &pwzRollbackActionData);
92 ExitOnFailure(hr, "Failed to add message queues to rollback action data");
93
94 hr = WcaDoDeferredAction(L"MessageQueuingRollbackInstall", pwzRollbackActionData, 0);
95 ExitOnFailure(hr, "Failed to schedule MessageQueuingRollbackInstall");
96
97 // schedule execute action
98 hr = MqiMessageQueueInstall(&lstMessageQueues, FALSE, &pwzExecuteActionData);
99 ExitOnFailure(hr, "Failed to add message queues to execute action data");
100 iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_CREATE;
101
102 hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzExecuteActionData);
103 ExitOnFailure(hr, "Failed to add message queue permissions to execute action data");
104 iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_PERMISSION_ADD;
105
106 hr = WcaDoDeferredAction(L"MessageQueuingExecuteInstall", pwzExecuteActionData, iCost);
107 ExitOnFailure(hr, "Failed to schedule MessageQueuingExecuteInstall");
108 }
109
110 hr = S_OK;
111
112LExit:
113 // clean up
114 MqiMessageQueueFreeList(&lstMessageQueues);
115 MqiMessageQueuePermissionFreeList(&lstMessageQueuePermissions);
116
117 ReleaseStr(pwzRollbackActionData);
118 ReleaseStr(pwzExecuteActionData);
119
120 // uninitialize
121 MqiUninitialize();
122
123 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
124 return WcaFinalize(er);
125}
126
127
128/********************************************************************
129 MessageQueuingUninstall - CUSTOM ACTION ENTRY POINT for uninstalling MSMQ message queues
130
131********************************************************************/
132extern "C" UINT __stdcall MessageQueuingUninstall(MSIHANDLE hInstall)
133{
134 HRESULT hr = S_OK;
135 UINT er = ERROR_SUCCESS;
136
137 MQI_MESSAGE_QUEUE_LIST lstMessageQueues;
138 MQI_MESSAGE_QUEUE_PERMISSION_LIST lstMessageQueuePermissions;
139
140 int iCost = 0;
141 LPWSTR pwzRollbackActionData = NULL;
142 LPWSTR pwzExecuteActionData = NULL;
143
144 ::ZeroMemory(&lstMessageQueues, sizeof(lstMessageQueues));
145 ::ZeroMemory(&lstMessageQueuePermissions, sizeof(lstMessageQueuePermissions));
146
147 // initialize
148 hr = WcaInitialize(hInstall, "MessageQueuingUninstall");
149 ExitOnFailure(hr, "Failed to initialize");
150
151 do
152 {
153 hr = MqiInitialize();
154 if (S_FALSE == hr)
155 {
156 WcaLog(LOGMSG_STANDARD, "Failed to load mqrt.dll.");
157 er = WcaErrorMessage(msierrMsmqCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
158 switch (er)
159 {
160 case IDABORT:
161 ExitFunction1(hr = E_FAIL); // bail with error
162 case IDRETRY:
163 break; // retry
164 case IDIGNORE: __fallthrough;
165 default:
166 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
167 }
168 }
169 ExitOnFailure(hr, "Failed to initialize MSMQ.");
170 } while (S_FALSE == hr);
171
172 // read message queues
173 hr = MqiMessageQueueRead(&lstMessageQueues);
174 ExitOnFailure(hr, "Failed to read MessageQueue table");
175
176 // read message queue permissions
177 hr = MqiMessageQueuePermissionRead(&lstMessageQueues, &lstMessageQueuePermissions);
178 ExitOnFailure(hr, "Failed to read message queue permissions");
179
180 if (lstMessageQueues.iUninstallCount || lstMessageQueuePermissions.iUninstallCount)
181 {
182 // schedule rollback action
183 hr = MqiMessageQueueUninstall(&lstMessageQueues, TRUE, &pwzRollbackActionData);
184 ExitOnFailure(hr, "Failed to add message queues to rollback action data");
185
186 hr = MqiMessageQueuePermissionUninstall(&lstMessageQueuePermissions, &pwzRollbackActionData);
187 ExitOnFailure(hr, "Failed to add message queue permissions to rollback action data");
188
189 hr = WcaDoDeferredAction(L"MessageQueuingRollbackUninstall", pwzRollbackActionData, 0);
190 ExitOnFailure(hr, "Failed to schedule MessageQueuingRollbackUninstall");
191
192 // schedule execute action
193 hr = MqiMessageQueuePermissionUninstall(&lstMessageQueuePermissions, &pwzExecuteActionData);
194 ExitOnFailure(hr, "Failed to add message queue permissions to execute action data");
195
196 hr = MqiMessageQueueUninstall(&lstMessageQueues, FALSE, &pwzExecuteActionData);
197 ExitOnFailure(hr, "Failed to add message queues to execute action data");
198 iCost += lstMessageQueues.iUninstallCount * COST_MESSAGE_QUEUE_DELETE;
199
200 hr = WcaDoDeferredAction(L"MessageQueuingExecuteUninstall", pwzExecuteActionData, iCost);
201 ExitOnFailure(hr, "Failed to schedule MessageQueuingExecuteUninstall");
202 }
203
204 hr = S_OK;
205
206LExit:
207 // clean up
208 MqiMessageQueueFreeList(&lstMessageQueues);
209 MqiMessageQueuePermissionFreeList(&lstMessageQueuePermissions);
210
211 ReleaseStr(pwzRollbackActionData);
212 ReleaseStr(pwzExecuteActionData);
213
214 // uninitialize
215 MqiUninitialize();
216
217 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
218 return WcaFinalize(er);
219}
diff --git a/src/ca/mqutilexec.cpp b/src/ca/mqutilexec.cpp
new file mode 100644
index 00000000..a9c56e02
--- /dev/null
+++ b/src/ca/mqutilexec.cpp
@@ -0,0 +1,380 @@
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 PCA_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
19PCA_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 CreateSidFromDomainRidPair(
36 PSID pDomainSid,
37 DWORD dwRid,
38 PSID* ppSid
39 );
40static HRESULT InitLsaUnicodeString(
41 PLSA_UNICODE_STRING plusStr,
42 LPCWSTR pwzStr,
43 DWORD dwLen
44 );
45static void FreeLsaUnicodeString(
46 PLSA_UNICODE_STRING plusStr
47 );
48
49
50// function definitions
51
52HRESULT PcaActionDataMessage(
53 DWORD cArgs,
54 ...
55 )
56{
57 HRESULT hr = S_OK;
58 UINT er = ERROR_SUCCESS;
59
60 PMSIHANDLE hRec;
61 va_list args;
62
63 // record
64 hRec = ::MsiCreateRecord(cArgs);
65 ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record");
66
67 va_start(args, cArgs);
68 for (DWORD i = 1; i <= cArgs; i++)
69 {
70 LPCWSTR pwzArg = va_arg(args, WCHAR*);
71 if (pwzArg && *pwzArg)
72 {
73 er = ::MsiRecordSetStringW(hRec, i, pwzArg);
74 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set record field string");
75 }
76 }
77 va_end(args);
78
79 // message
80 er = WcaProcessMessage(INSTALLMESSAGE_ACTIONDATA, hRec);
81 if (0 == er || IDOK == er || IDYES == er)
82 {
83 hr = S_OK;
84 }
85 else if (ERROR_INSTALL_USEREXIT == er || IDABORT == er || IDCANCEL == er)
86 {
87 WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit
88 hr = S_FALSE;
89 }
90 else
91 hr = E_UNEXPECTED;
92
93LExit:
94 return hr;
95}
96
97HRESULT PcaAccountNameToSid(
98 LPCWSTR pwzAccountName,
99 PSID* ppSid
100 )
101{
102 HRESULT hr = S_OK;
103 UINT er = ERROR_SUCCESS;
104 NTSTATUS st = 0;
105
106 PSID pSid = NULL;
107 LSA_OBJECT_ATTRIBUTES loaAttributes;
108 LSA_HANDLE lsahPolicy = NULL;
109 LSA_UNICODE_STRING lusName;
110 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
111 PLSA_TRANSLATED_SID pltsSid = NULL;
112
113 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
114 ::ZeroMemory(&lusName, sizeof(lusName));
115
116 // identify well known SIDs
117 for (PCA_WELLKNOWN_SID* pWS = wsWellKnownSids; pWS->pwzName; pWS++)
118 {
119 if (0 == lstrcmpiW(pwzAccountName, pWS->pwzName))
120 {
121 // allocate SID buffer
122 pSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, ::GetSidLengthRequired(pWS->nSubAuthorityCount));
123 ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID");
124
125 // initialize SID
126 ::InitializeSid(pSid, &pWS->iaIdentifierAuthority, pWS->nSubAuthorityCount);
127
128 // copy sub autorities
129 for (DWORD i = 0; i < pWS->nSubAuthorityCount; i++)
130 *::GetSidSubAuthority(pSid, i) = pWS->dwSubAuthority[i];
131
132 break;
133 }
134 }
135
136 // lookup name
137 if (!pSid)
138 {
139 // open policy handle
140 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
141 er = ::LsaNtStatusToWinError(st);
142 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
143
144 // create account name lsa unicode string
145 hr = InitLsaUnicodeString(&lusName, pwzAccountName, wcslen(pwzAccountName));
146 ExitOnFailure(hr, "Failed to initialize account name string");
147
148 // lookup name
149 st = ::LsaLookupNames(lsahPolicy, 1, &lusName, &plrdsDomains, &pltsSid);
150 er = ::LsaNtStatusToWinError(st);
151 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names");
152
153 if (SidTypeDomain == pltsSid->Use)
154 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported");
155
156 // convert sid
157 hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pSid);
158 ExitOnFailure(hr, "Failed to convert SID");
159 }
160
161 *ppSid = pSid;
162 pSid = NULL;
163
164 hr = S_OK;
165
166LExit:
167 // clean up
168 if (pSid)
169 ::HeapFree(::GetProcessHeap(), 0, pSid);
170 if (lsahPolicy)
171 ::LsaClose(lsahPolicy);
172 if (plrdsDomains)
173 ::LsaFreeMemory(plrdsDomains);
174 if (pltsSid)
175 ::LsaFreeMemory(pltsSid);
176 FreeLsaUnicodeString(&lusName);
177
178 return hr;
179}
180
181HRESULT PcaSidToAccountName(
182 PSID pSid,
183 LPWSTR* ppwzAccountName
184 )
185{
186 HRESULT hr = S_OK;
187 UINT er = ERROR_SUCCESS;
188 NTSTATUS st = 0;
189
190 LSA_OBJECT_ATTRIBUTES loaAttributes;
191 LSA_HANDLE lsahPolicy = NULL;
192 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
193 PLSA_TRANSLATED_NAME pltnName = NULL;
194
195 LPWSTR pwzDomain = NULL;
196 LPWSTR pwzName = NULL;
197
198 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
199
200 // open policy handle
201 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
202 er = ::LsaNtStatusToWinError(st);
203 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
204
205 // lookup SID
206 st = ::LsaLookupSids(lsahPolicy, 1, &pSid, &plrdsDomains, &pltnName);
207 er = ::LsaNtStatusToWinError(st);
208 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup SID");
209
210 if (SidTypeDomain == pltnName->Use)
211 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported");
212
213 // format account name string
214 if (SidTypeWellKnownGroup != pltnName->Use)
215 {
216 PLSA_UNICODE_STRING plusDomain = &plrdsDomains->Domains[pltnName->DomainIndex].Name;
217 hr = StrAllocString(&pwzDomain, plusDomain->Buffer, plusDomain->Length / sizeof(WCHAR));
218 ExitOnFailure(hr, "Failed to allocate name string");
219 }
220
221 hr = StrAllocString(&pwzName, pltnName->Name.Buffer, pltnName->Name.Length / sizeof(WCHAR));
222 ExitOnFailure(hr, "Failed to allocate domain string");
223
224 hr = StrAllocFormatted(ppwzAccountName, L"%s\\%s", pwzDomain ? pwzDomain : L"", pwzName);
225 ExitOnFailure(hr, "Failed to format account name string");
226
227 hr = S_OK;
228
229LExit:
230 // clean up
231 if (lsahPolicy)
232 ::LsaClose(lsahPolicy);
233 if (plrdsDomains)
234 ::LsaFreeMemory(plrdsDomains);
235 if (pltnName)
236 ::LsaFreeMemory(pltnName);
237
238 ReleaseStr(pwzDomain);
239 ReleaseStr(pwzName);
240
241 return hr;
242}
243
244HRESULT PcaBuildAccountName(
245 LPCWSTR pwzDomain,
246 LPCWSTR pwzName,
247 LPWSTR* ppwzAccount
248 )
249{
250 HRESULT hr = S_OK;
251
252 WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1];
253 ::ZeroMemory(wzComputerName, sizeof(wzComputerName));
254
255 // if domain is '.', get computer name
256 if (0 == lstrcmpW(pwzDomain, L"."))
257 {
258 DWORD dwSize = countof(wzComputerName);
259 if (!::GetComputerNameW(wzComputerName, &dwSize))
260 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get computer name");
261 }
262
263 // build account name
264 hr = StrAllocFormatted(ppwzAccount, L"%s\\%s", *wzComputerName ? wzComputerName : pwzDomain, pwzName);
265 ExitOnFailure(hr, "Failed to build domain user name");
266
267 hr = S_OK;
268
269LExit:
270 return hr;
271}
272
273HRESULT PcaGuidFromString(
274 LPCWSTR pwzGuid,
275 LPGUID pGuid
276 )
277{
278 HRESULT hr = S_OK;
279
280 int cch = 0;
281
282 WCHAR wz[39];
283 ::ZeroMemory(wz, sizeof(wz));
284
285 cch = lstrlenW(pwzGuid);
286
287 if (38 == cch && L'{' == pwzGuid[0] && L'}' == pwzGuid[37])
288 StringCchCopyW(wz, countof(wz), pwzGuid);
289 else if (36 == cch)
290 StringCchPrintfW(wz, countof(wz), L"{%s}", pwzGuid);
291 else
292 ExitFunction1(hr = E_INVALIDARG);
293
294 hr = ::CLSIDFromString(wz, pGuid);
295
296LExit:
297 return hr;
298}
299
300
301// helper function definitions
302
303static HRESULT CreateSidFromDomainRidPair(
304 PSID pDomainSid,
305 DWORD dwRid,
306 PSID* ppSid
307 )
308{
309 HRESULT hr = S_OK;
310
311 PSID pSid = NULL;
312
313 // get domain SID sub authority count
314 UCHAR ucSubAuthorityCount = *::GetSidSubAuthorityCount(pDomainSid);
315
316 // allocate SID buffer
317 DWORD dwLengthRequired = ::GetSidLengthRequired(ucSubAuthorityCount + (UCHAR)1);
318 if (*ppSid)
319 {
320 SIZE_T ccb = ::HeapSize(::GetProcessHeap(), 0, *ppSid);
321 if (-1 == ccb)
322 ExitOnFailure(hr = E_FAIL, "Failed to get size of SID buffer");
323
324 if (ccb < dwLengthRequired)
325 {
326 pSid = (PSID)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, *ppSid, dwLengthRequired);
327 ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for SID, len: %d", dwLengthRequired);
328 *ppSid = pSid;
329 }
330 }
331 else
332 {
333 *ppSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwLengthRequired);
334 ExitOnNull(*ppSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID, len: %d", dwLengthRequired);
335 }
336
337 ::InitializeSid(*ppSid, ::GetSidIdentifierAuthority(pDomainSid), ucSubAuthorityCount + (UCHAR)1);
338
339 // copy sub autorities
340 DWORD i = 0;
341 for (; i < ucSubAuthorityCount; i++)
342 *::GetSidSubAuthority(*ppSid, i) = *::GetSidSubAuthority(pDomainSid, i);
343 *::GetSidSubAuthority(*ppSid, i) = dwRid;
344
345 hr = S_OK;
346
347LExit:
348 return hr;
349}
350
351static HRESULT InitLsaUnicodeString(
352 PLSA_UNICODE_STRING plusStr,
353 LPCWSTR pwzStr,
354 DWORD dwLen
355 )
356{
357 HRESULT hr = S_OK;
358
359 plusStr->Length = (USHORT)dwLen * sizeof(WCHAR);
360 plusStr->MaximumLength = (USHORT)(dwLen + 1) * sizeof(WCHAR);
361
362 plusStr->Buffer = (WCHAR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * (dwLen + 1));
363 ExitOnNull(plusStr->Buffer, hr, E_OUTOFMEMORY, "Failed to allocate account name string");
364
365 hr = StringCchCopyW(plusStr->Buffer, dwLen + 1, pwzStr);
366 ExitOnFailure(hr, "Failed to copy buffer");
367
368 hr = S_OK;
369
370LExit:
371 return hr;
372}
373
374static void FreeLsaUnicodeString(
375 PLSA_UNICODE_STRING plusStr
376 )
377{
378 if (plusStr->Buffer)
379 ::HeapFree(::GetProcessHeap(), 0, plusStr->Buffer);
380}
diff --git a/src/ca/mqutilexec.h b/src/ca/mqutilexec.h
new file mode 100644
index 00000000..d3dc17a1
--- /dev/null
+++ b/src/ca/mqutilexec.h
@@ -0,0 +1,23 @@
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
3HRESULT PcaActionDataMessage(
4 DWORD cArgs,
5 ...
6 );
7HRESULT PcaAccountNameToSid(
8 LPCWSTR pwzAccountName,
9 PSID* ppSid
10 );
11HRESULT PcaSidToAccountName(
12 PSID pSid,
13 LPWSTR* ppwzAccountName
14 );
15HRESULT PcaBuildAccountName(
16 LPCWSTR pwzDomain,
17 LPCWSTR pwzName,
18 LPWSTR* ppwzAccount
19 );
20HRESULT PcaGuidFromString(
21 LPCWSTR pwzGuid,
22 GUID* pGuid
23 );
diff --git a/src/ca/mqutilsched.cpp b/src/ca/mqutilsched.cpp
new file mode 100644
index 00000000..4353a6d6
--- /dev/null
+++ b/src/ca/mqutilsched.cpp
@@ -0,0 +1,43 @@
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// function definitions
7
8HRESULT PcaGuidToRegFormat(
9 LPWSTR pwzGuid,
10 LPWSTR pwzDest,
11 SIZE_T cchDest
12 )
13{
14 HRESULT hr = S_OK;
15
16 GUID guid = GUID_NULL;
17 int cch = 0;
18
19 WCHAR wz[39];
20 ::ZeroMemory(wz, sizeof(wz));
21
22 cch = lstrlenW(pwzGuid);
23
24 if (38 == cch && L'{' == pwzGuid[0] && L'}' == pwzGuid[37])
25 StringCchCopyW(wz, countof(wz), pwzGuid);
26 else if (36 == cch)
27 StringCchPrintfW(wz, countof(wz), L"{%s}", pwzGuid);
28 else
29 ExitFunction1(hr = E_INVALIDARG);
30
31 // convert string to guid
32 hr = ::CLSIDFromString(wz, &guid);
33 ExitOnFailure(hr, "Failed to parse guid string");
34
35 // convert guid to string
36 if (0 == ::StringFromGUID2(guid, pwzDest, cchDest))
37 ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string");
38
39 hr = S_OK;
40
41LExit:
42 return hr;
43}
diff --git a/src/ca/mqutilsched.h b/src/ca/mqutilsched.h
new file mode 100644
index 00000000..e172257d
--- /dev/null
+++ b/src/ca/mqutilsched.h
@@ -0,0 +1,9 @@
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 PcaGuidToRegFormat(
6 LPWSTR pwzGuid,
7 LPWSTR pwzDest,
8 SIZE_T cchDest
9 );
diff --git a/src/wixext/MsmqCompiler.cs b/src/wixext/MsmqCompiler.cs
new file mode 100644
index 00000000..b40e2dc1
--- /dev/null
+++ b/src/wixext/MsmqCompiler.cs
@@ -0,0 +1,536 @@
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
3namespace WixToolset.Extensions
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Globalization;
9 using System.Reflection;
10 using System.Xml;
11 using System.Xml.Linq;
12 using System.Xml.Schema;
13 using WixToolset.Data;
14 using WixToolset.Extensibility;
15
16 /// <summary>
17 /// The compiler for the WiX Toolset Internet Information Services Extension.
18 /// </summary>
19 public sealed class MsmqCompiler : CompilerExtension
20 {
21 /// <summary>
22 /// Instantiate a new MsmqCompiler.
23 /// </summary>
24 public MsmqCompiler()
25 {
26 this.Namespace = "http://wixtoolset.org/schemas/v4/wxs/msmq";
27 }
28
29 /// <summary>
30 /// </summary>
31 /// <remarks></remarks>
32 public enum MqiMessageQueueAttributes
33 {
34 Authenticate = (1 << 0),
35 Journal = (1 << 1),
36 Transactional = (1 << 2)
37 }
38
39 /// <summary>
40 /// </summary>
41 /// <remarks></remarks>
42 public enum MqiMessageQueuePrivacyLevel
43 {
44 None = 0,
45 Optional = 1,
46 Body = 2
47 }
48
49 /// <summary>
50 /// </summary>
51 /// <remarks></remarks>
52 public enum MqiMessageQueuePermission
53 {
54 DeleteMessage = (1 << 0),
55 PeekMessage = (1 << 1),
56 WriteMessage = (1 << 2),
57 DeleteJournalMessage = (1 << 3),
58 SetQueueProperties = (1 << 4),
59 GetQueueProperties = (1 << 5),
60 DeleteQueue = (1 << 6),
61 GetQueuePermissions = (1 << 7),
62 ChangeQueuePermissions = (1 << 8),
63 TakeQueueOwnership = (1 << 9),
64 ReceiveMessage = (1 << 10),
65 ReceiveJournalMessage = (1 << 11),
66 QueueGenericRead = (1 << 12),
67 QueueGenericWrite = (1 << 13),
68 QueueGenericExecute = (1 << 14),
69 QueueGenericAll = (1 << 15)
70 }
71
72 /// <summary>
73 /// Processes an element for the Compiler.
74 /// </summary>
75 /// <param name="parentElement">Parent element of element to process.</param>
76 /// <param name="element">Element to process.</param>
77 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
78 public override void ParseElement(XElement parentElement, XElement element, IDictionary<string, string> context)
79 {
80 switch (parentElement.Name.LocalName)
81 {
82 case "Component":
83 string componentId = context["ComponentId"];
84 string directoryId = context["DirectoryId"];
85
86 switch (element.Name.LocalName)
87 {
88 case "MessageQueue":
89 this.ParseMessageQueueElement(element, componentId);
90 break;
91 case "MessageQueuePermission":
92 this.ParseMessageQueuePermissionElement(element, componentId, null);
93 break;
94 default:
95 this.Core.UnexpectedElement(parentElement, element);
96 break;
97 }
98 break;
99 default:
100 this.Core.UnexpectedElement(parentElement, element);
101 break;
102 }
103 }
104
105 /// <summary>
106 /// Parses an MSMQ message queue element.
107 /// </summary>
108 /// <param name="node">Element to parse.</param>
109 /// <param name="componentKey">Identifier of parent component.</param>
110 private void ParseMessageQueueElement(XElement node, string componentId)
111 {
112 SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
113
114 string id = null;
115 int basePriority = CompilerConstants.IntegerNotSet;
116 int journalQuota = CompilerConstants.IntegerNotSet;
117 string label = null;
118 string multicastAddress = null;
119 string pathName = null;
120 int privLevel = CompilerConstants.IntegerNotSet;
121 int quota = CompilerConstants.IntegerNotSet;
122 string serviceTypeGuid = null;
123 int attributes = 0;
124
125 foreach (XAttribute attrib in node.Attributes())
126 {
127 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
128 {
129 switch (attrib.Name.LocalName)
130 {
131 case "Id":
132 id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
133 break;
134 case "Authenticate":
135 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
136 {
137 attributes |= (int)MqiMessageQueueAttributes.Authenticate;
138 }
139 else
140 {
141 attributes &= ~(int)MqiMessageQueueAttributes.Authenticate;
142 }
143 break;
144 case "BasePriority":
145 basePriority = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
146 break;
147 case "Journal":
148 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
149 {
150 attributes |= (int)MqiMessageQueueAttributes.Journal;
151 }
152 else
153 {
154 attributes &= ~(int)MqiMessageQueueAttributes.Journal;
155 }
156 break;
157 case "JournalQuota":
158 journalQuota = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
159 break;
160 case "Label":
161 label = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
162 break;
163 case "MulticastAddress":
164 multicastAddress = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
165 break;
166 case "PathName":
167 pathName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
168 break;
169 case "PrivLevel":
170 string privLevelAttr = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
171 switch (privLevelAttr)
172 {
173 case "none":
174 privLevel = (int)MqiMessageQueuePrivacyLevel.None;
175 break;
176 case "optional":
177 privLevel = (int)MqiMessageQueuePrivacyLevel.Optional;
178 break;
179 case "body":
180 privLevel = (int)MqiMessageQueuePrivacyLevel.Body;
181 break;
182 default:
183 this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "MessageQueue", "PrivLevel", privLevelAttr, "none", "body", "optional"));
184 break;
185 }
186 break;
187 case "Quota":
188 quota = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
189 break;
190 case "Transactional":
191 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
192 {
193 attributes |= (int)MqiMessageQueueAttributes.Transactional;
194 }
195 else
196 {
197 attributes &= ~(int)MqiMessageQueueAttributes.Transactional;
198 }
199 break;
200 case "ServiceTypeGuid":
201 serviceTypeGuid = TryFormatGuidValue(this.Core.GetAttributeValue(sourceLineNumbers, attrib));
202 break;
203 default:
204 this.Core.UnexpectedAttribute(node, attrib);
205 break;
206 }
207 }
208 else
209 {
210 this.Core.ParseExtensionAttribute(node, attrib);
211 }
212 }
213
214 foreach (XElement child in node.Elements())
215 {
216 if (this.Namespace == child.Name.Namespace)
217 {
218 switch (child.Name.LocalName)
219 {
220 case "MessageQueuePermission":
221 this.ParseMessageQueuePermissionElement(child, componentId, id);
222 break;
223 default:
224 this.Core.UnexpectedElement(node, child);
225 break;
226 }
227 }
228 else
229 {
230 this.Core.ParseExtensionElement(node, child);
231 }
232 }
233
234 Row row = this.Core.CreateRow(sourceLineNumbers, "MessageQueue");
235 row[0] = id;
236 row[1] = componentId;
237 if (CompilerConstants.IntegerNotSet != basePriority)
238 {
239 row[2] = basePriority;
240 }
241 if (CompilerConstants.IntegerNotSet != journalQuota)
242 {
243 row[3] = journalQuota;
244 }
245 row[4] = label;
246 row[5] = multicastAddress;
247 row[6] = pathName;
248 if (CompilerConstants.IntegerNotSet != privLevel)
249 {
250 row[7] = privLevel;
251 }
252 if (CompilerConstants.IntegerNotSet != quota)
253 {
254 row[8] = quota;
255 }
256 row[9] = serviceTypeGuid;
257 row[10] = attributes;
258
259 this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "MessageQueuingInstall");
260 this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "MessageQueuingUninstall");
261 }
262
263 /// <summary>
264 /// Parses an MSMQ message queue permission element.
265 /// </summary>
266 /// <param name="node">Element to parse.</param>
267 /// <param name="componentKey">Identifier of parent component.</param>
268 /// <param name="applicationKey">Optional identifier of parent message queue.</param>
269 private void ParseMessageQueuePermissionElement(XElement node, string componentId, string messageQueueId)
270 {
271 SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
272
273 string id = null;
274 string user = null;
275 string group = null;
276 int permissions = 0;
277
278 foreach (XAttribute attrib in node.Attributes())
279 {
280 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
281 {
282 switch (attrib.Name.LocalName)
283 {
284 case "Id":
285 id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
286 break;
287 case "MessageQueue":
288 if (null != messageQueueId)
289 {
290 this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName));
291 }
292 messageQueueId = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
293 this.Core.CreateSimpleReference(sourceLineNumbers, "MessageQueue", messageQueueId);
294 break;
295 case "User":
296 if (null != group)
297 {
298 this.Core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "User", "Group"));
299 }
300 user = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
301 this.Core.CreateSimpleReference(sourceLineNumbers, "User", user);
302 break;
303 case "Group":
304 if (null != user)
305 {
306 this.Core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Group", "User"));
307 }
308 group = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
309 this.Core.CreateSimpleReference(sourceLineNumbers, "Group", group);
310 break;
311 case "DeleteMessage":
312 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
313 {
314 permissions |= (int)MqiMessageQueuePermission.DeleteMessage;
315 }
316 else
317 {
318 permissions &= ~(int)MqiMessageQueuePermission.DeleteMessage;
319 }
320 break;
321 case "PeekMessage":
322 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
323 {
324 permissions |= (int)MqiMessageQueuePermission.PeekMessage;
325 }
326 else
327 {
328 permissions &= ~(int)MqiMessageQueuePermission.PeekMessage;
329 }
330 break;
331 case "WriteMessage":
332 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
333 {
334 permissions |= (int)MqiMessageQueuePermission.WriteMessage;
335 }
336 else
337 {
338 permissions &= ~(int)MqiMessageQueuePermission.WriteMessage;
339 }
340 break;
341 case "DeleteJournalMessage":
342 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
343 {
344 permissions |= (int)MqiMessageQueuePermission.DeleteJournalMessage;
345 }
346 else
347 {
348 permissions &= ~(int)MqiMessageQueuePermission.DeleteJournalMessage;
349 }
350 break;
351 case "SetQueueProperties":
352 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
353 {
354 permissions |= (int)MqiMessageQueuePermission.SetQueueProperties;
355 }
356 else
357 {
358 permissions &= ~(int)MqiMessageQueuePermission.SetQueueProperties;
359 }
360 break;
361 case "GetQueueProperties":
362 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
363 {
364 permissions |= (int)MqiMessageQueuePermission.GetQueueProperties;
365 }
366 else
367 {
368 permissions &= ~(int)MqiMessageQueuePermission.GetQueueProperties;
369 }
370 break;
371 case "DeleteQueue":
372 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
373 {
374 permissions |= (int)MqiMessageQueuePermission.DeleteQueue;
375 }
376 else
377 {
378 permissions &= ~(int)MqiMessageQueuePermission.DeleteQueue;
379 }
380 break;
381 case "GetQueuePermissions":
382 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
383 {
384 permissions |= (int)MqiMessageQueuePermission.GetQueuePermissions;
385 }
386 else
387 {
388 permissions &= ~(int)MqiMessageQueuePermission.GetQueuePermissions;
389 }
390 break;
391 case "ChangeQueuePermissions":
392 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
393 {
394 permissions |= (int)MqiMessageQueuePermission.ChangeQueuePermissions;
395 }
396 else
397 {
398 permissions &= ~(int)MqiMessageQueuePermission.ChangeQueuePermissions;
399 }
400 break;
401 case "TakeQueueOwnership":
402 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
403 {
404 permissions |= (int)MqiMessageQueuePermission.TakeQueueOwnership;
405 }
406 else
407 {
408 permissions &= ~(int)MqiMessageQueuePermission.TakeQueueOwnership;
409 }
410 break;
411 case "ReceiveMessage":
412 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
413 {
414 permissions |= (int)MqiMessageQueuePermission.ReceiveMessage;
415 }
416 else
417 {
418 permissions &= ~(int)MqiMessageQueuePermission.ReceiveMessage;
419 }
420 break;
421 case "ReceiveJournalMessage":
422 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
423 {
424 permissions |= (int)MqiMessageQueuePermission.ReceiveJournalMessage;
425 }
426 else
427 {
428 permissions &= ~(int)MqiMessageQueuePermission.ReceiveJournalMessage;
429 }
430 break;
431 case "QueueGenericRead":
432 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
433 {
434 permissions |= (int)MqiMessageQueuePermission.QueueGenericRead;
435 }
436 else
437 {
438 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericRead;
439 }
440 break;
441 case "QueueGenericWrite":
442 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
443 {
444 permissions |= (int)MqiMessageQueuePermission.QueueGenericWrite;
445 }
446 else
447 {
448 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericWrite;
449 }
450 break;
451 case "QueueGenericExecute":
452 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
453 {
454 permissions |= (int)MqiMessageQueuePermission.QueueGenericExecute;
455 }
456 else
457 {
458 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericExecute;
459 }
460 break;
461 case "QueueGenericAll":
462 if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
463 {
464 permissions |= (int)MqiMessageQueuePermission.QueueGenericAll;
465 }
466 else
467 {
468 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericAll;
469 }
470 break;
471 default:
472 this.Core.UnexpectedAttribute(node, attrib);
473 break;
474 }
475 }
476 else
477 {
478 this.Core.ParseExtensionAttribute(node, attrib);
479 }
480 }
481
482 if (null == messageQueueId)
483 {
484 this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "MessageQueue"));
485 }
486 if (null == user && null == group)
487 {
488 this.Core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "User", "Group"));
489 }
490
491 this.Core.ParseForExtensionElements(node);
492
493 if (null != user)
494 {
495 Row row = this.Core.CreateRow(sourceLineNumbers, "MessageQueueUserPermission");
496 row[0] = id;
497 row[1] = componentId;
498 row[2] = messageQueueId;
499 row[3] = user;
500 row[4] = permissions;
501 }
502 if (null != group)
503 {
504 Row row = this.Core.CreateRow(sourceLineNumbers, "MessageQueueGroupPermission");
505 row[0] = id;
506 row[1] = componentId;
507 row[2] = messageQueueId;
508 row[3] = group;
509 row[4] = permissions;
510 }
511 }
512
513 /// <summary>
514 /// Attempts to parse the input value as a GUID, and in case the value is a valid
515 /// GUID returnes it in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}".
516 /// </summary>
517 /// <param name="val"></param>
518 /// <returns></returns>
519 string TryFormatGuidValue(string val)
520 {
521 try
522 {
523 Guid guid = new Guid(val);
524 return guid.ToString("B").ToUpper();
525 }
526 catch (FormatException)
527 {
528 return val;
529 }
530 catch (OverflowException)
531 {
532 return val;
533 }
534 }
535 }
536}
diff --git a/src/wixext/MsmqDecompiler.cs b/src/wixext/MsmqDecompiler.cs
new file mode 100644
index 00000000..396fc49a
--- /dev/null
+++ b/src/wixext/MsmqDecompiler.cs
@@ -0,0 +1,303 @@
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
3namespace WixToolset.Extensions
4{
5 using System;
6 using System.Collections;
7 using System.Globalization;
8 using WixToolset.Data;
9 using WixToolset.Extensibility;
10 using Msmq = WixToolset.Extensions.Serialize.Msmq;
11 using Wix = WixToolset.Data.Serialize;
12
13 /// <summary>
14 /// The decompiler for the WiX Toolset MSMQ Extension.
15 /// </summary>
16 public sealed class MsmqDecompiler : DecompilerExtension
17 {
18 /// <summary>
19 /// Creates a decompiler for MSMQ Extension.
20 /// </summary>
21 public MsmqDecompiler()
22 {
23 this.TableDefinitions = MsmqExtensionData.GetExtensionTableDefinitions();
24 }
25
26 /// <summary>
27 /// Get the extensions library to be removed.
28 /// </summary>
29 /// <param name="tableDefinitions">Table definitions for library.</param>
30 /// <returns>Library to remove from decompiled output.</returns>
31 public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
32 {
33 return MsmqExtensionData.GetExtensionLibrary(tableDefinitions);
34 }
35
36 /// <summary>
37 /// Decompiles an extension table.
38 /// </summary>
39 /// <param name="table">The table to decompile.</param>
40 public override void DecompileTable(Table table)
41 {
42 switch (table.Name)
43 {
44 case "MessageQueue":
45 this.DecompileMessageQueueTable(table);
46 break;
47 case "MessageQueueUserPermission":
48 this.DecompileMessageQueueUserPermissionTable(table);
49 break;
50 case "MessageQueueGroupPermission":
51 this.DecompileMessageQueueGroupPermissionTable(table);
52 break;
53 default:
54 base.DecompileTable(table);
55 break;
56 }
57 }
58
59 /// <summary>
60 /// Decompile the MessageQueue table.
61 /// </summary>
62 /// <param name="table">The table to decompile.</param>
63 private void DecompileMessageQueueTable(Table table)
64 {
65 foreach (Row row in table.Rows)
66 {
67 Msmq.MessageQueue queue = new Msmq.MessageQueue();
68
69 queue.Id = (string)row[0];
70
71 if (null != row[2])
72 {
73 queue.BasePriority = (int)row[2];
74 }
75
76 if (null != row[3])
77 {
78 queue.JournalQuota = (int)row[3];
79 }
80
81 queue.Label = (string)row[4];
82
83 if (null != row[5])
84 {
85 queue.MulticastAddress = (string)row[5];
86 }
87
88 queue.PathName = (string)row[6];
89
90 if (null != row[7])
91 {
92 switch ((MsmqCompiler.MqiMessageQueuePrivacyLevel)row[7])
93 {
94 case MsmqCompiler.MqiMessageQueuePrivacyLevel.None:
95 queue.PrivLevel = Msmq.MessageQueue.PrivLevelType.none;
96 break;
97 case MsmqCompiler.MqiMessageQueuePrivacyLevel.Optional:
98 queue.PrivLevel = Msmq.MessageQueue.PrivLevelType.optional;
99 break;
100 case MsmqCompiler.MqiMessageQueuePrivacyLevel.Body:
101 queue.PrivLevel = Msmq.MessageQueue.PrivLevelType.body;
102 break;
103 default:
104 break;
105 }
106 }
107
108 if (null != row[8])
109 {
110 queue.Quota = (int)row[8];
111 }
112
113 if (null != row[9])
114 {
115 queue.ServiceTypeGuid = (string)row[9];
116 }
117
118 int attributes = (int)row[10];
119
120 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Authenticate))
121 {
122 queue.Authenticate = Msmq.YesNoType.yes;
123 }
124
125 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Journal))
126 {
127 queue.Journal = Msmq.YesNoType.yes;
128 }
129
130 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Transactional))
131 {
132 queue.Transactional = Msmq.YesNoType.yes;
133 }
134
135 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
136 if (null != component)
137 {
138 component.AddChild(queue);
139 }
140 else
141 {
142 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
143 }
144 }
145 }
146
147 /// <summary>
148 /// Decompile the MessageQueueUserPermission table.
149 /// </summary>
150 /// <param name="table">The table to decompile.</param>
151 private void DecompileMessageQueueUserPermissionTable(Table table)
152 {
153 foreach (Row row in table.Rows)
154 {
155 Msmq.MessageQueuePermission queuePermission = new Msmq.MessageQueuePermission();
156
157 queuePermission.Id = (string)row[0];
158
159 if (null != row[2])
160 {
161 queuePermission.MessageQueue = (string)row[2];
162 }
163
164 queuePermission.User = (string)row[3];
165
166 DecompileMessageQueuePermissionAttributes(row, queuePermission);
167
168 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
169 if (null != component)
170 {
171 component.AddChild(queuePermission);
172 }
173 else
174 {
175 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
176 }
177 }
178 }
179
180 /// <summary>
181 /// Decompile the MessageQueueGroupPermission table.
182 /// </summary>
183 /// <param name="table">The table to decompile.</param>
184 private void DecompileMessageQueueGroupPermissionTable(Table table)
185 {
186 foreach (Row row in table.Rows)
187 {
188 Msmq.MessageQueuePermission queuePermission = new Msmq.MessageQueuePermission();
189
190 queuePermission.Id = (string)row[0];
191
192 if (null != row[2])
193 {
194 queuePermission.MessageQueue = (string)row[2];
195 }
196
197 queuePermission.Group = (string)row[3];
198
199 DecompileMessageQueuePermissionAttributes(row, queuePermission);
200
201 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
202 if (null != component)
203 {
204 component.AddChild(queuePermission);
205 }
206 else
207 {
208 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
209 }
210 }
211 }
212
213 /// <summary>
214 /// Decompile row attributes for the MessageQueueUserPermission and MessageQueueGroupPermission tables.
215 /// </summary>
216 /// <param name="row">The row to decompile.</param>
217 /// <param name="table">Target element.</param>
218 private void DecompileMessageQueuePermissionAttributes(Row row, Msmq.MessageQueuePermission queuePermission)
219 {
220 int attributes = (int)row[4];
221
222 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteMessage))
223 {
224 queuePermission.DeleteMessage = Msmq.YesNoType.yes;
225 }
226
227 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.PeekMessage))
228 {
229 queuePermission.PeekMessage = Msmq.YesNoType.yes;
230 }
231
232 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.WriteMessage))
233 {
234 queuePermission.WriteMessage = Msmq.YesNoType.yes;
235 }
236
237 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteJournalMessage))
238 {
239 queuePermission.DeleteJournalMessage = Msmq.YesNoType.yes;
240 }
241
242 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.SetQueueProperties))
243 {
244 queuePermission.SetQueueProperties = Msmq.YesNoType.yes;
245 }
246
247 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.GetQueueProperties))
248 {
249 queuePermission.GetQueueProperties = Msmq.YesNoType.yes;
250 }
251
252 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteQueue))
253 {
254 queuePermission.DeleteQueue = Msmq.YesNoType.yes;
255 }
256
257 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.GetQueuePermissions))
258 {
259 queuePermission.GetQueuePermissions = Msmq.YesNoType.yes;
260 }
261
262 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ChangeQueuePermissions))
263 {
264 queuePermission.ChangeQueuePermissions = Msmq.YesNoType.yes;
265 }
266
267 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.TakeQueueOwnership))
268 {
269 queuePermission.TakeQueueOwnership = Msmq.YesNoType.yes;
270 }
271
272 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ReceiveMessage))
273 {
274 queuePermission.ReceiveMessage = Msmq.YesNoType.yes;
275 }
276
277 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ReceiveJournalMessage))
278 {
279 queuePermission.ReceiveJournalMessage = Msmq.YesNoType.yes;
280 }
281
282 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericRead))
283 {
284 queuePermission.QueueGenericRead = Msmq.YesNoType.yes;
285 }
286
287 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericWrite))
288 {
289 queuePermission.QueueGenericWrite = Msmq.YesNoType.yes;
290 }
291
292 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericExecute))
293 {
294 queuePermission.QueueGenericExecute = Msmq.YesNoType.yes;
295 }
296
297 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericAll))
298 {
299 queuePermission.QueueGenericAll = Msmq.YesNoType.yes;
300 }
301 }
302 }
303}
diff --git a/src/wixext/MsmqExtensionData.cs b/src/wixext/MsmqExtensionData.cs
new file mode 100644
index 00000000..81d53ce7
--- /dev/null
+++ b/src/wixext/MsmqExtensionData.cs
@@ -0,0 +1,64 @@
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
3namespace WixToolset.Extensions
4{
5 using System;
6 using System.Reflection;
7 using WixToolset.Data;
8 using WixToolset.Extensibility;
9
10 /// <summary>
11 /// The WiX Toolset MSMQ Extension.
12 /// </summary>
13 public sealed class MsmqExtensionData : ExtensionData
14 {
15 /// <summary>
16 /// Gets the default culture.
17 /// </summary>
18 /// <value>The default culture.</value>
19 public override string DefaultCulture
20 {
21 get { return "en-us"; }
22 }
23
24 /// <summary>
25 /// Gets the optional table definitions for this extension.
26 /// </summary>
27 /// <value>The optional table definitions for this extension.</value>
28 public override TableDefinitionCollection TableDefinitions
29 {
30 get
31 {
32 return MsmqExtensionData.GetExtensionTableDefinitions();
33 }
34 }
35
36 /// <summary>
37 /// Gets the library associated with this extension.
38 /// </summary>
39 /// <param name="tableDefinitions">The table definitions to use while loading the library.</param>
40 /// <returns>The loaded library.</returns>
41 public override Library GetLibrary(TableDefinitionCollection tableDefinitions)
42 {
43 return MsmqExtensionData.GetExtensionLibrary(tableDefinitions);
44 }
45
46 /// <summary>
47 /// Internal mechanism to access the extension's table definitions.
48 /// </summary>
49 /// <returns>Extension's table definitions.</returns>
50 internal static TableDefinitionCollection GetExtensionTableDefinitions()
51 {
52 return ExtensionData.LoadTableDefinitionHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.tables.xml");
53 }
54
55 /// <summary>
56 /// Internal mechanism to access the extension's library.
57 /// </summary>
58 /// <returns>Extension's library.</returns>
59 internal static Library GetExtensionLibrary(TableDefinitionCollection tableDefinitions)
60 {
61 return ExtensionData.LoadLibraryHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.msmq.wixlib", tableDefinitions);
62 }
63 }
64}
diff --git a/src/wixext/WixMsmqExtension.csproj b/src/wixext/WixMsmqExtension.csproj
new file mode 100644
index 00000000..e37d62a3
--- /dev/null
+++ b/src/wixext/WixMsmqExtension.csproj
@@ -0,0 +1,49 @@
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
5<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
6 <PropertyGroup>
7 <ProjectGuid>{B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}</ProjectGuid>
8 <AssemblyName>WixMsmqExtension</AssemblyName>
9 <OutputType>Library</OutputType>
10 <RootNamespace>WixToolset.Extensions</RootNamespace>
11 </PropertyGroup>
12 <ItemGroup>
13 <Compile Include="AssemblyInfo.cs" />
14 <Compile Include="MsmqCompiler.cs" />
15 <Compile Include="MsmqDecompiler.cs" />
16 <Compile Include="MsmqExtensionData.cs" />
17 <EmbeddedFlattenedResource Include="Data\tables.xml">
18 <LogicalName>$(RootNamespace).Data.tables.xml</LogicalName>
19 </EmbeddedFlattenedResource>
20 <EmbeddedFlattenedResource Include="Xsd\msmq.xsd">
21 <LogicalName>$(RootNamespace).Xsd.msmq.xsd</LogicalName>
22 </EmbeddedFlattenedResource>
23 <XsdGenSource Include="Xsd\msmq.xsd">
24 <CommonNamespace>WixToolset.Data.Serialize</CommonNamespace>
25 <Namespace>WixToolset.Extensions.Serialize.Msmq</Namespace>
26 </XsdGenSource>
27 <None Include="Xsd\msmq.xsd">
28 <Link>msmq.xsd</Link>
29 <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
30 </None>
31 <EmbeddedResource Include="$(OutputPath)\msmq.wixlib">
32 <Link>Data\msmq.wixlib</Link>
33 </EmbeddedResource>
34 </ItemGroup>
35
36 <ItemGroup>
37 <Reference Include="System" />
38 <Reference Include="System.Xml" />
39 <Reference Include="System.Xml.Linq" />
40 <ProjectReference Include="..\..\..\libs\WixToolset.Data\WixToolset.Data.csproj" />
41 <ProjectReference Include="..\..\..\libs\WixToolset.Extensibility\WixToolset.Extensibility.csproj" />
42 <ProjectReference Include="..\..\..\tools\wix\Wix.csproj" />
43 <ProjectReference Include="..\wixlib\MsmqExtension.wixproj">
44 <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
45 </ProjectReference>
46 </ItemGroup>
47
48 <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
49</Project>
diff --git a/src/wixext/messages.xml b/src/wixext/messages.xml
new file mode 100644
index 00000000..5ab6417f
--- /dev/null
+++ b/src/wixext/messages.xml
@@ -0,0 +1,77 @@
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
5<Messages Namespace="WixToolset.Extensions" Resources="Data.Messages" xmlns="http://schemas.microsoft.com/genmsgs/2004/07/messages">
6 <Class Name="MsmqErrors" ContainerName="MsmqErrorEventArgs" BaseContainerName="WixErrorEventArgs">
7 <Message Id="IllegalAttributeWithoutComponent" Number="6000">
8 <Instance>
9 The {0}/@{1} attribute cannot be specified unless the element has a component as an ancestor. A {0} that does not have a component ancestor is not installed.
10 <Parameter Type="System.String" Name="elementName" />
11 <Parameter Type="System.String" Name="attributeName" />
12 </Instance>
13 </Message>
14 <Message Id="IllegalElementWithoutComponent" Number="6001">
15 <Instance>
16 The {0} element cannot be specified unless the element has a component as an ancestor. A {0} that does not have a component ancestor is not installed.
17 <Parameter Type="System.String" Name="elementName" />
18 </Instance>
19 </Message>
20 <Message Id="UnexpectedAttributeWithOtherValue" Number="6002">
21 <Instance>
22 The {0}/@{1} attribute cannot coexist with the {2} attribute's value of '{3}'.
23 <Parameter Type="System.String" Name="elementName" />
24 <Parameter Type="System.String" Name="attributeName" />
25 <Parameter Type="System.String" Name="otherAttributeName" />
26 <Parameter Type="System.String" Name="otherValue" />
27 </Instance>
28 <Instance>
29 The {0}/@{1} attribute's value, '{2}', cannot coexist with the {3} attribute's value of '{4}'.
30 <Parameter Type="System.String" Name="elementName" />
31 <Parameter Type="System.String" Name="attributeName" />
32 <Parameter Type="System.String" Name="value" />
33 <Parameter Type="System.String" Name="otherAttributeName" />
34 <Parameter Type="System.String" Name="otherValue" />
35 </Instance>
36 </Message>
37 <Message Id="UnexpectedAttributeWithoutOtherValue" Number="6003">
38 <Instance>
39 The {0}/@{1} cannot be provided unless the {2} attribute is provided with a value of '{3}'.
40 <Parameter Type="System.String" Name="elementName" />
41 <Parameter Type="System.String" Name="attributeName" />
42 <Parameter Type="System.String" Name="otherAttributeName" />
43 <Parameter Type="System.String" Name="otherValue" />
44 </Instance>
45 </Message>
46 <Message Id="RequiredAttributeUnderComponent" Number="6004">
47 <Instance>
48 The {0}/@{1} attribute must be provided when {0} element is nested under a component.
49 <Parameter Type="System.String" Name="elementName" />
50 <Parameter Type="System.String" Name="attributeName" />
51 </Instance>
52 </Message>
53 <Message Id="RequiredAttribute" Number="6005">
54 <Instance>
55 A {0} element must have either a {1} attribute or a {2} attribute, or both set.
56 <Parameter Type="System.String" Name="elementName" />
57 <Parameter Type="System.String" Name="attributeName1" />
58 <Parameter Type="System.String" Name="attributeName2" />
59 </Instance>
60 </Message>
61 <Message Id="RequiredAttributeNotUnderComponent" Number="6006">
62 <Instance>
63 A {0} element not nested under a component must have either a {1} attribute or a {2} attribute, or both set.
64 <Parameter Type="System.String" Name="elementName" />
65 <Parameter Type="System.String" Name="attributeName1" />
66 <Parameter Type="System.String" Name="attributeName2" />
67 </Instance>
68 </Message>
69 </Class>
70 <Class Name="MsmqWarnings" ContainerName="MsmqWarningEventArgs" BaseContainerName="WixWarningEventArgs">
71 <Message Id="MissingComponents" Number="6007">
72 <Instance>The MsmqAssembly element has a Type attribute with a value of 'native', but the element does not contain any MsmqComponent elements. All components contained in a native assembly must be listed, or they will not be correctly removed during uninstall.</Instance>
73 </Message>
74 </Class>
75 <Class Name="MsmqVerboses" ContainerName="MsmqVerboseEventArgs" BaseContainerName="WixVerboseEventArgs">
76 </Class>
77</Messages>
diff --git a/src/wixext/msmq.xsd b/src/wixext/msmq.xsd
new file mode 100644
index 00000000..26348330
--- /dev/null
+++ b/src/wixext/msmq.xsd
@@ -0,0 +1,121 @@
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
5<xs:schema xmlns:html="http://www.w3.org/1999/xhtml"
6 xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
7 xmlns:xs="http://www.w3.org/2001/XMLSchema"
8 xmlns:xse=" http://wixtoolset.org/schemas/XmlSchemaExtension"
9 targetNamespace="http://wixtoolset.org/schemas/v4/wxs/msmq"
10 xmlns="http://wixtoolset.org/schemas/v4/wxs/msmq">
11 <xs:annotation>
12 <xs:documentation>
13 The source code schema for the WiX Toolset MSMQ Extension.
14 </xs:documentation>
15 </xs:annotation>
16
17 <xs:import namespace="http://wixtoolset.org/schemas/v4/wxs" />
18
19 <xs:element name="MessageQueue">
20 <xs:annotation><xs:documentation>
21 </xs:documentation>
22 <xs:appinfo>
23 <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Component" />
24 </xs:appinfo>
25 </xs:annotation>
26 <xs:complexType>
27 <xs:sequence>
28 <xs:element ref="MessageQueuePermission" minOccurs="0" maxOccurs="unbounded" />
29 </xs:sequence>
30 <xs:attribute name="Id" use="required" type="xs:string">
31 <xs:annotation><xs:documentation>
32 </xs:documentation></xs:annotation>
33 </xs:attribute>
34 <xs:attribute name="Authenticate" use="optional" type="YesNoType">
35 <xs:annotation><xs:documentation>
36 Default: No.
37 </xs:documentation></xs:annotation>
38 </xs:attribute>
39 <xs:attribute name="BasePriority" use="optional" type="xs:integer" />
40 <xs:attribute name="Journal" use="optional" type="YesNoType">
41 <xs:annotation><xs:documentation>
42 Default: No.
43 </xs:documentation></xs:annotation>
44 </xs:attribute>
45 <xs:attribute name="JournalQuota" use="optional" type="xs:integer" />
46 <xs:attribute name="Label" use="required" type="xs:string" />
47 <xs:attribute name="MulticastAddress" use="optional" type="xs:string" />
48 <xs:attribute name="PathName" use="required" type="xs:string" />
49 <xs:attribute name="PrivLevel" use="optional">
50 <xs:simpleType>
51 <xs:restriction base="xs:NMTOKEN">
52 <xs:enumeration value="none" />
53 <xs:enumeration value="optional" />
54 <xs:enumeration value="body" />
55 </xs:restriction>
56 </xs:simpleType>
57 </xs:attribute>
58 <xs:attribute name="Quota" use="optional" type="xs:integer" />
59 <xs:attribute name="Transactional" use="optional" type="YesNoType">
60 <xs:annotation><xs:documentation>
61 Default: No.
62 </xs:documentation></xs:annotation>
63 </xs:attribute>
64 <xs:attribute name="ServiceTypeGuid" use="optional" type="xs:string" />
65 </xs:complexType>
66 </xs:element>
67
68 <xs:element name="MessageQueuePermission">
69 <xs:annotation><xs:documentation>
70 </xs:documentation>
71 <xs:appinfo>
72 <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Component" />
73 </xs:appinfo>
74 </xs:annotation>
75 <xs:complexType>
76 <xs:attribute name="Id" use="required" type="xs:string">
77 <xs:annotation><xs:documentation>
78 </xs:documentation></xs:annotation>
79 </xs:attribute>
80 <xs:attribute name="MessageQueue" use="optional" type="xs:string">
81 <xs:annotation><xs:documentation>
82 </xs:documentation></xs:annotation>
83 </xs:attribute>
84 <xs:attribute name="User" use="optional" type="xs:string">
85 <xs:annotation><xs:documentation>
86 </xs:documentation></xs:annotation>
87 </xs:attribute>
88 <xs:attribute name="Group" use="optional" type="xs:string">
89 <xs:annotation><xs:documentation>
90 </xs:documentation></xs:annotation>
91 </xs:attribute>
92 <xs:attribute name="DeleteMessage" use="optional" type="YesNoType" />
93 <xs:attribute name="PeekMessage" use="optional" type="YesNoType" />
94 <xs:attribute name="WriteMessage" use="optional" type="YesNoType" />
95 <xs:attribute name="DeleteJournalMessage" use="optional" type="YesNoType" />
96 <xs:attribute name="SetQueueProperties" use="optional" type="YesNoType" />
97 <xs:attribute name="GetQueueProperties" use="optional" type="YesNoType" />
98 <xs:attribute name="DeleteQueue" use="optional" type="YesNoType" />
99 <xs:attribute name="GetQueuePermissions" use="optional" type="YesNoType" />
100 <xs:attribute name="ChangeQueuePermissions" use="optional" type="YesNoType" />
101 <xs:attribute name="TakeQueueOwnership" use="optional" type="YesNoType" />
102 <xs:attribute name="ReceiveMessage" use="optional" type="YesNoType" />
103 <xs:attribute name="ReceiveJournalMessage" use="optional" type="YesNoType" />
104 <xs:attribute name="QueueGenericRead" use="optional" type="YesNoType" />
105 <xs:attribute name="QueueGenericWrite" use="optional" type="YesNoType" />
106 <xs:attribute name="QueueGenericExecute" use="optional" type="YesNoType" />
107 <xs:attribute name="QueueGenericAll" use="optional" type="YesNoType" />
108 </xs:complexType>
109 </xs:element>
110
111 <xs:simpleType name="YesNoType">
112 <xs:annotation>
113 <xs:documentation>Values of this type will either be "yes" or "no".</xs:documentation>
114 </xs:annotation>
115 <xs:restriction base="xs:NMTOKEN">
116 <xs:enumeration value="no" />
117 <xs:enumeration value="yes" />
118 </xs:restriction>
119 </xs:simpleType>
120
121</xs:schema>
diff --git a/src/wixext/tables.xml b/src/wixext/tables.xml
new file mode 100644
index 00000000..5fdd1fad
--- /dev/null
+++ b/src/wixext/tables.xml
@@ -0,0 +1,54 @@
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
5<tableDefinitions xmlns="http://wixtoolset.org/schemas/v4/wi/tables">
6 <tableDefinition name="MessageQueue" createSymbols="yes">
7 <columnDefinition name="MessageQueue" type="string" length="72" primaryKey="yes" modularize="column"
8 category="identifier" description=""/>
9 <columnDefinition name="Component_" type="string" length="72" modularize="column"
10 keyTable="Component" keyColumn="1" category="identifier" description=""/>
11 <columnDefinition name="BasePriority" type="number" length="4" nullable="yes"
12 description=""/>
13 <columnDefinition name="JournalQuota" type="number" length="4" nullable="yes"
14 description=""/>
15 <columnDefinition name="Label" type="localized" length="255" modularize="property" escapeIdtCharacters="yes"
16 category="formatted" description=""/>
17 <columnDefinition name="MulticastAddress" type="string" length="255" nullable="yes" modularize="property"
18 category="formatted" description=""/>
19 <columnDefinition name="PathName" type="string" length="255" modularize="property"
20 category="formatted" description=""/>
21 <columnDefinition name="PrivLevel" type="number" length="4" nullable="yes"
22 description=""/>
23 <columnDefinition name="Quota" type="number" length="4" nullable="yes"
24 description=""/>
25 <columnDefinition name="ServiceTypeGuid" type="string" length="72" nullable="yes" modularize="property"
26 category="formatted" description=""/>
27 <columnDefinition name="Attributes" type="number" length="4"
28 description=""/>
29 </tableDefinition>
30 <tableDefinition name="MessageQueueUserPermission" createSymbols="yes">
31 <columnDefinition name="MessageQueueUserPermission" type="string" length="72" primaryKey="yes" modularize="column"
32 category="identifier" description=""/>
33 <columnDefinition name="Component_" type="string" length="72" modularize="column"
34 keyTable="Component" keyColumn="1" category="identifier" description=""/>
35 <columnDefinition name="MessageQueue_" type="string" length="72" modularize="column"
36 keyTable="MessageQueue" keyColumn="1" category="identifier" description=""/>
37 <columnDefinition name="User_" type="string" length="72" modularize="column"
38 category="identifier" description=""/>
39 <columnDefinition name="Permissions" type="number" length="4"
40 description=""/>
41 </tableDefinition>
42 <tableDefinition name="MessageQueueGroupPermission" createSymbols="yes">
43 <columnDefinition name="MessageQueueGroupPermission" type="string" length="72" primaryKey="yes" modularize="column"
44 category="identifier" description=""/>
45 <columnDefinition name="Component_" type="string" length="72" modularize="column"
46 keyTable="Component" keyColumn="1" category="identifier" description=""/>
47 <columnDefinition name="MessageQueue_" type="string" length="72" modularize="column"
48 keyTable="MessageQueue" keyColumn="1" category="identifier" description=""/>
49 <columnDefinition name="Group_" type="string" length="72" modularize="column"
50 category="identifier" description=""/>
51 <columnDefinition name="Permissions" type="number" length="4"
52 description=""/>
53 </tableDefinition>
54</tableDefinitions>
diff --git a/src/wixlib/MsmqExtension.wixproj b/src/wixlib/MsmqExtension.wixproj
new file mode 100644
index 00000000..6dcdfbc7
--- /dev/null
+++ b/src/wixlib/MsmqExtension.wixproj
@@ -0,0 +1,24 @@
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
5<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
6 <PropertyGroup>
7 <ProjectGuid>{42493058-5FC8-4F85-9884-FF3190E084B6}</ProjectGuid>
8 <OutputName>msmq</OutputName>
9 <OutputType>Library</OutputType>
10 <BindFiles>true</BindFiles>
11 </PropertyGroup>
12
13 <ItemGroup>
14 <Compile Include="MsmqExtension.wxs" />
15 <EmbeddedResource Include="en-us.wxl" />
16 <EmbeddedResource Include="ja-jp.wxl" />
17 </ItemGroup>
18
19 <ItemGroup>
20 <ProjectReference Include="..\ca\msmqca.proj" />
21 </ItemGroup>
22
23 <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
24</Project>
diff --git a/src/wixlib/MsmqExtension.wxs b/src/wixlib/MsmqExtension.wxs
new file mode 100644
index 00000000..b8622580
--- /dev/null
+++ b/src/wixlib/MsmqExtension.wxs
@@ -0,0 +1,31 @@
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
5<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
6 <?include caerr.wxi ?>
7
8 <Fragment>
9 <UI>
10 <ProgressText Action="MessageQueuingExecuteInstall" Template="!(loc.MessageQueuingExecuteInstallTemplate)">!(loc.MessageQueuingExecuteInstall)</ProgressText>
11 <ProgressText Action="MessageQueuingExecuteUninstall" Template="!(loc.MessageQueuingExecuteUninstallTemplate)">!(loc.MessageQueuingExecuteUninstall)</ProgressText>
12 </UI>
13
14 <CustomAction Id="MessageQueuingInstall" BinaryKey="WixMsmqSched" DllEntry="MessageQueuingInstall" Execute="immediate" Return="check" SuppressModularization="yes"/>
15 <CustomAction Id="MessageQueuingUninstall" BinaryKey="WixMsmqSched" DllEntry="MessageQueuingUninstall" Execute="immediate" Return="check" SuppressModularization="yes"/>
16 <CustomAction Id="MessageQueuingExecuteInstall" BinaryKey="WixMsmqExec" DllEntry="MessageQueuingExecuteInstall" Execute="deferred" Return="check" Impersonate="no" SuppressModularization="yes"/>
17 <CustomAction Id="MessageQueuingRollbackInstall" BinaryKey="WixMsmqExec" DllEntry="MessageQueuingRollbackInstall" Execute="rollback" Return="check" Impersonate="no" SuppressModularization="yes"/>
18 <CustomAction Id="MessageQueuingExecuteUninstall" BinaryKey="WixMsmqExec" DllEntry="MessageQueuingExecuteUninstall" Execute="deferred" Return="check" Impersonate="no" SuppressModularization="yes"/>
19 <CustomAction Id="MessageQueuingRollbackUninstall" BinaryKey="WixMsmqExec" DllEntry="MessageQueuingRollbackUninstall" Execute="rollback" Return="check" Impersonate="no" SuppressModularization="yes"/>
20
21 <InstallExecuteSequence>
22 <Custom Action="MessageQueuingUninstall" After="DeleteServices" Overridable="yes">VersionNT >= 500</Custom>
23 <Custom Action="MessageQueuingInstall" Before="InstallServices" Overridable="yes">VersionNT >= 500</Custom>
24 </InstallExecuteSequence>
25 </Fragment>
26
27 <Fragment>
28 <Binary Id="WixMsmqExec" SourceFile="mqexec.dll"/>
29 <Binary Id="WixMsmqSched" SourceFile="mqsched.dll"/>
30 </Fragment>
31</Wix>
diff --git a/src/wixlib/en-us.wxl b/src/wixlib/en-us.wxl
new file mode 100644
index 00000000..ebe08095
--- /dev/null
+++ b/src/wixlib/en-us.wxl
@@ -0,0 +1,10 @@
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
5<WixLocalization Culture="en-us" xmlns="http://wixtoolset.org/schemas/v4/wxl">
6 <String Id="MessageQueuingExecuteInstall" Overridable="yes">Configuring message queues</String>
7 <String Id="MessageQueuingExecuteInstallTemplate" Overridable="yes">Queue: [1]</String>
8 <String Id="MessageQueuingExecuteUninstall" Overridable="yes">Configuring message queues</String>
9 <String Id="MessageQueuingExecuteUninstallTemplate" Overridable="yes">Queue: [1]</String>
10</WixLocalization>
diff --git a/src/wixlib/ja-jp.wxl b/src/wixlib/ja-jp.wxl
new file mode 100644
index 00000000..d56cd7ec
--- /dev/null
+++ b/src/wixlib/ja-jp.wxl
@@ -0,0 +1,10 @@
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
5<WixLocalization Culture="ja-jp" xmlns="http://wixtoolset.org/schemas/v4/wxl">
6 <String Id="MessageQueuingExecuteInstall" Overridable="yes">メッセージ キューを構成しています</String>
7 <String Id="MessageQueuingExecuteInstallTemplate" Overridable="yes">キュー: [1]</String>
8 <String Id="MessageQueuingExecuteUninstall" Overridable="yes">メッセージ キューを構成しています</String>
9 <String Id="MessageQueuingExecuteUninstallTemplate" Overridable="yes">キュー: [1]</String>
10</WixLocalization>