aboutsummaryrefslogtreecommitdiff
path: root/src/ext
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-05-11 08:06:11 -0700
committerRob Mensching <rob@firegiant.com>2021-05-11 08:06:11 -0700
commit3ae536eb53fe0cc9bbcb1aeb0cd88c89f4f3e2cc (patch)
tree4a350e72c1a0bbe0012bdf4d6451d691ccf39e6b /src/ext
parent400d3eaae96f9cf9d15b448240b944473964ee31 (diff)
parentd77dca43e87e8711b19910a8fd49138f939bf0a4 (diff)
downloadwix-3ae536eb53fe0cc9bbcb1aeb0cd88c89f4f3e2cc.tar.gz
wix-3ae536eb53fe0cc9bbcb1aeb0cd88c89f4f3e2cc.tar.bz2
wix-3ae536eb53fe0cc9bbcb1aeb0cd88c89f4f3e2cc.zip
Merge Msmq.wixext
Diffstat (limited to 'src/ext')
-rw-r--r--src/ext/Msmq/CSharp.Build.props11
-rw-r--r--src/ext/Msmq/Cpp.Build.props86
-rw-r--r--src/ext/Msmq/Directory.Build.props29
-rw-r--r--src/ext/Msmq/Directory.Build.targets48
-rw-r--r--src/ext/Msmq/Msmq.wixext.sln61
-rw-r--r--src/ext/Msmq/README.md2
-rw-r--r--src/ext/Msmq/appveyor.cmd14
-rw-r--r--src/ext/Msmq/appveyor.yml40
-rw-r--r--src/ext/Msmq/ca/custommsierrors.h4
-rw-r--r--src/ext/Msmq/ca/dllmain.cpp26
-rw-r--r--src/ext/Msmq/ca/mqcost.h9
-rw-r--r--src/ext/Msmq/ca/mqexec.cpp192
-rw-r--r--src/ext/Msmq/ca/mqqueueexec.cpp927
-rw-r--r--src/ext/Msmq/ca/mqqueueexec.h30
-rw-r--r--src/ext/Msmq/ca/mqqueuesched.cpp582
-rw-r--r--src/ext/Msmq/ca/mqqueuesched.h92
-rw-r--r--src/ext/Msmq/ca/mqsched.cpp196
-rw-r--r--src/ext/Msmq/ca/mqutilexec.cpp380
-rw-r--r--src/ext/Msmq/ca/mqutilexec.h23
-rw-r--r--src/ext/Msmq/ca/mqutilsched.cpp43
-rw-r--r--src/ext/Msmq/ca/mqutilsched.h9
-rw-r--r--src/ext/Msmq/ca/msmqca.def12
-rw-r--r--src/ext/Msmq/ca/msmqca.vcxproj71
-rw-r--r--src/ext/Msmq/ca/packages.config5
-rw-r--r--src/ext/Msmq/ca/precomp.h23
-rw-r--r--src/ext/Msmq/nuget.config17
-rw-r--r--src/ext/Msmq/test/WixToolsetTest.Msmq/MsmqExtensionFixture.cs32
-rw-r--r--src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/Package.en-us.wxl11
-rw-r--r--src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/Package.wxs15
-rw-r--r--src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/PackageComponents.wxs12
-rw-r--r--src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/example.txt1
-rw-r--r--src/ext/Msmq/test/WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj41
-rw-r--r--src/ext/Msmq/wix.snkbin0 -> 596 bytes
-rw-r--r--src/ext/Msmq/wixext/MsmqCompiler.cs528
-rw-r--r--src/ext/Msmq/wixext/MsmqDecompiler.cs305
-rw-r--r--src/ext/Msmq/wixext/MsmqErrors.cs71
-rw-r--r--src/ext/Msmq/wixext/MsmqExtensionData.cs30
-rw-r--r--src/ext/Msmq/wixext/MsmqExtensionFactory.cs18
-rw-r--r--src/ext/Msmq/wixext/MsmqTableDefinitions.cs64
-rw-r--r--src/ext/Msmq/wixext/MsmqWarnings.cs30
-rw-r--r--src/ext/Msmq/wixext/MsmqWindowsInstallerBackendExtension.cs13
-rw-r--r--src/ext/Msmq/wixext/Symbols/MessageQueueGroupPermissionSymbol.cs71
-rw-r--r--src/ext/Msmq/wixext/Symbols/MessageQueueSymbol.cs119
-rw-r--r--src/ext/Msmq/wixext/Symbols/MessageQueueUserPermissionSymbol.cs71
-rw-r--r--src/ext/Msmq/wixext/Symbols/MsmqSymbolDefinitions.cs47
-rw-r--r--src/ext/Msmq/wixext/WixToolset.Msmq.wixext.csproj30
-rw-r--r--src/ext/Msmq/wixext/WixToolset.Msmq.wixext.targets11
-rw-r--r--src/ext/Msmq/wixlib/MsmqExtension.wxs29
-rw-r--r--src/ext/Msmq/wixlib/caerr.wxi96
-rw-r--r--src/ext/Msmq/wixlib/en-us.wxl10
-rw-r--r--src/ext/Msmq/wixlib/ja-jp.wxl10
-rw-r--r--src/ext/Msmq/wixlib/msmq.wixproj18
52 files changed, 4615 insertions, 0 deletions
diff --git a/src/ext/Msmq/CSharp.Build.props b/src/ext/Msmq/CSharp.Build.props
new file mode 100644
index 00000000..b12f4c6e
--- /dev/null
+++ b/src/ext/Msmq/CSharp.Build.props
@@ -0,0 +1,11 @@
1<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2<!--
3 Do NOT modify this file. Update the canonical version in Home\repo-template\src\CSharp.Build.props
4 then update all of the repos.
5-->
6<Project>
7 <PropertyGroup>
8 <SignAssembly>true</SignAssembly>
9 <AssemblyOriginatorKeyFile>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk))</AssemblyOriginatorKeyFile>
10 </PropertyGroup>
11</Project>
diff --git a/src/ext/Msmq/Cpp.Build.props b/src/ext/Msmq/Cpp.Build.props
new file mode 100644
index 00000000..9b7a1bb5
--- /dev/null
+++ b/src/ext/Msmq/Cpp.Build.props
@@ -0,0 +1,86 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project>
5 <PropertyGroup>
6 <Platform Condition=" '$(Platform)' == '' OR '$(Platform)' == 'AnyCPU' ">Win32</Platform>
7 <IntDir>$(BaseIntermediateOutputPath)$(Configuration)\$(Platform)\</IntDir>
8 <OutDir>$(OutputPath)$(Platform)\</OutDir>
9 </PropertyGroup>
10
11 <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'=='' AND '$(VisualStudioVersion)'>='15.0'">
12 <WindowsTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</WindowsTargetPlatformVersion>
13 </PropertyGroup>
14
15 <ItemDefinitionGroup>
16 <ClCompile>
17 <DisableSpecificWarnings>$(DisableSpecificCompilerWarnings)</DisableSpecificWarnings>
18 <WarningLevel>Level4</WarningLevel>
19 <AdditionalIncludeDirectories>$(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
20 <PreprocessorDefinitions>WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
21 <PrecompiledHeader>Use</PrecompiledHeader>
22 <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
23 <CallingConvention Condition="'$(Platform)'=='Win32'">StdCall</CallingConvention>
24 <TreatWarningAsError>true</TreatWarningAsError>
25 <ExceptionHandling>false</ExceptionHandling>
26 <AdditionalOptions>-YlprecompDefine</AdditionalOptions>
27 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
28 <MultiProcessorCompilation Condition=" $(NUMBER_OF_PROCESSORS) &gt; 4 ">true</MultiProcessorCompilation>
29 </ClCompile>
30 <ResourceCompile>
31 <PreprocessorDefinitions>$(ArmPreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
32 <AdditionalIncludeDirectories>$(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
33 </ResourceCompile>
34 <Lib>
35 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
36 </Lib>
37 <Link>
38 <SubSystem>$(ProjectSubSystem)</SubSystem>
39 <ModuleDefinitionFile>$(ProjectModuleDefinitionFile)</ModuleDefinitionFile>
40 <NoEntryPoint>$(ResourceOnlyDll)</NoEntryPoint>
41 <GenerateDebugInformation>true</GenerateDebugInformation>
42 <AdditionalDependencies>$(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
43 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
44 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/IGNORE:4099 %(AdditionalOptions)</AdditionalOptions>
45 </Link>
46 </ItemDefinitionGroup>
47
48 <ItemDefinitionGroup Condition=" '$(Platform)'=='Win32' and '$(PlatformToolset)'!='v100'">
49 <ClCompile>
50 <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
51 </ClCompile>
52 </ItemDefinitionGroup>
53 <ItemDefinitionGroup Condition=" '$(Platform)'=='arm' ">
54 <ClCompile>
55 <CallingConvention>CDecl</CallingConvention>
56 </ClCompile>
57 </ItemDefinitionGroup>
58 <ItemDefinitionGroup Condition=" '$(ConfigurationType)'=='StaticLibrary' ">
59 <ClCompile>
60 <DebugInformationFormat>OldStyle</DebugInformationFormat>
61 <OmitDefaultLibName>true</OmitDefaultLibName>
62 <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
63 </ClCompile>
64 </ItemDefinitionGroup>
65 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Debug' ">
66 <ClCompile>
67 <Optimization>Disabled</Optimization>
68 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
69 <PreprocessorDefinitions>_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
70 <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
71 </ClCompile>
72 </ItemDefinitionGroup>
73 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' ">
74 <ClCompile>
75 <Optimization>MinSpace</Optimization>
76 <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
77 <FunctionLevelLinking>true</FunctionLevelLinking>
78 <IntrinsicFunctions>true</IntrinsicFunctions>
79 <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
80 </ClCompile>
81 <Link>
82 <EnableCOMDATFolding>true</EnableCOMDATFolding>
83 <OptimizeReferences>true</OptimizeReferences>
84 </Link>
85 </ItemDefinitionGroup>
86</Project>
diff --git a/src/ext/Msmq/Directory.Build.props b/src/ext/Msmq/Directory.Build.props
new file mode 100644
index 00000000..f83cc154
--- /dev/null
+++ b/src/ext/Msmq/Directory.Build.props
@@ -0,0 +1,29 @@
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 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.props
5 then update all of the repos.
6-->
7<Project>
8 <PropertyGroup>
9 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
10 <EnableSourceLink Condition=" '$(NCrunch)' == '1' ">false</EnableSourceLink>
11 <MSBuildWarningsAsMessages>MSB3246</MSBuildWarningsAsMessages>
12
13 <ProjectName Condition=" '$(ProjectName)' == '' ">$(MSBuildProjectName)</ProjectName>
14 <BaseOutputPath>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\))</BaseOutputPath>
15 <BaseIntermediateOutputPath>$(BaseOutputPath)obj\$(ProjectName)\</BaseIntermediateOutputPath>
16 <OutputPath>$(BaseOutputPath)$(Configuration)\</OutputPath>
17
18 <Authors>WiX Toolset Team</Authors>
19 <Company>WiX Toolset</Company>
20 <Copyright>Copyright (c) .NET Foundation and contributors. All rights reserved.</Copyright>
21 <PackageLicenseExpression>MS-RL</PackageLicenseExpression>
22 <Product>WiX Toolset</Product>
23 </PropertyGroup>
24
25 <Import Project="CSharp.Build.props" Condition=" '$(MSBuildProjectExtension)'=='.csproj' and Exists('CSharp.Build.props') " />
26 <Import Project="Cpp.Build.props" Condition=" Exists('Cpp.Build.props') And '$(MSBuildProjectExtension)'=='.vcxproj' " />
27 <Import Project="Wix.Build.props" Condition=" Exists('Wix.Build.props') And '$(MSBuildProjectExtension)'=='.wixproj' " />
28 <Import Project="Custom.Build.props" Condition=" Exists('Custom.Build.props') " />
29</Project>
diff --git a/src/ext/Msmq/Directory.Build.targets b/src/ext/Msmq/Directory.Build.targets
new file mode 100644
index 00000000..dac7452a
--- /dev/null
+++ b/src/ext/Msmq/Directory.Build.targets
@@ -0,0 +1,48 @@
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 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.targets
5 then update all of the repos.
6-->
7<!--
8 Replace PackageReferences with ProjectReferences when the projects can be found in .sln.
9 See the original here: https://github.com/dotnet/sdk/issues/1151#issuecomment-385133284
10-->
11<Project>
12 <PropertyGroup>
13 <ReplacePackageReferences>true</ReplacePackageReferences>
14 <TheSolutionPath Condition=" '$(NCrunch)'=='' ">$(SolutionPath)</TheSolutionPath>
15 <TheSolutionPath Condition=" '$(NCrunch)'=='1' ">$(NCrunchOriginalSolutionPath)</TheSolutionPath>
16 </PropertyGroup>
17
18 <Choose>
19 <When Condition="$(ReplacePackageReferences) AND '$(TheSolutionPath)' != '' AND '$(TheSolutionPath)' != '*undefined*' AND Exists('$(TheSolutionPath)')">
20
21 <PropertyGroup>
22 <SolutionFileContent>$([System.IO.File]::ReadAllText($(TheSolutionPath)))</SolutionFileContent>
23 <SmartSolutionDir>$([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) ))</SmartSolutionDir>
24 <RegexPattern>(?&lt;="[PackageName]", ")(.*)(?=", ")</RegexPattern>
25 </PropertyGroup>
26
27 <ItemGroup>
28 <!-- Keep the identity of the PackageReference -->
29 <SmartPackageReference Include="@(PackageReference)">
30 <PackageName>%(Identity)</PackageName>
31 <InSolution>$(SolutionFileContent.Contains('\%(Identity).csproj'))</InSolution>
32 </SmartPackageReference>
33
34 <!-- Filter them by mapping them to another ItemGroup using the WithMetadataValue item function -->
35 <PackageInSolution Include="@(SmartPackageReference->WithMetadataValue('InSolution', True))">
36 <Pattern>$(RegexPattern.Replace('[PackageName]','%(PackageName)') )</Pattern>
37 <SmartPath>$([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)'))</SmartPath>
38 </PackageInSolution>
39
40 <ProjectReference Include="@(PackageInSolution->'$(SmartSolutionDir)\%(SmartPath)' )"/>
41
42 <!-- Remove the package references that are now referenced as projects -->
43 <PackageReference Remove="@(PackageInSolution->'%(PackageName)' )"/>
44 </ItemGroup>
45
46 </When>
47 </Choose>
48</Project>
diff --git a/src/ext/Msmq/Msmq.wixext.sln b/src/ext/Msmq/Msmq.wixext.sln
new file mode 100644
index 00000000..e3ebed6d
--- /dev/null
+++ b/src/ext/Msmq/Msmq.wixext.sln
@@ -0,0 +1,61 @@
1
2Microsoft Visual Studio Solution File, Format Version 12.00
3# Visual Studio 15
4VisualStudioVersion = 15.0.28010.2016
5MinimumVisualStudioVersion = 10.0.40219.1
6Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msmqca", "src\ca\msmqca.vcxproj", "{CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}"
7EndProject
8Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "msmq", "src\wixlib\msmq.wixproj", "{42493058-5FC8-4F85-9884-FF3190E084B6}"
9EndProject
10Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Msmq.wixext", "src\wixext\WixToolset.Msmq.wixext.csproj", "{B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}"
11EndProject
12Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Msmq", "src\test\WixToolsetTest.Msmq\WixToolsetTest.Msmq.csproj", "{B63DA068-338F-473B-9097-FC4E64830A2A}"
13EndProject
14Global
15 GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 Debug|Any CPU = Debug|Any CPU
17 Debug|x86 = Debug|x86
18 Release|Any CPU = Release|Any CPU
19 Release|x86 = Release|x86
20 EndGlobalSection
21 GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 {CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}.Debug|Any CPU.ActiveCfg = Debug|Win32
23 {CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}.Debug|Any CPU.Build.0 = Debug|Win32
24 {CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}.Debug|x86.ActiveCfg = Debug|Win32
25 {CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}.Debug|x86.Build.0 = Debug|Win32
26 {CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}.Release|Any CPU.ActiveCfg = Release|Win32
27 {CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}.Release|Any CPU.Build.0 = Release|Win32
28 {CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}.Release|x86.ActiveCfg = Release|Win32
29 {CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}.Release|x86.Build.0 = Release|Win32
30 {42493058-5FC8-4F85-9884-FF3190E084B6}.Debug|Any CPU.ActiveCfg = Debug|x86
31 {42493058-5FC8-4F85-9884-FF3190E084B6}.Debug|Any CPU.Build.0 = Debug|x86
32 {42493058-5FC8-4F85-9884-FF3190E084B6}.Debug|x86.ActiveCfg = Debug|x86
33 {42493058-5FC8-4F85-9884-FF3190E084B6}.Debug|x86.Build.0 = Debug|x86
34 {42493058-5FC8-4F85-9884-FF3190E084B6}.Release|Any CPU.ActiveCfg = Release|x86
35 {42493058-5FC8-4F85-9884-FF3190E084B6}.Release|Any CPU.Build.0 = Release|x86
36 {42493058-5FC8-4F85-9884-FF3190E084B6}.Release|x86.ActiveCfg = Release|x86
37 {42493058-5FC8-4F85-9884-FF3190E084B6}.Release|x86.Build.0 = Release|x86
38 {B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 {B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 {B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}.Debug|x86.ActiveCfg = Debug|Any CPU
41 {B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}.Debug|x86.Build.0 = Debug|Any CPU
42 {B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 {B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}.Release|Any CPU.Build.0 = Release|Any CPU
44 {B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}.Release|x86.ActiveCfg = Release|Any CPU
45 {B990D81B-9F60-4EEE-B31D-B5D1EAA799EE}.Release|x86.Build.0 = Release|Any CPU
46 {B63DA068-338F-473B-9097-FC4E64830A2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 {B63DA068-338F-473B-9097-FC4E64830A2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 {B63DA068-338F-473B-9097-FC4E64830A2A}.Debug|x86.ActiveCfg = Debug|Any CPU
49 {B63DA068-338F-473B-9097-FC4E64830A2A}.Debug|x86.Build.0 = Debug|Any CPU
50 {B63DA068-338F-473B-9097-FC4E64830A2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 {B63DA068-338F-473B-9097-FC4E64830A2A}.Release|Any CPU.Build.0 = Release|Any CPU
52 {B63DA068-338F-473B-9097-FC4E64830A2A}.Release|x86.ActiveCfg = Release|Any CPU
53 {B63DA068-338F-473B-9097-FC4E64830A2A}.Release|x86.Build.0 = Release|Any CPU
54 EndGlobalSection
55 GlobalSection(SolutionProperties) = preSolution
56 HideSolutionNode = FALSE
57 EndGlobalSection
58 GlobalSection(ExtensibilityGlobals) = postSolution
59 SolutionGuid = {5524C948-C115-4690-9BC4-44E3E963F960}
60 EndGlobalSection
61EndGlobal
diff --git a/src/ext/Msmq/README.md b/src/ext/Msmq/README.md
new file mode 100644
index 00000000..fa3c277f
--- /dev/null
+++ b/src/ext/Msmq/README.md
@@ -0,0 +1,2 @@
1# Msmq.wixext
2WixToolset.Msmq.wixext - MSMQ WiX Toolset Extension
diff --git a/src/ext/Msmq/appveyor.cmd b/src/ext/Msmq/appveyor.cmd
new file mode 100644
index 00000000..f493b577
--- /dev/null
+++ b/src/ext/Msmq/appveyor.cmd
@@ -0,0 +1,14 @@
1@setlocal
2@pushd %~dp0
3
4nuget restore || exit /b
5
6msbuild -p:Configuration=Release -t:Restore || exit /b
7
8msbuild -p:Configuration=Release src\test\WixToolsetTest.Msmq\WixToolsetTest.Msmq.csproj || exit /b
9dotnet test -c Release --no-build src\test\WixToolsetTest.Msmq || exit /b
10
11msbuild -p:Configuration=Release -t:Pack src\wixext\WixToolset.Msmq.wixext.csproj || exit /b
12
13@popd
14@endlocal \ No newline at end of file
diff --git a/src/ext/Msmq/appveyor.yml b/src/ext/Msmq/appveyor.yml
new file mode 100644
index 00000000..7c686b04
--- /dev/null
+++ b/src/ext/Msmq/appveyor.yml
@@ -0,0 +1,40 @@
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# Do NOT modify this file. Update the canonical version in Home\repo-template\src\appveyor.yml
4# then update all of the repos.
5
6branches:
7 only:
8 - master
9 - develop
10
11image: Visual Studio 2019
12
13version: 0.0.0.{build}
14configuration: Release
15
16environment:
17 DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
18 DOTNET_CLI_TELEMETRY_OPTOUT: 1
19 NUGET_XMLDOC_MODE: skip
20
21build_script:
22 - appveyor.cmd
23
24pull_requests:
25 do_not_increment_build_number: true
26
27nuget:
28 disable_publish_on_pr: true
29
30skip_branch_with_pr: true
31skip_tags: true
32
33artifacts:
34- path: build\Release\**\*.nupkg
35 name: nuget
36
37notifications:
38- provider: Slack
39 incoming_webhook:
40 secure: p5xuu+4x2JHfwGDMDe5KcG1k7gZxqYc4jWVwvyNZv5cvkubPD2waJs5yXMAXZNN7Z63/3PWHb7q4KoY/99AjauYa1nZ4c5qYqRPFRBKTHfA=
diff --git a/src/ext/Msmq/ca/custommsierrors.h b/src/ext/Msmq/ca/custommsierrors.h
new file mode 100644
index 00000000..0c1b23b7
--- /dev/null
+++ b/src/ext/Msmq/ca/custommsierrors.h
@@ -0,0 +1,4 @@
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#define msierrMsmqCannotConnect 28101
diff --git a/src/ext/Msmq/ca/dllmain.cpp b/src/ext/Msmq/ca/dllmain.cpp
new file mode 100644
index 00000000..35ae6d1c
--- /dev/null
+++ b/src/ext/Msmq/ca/dllmain.cpp
@@ -0,0 +1,26 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5/********************************************************************
6DllMain - standard entry point for all WiX custom actions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE 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}
diff --git a/src/ext/Msmq/ca/mqcost.h b/src/ext/Msmq/ca/mqcost.h
new file mode 100644
index 00000000..a40b7437
--- /dev/null
+++ b/src/ext/Msmq/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/ext/Msmq/ca/mqexec.cpp b/src/ext/Msmq/ca/mqexec.cpp
new file mode 100644
index 00000000..ff7e9b14
--- /dev/null
+++ b/src/ext/Msmq/ca/mqexec.cpp
@@ -0,0 +1,192 @@
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 MessageQueuingExecuteInstall - CUSTOM ACTION ENTRY POINT
8
9 Input: deferred CustomActionData - MessageQueuingExecuteInstall
10********************************************************************/
11extern "C" UINT __stdcall MessageQueuingExecuteInstall(MSIHANDLE hInstall)
12{
13 HRESULT hr = S_OK;
14 UINT er = ERROR_SUCCESS;
15
16 LPWSTR pwzCustomActionData = NULL;
17 LPWSTR pwzData = NULL;
18
19 // initialize
20 hr = WcaInitialize(hInstall, "MessageQueuingExecuteInstall");
21 ExitOnFailure(hr, "Failed to initialize MessageQueuingExecuteInstall");
22
23 hr = MqiExecInitialize();
24 ExitOnFailure(hr, "Failed to initialize");
25
26 // get custom action data
27 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
28 ExitOnFailure(hr, "Failed to get CustomActionData");
29 pwzData = pwzCustomActionData;
30
31 // create message queues
32 hr = MqiCreateMessageQueues(&pwzData);
33 ExitOnFailure(hr, "Failed to create message queues");
34 if (S_FALSE == hr) ExitFunction();
35
36 // add message queue permissions
37 hr = MqiAddMessageQueuePermissions(&pwzData);
38 ExitOnFailure(hr, "Failed to add message queue permissions");
39 if (S_FALSE == hr) ExitFunction();
40
41 hr = S_OK;
42
43LExit:
44 // clean up
45 ReleaseStr(pwzCustomActionData);
46
47 // uninitialize
48 MqiExecUninitialize();
49
50 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
51 return WcaFinalize(er);
52}
53
54/********************************************************************
55 MessageQueuingRollbackInstall - CUSTOM ACTION ENTRY POINT
56
57 Input: deferred CustomActionData - MessageQueuingRollbackInstall
58********************************************************************/
59extern "C" UINT __stdcall MessageQueuingRollbackInstall(MSIHANDLE hInstall)
60{
61 HRESULT hr = S_OK;
62 UINT er = ERROR_SUCCESS;
63
64 LPWSTR pwzCustomActionData = NULL;
65 LPWSTR pwzData = NULL;
66
67 // initialize
68 hr = WcaInitialize(hInstall, "MessageQueuingRollbackInstall");
69 ExitOnFailure(hr, "Failed to initialize MessageQueuingRollbackInstall");
70
71 hr = MqiExecInitialize();
72 ExitOnFailure(hr, "Failed to initialize");
73
74 // get custom action data
75 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
76 ExitOnFailure(hr, "Failed to get CustomActionData");
77 pwzData = pwzCustomActionData;
78
79 // add message queue permissions
80 hr = MqiRollbackAddMessageQueuePermissions(&pwzData);
81 ExitOnFailure(hr, "Failed to rollback add message queue permissions");
82
83 // create message queues
84 hr = MqiRollbackCreateMessageQueues(&pwzData);
85 ExitOnFailure(hr, "Failed to rollback create message queues");
86
87 hr = S_OK;
88
89LExit:
90 // clean up
91 ReleaseStr(pwzCustomActionData);
92
93 // uninitialize
94 MqiExecUninitialize();
95
96 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
97 return WcaFinalize(er);
98}
99
100/********************************************************************
101 MessageQueuingExecuteUninstall - CUSTOM ACTION ENTRY POINT
102
103 Input: deferred CustomActionData - MessageQueuingExecuteUninstall
104********************************************************************/
105extern "C" UINT __stdcall MessageQueuingExecuteUninstall(MSIHANDLE hInstall)
106{
107 HRESULT hr = S_OK;
108 UINT er = ERROR_SUCCESS;
109
110 LPWSTR pwzCustomActionData = NULL;
111 LPWSTR pwzData = NULL;
112
113 // initialize
114 hr = WcaInitialize(hInstall, "MessageQueuingExecuteUninstall");
115 ExitOnFailure(hr, "Failed to initialize MessageQueuingExecuteUninstall");
116
117 hr = MqiExecInitialize();
118 ExitOnFailure(hr, "Failed to initialize");
119
120 // get custom action data
121 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
122 ExitOnFailure(hr, "Failed to get CustomActionData");
123 pwzData = pwzCustomActionData;
124
125 // remove message queue permissions
126 hr = MqiRemoveMessageQueuePermissions(&pwzData);
127 ExitOnFailure(hr, "Failed to remove message queue permissions");
128 if (S_FALSE == hr) ExitFunction();
129
130 // delete message queues
131 hr = MqiDeleteMessageQueues(&pwzData);
132 ExitOnFailure(hr, "Failed to delete message queues");
133 if (S_FALSE == hr) ExitFunction();
134
135 hr = S_OK;
136
137LExit:
138 // clean up
139 ReleaseStr(pwzCustomActionData);
140
141 // uninitialize
142 MqiExecUninitialize();
143
144 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
145 return WcaFinalize(er);
146}
147
148/********************************************************************
149 MessageQueuingRollbackUninstall - CUSTOM ACTION ENTRY POINT
150
151 Input: deferred CustomActionData - MessageQueuingRollbackUninstall
152********************************************************************/
153extern "C" UINT __stdcall MessageQueuingRollbackUninstall(MSIHANDLE hInstall)
154{
155 HRESULT hr = S_OK;
156 UINT er = ERROR_SUCCESS;
157
158 LPWSTR pwzCustomActionData = NULL;
159 LPWSTR pwzData = NULL;
160
161 // initialize
162 hr = WcaInitialize(hInstall, "MessageQueuingRollbackUninstall");
163 ExitOnFailure(hr, "Failed to initialize MessageQueuingRollbackUninstall");
164
165 hr = MqiExecInitialize();
166 ExitOnFailure(hr, "Failed to initialize");
167
168 // get custom action data
169 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
170 ExitOnFailure(hr, "Failed to get CustomActionData");
171 pwzData = pwzCustomActionData;
172
173 // delete message queues
174 hr = MqiRollbackDeleteMessageQueues(&pwzData);
175 ExitOnFailure(hr, "Failed to delete message queues");
176
177 // remove message queue permissions
178 hr = MqiRollbackRemoveMessageQueuePermissions(&pwzData);
179 ExitOnFailure(hr, "Failed to remove message queue permissions");
180
181 hr = S_OK;
182
183LExit:
184 // clean up
185 ReleaseStr(pwzCustomActionData);
186
187 // uninitialize
188 MqiExecUninitialize();
189
190 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
191 return WcaFinalize(er);
192}
diff --git a/src/ext/Msmq/ca/mqqueueexec.cpp b/src/ext/Msmq/ca/mqqueueexec.cpp
new file mode 100644
index 00000000..e4304ab8
--- /dev/null
+++ b/src/ext/Msmq/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 MqiExecInitialize()
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 MqiExecUninitialize()
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/ext/Msmq/ca/mqqueueexec.h b/src/ext/Msmq/ca/mqqueueexec.h
new file mode 100644
index 00000000..76bc2023
--- /dev/null
+++ b/src/ext/Msmq/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 MqiExecInitialize();
6void MqiExecUninitialize();
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/ext/Msmq/ca/mqqueuesched.cpp b/src/ext/Msmq/ca/mqqueuesched.cpp
new file mode 100644
index 00000000..01777ea4
--- /dev/null
+++ b/src/ext/Msmq/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 MqiSchedInitialize()
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 MqiSchedUninitialize()
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/ext/Msmq/ca/mqqueuesched.h b/src/ext/Msmq/ca/mqqueuesched.h
new file mode 100644
index 00000000..c9381e0a
--- /dev/null
+++ b/src/ext/Msmq/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 MqiSchedInitialize();
58void MqiSchedUninitialize();
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/ext/Msmq/ca/mqsched.cpp b/src/ext/Msmq/ca/mqsched.cpp
new file mode 100644
index 00000000..4c994901
--- /dev/null
+++ b/src/ext/Msmq/ca/mqsched.cpp
@@ -0,0 +1,196 @@
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 MessageQueuingInstall - CUSTOM ACTION ENTRY POINT for installing MSMQ message queues
8
9********************************************************************/
10extern "C" UINT __stdcall MessageQueuingInstall(MSIHANDLE hInstall)
11{
12 HRESULT hr = S_OK;
13 UINT er = ERROR_SUCCESS;
14
15 MQI_MESSAGE_QUEUE_LIST lstMessageQueues;
16 MQI_MESSAGE_QUEUE_PERMISSION_LIST lstMessageQueuePermissions;
17
18 int iCost = 0;
19 LPWSTR pwzRollbackActionData = NULL;
20 LPWSTR pwzExecuteActionData = NULL;
21
22 ::ZeroMemory(&lstMessageQueues, sizeof(lstMessageQueues));
23 ::ZeroMemory(&lstMessageQueuePermissions, sizeof(lstMessageQueuePermissions));
24
25 // initialize
26 hr = WcaInitialize(hInstall, "MessageQueuingInstall");
27 ExitOnFailure(hr, "Failed to initialize");
28
29 do
30 {
31 hr = MqiSchedInitialize();
32 if (S_FALSE == hr)
33 {
34 WcaLog(LOGMSG_STANDARD, "Failed to load mqrt.dll.");
35 er = WcaErrorMessage(msierrMsmqCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
36 switch (er)
37 {
38 case IDABORT:
39 ExitFunction1(hr = E_FAIL); // bail with error
40 case IDRETRY:
41 break; // retry
42 case IDIGNORE: __fallthrough;
43 default:
44 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
45 }
46 }
47 ExitOnFailure(hr, "Failed to initialize MSMQ.");
48 } while (S_FALSE == hr);
49
50 // read message queues
51 hr = MqiMessageQueueRead(&lstMessageQueues);
52 ExitOnFailure(hr, "Failed to read MessageQueue table");
53
54 // read message queue permissions
55 hr = MqiMessageQueuePermissionRead(&lstMessageQueues, &lstMessageQueuePermissions);
56 ExitOnFailure(hr, "Failed to read message queue permissions");
57
58 // verify message queue elementes
59 hr = MqiMessageQueueVerify(&lstMessageQueues);
60 ExitOnFailure(hr, "Failed to verify message queue elements.");
61
62 if (lstMessageQueues.iInstallCount || lstMessageQueuePermissions.iInstallCount)
63 {
64 // schedule rollback action
65 hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzRollbackActionData);
66 ExitOnFailure(hr, "Failed to add message queue permissions to rollback action data");
67
68 hr = MqiMessageQueueInstall(&lstMessageQueues, TRUE, &pwzRollbackActionData);
69 ExitOnFailure(hr, "Failed to add message queues to rollback action data");
70
71 hr = WcaDoDeferredAction(L"MessageQueuingRollbackInstall", pwzRollbackActionData, 0);
72 ExitOnFailure(hr, "Failed to schedule MessageQueuingRollbackInstall");
73
74 // schedule execute action
75 hr = MqiMessageQueueInstall(&lstMessageQueues, FALSE, &pwzExecuteActionData);
76 ExitOnFailure(hr, "Failed to add message queues to execute action data");
77 iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_CREATE;
78
79 hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzExecuteActionData);
80 ExitOnFailure(hr, "Failed to add message queue permissions to execute action data");
81 iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_PERMISSION_ADD;
82
83 hr = WcaDoDeferredAction(L"MessageQueuingExecuteInstall", pwzExecuteActionData, iCost);
84 ExitOnFailure(hr, "Failed to schedule MessageQueuingExecuteInstall");
85 }
86
87 hr = S_OK;
88
89LExit:
90 // clean up
91 MqiMessageQueueFreeList(&lstMessageQueues);
92 MqiMessageQueuePermissionFreeList(&lstMessageQueuePermissions);
93
94 ReleaseStr(pwzRollbackActionData);
95 ReleaseStr(pwzExecuteActionData);
96
97 // uninitialize
98 MqiSchedUninitialize();
99
100 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
101 return WcaFinalize(er);
102}
103
104
105/********************************************************************
106 MessageQueuingUninstall - CUSTOM ACTION ENTRY POINT for uninstalling MSMQ message queues
107
108********************************************************************/
109extern "C" UINT __stdcall MessageQueuingUninstall(MSIHANDLE hInstall)
110{
111 HRESULT hr = S_OK;
112 UINT er = ERROR_SUCCESS;
113
114 MQI_MESSAGE_QUEUE_LIST lstMessageQueues;
115 MQI_MESSAGE_QUEUE_PERMISSION_LIST lstMessageQueuePermissions;
116
117 int iCost = 0;
118 LPWSTR pwzRollbackActionData = NULL;
119 LPWSTR pwzExecuteActionData = NULL;
120
121 ::ZeroMemory(&lstMessageQueues, sizeof(lstMessageQueues));
122 ::ZeroMemory(&lstMessageQueuePermissions, sizeof(lstMessageQueuePermissions));
123
124 // initialize
125 hr = WcaInitialize(hInstall, "MessageQueuingUninstall");
126 ExitOnFailure(hr, "Failed to initialize");
127
128 do
129 {
130 hr = MqiSchedInitialize();
131 if (S_FALSE == hr)
132 {
133 WcaLog(LOGMSG_STANDARD, "Failed to load mqrt.dll.");
134 er = WcaErrorMessage(msierrMsmqCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
135 switch (er)
136 {
137 case IDABORT:
138 ExitFunction1(hr = E_FAIL); // bail with error
139 case IDRETRY:
140 break; // retry
141 case IDIGNORE: __fallthrough;
142 default:
143 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
144 }
145 }
146 ExitOnFailure(hr, "Failed to initialize MSMQ.");
147 } while (S_FALSE == hr);
148
149 // read message queues
150 hr = MqiMessageQueueRead(&lstMessageQueues);
151 ExitOnFailure(hr, "Failed to read MessageQueue table");
152
153 // read message queue permissions
154 hr = MqiMessageQueuePermissionRead(&lstMessageQueues, &lstMessageQueuePermissions);
155 ExitOnFailure(hr, "Failed to read message queue permissions");
156
157 if (lstMessageQueues.iUninstallCount || lstMessageQueuePermissions.iUninstallCount)
158 {
159 // schedule rollback action
160 hr = MqiMessageQueueUninstall(&lstMessageQueues, TRUE, &pwzRollbackActionData);
161 ExitOnFailure(hr, "Failed to add message queues to rollback action data");
162
163 hr = MqiMessageQueuePermissionUninstall(&lstMessageQueuePermissions, &pwzRollbackActionData);
164 ExitOnFailure(hr, "Failed to add message queue permissions to rollback action data");
165
166 hr = WcaDoDeferredAction(L"MessageQueuingRollbackUninstall", pwzRollbackActionData, 0);
167 ExitOnFailure(hr, "Failed to schedule MessageQueuingRollbackUninstall");
168
169 // schedule execute action
170 hr = MqiMessageQueuePermissionUninstall(&lstMessageQueuePermissions, &pwzExecuteActionData);
171 ExitOnFailure(hr, "Failed to add message queue permissions to execute action data");
172
173 hr = MqiMessageQueueUninstall(&lstMessageQueues, FALSE, &pwzExecuteActionData);
174 ExitOnFailure(hr, "Failed to add message queues to execute action data");
175 iCost += lstMessageQueues.iUninstallCount * COST_MESSAGE_QUEUE_DELETE;
176
177 hr = WcaDoDeferredAction(L"MessageQueuingExecuteUninstall", pwzExecuteActionData, iCost);
178 ExitOnFailure(hr, "Failed to schedule MessageQueuingExecuteUninstall");
179 }
180
181 hr = S_OK;
182
183LExit:
184 // clean up
185 MqiMessageQueueFreeList(&lstMessageQueues);
186 MqiMessageQueuePermissionFreeList(&lstMessageQueuePermissions);
187
188 ReleaseStr(pwzRollbackActionData);
189 ReleaseStr(pwzExecuteActionData);
190
191 // uninitialize
192 MqiSchedUninitialize();
193
194 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
195 return WcaFinalize(er);
196}
diff --git a/src/ext/Msmq/ca/mqutilexec.cpp b/src/ext/Msmq/ca/mqutilexec.cpp
new file mode 100644
index 00000000..a9c56e02
--- /dev/null
+++ b/src/ext/Msmq/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/ext/Msmq/ca/mqutilexec.h b/src/ext/Msmq/ca/mqutilexec.h
new file mode 100644
index 00000000..d3dc17a1
--- /dev/null
+++ b/src/ext/Msmq/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/ext/Msmq/ca/mqutilsched.cpp b/src/ext/Msmq/ca/mqutilsched.cpp
new file mode 100644
index 00000000..4353a6d6
--- /dev/null
+++ b/src/ext/Msmq/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/ext/Msmq/ca/mqutilsched.h b/src/ext/Msmq/ca/mqutilsched.h
new file mode 100644
index 00000000..e172257d
--- /dev/null
+++ b/src/ext/Msmq/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/ext/Msmq/ca/msmqca.def b/src/ext/Msmq/ca/msmqca.def
new file mode 100644
index 00000000..4902858f
--- /dev/null
+++ b/src/ext/Msmq/ca/msmqca.def
@@ -0,0 +1,12 @@
1; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3
4LIBRARY "msmqca"
5
6EXPORTS
7 MessageQueuingInstall
8 MessageQueuingUninstall
9 MessageQueuingExecuteInstall
10 MessageQueuingRollbackInstall
11 MessageQueuingExecuteUninstall
12 MessageQueuingRollbackUninstall
diff --git a/src/ext/Msmq/ca/msmqca.vcxproj b/src/ext/Msmq/ca/msmqca.vcxproj
new file mode 100644
index 00000000..c4cb3323
--- /dev/null
+++ b/src/ext/Msmq/ca/msmqca.vcxproj
@@ -0,0 +1,71 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <Import Project="..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props')" />
6 <Import Project="..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props" Condition="Exists('..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props')" />
7
8 <ItemGroup Label="ProjectConfigurations">
9 <ProjectConfiguration Include="Debug|Win32">
10 <Configuration>Debug</Configuration>
11 <Platform>Win32</Platform>
12 </ProjectConfiguration>
13 <ProjectConfiguration Include="Release|Win32">
14 <Configuration>Release</Configuration>
15 <Platform>Win32</Platform>
16 </ProjectConfiguration>
17 </ItemGroup>
18
19 <PropertyGroup Label="Globals">
20 <ProjectGuid>{CAD56A7E-342B-4324-9DCB-BCEB8F3BC80D}</ProjectGuid>
21 <ConfigurationType>DynamicLibrary</ConfigurationType>
22 <TargetName>msmqca</TargetName>
23 <PlatformToolset>v142</PlatformToolset>
24 <CharacterSet>Unicode</CharacterSet>
25 <ProjectModuleDefinitionFile>msmqca.def</ProjectModuleDefinitionFile>
26 <Description>WiX Toolset MSMQ CustomAction</Description>
27 </PropertyGroup>
28
29 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
30 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
31
32 <PropertyGroup>
33 <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries>
34 </PropertyGroup>
35
36 <ItemGroup>
37 <ClCompile Include="dllmain.cpp">
38 <PrecompiledHeader>Create</PrecompiledHeader>
39 </ClCompile>
40 <ClCompile Include="mqexec.cpp" />
41 <ClCompile Include="mqqueueexec.cpp" />
42 <ClCompile Include="mqqueuesched.cpp" />
43 <ClCompile Include="mqsched.cpp" />
44 <ClCompile Include="mqutilexec.cpp" />
45 <ClCompile Include="mqutilsched.cpp" />
46 </ItemGroup>
47
48 <ItemGroup>
49 <ClInclude Include="mqcost.h" />
50 <ClInclude Include="mqqueueexec.h" />
51 <ClInclude Include="mqqueuesched.h" />
52 <ClInclude Include="mqutilexec.h" />
53 <ClInclude Include="mqutilsched.h" />
54 <ClInclude Include="precomp.h" />
55 </ItemGroup>
56
57 <ItemGroup>
58 <None Include="packages.config" />
59 <None Include="msmqca.def" />
60 </ItemGroup>
61
62 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
63
64 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
65 <PropertyGroup>
66 <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
67 </PropertyGroup>
68 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props'))" />
69 <Error Condition="!Exists('..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props'))" />
70 </Target>
71</Project>
diff --git a/src/ext/Msmq/ca/packages.config b/src/ext/Msmq/ca/packages.config
new file mode 100644
index 00000000..9d88f529
--- /dev/null
+++ b/src/ext/Msmq/ca/packages.config
@@ -0,0 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="WixToolset.DUtil" version="4.0.56" targetFramework="native" />
4 <package id="WixToolset.WcaUtil" version="4.0.17" targetFramework="native" />
5</packages> \ No newline at end of file
diff --git a/src/ext/Msmq/ca/precomp.h b/src/ext/Msmq/ca/precomp.h
new file mode 100644
index 00000000..cbbff6ea
--- /dev/null
+++ b/src/ext/Msmq/ca/precomp.h
@@ -0,0 +1,23 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#include <windows.h>
6#include <msiquery.h>
7#include <strsafe.h>
8#include <ntsecapi.h>
9#include <aclapi.h>
10#include <mq.h>
11
12#include "wcautil.h"
13#include "memutil.h"
14#include "strutil.h"
15#include "wiutil.h"
16
17#include "CustomMsiErrors.h"
18
19#include "mqcost.h"
20#include "mqutilsched.h"
21#include "mqqueuesched.h"
22#include "mqutilexec.h"
23#include "mqqueueexec.h"
diff --git a/src/ext/Msmq/nuget.config b/src/ext/Msmq/nuget.config
new file mode 100644
index 00000000..db7aba29
--- /dev/null
+++ b/src/ext/Msmq/nuget.config
@@ -0,0 +1,17 @@
1<?xml version="1.0" encoding="utf-8"?>
2<configuration>
3 <packageSources>
4 <clear />
5 <add key="wixtoolset-burn" value="https://ci.appveyor.com/nuget/wixtoolset-burn" />
6 <add key="wixtoolset-data" value="https://ci.appveyor.com/nuget/wixtoolset-data" />
7 <add key="wixtoolset-extensibility" value="https://ci.appveyor.com/nuget/wixtoolset-extensibility" />
8 <add key="wixtoolset-core" value="https://ci.appveyor.com/nuget/wixtoolset-core" />
9 <add key="wixtoolset-core-native" value="https://ci.appveyor.com/nuget/wixtoolset-core-native" />
10 <add key="wixtoolset-dtf" value="https://ci.appveyor.com/nuget/wixtoolset-dtf" />
11 <add key="wixtoolset-dutil" value="https://ci.appveyor.com/nuget/wixtoolset-dutil" />
12 <add key="wixtoolset-wcautil" value="https://ci.appveyor.com/nuget/wixtoolset-wcautil" />
13 <add key="wixtoolset-tools" value="https://ci.appveyor.com/nuget/wixtoolset-tools" />
14 <add key="wixbuildtools" value="https://ci.appveyor.com/nuget/wixbuildtools" />
15 <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
16 </packageSources>
17</configuration> \ No newline at end of file
diff --git a/src/ext/Msmq/test/WixToolsetTest.Msmq/MsmqExtensionFixture.cs b/src/ext/Msmq/test/WixToolsetTest.Msmq/MsmqExtensionFixture.cs
new file mode 100644
index 00000000..057b0a9d
--- /dev/null
+++ b/src/ext/Msmq/test/WixToolsetTest.Msmq/MsmqExtensionFixture.cs
@@ -0,0 +1,32 @@
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 WixToolsetTest.Msmq
4{
5 using System.Linq;
6 using WixBuildTools.TestSupport;
7 using WixToolset.Core.TestPackage;
8 using WixToolset.Msmq;
9 using Xunit;
10
11 public class MsmqExtensionFixture
12 {
13 [Fact]
14 public void CanBuildUsingMessageQueue()
15 {
16 var folder = TestData.Get(@"TestData\UsingMessageQueue");
17 var build = new Builder(folder, typeof(MsmqExtensionFactory), new[] { folder });
18
19 var results = build.BuildAndQuery(Build, "MessageQueue");
20 Assert.Equal(new[]
21 {
22 "MessageQueue:TestMQ\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\t\t\tMQLabel\t\tMQPath\t\t\t\t0",
23 }, results);
24 }
25
26 private static void Build(string[] args)
27 {
28 var result = WixRunner.Execute(args)
29 .AssertSuccess();
30 }
31 }
32}
diff --git a/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/Package.en-us.wxl b/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/Package.en-us.wxl
new file mode 100644
index 00000000..38c12ac1
--- /dev/null
+++ b/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/Package.en-us.wxl
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2
3<!--
4This file contains the declaration of all the localizable strings.
5-->
6<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7
8 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
9 <String Id="FeatureTitle">MsiPackage</String>
10
11</WixLocalization>
diff --git a/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/Package.wxs b/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/Package.wxs
new file mode 100644
index 00000000..bd31e81f
--- /dev/null
+++ b/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/Package.wxs
@@ -0,0 +1,15 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" InstallerVersion="200">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 <ComponentGroupRef Id="ProductComponents" />
7 </Feature>
8 </Package>
9
10 <Fragment>
11 <StandardDirectory Id="ProgramFilesFolder">
12 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
13 </StandardDirectory>
14 </Fragment>
15</Wix>
diff --git a/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/PackageComponents.wxs b/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/PackageComponents.wxs
new file mode 100644
index 00000000..ff9f7d92
--- /dev/null
+++ b/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/PackageComponents.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:msmq="http://wixtoolset.org/schemas/v4/wxs/msmq">
4 <Fragment>
5 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
6 <Component>
7 <File Source="example.txt" />
8 <msmq:MessageQueue Id="TestMQ" Label="MQLabel" PathName="MQPath" />
9 </Component>
10 </ComponentGroup>
11 </Fragment>
12</Wix>
diff --git a/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/example.txt b/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Msmq/test/WixToolsetTest.Msmq/TestData/UsingMessageQueue/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Msmq/test/WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj b/src/ext/Msmq/test/WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj
new file mode 100644
index 00000000..7f74e043
--- /dev/null
+++ b/src/ext/Msmq/test/WixToolsetTest.Msmq/WixToolsetTest.Msmq.csproj
@@ -0,0 +1,41 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netcoreapp3.1</TargetFramework>
7 <IsPackable>false</IsPackable>
8 </PropertyGroup>
9
10 <PropertyGroup>
11 <NoWarn>NU1701</NoWarn>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <Content Include="TestData\UsingMessageQueue\example.txt" CopyToOutputDirectory="PreserveNewest" />
16 <Content Include="TestData\UsingMessageQueue\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
17 <Content Include="TestData\UsingMessageQueue\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
18 <Content Include="TestData\UsingMessageQueue\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
19 </ItemGroup>
20
21 <ItemGroup>
22 <ProjectReference Include="..\..\wixext\WixToolset.Msmq.wixext.csproj" />
23 </ItemGroup>
24
25 <ItemGroup>
26 <PackageReference Include="WixToolset.Core" Version="4.0.*" />
27 <PackageReference Include="WixToolset.Core.Burn" Version="4.0.*" />
28 <PackageReference Include="WixToolset.Core.WindowsInstaller" Version="4.0.*" />
29 <PackageReference Include="WixToolset.Core.TestPackage" Version="4.0.*" />
30 </ItemGroup>
31
32 <ItemGroup>
33 <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" />
34 </ItemGroup>
35
36 <ItemGroup>
37 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
38 <PackageReference Include="xunit" Version="2.4.1" />
39 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
40 </ItemGroup>
41</Project>
diff --git a/src/ext/Msmq/wix.snk b/src/ext/Msmq/wix.snk
new file mode 100644
index 00000000..3908a66a
--- /dev/null
+++ b/src/ext/Msmq/wix.snk
Binary files differ
diff --git a/src/ext/Msmq/wixext/MsmqCompiler.cs b/src/ext/Msmq/wixext/MsmqCompiler.cs
new file mode 100644
index 00000000..cfc4ef65
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqCompiler.cs
@@ -0,0 +1,528 @@
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.Msmq
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Xml.Linq;
8 using WixToolset.Data;
9 using WixToolset.Extensibility;
10 using WixToolset.Msmq.Symbols;
11
12 /// <summary>
13 /// The compiler for the WiX Toolset MSMQ Extension.
14 /// </summary>
15 public sealed class MsmqCompiler : BaseCompilerExtension
16 {
17 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/msmq";
18
19 /// <summary>
20 /// </summary>
21 /// <remarks></remarks>
22 public enum MqiMessageQueueAttributes
23 {
24 Authenticate = (1 << 0),
25 Journal = (1 << 1),
26 Transactional = (1 << 2)
27 }
28
29 /// <summary>
30 /// </summary>
31 /// <remarks></remarks>
32 public enum MqiMessageQueuePrivacyLevel
33 {
34 None = 0,
35 Optional = 1,
36 Body = 2
37 }
38
39 /// <summary>
40 /// </summary>
41 /// <remarks></remarks>
42 public enum MqiMessageQueuePermission
43 {
44 DeleteMessage = (1 << 0),
45 PeekMessage = (1 << 1),
46 WriteMessage = (1 << 2),
47 DeleteJournalMessage = (1 << 3),
48 SetQueueProperties = (1 << 4),
49 GetQueueProperties = (1 << 5),
50 DeleteQueue = (1 << 6),
51 GetQueuePermissions = (1 << 7),
52 ChangeQueuePermissions = (1 << 8),
53 TakeQueueOwnership = (1 << 9),
54 ReceiveMessage = (1 << 10),
55 ReceiveJournalMessage = (1 << 11),
56 QueueGenericRead = (1 << 12),
57 QueueGenericWrite = (1 << 13),
58 QueueGenericExecute = (1 << 14),
59 QueueGenericAll = (1 << 15)
60 }
61
62 /// <summary>
63 /// Processes an element for the Compiler.
64 /// </summary>
65 /// <param name="parentElement">Parent element of element to process.</param>
66 /// <param name="element">Element to process.</param>
67 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
68 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
69 {
70 switch (parentElement.Name.LocalName)
71 {
72 case "Component":
73 var componentId = context["ComponentId"];
74 var directoryId = context["DirectoryId"];
75
76 switch (element.Name.LocalName)
77 {
78 case "MessageQueue":
79 this.ParseMessageQueueElement(intermediate, section, element, componentId);
80 break;
81 case "MessageQueuePermission":
82 this.ParseMessageQueuePermissionElement(intermediate, section, element, componentId, null);
83 break;
84 default:
85 this.ParseHelper.UnexpectedElement(parentElement, element);
86 break;
87 }
88 break;
89 default:
90 this.ParseHelper.UnexpectedElement(parentElement, element);
91 break;
92 }
93 }
94
95 /// <summary>
96 /// Parses an MSMQ message queue element.
97 /// </summary>
98 /// <param name="node">Element to parse.</param>
99 /// <param name="componentKey">Identifier of parent component.</param>
100 private void ParseMessageQueueElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentId)
101 {
102 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
103
104 Identifier id = null;
105 var basePriority = CompilerConstants.IntegerNotSet;
106 var journalQuota = CompilerConstants.IntegerNotSet;
107 string label = null;
108 string multicastAddress = null;
109 string pathName = null;
110 var privLevel = CompilerConstants.IntegerNotSet;
111 var quota = CompilerConstants.IntegerNotSet;
112 string serviceTypeGuid = null;
113 int attributes = 0;
114
115 foreach (var attrib in node.Attributes())
116 {
117 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
118 {
119 switch (attrib.Name.LocalName)
120 {
121 case "Id":
122 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
123 break;
124 case "Authenticate":
125 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
126 {
127 attributes |= (int)MqiMessageQueueAttributes.Authenticate;
128 }
129 else
130 {
131 attributes &= ~(int)MqiMessageQueueAttributes.Authenticate;
132 }
133 break;
134 case "BasePriority":
135 basePriority = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
136 break;
137 case "Journal":
138 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
139 {
140 attributes |= (int)MqiMessageQueueAttributes.Journal;
141 }
142 else
143 {
144 attributes &= ~(int)MqiMessageQueueAttributes.Journal;
145 }
146 break;
147 case "JournalQuota":
148 journalQuota = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
149 break;
150 case "Label":
151 label = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
152 break;
153 case "MulticastAddress":
154 multicastAddress = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
155 break;
156 case "PathName":
157 pathName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
158 break;
159 case "PrivLevel":
160 var privLevelAttr = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
161 switch (privLevelAttr)
162 {
163 case "none":
164 privLevel = (int)MqiMessageQueuePrivacyLevel.None;
165 break;
166 case "optional":
167 privLevel = (int)MqiMessageQueuePrivacyLevel.Optional;
168 break;
169 case "body":
170 privLevel = (int)MqiMessageQueuePrivacyLevel.Body;
171 break;
172 default:
173 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "MessageQueue", "PrivLevel", privLevelAttr, "none", "body", "optional"));
174 break;
175 }
176 break;
177 case "Quota":
178 quota = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
179 break;
180 case "Transactional":
181 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
182 {
183 attributes |= (int)MqiMessageQueueAttributes.Transactional;
184 }
185 else
186 {
187 attributes &= ~(int)MqiMessageQueueAttributes.Transactional;
188 }
189 break;
190 case "ServiceTypeGuid":
191 serviceTypeGuid = this.TryFormatGuidValue(this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib));
192 break;
193 default:
194 this.ParseHelper.UnexpectedAttribute(node, attrib);
195 break;
196 }
197 }
198 else
199 {
200 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
201 }
202 }
203
204 foreach (var child in node.Elements())
205 {
206 if (this.Namespace == child.Name.Namespace)
207 {
208 switch (child.Name.LocalName)
209 {
210 case "MessageQueuePermission":
211 this.ParseMessageQueuePermissionElement(intermediate, section, child, componentId, id?.Id);
212 break;
213 default:
214 this.ParseHelper.UnexpectedElement(node, child);
215 break;
216 }
217 }
218 else
219 {
220 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child);
221 }
222 }
223
224 var symbol = section.AddSymbol(new MessageQueueSymbol(sourceLineNumbers, id)
225 {
226 ComponentRef = componentId,
227 Label = label,
228 MulticastAddress = multicastAddress,
229 PathName = pathName,
230 ServiceTypeGuid = serviceTypeGuid,
231 Attributes = attributes,
232 });
233
234 if (CompilerConstants.IntegerNotSet != basePriority)
235 {
236 symbol.BasePriority = basePriority;
237 }
238 if (CompilerConstants.IntegerNotSet != journalQuota)
239 {
240 symbol.JournalQuota = journalQuota;
241 }
242
243 if (CompilerConstants.IntegerNotSet != privLevel)
244 {
245 symbol.PrivLevel = privLevel;
246 }
247 if (CompilerConstants.IntegerNotSet != quota)
248 {
249 symbol.Quota = quota;
250 }
251
252 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, "MessageQueuingInstall");
253 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, "MessageQueuingUninstall");
254 }
255
256 /// <summary>
257 /// Parses an MSMQ message queue permission element.
258 /// </summary>
259 /// <param name="node">Element to parse.</param>
260 /// <param name="componentKey">Identifier of parent component.</param>
261 /// <param name="applicationKey">Optional identifier of parent message queue.</param>
262 private void ParseMessageQueuePermissionElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentId, string messageQueueId)
263 {
264 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
265
266 Identifier id = null;
267 string user = null;
268 string group = null;
269 int permissions = 0;
270
271 foreach (var attrib in node.Attributes())
272 {
273 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
274 {
275 switch (attrib.Name.LocalName)
276 {
277 case "Id":
278 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
279 break;
280 case "MessageQueue":
281 if (null != messageQueueId)
282 {
283 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName));
284 }
285 messageQueueId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
286 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, MsmqSymbolDefinitions.MessageQueue, messageQueueId);
287 break;
288 case "User":
289 if (null != group)
290 {
291 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "User", "Group"));
292 }
293 user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
294 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user);
295 break;
296 case "Group":
297 if (null != user)
298 {
299 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Group", "User"));
300 }
301 group = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
302 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "Group", group);
303 break;
304 case "DeleteMessage":
305 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
306 {
307 permissions |= (int)MqiMessageQueuePermission.DeleteMessage;
308 }
309 else
310 {
311 permissions &= ~(int)MqiMessageQueuePermission.DeleteMessage;
312 }
313 break;
314 case "PeekMessage":
315 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
316 {
317 permissions |= (int)MqiMessageQueuePermission.PeekMessage;
318 }
319 else
320 {
321 permissions &= ~(int)MqiMessageQueuePermission.PeekMessage;
322 }
323 break;
324 case "WriteMessage":
325 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
326 {
327 permissions |= (int)MqiMessageQueuePermission.WriteMessage;
328 }
329 else
330 {
331 permissions &= ~(int)MqiMessageQueuePermission.WriteMessage;
332 }
333 break;
334 case "DeleteJournalMessage":
335 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
336 {
337 permissions |= (int)MqiMessageQueuePermission.DeleteJournalMessage;
338 }
339 else
340 {
341 permissions &= ~(int)MqiMessageQueuePermission.DeleteJournalMessage;
342 }
343 break;
344 case "SetQueueProperties":
345 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
346 {
347 permissions |= (int)MqiMessageQueuePermission.SetQueueProperties;
348 }
349 else
350 {
351 permissions &= ~(int)MqiMessageQueuePermission.SetQueueProperties;
352 }
353 break;
354 case "GetQueueProperties":
355 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
356 {
357 permissions |= (int)MqiMessageQueuePermission.GetQueueProperties;
358 }
359 else
360 {
361 permissions &= ~(int)MqiMessageQueuePermission.GetQueueProperties;
362 }
363 break;
364 case "DeleteQueue":
365 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
366 {
367 permissions |= (int)MqiMessageQueuePermission.DeleteQueue;
368 }
369 else
370 {
371 permissions &= ~(int)MqiMessageQueuePermission.DeleteQueue;
372 }
373 break;
374 case "GetQueuePermissions":
375 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
376 {
377 permissions |= (int)MqiMessageQueuePermission.GetQueuePermissions;
378 }
379 else
380 {
381 permissions &= ~(int)MqiMessageQueuePermission.GetQueuePermissions;
382 }
383 break;
384 case "ChangeQueuePermissions":
385 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
386 {
387 permissions |= (int)MqiMessageQueuePermission.ChangeQueuePermissions;
388 }
389 else
390 {
391 permissions &= ~(int)MqiMessageQueuePermission.ChangeQueuePermissions;
392 }
393 break;
394 case "TakeQueueOwnership":
395 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
396 {
397 permissions |= (int)MqiMessageQueuePermission.TakeQueueOwnership;
398 }
399 else
400 {
401 permissions &= ~(int)MqiMessageQueuePermission.TakeQueueOwnership;
402 }
403 break;
404 case "ReceiveMessage":
405 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
406 {
407 permissions |= (int)MqiMessageQueuePermission.ReceiveMessage;
408 }
409 else
410 {
411 permissions &= ~(int)MqiMessageQueuePermission.ReceiveMessage;
412 }
413 break;
414 case "ReceiveJournalMessage":
415 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
416 {
417 permissions |= (int)MqiMessageQueuePermission.ReceiveJournalMessage;
418 }
419 else
420 {
421 permissions &= ~(int)MqiMessageQueuePermission.ReceiveJournalMessage;
422 }
423 break;
424 case "QueueGenericRead":
425 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
426 {
427 permissions |= (int)MqiMessageQueuePermission.QueueGenericRead;
428 }
429 else
430 {
431 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericRead;
432 }
433 break;
434 case "QueueGenericWrite":
435 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
436 {
437 permissions |= (int)MqiMessageQueuePermission.QueueGenericWrite;
438 }
439 else
440 {
441 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericWrite;
442 }
443 break;
444 case "QueueGenericExecute":
445 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
446 {
447 permissions |= (int)MqiMessageQueuePermission.QueueGenericExecute;
448 }
449 else
450 {
451 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericExecute;
452 }
453 break;
454 case "QueueGenericAll":
455 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
456 {
457 permissions |= (int)MqiMessageQueuePermission.QueueGenericAll;
458 }
459 else
460 {
461 permissions &= ~(int)MqiMessageQueuePermission.QueueGenericAll;
462 }
463 break;
464 default:
465 this.ParseHelper.UnexpectedAttribute(node, attrib);
466 break;
467 }
468 }
469 else
470 {
471 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
472 }
473 }
474
475 if (null == id)
476 {
477 id = this.ParseHelper.CreateIdentifier("mqp", componentId, messageQueueId, user, group);
478 }
479
480 if (null == messageQueueId)
481 {
482 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "MessageQueue"));
483 }
484 if (null == user && null == group)
485 {
486 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "User", "Group"));
487 }
488
489 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
490
491 if (null != user)
492 {
493 section.AddSymbol(new MessageQueueUserPermissionSymbol(sourceLineNumbers, id)
494 {
495 ComponentRef = componentId,
496 MessageQueueRef = messageQueueId,
497 UserRef = user,
498 Permissions = permissions,
499 });
500 }
501 if (null != group)
502 {
503 section.AddSymbol(new MessageQueueGroupPermissionSymbol(sourceLineNumbers, id)
504 {
505 ComponentRef = componentId,
506 MessageQueueRef = messageQueueId,
507 GroupRef = group,
508 Permissions = permissions,
509 });
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 if (!Guid.TryParse(val, out var guid))
522 {
523 return val;
524 }
525 return guid.ToString("B").ToUpper();
526 }
527 }
528}
diff --git a/src/ext/Msmq/wixext/MsmqDecompiler.cs b/src/ext/Msmq/wixext/MsmqDecompiler.cs
new file mode 100644
index 00000000..aa8c34b6
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqDecompiler.cs
@@ -0,0 +1,305 @@
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.Msmq
4{
5#if TODO_CONSIDER_DECOMPILER
6 using System;
7 using System.Collections;
8 using System.Globalization;
9 using WixToolset.Data;
10 using WixToolset.Extensibility;
11 using Msmq = WixToolset.Extensions.Serialize.Msmq;
12 using Wix = WixToolset.Data.Serialize;
13
14 /// <summary>
15 /// The decompiler for the WiX Toolset MSMQ Extension.
16 /// </summary>
17 public sealed class MsmqDecompiler : DecompilerExtension
18 {
19 /// <summary>
20 /// Creates a decompiler for MSMQ Extension.
21 /// </summary>
22 public MsmqDecompiler()
23 {
24 this.TableDefinitions = MsmqExtensionData.GetExtensionTableDefinitions();
25 }
26
27 /// <summary>
28 /// Get the extensions library to be removed.
29 /// </summary>
30 /// <param name="tableDefinitions">Table definitions for library.</param>
31 /// <returns>Library to remove from decompiled output.</returns>
32 public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
33 {
34 return MsmqExtensionData.GetExtensionLibrary(tableDefinitions);
35 }
36
37 /// <summary>
38 /// Decompiles an extension table.
39 /// </summary>
40 /// <param name="table">The table to decompile.</param>
41 public override void DecompileTable(Table table)
42 {
43 switch (table.Name)
44 {
45 case "MessageQueue":
46 this.DecompileMessageQueueTable(table);
47 break;
48 case "MessageQueueUserPermission":
49 this.DecompileMessageQueueUserPermissionTable(table);
50 break;
51 case "MessageQueueGroupPermission":
52 this.DecompileMessageQueueGroupPermissionTable(table);
53 break;
54 default:
55 base.DecompileTable(table);
56 break;
57 }
58 }
59
60 /// <summary>
61 /// Decompile the MessageQueue table.
62 /// </summary>
63 /// <param name="table">The table to decompile.</param>
64 private void DecompileMessageQueueTable(Table table)
65 {
66 foreach (Row row in table.Rows)
67 {
68 Msmq.MessageQueue queue = new Msmq.MessageQueue();
69
70 queue.Id = (string)row[0];
71
72 if (null != row[2])
73 {
74 queue.BasePriority = (int)row[2];
75 }
76
77 if (null != row[3])
78 {
79 queue.JournalQuota = (int)row[3];
80 }
81
82 queue.Label = (string)row[4];
83
84 if (null != row[5])
85 {
86 queue.MulticastAddress = (string)row[5];
87 }
88
89 queue.PathName = (string)row[6];
90
91 if (null != row[7])
92 {
93 switch ((MsmqCompiler.MqiMessageQueuePrivacyLevel)row[7])
94 {
95 case MsmqCompiler.MqiMessageQueuePrivacyLevel.None:
96 queue.PrivLevel = Msmq.MessageQueue.PrivLevelType.none;
97 break;
98 case MsmqCompiler.MqiMessageQueuePrivacyLevel.Optional:
99 queue.PrivLevel = Msmq.MessageQueue.PrivLevelType.optional;
100 break;
101 case MsmqCompiler.MqiMessageQueuePrivacyLevel.Body:
102 queue.PrivLevel = Msmq.MessageQueue.PrivLevelType.body;
103 break;
104 default:
105 break;
106 }
107 }
108
109 if (null != row[8])
110 {
111 queue.Quota = (int)row[8];
112 }
113
114 if (null != row[9])
115 {
116 queue.ServiceTypeGuid = (string)row[9];
117 }
118
119 int attributes = (int)row[10];
120
121 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Authenticate))
122 {
123 queue.Authenticate = Msmq.YesNoType.yes;
124 }
125
126 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Journal))
127 {
128 queue.Journal = Msmq.YesNoType.yes;
129 }
130
131 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueueAttributes.Transactional))
132 {
133 queue.Transactional = Msmq.YesNoType.yes;
134 }
135
136 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
137 if (null != component)
138 {
139 component.AddChild(queue);
140 }
141 else
142 {
143 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
144 }
145 }
146 }
147
148 /// <summary>
149 /// Decompile the MessageQueueUserPermission table.
150 /// </summary>
151 /// <param name="table">The table to decompile.</param>
152 private void DecompileMessageQueueUserPermissionTable(Table table)
153 {
154 foreach (Row row in table.Rows)
155 {
156 Msmq.MessageQueuePermission queuePermission = new Msmq.MessageQueuePermission();
157
158 queuePermission.Id = (string)row[0];
159
160 if (null != row[2])
161 {
162 queuePermission.MessageQueue = (string)row[2];
163 }
164
165 queuePermission.User = (string)row[3];
166
167 DecompileMessageQueuePermissionAttributes(row, queuePermission);
168
169 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
170 if (null != component)
171 {
172 component.AddChild(queuePermission);
173 }
174 else
175 {
176 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
177 }
178 }
179 }
180
181 /// <summary>
182 /// Decompile the MessageQueueGroupPermission table.
183 /// </summary>
184 /// <param name="table">The table to decompile.</param>
185 private void DecompileMessageQueueGroupPermissionTable(Table table)
186 {
187 foreach (Row row in table.Rows)
188 {
189 Msmq.MessageQueuePermission queuePermission = new Msmq.MessageQueuePermission();
190
191 queuePermission.Id = (string)row[0];
192
193 if (null != row[2])
194 {
195 queuePermission.MessageQueue = (string)row[2];
196 }
197
198 queuePermission.Group = (string)row[3];
199
200 DecompileMessageQueuePermissionAttributes(row, queuePermission);
201
202 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
203 if (null != component)
204 {
205 component.AddChild(queuePermission);
206 }
207 else
208 {
209 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
210 }
211 }
212 }
213
214 /// <summary>
215 /// Decompile row attributes for the MessageQueueUserPermission and MessageQueueGroupPermission tables.
216 /// </summary>
217 /// <param name="row">The row to decompile.</param>
218 /// <param name="table">Target element.</param>
219 private void DecompileMessageQueuePermissionAttributes(Row row, Msmq.MessageQueuePermission queuePermission)
220 {
221 int attributes = (int)row[4];
222
223 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteMessage))
224 {
225 queuePermission.DeleteMessage = Msmq.YesNoType.yes;
226 }
227
228 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.PeekMessage))
229 {
230 queuePermission.PeekMessage = Msmq.YesNoType.yes;
231 }
232
233 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.WriteMessage))
234 {
235 queuePermission.WriteMessage = Msmq.YesNoType.yes;
236 }
237
238 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteJournalMessage))
239 {
240 queuePermission.DeleteJournalMessage = Msmq.YesNoType.yes;
241 }
242
243 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.SetQueueProperties))
244 {
245 queuePermission.SetQueueProperties = Msmq.YesNoType.yes;
246 }
247
248 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.GetQueueProperties))
249 {
250 queuePermission.GetQueueProperties = Msmq.YesNoType.yes;
251 }
252
253 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.DeleteQueue))
254 {
255 queuePermission.DeleteQueue = Msmq.YesNoType.yes;
256 }
257
258 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.GetQueuePermissions))
259 {
260 queuePermission.GetQueuePermissions = Msmq.YesNoType.yes;
261 }
262
263 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ChangeQueuePermissions))
264 {
265 queuePermission.ChangeQueuePermissions = Msmq.YesNoType.yes;
266 }
267
268 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.TakeQueueOwnership))
269 {
270 queuePermission.TakeQueueOwnership = Msmq.YesNoType.yes;
271 }
272
273 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ReceiveMessage))
274 {
275 queuePermission.ReceiveMessage = Msmq.YesNoType.yes;
276 }
277
278 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.ReceiveJournalMessage))
279 {
280 queuePermission.ReceiveJournalMessage = Msmq.YesNoType.yes;
281 }
282
283 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericRead))
284 {
285 queuePermission.QueueGenericRead = Msmq.YesNoType.yes;
286 }
287
288 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericWrite))
289 {
290 queuePermission.QueueGenericWrite = Msmq.YesNoType.yes;
291 }
292
293 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericExecute))
294 {
295 queuePermission.QueueGenericExecute = Msmq.YesNoType.yes;
296 }
297
298 if (0 != (attributes & (int)MsmqCompiler.MqiMessageQueuePermission.QueueGenericAll))
299 {
300 queuePermission.QueueGenericAll = Msmq.YesNoType.yes;
301 }
302 }
303 }
304#endif
305}
diff --git a/src/ext/Msmq/wixext/MsmqErrors.cs b/src/ext/Msmq/wixext/MsmqErrors.cs
new file mode 100644
index 00000000..4342e1cf
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqErrors.cs
@@ -0,0 +1,71 @@
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.Data
4{
5 using System;
6 using System.Resources;
7
8 public static class MsmqErrors
9 {
10 public static Message IllegalAttributeWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName)
11 {
12 return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutComponent, "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.", elementName, attributeName);
13 }
14
15 public static Message IllegalElementWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName)
16 {
17 return Message(sourceLineNumbers, Ids.IllegalElementWithoutComponent, "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.", elementName);
18 }
19
20 public static Message RequiredAttribute(SourceLineNumber sourceLineNumbers, string elementName, string attributeName1, string attributeName2)
21 {
22 return Message(sourceLineNumbers, Ids.RequiredAttribute, "A {0} element must have either a {1} attribute or a {2} attribute, or both set.", elementName, attributeName1, attributeName2);
23 }
24
25 public static Message RequiredAttributeNotUnderComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName1, string attributeName2)
26 {
27 return Message(sourceLineNumbers, Ids.RequiredAttributeNotUnderComponent, "A {0} element not nested under a component must have either a {1} attribute or a {2} attribute, or both set.", elementName, attributeName1, attributeName2);
28 }
29
30 public static Message RequiredAttributeUnderComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName)
31 {
32 return Message(sourceLineNumbers, Ids.RequiredAttributeUnderComponent, "The {0}/@{1} attribute must be provided when {0} element is nested under a component.", elementName, attributeName);
33 }
34
35 public static Message UnexpectedAttributeWithOtherValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string otherAttributeName, string otherValue)
36 {
37 return Message(sourceLineNumbers, Ids.UnexpectedAttributeWithOtherValue, "The {0}/@{1} attribute cannot coexist with the {2} attribute's value of '{3}'.", elementName, attributeName, otherAttributeName, otherValue);
38 }
39
40 public static Message UnexpectedAttributeWithOtherValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value, string otherAttributeName, string otherValue)
41 {
42 return Message(sourceLineNumbers, Ids.UnexpectedAttributeWithOtherValue, "The {0}/@{1} attribute's value, '{2}', cannot coexist with the {3} attribute's value of '{4}'.", elementName, attributeName, value, otherAttributeName, otherValue);
43 }
44
45 public static Message UnexpectedAttributeWithoutOtherValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string otherAttributeName, string otherValue)
46 {
47 return Message(sourceLineNumbers, Ids.UnexpectedAttributeWithoutOtherValue, "The {0}/@{1} cannot be provided unless the {2} attribute is provided with a value of '{3}'.", elementName, attributeName, otherAttributeName, otherValue);
48 }
49
50 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
51 {
52 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
53 }
54
55 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
56 {
57 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args);
58 }
59
60 public enum Ids
61 {
62 IllegalAttributeWithoutComponent = 6000,
63 IllegalElementWithoutComponent = 6001,
64 UnexpectedAttributeWithOtherValue = 6002,
65 UnexpectedAttributeWithoutOtherValue = 6003,
66 RequiredAttributeUnderComponent = 6004,
67 RequiredAttribute = 6005,
68 RequiredAttributeNotUnderComponent = 6006,
69 }
70 }
71}
diff --git a/src/ext/Msmq/wixext/MsmqExtensionData.cs b/src/ext/Msmq/wixext/MsmqExtensionData.cs
new file mode 100644
index 00000000..91485724
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqExtensionData.cs
@@ -0,0 +1,30 @@
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.Msmq
4{
5 using WixToolset.Data;
6 using WixToolset.Extensibility;
7
8 /// <summary>
9 /// The WiX Toolset MSMQ Extension.
10 /// </summary>
11 public sealed class MsmqExtensionData : BaseExtensionData
12 {
13 /// <summary>
14 /// Gets the default culture.
15 /// </summary>
16 /// <value>The default culture.</value>
17 public override string DefaultCulture => "en-US";
18
19 public override bool TryGetSymbolDefinitionByName(string name, out IntermediateSymbolDefinition symbolDefinition)
20 {
21 symbolDefinition = MsmqSymbolDefinitions.ByName(name);
22 return symbolDefinition != null;
23 }
24
25 public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions)
26 {
27 return Intermediate.Load(typeof(MsmqExtensionData).Assembly, "WixToolset.Msmq.msmq.wixlib", symbolDefinitions);
28 }
29 }
30}
diff --git a/src/ext/Msmq/wixext/MsmqExtensionFactory.cs b/src/ext/Msmq/wixext/MsmqExtensionFactory.cs
new file mode 100644
index 00000000..de9f786d
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqExtensionFactory.cs
@@ -0,0 +1,18 @@
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.Msmq
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Extensibility;
8
9 public class MsmqExtensionFactory : BaseExtensionFactory
10 {
11 protected override IReadOnlyCollection<Type> ExtensionTypes => new[]
12 {
13 typeof(MsmqCompiler),
14 typeof(MsmqExtensionData),
15 typeof(MsmqWindowsInstallerBackendBinderExtension),
16 };
17 }
18}
diff --git a/src/ext/Msmq/wixext/MsmqTableDefinitions.cs b/src/ext/Msmq/wixext/MsmqTableDefinitions.cs
new file mode 100644
index 00000000..46e2dd10
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqTableDefinitions.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.Msmq
4{
5 using WixToolset.Data.WindowsInstaller;
6
7 public static class MsmqTableDefinitions
8 {
9 public static readonly TableDefinition MessageQueue = new TableDefinition(
10 "MessageQueue",
11 MsmqSymbolDefinitions.MessageQueue,
12 new[]
13 {
14 new ColumnDefinition("MessageQueue", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, modularizeType: ColumnModularizeType.Column),
15 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, modularizeType: ColumnModularizeType.Column),
16 new ColumnDefinition("BasePriority", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown),
17 new ColumnDefinition("JournalQuota", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown),
18 new ColumnDefinition("Label", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, modularizeType: ColumnModularizeType.Property),
19 new ColumnDefinition("MulticastAddress", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, modularizeType: ColumnModularizeType.Property),
20 new ColumnDefinition("PathName", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, modularizeType: ColumnModularizeType.Property),
21 new ColumnDefinition("PrivLevel", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown),
22 new ColumnDefinition("Quota", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown),
23 new ColumnDefinition("ServiceTypeGuid", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Formatted, modularizeType: ColumnModularizeType.Property),
24 new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown),
25 },
26 symbolIdIsPrimaryKey: true
27 );
28
29 public static readonly TableDefinition MessageQueueUserPermission = new TableDefinition(
30 "MessageQueueUserPermission",
31 MsmqSymbolDefinitions.MessageQueueUserPermission,
32 new[]
33 {
34 new ColumnDefinition("MessageQueueUserPermission", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, modularizeType: ColumnModularizeType.Column),
35 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, modularizeType: ColumnModularizeType.Column),
36 new ColumnDefinition("MessageQueue_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "MessageQueue", keyColumn: 1, modularizeType: ColumnModularizeType.Column),
37 new ColumnDefinition("User_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, modularizeType: ColumnModularizeType.Column),
38 new ColumnDefinition("Permissions", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown),
39 },
40 symbolIdIsPrimaryKey: true
41 );
42
43 public static readonly TableDefinition MessageQueueGroupPermission = new TableDefinition(
44 "MessageQueueGroupPermission",
45 MsmqSymbolDefinitions.MessageQueueGroupPermission,
46 new[]
47 {
48 new ColumnDefinition("MessageQueueGroupPermission", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, modularizeType: ColumnModularizeType.Column),
49 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, modularizeType: ColumnModularizeType.Column),
50 new ColumnDefinition("MessageQueue_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "MessageQueue", keyColumn: 1, modularizeType: ColumnModularizeType.Column),
51 new ColumnDefinition("Group_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, modularizeType: ColumnModularizeType.Column),
52 new ColumnDefinition("Permissions", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown),
53 },
54 symbolIdIsPrimaryKey: true
55 );
56
57 public static readonly TableDefinition[] All = new[]
58 {
59 MessageQueue,
60 MessageQueueUserPermission,
61 MessageQueueGroupPermission,
62 };
63 }
64}
diff --git a/src/ext/Msmq/wixext/MsmqWarnings.cs b/src/ext/Msmq/wixext/MsmqWarnings.cs
new file mode 100644
index 00000000..41d160e9
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqWarnings.cs
@@ -0,0 +1,30 @@
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.Data
4{
5 using System;
6 using System.Resources;
7
8 public static class MsmqWarnings
9 {
10 public static Message MissingComponents(SourceLineNumber sourceLineNumbers)
11 {
12 return Message(sourceLineNumbers, Ids.MissingComponents, "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.");
13 }
14
15 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
16 {
17 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args);
18 }
19
20 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
21 {
22 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, resourceManager, resourceName, args);
23 }
24
25 public enum Ids
26 {
27 MissingComponents = 6007,
28 }
29 }
30}
diff --git a/src/ext/Msmq/wixext/MsmqWindowsInstallerBackendExtension.cs b/src/ext/Msmq/wixext/MsmqWindowsInstallerBackendExtension.cs
new file mode 100644
index 00000000..d317fb60
--- /dev/null
+++ b/src/ext/Msmq/wixext/MsmqWindowsInstallerBackendExtension.cs
@@ -0,0 +1,13 @@
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.Msmq
4{
5 using System.Collections.Generic;
6 using WixToolset.Data.WindowsInstaller;
7 using WixToolset.Extensibility;
8
9 public class MsmqWindowsInstallerBackendBinderExtension : BaseWindowsInstallerBackendBinderExtension
10 {
11 public override IReadOnlyCollection<TableDefinition> TableDefinitions => MsmqTableDefinitions.All;
12 }
13}
diff --git a/src/ext/Msmq/wixext/Symbols/MessageQueueGroupPermissionSymbol.cs b/src/ext/Msmq/wixext/Symbols/MessageQueueGroupPermissionSymbol.cs
new file mode 100644
index 00000000..404c061c
--- /dev/null
+++ b/src/ext/Msmq/wixext/Symbols/MessageQueueGroupPermissionSymbol.cs
@@ -0,0 +1,71 @@
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.Msmq
4{
5 using WixToolset.Data;
6 using WixToolset.Msmq.Symbols;
7
8 public static partial class MsmqSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition MessageQueueGroupPermission = new IntermediateSymbolDefinition(
11 MsmqSymbolDefinitionType.MessageQueueGroupPermission.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(MessageQueueGroupPermissionSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(MessageQueueGroupPermissionSymbolFields.MessageQueueRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(MessageQueueGroupPermissionSymbolFields.GroupRef), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(MessageQueueGroupPermissionSymbolFields.Permissions), IntermediateFieldType.Number),
18 },
19 typeof(MessageQueueGroupPermissionSymbol));
20 }
21}
22
23namespace WixToolset.Msmq.Symbols
24{
25 using WixToolset.Data;
26
27 public enum MessageQueueGroupPermissionSymbolFields
28 {
29 ComponentRef,
30 MessageQueueRef,
31 GroupRef,
32 Permissions,
33 }
34
35 public class MessageQueueGroupPermissionSymbol : IntermediateSymbol
36 {
37 public MessageQueueGroupPermissionSymbol() : base(MsmqSymbolDefinitions.MessageQueueGroupPermission, null, null)
38 {
39 }
40
41 public MessageQueueGroupPermissionSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(MsmqSymbolDefinitions.MessageQueueGroupPermission, sourceLineNumber, id)
42 {
43 }
44
45 public IntermediateField this[MessageQueueGroupPermissionSymbolFields index] => this.Fields[(int)index];
46
47 public string ComponentRef
48 {
49 get => this.Fields[(int)MessageQueueGroupPermissionSymbolFields.ComponentRef].AsString();
50 set => this.Set((int)MessageQueueGroupPermissionSymbolFields.ComponentRef, value);
51 }
52
53 public string MessageQueueRef
54 {
55 get => this.Fields[(int)MessageQueueGroupPermissionSymbolFields.MessageQueueRef].AsString();
56 set => this.Set((int)MessageQueueGroupPermissionSymbolFields.MessageQueueRef, value);
57 }
58
59 public string GroupRef
60 {
61 get => this.Fields[(int)MessageQueueGroupPermissionSymbolFields.GroupRef].AsString();
62 set => this.Set((int)MessageQueueGroupPermissionSymbolFields.GroupRef, value);
63 }
64
65 public int Permissions
66 {
67 get => this.Fields[(int)MessageQueueGroupPermissionSymbolFields.Permissions].AsNumber();
68 set => this.Set((int)MessageQueueGroupPermissionSymbolFields.Permissions, value);
69 }
70 }
71} \ No newline at end of file
diff --git a/src/ext/Msmq/wixext/Symbols/MessageQueueSymbol.cs b/src/ext/Msmq/wixext/Symbols/MessageQueueSymbol.cs
new file mode 100644
index 00000000..b911f0ea
--- /dev/null
+++ b/src/ext/Msmq/wixext/Symbols/MessageQueueSymbol.cs
@@ -0,0 +1,119 @@
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.Msmq
4{
5 using WixToolset.Data;
6 using WixToolset.Msmq.Symbols;
7
8 public static partial class MsmqSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition MessageQueue = new IntermediateSymbolDefinition(
11 MsmqSymbolDefinitionType.MessageQueue.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.BasePriority), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.JournalQuota), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.Label), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.MulticastAddress), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.PathName), IntermediateFieldType.String),
20 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.PrivLevel), IntermediateFieldType.Number),
21 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.Quota), IntermediateFieldType.Number),
22 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.ServiceTypeGuid), IntermediateFieldType.String),
23 new IntermediateFieldDefinition(nameof(MessageQueueSymbolFields.Attributes), IntermediateFieldType.Number),
24 },
25 typeof(MessageQueueSymbol));
26 }
27}
28
29namespace WixToolset.Msmq.Symbols
30{
31 using WixToolset.Data;
32
33 public enum MessageQueueSymbolFields
34 {
35 ComponentRef,
36 BasePriority,
37 JournalQuota,
38 Label,
39 MulticastAddress,
40 PathName,
41 PrivLevel,
42 Quota,
43 ServiceTypeGuid,
44 Attributes,
45 }
46
47 public class MessageQueueSymbol : IntermediateSymbol
48 {
49 public MessageQueueSymbol() : base(MsmqSymbolDefinitions.MessageQueue, null, null)
50 {
51 }
52
53 public MessageQueueSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(MsmqSymbolDefinitions.MessageQueue, sourceLineNumber, id)
54 {
55 }
56
57 public IntermediateField this[MessageQueueSymbolFields index] => this.Fields[(int)index];
58
59 public string ComponentRef
60 {
61 get => this.Fields[(int)MessageQueueSymbolFields.ComponentRef].AsString();
62 set => this.Set((int)MessageQueueSymbolFields.ComponentRef, value);
63 }
64
65 public int? BasePriority
66 {
67 get => this.Fields[(int)MessageQueueSymbolFields.BasePriority].AsNullableNumber();
68 set => this.Set((int)MessageQueueSymbolFields.BasePriority, value);
69 }
70
71 public int? JournalQuota
72 {
73 get => this.Fields[(int)MessageQueueSymbolFields.JournalQuota].AsNullableNumber();
74 set => this.Set((int)MessageQueueSymbolFields.JournalQuota, value);
75 }
76
77 public string Label
78 {
79 get => this.Fields[(int)MessageQueueSymbolFields.Label].AsString();
80 set => this.Set((int)MessageQueueSymbolFields.Label, value);
81 }
82
83 public string MulticastAddress
84 {
85 get => this.Fields[(int)MessageQueueSymbolFields.MulticastAddress].AsString();
86 set => this.Set((int)MessageQueueSymbolFields.MulticastAddress, value);
87 }
88
89 public string PathName
90 {
91 get => this.Fields[(int)MessageQueueSymbolFields.PathName].AsString();
92 set => this.Set((int)MessageQueueSymbolFields.PathName, value);
93 }
94
95 public int? PrivLevel
96 {
97 get => this.Fields[(int)MessageQueueSymbolFields.PrivLevel].AsNullableNumber();
98 set => this.Set((int)MessageQueueSymbolFields.PrivLevel, value);
99 }
100
101 public int? Quota
102 {
103 get => this.Fields[(int)MessageQueueSymbolFields.Quota].AsNullableNumber();
104 set => this.Set((int)MessageQueueSymbolFields.Quota, value);
105 }
106
107 public string ServiceTypeGuid
108 {
109 get => this.Fields[(int)MessageQueueSymbolFields.ServiceTypeGuid].AsString();
110 set => this.Set((int)MessageQueueSymbolFields.ServiceTypeGuid, value);
111 }
112
113 public int Attributes
114 {
115 get => this.Fields[(int)MessageQueueSymbolFields.Attributes].AsNumber();
116 set => this.Set((int)MessageQueueSymbolFields.Attributes, value);
117 }
118 }
119} \ No newline at end of file
diff --git a/src/ext/Msmq/wixext/Symbols/MessageQueueUserPermissionSymbol.cs b/src/ext/Msmq/wixext/Symbols/MessageQueueUserPermissionSymbol.cs
new file mode 100644
index 00000000..cc783845
--- /dev/null
+++ b/src/ext/Msmq/wixext/Symbols/MessageQueueUserPermissionSymbol.cs
@@ -0,0 +1,71 @@
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.Msmq
4{
5 using WixToolset.Data;
6 using WixToolset.Msmq.Symbols;
7
8 public static partial class MsmqSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition MessageQueueUserPermission = new IntermediateSymbolDefinition(
11 MsmqSymbolDefinitionType.MessageQueueUserPermission.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(MessageQueueUserPermissionSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(MessageQueueUserPermissionSymbolFields.MessageQueueRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(MessageQueueUserPermissionSymbolFields.UserRef), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(MessageQueueUserPermissionSymbolFields.Permissions), IntermediateFieldType.Number),
18 },
19 typeof(MessageQueueUserPermissionSymbol));
20 }
21}
22
23namespace WixToolset.Msmq.Symbols
24{
25 using WixToolset.Data;
26
27 public enum MessageQueueUserPermissionSymbolFields
28 {
29 ComponentRef,
30 MessageQueueRef,
31 UserRef,
32 Permissions,
33 }
34
35 public class MessageQueueUserPermissionSymbol : IntermediateSymbol
36 {
37 public MessageQueueUserPermissionSymbol() : base(MsmqSymbolDefinitions.MessageQueueUserPermission, null, null)
38 {
39 }
40
41 public MessageQueueUserPermissionSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(MsmqSymbolDefinitions.MessageQueueUserPermission, sourceLineNumber, id)
42 {
43 }
44
45 public IntermediateField this[MessageQueueUserPermissionSymbolFields index] => this.Fields[(int)index];
46
47 public string ComponentRef
48 {
49 get => this.Fields[(int)MessageQueueUserPermissionSymbolFields.ComponentRef].AsString();
50 set => this.Set((int)MessageQueueUserPermissionSymbolFields.ComponentRef, value);
51 }
52
53 public string MessageQueueRef
54 {
55 get => this.Fields[(int)MessageQueueUserPermissionSymbolFields.MessageQueueRef].AsString();
56 set => this.Set((int)MessageQueueUserPermissionSymbolFields.MessageQueueRef, value);
57 }
58
59 public string UserRef
60 {
61 get => this.Fields[(int)MessageQueueUserPermissionSymbolFields.UserRef].AsString();
62 set => this.Set((int)MessageQueueUserPermissionSymbolFields.UserRef, value);
63 }
64
65 public int Permissions
66 {
67 get => this.Fields[(int)MessageQueueUserPermissionSymbolFields.Permissions].AsNumber();
68 set => this.Set((int)MessageQueueUserPermissionSymbolFields.Permissions, value);
69 }
70 }
71} \ No newline at end of file
diff --git a/src/ext/Msmq/wixext/Symbols/MsmqSymbolDefinitions.cs b/src/ext/Msmq/wixext/Symbols/MsmqSymbolDefinitions.cs
new file mode 100644
index 00000000..229417fe
--- /dev/null
+++ b/src/ext/Msmq/wixext/Symbols/MsmqSymbolDefinitions.cs
@@ -0,0 +1,47 @@
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.Msmq
4{
5 using System;
6 using WixToolset.Data;
7
8 public enum MsmqSymbolDefinitionType
9 {
10 MessageQueue,
11 MessageQueueGroupPermission,
12 MessageQueueUserPermission,
13 }
14
15 public static partial class MsmqSymbolDefinitions
16 {
17 public static readonly Version Version = new Version("4.0.0");
18
19 public static IntermediateSymbolDefinition ByName(string name)
20 {
21 if (!Enum.TryParse(name, out MsmqSymbolDefinitionType type))
22 {
23 return null;
24 }
25
26 return ByType(type);
27 }
28
29 public static IntermediateSymbolDefinition ByType(MsmqSymbolDefinitionType type)
30 {
31 switch (type)
32 {
33 case MsmqSymbolDefinitionType.MessageQueue:
34 return MsmqSymbolDefinitions.MessageQueue;
35
36 case MsmqSymbolDefinitionType.MessageQueueGroupPermission:
37 return MsmqSymbolDefinitions.MessageQueueGroupPermission;
38
39 case MsmqSymbolDefinitionType.MessageQueueUserPermission:
40 return MsmqSymbolDefinitions.MessageQueueUserPermission;
41
42 default:
43 throw new ArgumentOutOfRangeException(nameof(type));
44 }
45 }
46 }
47}
diff --git a/src/ext/Msmq/wixext/WixToolset.Msmq.wixext.csproj b/src/ext/Msmq/wixext/WixToolset.Msmq.wixext.csproj
new file mode 100644
index 00000000..4bd6a3f5
--- /dev/null
+++ b/src/ext/Msmq/wixext/WixToolset.Msmq.wixext.csproj
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netstandard2.0</TargetFramework>
7 <RootNamespace>WixToolset.Msmq</RootNamespace>
8 <Description>WiX Toolset MSMQ Extension</Description>
9 <Title>WiX Toolset MSMQ Extension</Title>
10 <IsTool>true</IsTool>
11 <ContentTargetFolders>build</ContentTargetFolders>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <Content Include="$(MSBuildThisFileName).targets" />
16 <EmbeddedResource Include="$(OutputPath)..\msmq.wixlib" />
17 </ItemGroup>
18
19 <ItemGroup>
20 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" PrivateAssets="all" />
21 </ItemGroup>
22
23 <ItemGroup>
24 <ProjectReference Include="..\wixlib\msmq.wixproj" ReferenceOutputAssembly="false" Condition=" '$(NCrunch)'=='' " />
25 </ItemGroup>
26
27 <ItemGroup>
28 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
29 </ItemGroup>
30</Project>
diff --git a/src/ext/Msmq/wixext/WixToolset.Msmq.wixext.targets b/src/ext/Msmq/wixext/WixToolset.Msmq.wixext.targets
new file mode 100644
index 00000000..5f69fe48
--- /dev/null
+++ b/src/ext/Msmq/wixext/WixToolset.Msmq.wixext.targets
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 <PropertyGroup>
6 <WixToolsetMsmqWixextPath Condition=" '$(WixToolsetMsmqWixextPath)' == '' ">$(MSBuildThisFileDirectory)..\tools\WixToolset.Msmq.wixext.dll</WixToolsetMsmqWixextPath>
7 </PropertyGroup>
8 <ItemGroup>
9 <WixExtension Include="$(WixToolsetMsmqWixextPath)" />
10 </ItemGroup>
11</Project>
diff --git a/src/ext/Msmq/wixlib/MsmqExtension.wxs b/src/ext/Msmq/wixlib/MsmqExtension.wxs
new file mode 100644
index 00000000..86239545
--- /dev/null
+++ b/src/ext/Msmq/wixlib/MsmqExtension.wxs
@@ -0,0 +1,29 @@
1<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2
3
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?include caerr.wxi ?>
6
7 <Fragment>
8 <UI>
9 <ProgressText Action="MessageQueuingExecuteInstall" Template="!(loc.MessageQueuingExecuteInstallTemplate)" Message="!(loc.MessageQueuingExecuteInstall)" />
10 <ProgressText Action="MessageQueuingExecuteUninstall" Template="!(loc.MessageQueuingExecuteUninstallTemplate)" Message="!(loc.MessageQueuingExecuteUninstall)" />
11 </UI>
12
13 <CustomAction Id="MessageQueuingInstall" DllEntry="MessageQueuingInstall" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="MsmqCA" />
14 <CustomAction Id="MessageQueuingUninstall" DllEntry="MessageQueuingUninstall" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="MsmqCA" />
15 <CustomAction Id="MessageQueuingExecuteInstall" DllEntry="MessageQueuingExecuteInstall" Execute="deferred" Return="check" Impersonate="no" SuppressModularization="yes" BinaryRef="MsmqCA" />
16 <CustomAction Id="MessageQueuingRollbackInstall" DllEntry="MessageQueuingRollbackInstall" Execute="rollback" Return="check" Impersonate="no" SuppressModularization="yes" BinaryRef="MsmqCA" />
17 <CustomAction Id="MessageQueuingExecuteUninstall" DllEntry="MessageQueuingExecuteUninstall" Execute="deferred" Return="check" Impersonate="no" SuppressModularization="yes" BinaryRef="MsmqCA" />
18 <CustomAction Id="MessageQueuingRollbackUninstall" DllEntry="MessageQueuingRollbackUninstall" Execute="rollback" Return="check" Impersonate="no" SuppressModularization="yes" BinaryRef="MsmqCA" />
19
20 <InstallExecuteSequence>
21 <Custom Action="MessageQueuingUninstall" After="DeleteServices" Overridable="yes" Condition="VersionNT &gt;= 500" />
22 <Custom Action="MessageQueuingInstall" Before="InstallServices" Overridable="yes" Condition="VersionNT &gt;= 500" />
23 </InstallExecuteSequence>
24 </Fragment>
25
26 <Fragment>
27 <Binary Id="MsmqCA" SourceFile="msmqca.dll" />
28 </Fragment>
29</Wix>
diff --git a/src/ext/Msmq/wixlib/caerr.wxi b/src/ext/Msmq/wixlib/caerr.wxi
new file mode 100644
index 00000000..ff7ec121
--- /dev/null
+++ b/src/ext/Msmq/wixlib/caerr.wxi
@@ -0,0 +1,96 @@
1<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <?define msierrSecureObjectsFailedCreateSD = 25520?>
3 <?define msierrSecureObjectsFailedSet = 25521?>
4 <?define msierrSecureObjectsUnknownType = 25522?>
5 <?define msierrXmlFileFailedRead = 25530?>
6 <?define msierrXmlFileFailedOpen = 25531?>
7 <?define msierrXmlFileFailedSelect = 25532?>
8 <?define msierrXmlFileFailedSave = 25533?>
9 <?define msierrXmlConfigFailedRead = 25540?>
10 <?define msierrXmlConfigFailedOpen = 25541?>
11 <?define msierrXmlConfigFailedSelect = 25542?>
12 <?define msierrXmlConfigFailedSave = 25543?>
13 <?define msierrFirewallCannotConnect = 25580?>
14 <?define msierrIISCannotConnect = 26001?>
15 <?define msierrIISFailedReadWebSite = 26002?>
16 <?define msierrIISFailedReadWebDirs = 26003?>
17 <?define msierrIISFailedReadVDirs = 26004?>
18 <?define msierrIISFailedReadFilters = 26005?>
19 <?define msierrIISFailedReadAppPool = 26006?>
20 <?define msierrIISFailedReadMimeMap = 26007?>
21 <?define msierrIISFailedReadProp = 26008?>
22 <?define msierrIISFailedReadWebSvcExt = 26009?>
23 <?define msierrIISFailedReadWebError = 26010?>
24 <?define msierrIISFailedReadHttpHeader = 26011?>
25 <?define msierrIISFailedSchedTransaction = 26031?>
26 <?define msierrIISFailedSchedInstallWebs = 26032?>
27 <?define msierrIISFailedSchedInstallWebDirs = 26033?>
28 <?define msierrIISFailedSchedInstallVDirs = 26034?>
29 <?define msierrIISFailedSchedInstallFilters = 26035?>
30 <?define msierrIISFailedSchedInstallAppPool = 26036?>
31 <?define msierrIISFailedSchedInstallProp = 26037?>
32 <?define msierrIISFailedSchedInstallWebSvcExt = 26038?>
33 <?define msierrIISFailedSchedUninstallWebs = 26051?>
34 <?define msierrIISFailedSchedUninstallWebDirs = 26052?>
35 <?define msierrIISFailedSchedUninstallVDirs = 26053?>
36 <?define msierrIISFailedSchedUninstallFilters = 26054?>
37 <?define msierrIISFailedSchedUninstallAppPool = 26055?>
38 <?define msierrIISFailedSchedUninstallProp = 26056?>
39 <?define msierrIISFailedSchedUninstallWebSvcExt = 26057?>
40 <?define msierrIISFailedStartTransaction = 26101?>
41 <?define msierrIISFailedOpenKey = 26102?>
42 <?define msierrIISFailedCreateKey = 26103?>
43 <?define msierrIISFailedWriteData = 26104?>
44 <?define msierrIISFailedCreateApp = 26105?>
45 <?define msierrIISFailedDeleteKey = 26106?>
46 <?define msierrIISFailedDeleteApp = 26107?>
47 <?define msierrIISFailedDeleteValue = 26108?>
48 <?define msierrIISFailedCommitInUse = 26109?>
49 <?define msierrSQLFailedCreateDatabase = 26201?>
50 <?define msierrSQLFailedDropDatabase = 26202?>
51 <?define msierrSQLFailedConnectDatabase = 26203?>
52 <?define msierrSQLFailedExecString = 26204?>
53 <?define msierrSQLDatabaseAlreadyExists = 26205?>
54 <?define msierrPERFMONFailedRegisterDLL = 26251?>
55 <?define msierrPERFMONFailedUnregisterDLL = 26252?>
56 <?define msierrInstallPerfCounterData = 26253?>
57 <?define msierrUninstallPerfCounterData = 26254?>
58 <?define msierrSMBFailedCreate = 26301?>
59 <?define msierrSMBFailedDrop = 26302?>
60 <?define msierrCERTFailedOpen = 26351?>
61 <?define msierrCERTFailedAdd = 26352?>
62 <?define msierrUSRFailedUserCreate = 26401?>
63 <?define msierrUSRFailedUserCreatePswd = 26402?>
64 <?define msierrUSRFailedUserGroupAdd = 26403?>
65 <?define msierrUSRFailedUserCreateExists = 26404?>
66 <?define msierrUSRFailedGrantLogonAsService = 26405?>
67 <?define msierrDependencyMissingDependencies = 26451?>
68 <?define msierrDependencyHasDependents = 26452?>
69 <?define msierrDotNetRuntimeRequired = 27000?>
70 <?define msierrComPlusCannotConnect = 28001?>
71 <?define msierrComPlusPartitionReadFailed = 28002?>
72 <?define msierrComPlusPartitionRoleReadFailed = 28003?>
73 <?define msierrComPlusUserInPartitionRoleReadFailed = 28004?>
74 <?define msierrComPlusPartitionUserReadFailed = 28005?>
75 <?define msierrComPlusApplicationReadFailed = 28006?>
76 <?define msierrComPlusApplicationRoleReadFailed = 28007?>
77 <?define msierrComPlusUserInApplicationRoleReadFailed = 28008?>
78 <?define msierrComPlusAssembliesReadFailed = 28009?>
79 <?define msierrComPlusSubscriptionReadFailed = 28010?>
80 <?define msierrComPlusPartitionDependency = 28011?>
81 <?define msierrComPlusPartitionNotFound = 28012?>
82 <?define msierrComPlusPartitionIdConflict = 28013?>
83 <?define msierrComPlusPartitionNameConflict = 28014?>
84 <?define msierrComPlusApplicationDependency = 28015?>
85 <?define msierrComPlusApplicationNotFound = 28016?>
86 <?define msierrComPlusApplicationIdConflict = 28017?>
87 <?define msierrComPlusApplicationNameConflict = 28018?>
88 <?define msierrComPlusApplicationRoleDependency = 28019?>
89 <?define msierrComPlusApplicationRoleNotFound = 28020?>
90 <?define msierrComPlusApplicationRoleConflict = 28021?>
91 <?define msierrComPlusAssemblyDependency = 28022?>
92 <?define msierrComPlusSubscriptionIdConflict = 28023?>
93 <?define msierrComPlusSubscriptionNameConflict = 28024?>
94 <?define msierrComPlusFailedLookupNames = 28025?>
95 <?define msierrMsmqCannotConnect = 28101?>
96</Include> \ No newline at end of file
diff --git a/src/ext/Msmq/wixlib/en-us.wxl b/src/ext/Msmq/wixlib/en-us.wxl
new file mode 100644
index 00000000..ebe08095
--- /dev/null
+++ b/src/ext/Msmq/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/ext/Msmq/wixlib/ja-jp.wxl b/src/ext/Msmq/wixlib/ja-jp.wxl
new file mode 100644
index 00000000..d56cd7ec
--- /dev/null
+++ b/src/ext/Msmq/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>
diff --git a/src/ext/Msmq/wixlib/msmq.wixproj b/src/ext/Msmq/wixlib/msmq.wixproj
new file mode 100644
index 00000000..ccccbf49
--- /dev/null
+++ b/src/ext/Msmq/wixlib/msmq.wixproj
@@ -0,0 +1,18 @@
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<Project Sdk="WixToolset.Sdk">
3
4 <PropertyGroup>
5 <OutputType>Library</OutputType>
6 <BindFiles>true</BindFiles>
7 <Cultures>en-us</Cultures>
8 </PropertyGroup>
9
10 <ItemGroup>
11 <ProjectReference Include="..\ca\msmqca.vcxproj" />
12 </ItemGroup>
13
14 <ItemGroup>
15 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="All" />
16 </ItemGroup>
17
18</Project>