diff options
author | Rob Mensching <rob@firegiant.com> | 2021-04-22 15:43:19 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2021-04-29 16:22:14 -0700 |
commit | 30827588eb0c189b7e2d04693d116080d333200e (patch) | |
tree | 866a7987d175ccac7f506dac6ba52ca16b5f9f08 /src/libs/wcautil | |
parent | 46897fefd6aef4168f35c1f366c833d715c3bdaa (diff) | |
download | wix-30827588eb0c189b7e2d04693d116080d333200e.tar.gz wix-30827588eb0c189b7e2d04693d116080d333200e.tar.bz2 wix-30827588eb0c189b7e2d04693d116080d333200e.zip |
Move wcautil into libs/wcautil
Diffstat (limited to 'src/libs/wcautil')
27 files changed, 5134 insertions, 0 deletions
diff --git a/src/libs/wcautil/Cpp.Build.props b/src/libs/wcautil/Cpp.Build.props new file mode 100644 index 00000000..44a042c7 --- /dev/null +++ b/src/libs/wcautil/Cpp.Build.props | |||
@@ -0,0 +1,104 @@ | |||
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) > 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)'=='Debug' and '$(CLRSupport)'=='true' "> | ||
74 | <ClCompile> | ||
75 | <BasicRuntimeChecks></BasicRuntimeChecks> | ||
76 | <RuntimeLibrary>MultiThreadedDebugDll</RuntimeLibrary> | ||
77 | </ClCompile> | ||
78 | </ItemDefinitionGroup> | ||
79 | <ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' "> | ||
80 | <ClCompile> | ||
81 | <Optimization>MinSpace</Optimization> | ||
82 | <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||
83 | <FunctionLevelLinking>true</FunctionLevelLinking> | ||
84 | <IntrinsicFunctions>true</IntrinsicFunctions> | ||
85 | <RuntimeLibrary>MultiThreaded</RuntimeLibrary> | ||
86 | </ClCompile> | ||
87 | <Link> | ||
88 | <EnableCOMDATFolding>true</EnableCOMDATFolding> | ||
89 | <OptimizeReferences>true</OptimizeReferences> | ||
90 | </Link> | ||
91 | </ItemDefinitionGroup> | ||
92 | <ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' and '$(CLRSupport)'=='true' "> | ||
93 | <ClCompile> | ||
94 | <BasicRuntimeChecks></BasicRuntimeChecks> | ||
95 | <RuntimeLibrary>MultiThreadedDll</RuntimeLibrary> | ||
96 | </ClCompile> | ||
97 | </ItemDefinitionGroup> | ||
98 | <ItemDefinitionGroup Condition=" '$(CLRSupport)'=='true' "> | ||
99 | <Link> | ||
100 | <KeyFile>$(LinkKeyFile)</KeyFile> | ||
101 | <DelaySign>$(LinkDelaySign)</DelaySign> | ||
102 | </Link> | ||
103 | </ItemDefinitionGroup> | ||
104 | </Project> | ||
diff --git a/src/libs/wcautil/Directory.Build.props b/src/libs/wcautil/Directory.Build.props new file mode 100644 index 00000000..e853e22d --- /dev/null +++ b/src/libs/wcautil/Directory.Build.props | |||
@@ -0,0 +1,26 @@ | |||
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 | |||
12 | <ProjectName Condition=" '$(ProjectName)' == '' ">$(MSBuildProjectName)</ProjectName> | ||
13 | <BaseOutputPath>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\))</BaseOutputPath> | ||
14 | <BaseIntermediateOutputPath>$(BaseOutputPath)obj\$(ProjectName)\</BaseIntermediateOutputPath> | ||
15 | <OutputPath>$(BaseOutputPath)$(Configuration)\</OutputPath> | ||
16 | |||
17 | <Authors>WiX Toolset Team</Authors> | ||
18 | <Company>WiX Toolset</Company> | ||
19 | <Copyright>Copyright (c) .NET Foundation and contributors. All rights reserved.</Copyright> | ||
20 | <PackageLicenseExpression>MS-RL</PackageLicenseExpression> | ||
21 | <Product>WiX Toolset</Product> | ||
22 | </PropertyGroup> | ||
23 | |||
24 | <Import Project="Cpp.Build.props" Condition=" '$(MSBuildProjectExtension)'=='.vcxproj' " /> | ||
25 | <Import Project="Custom.Build.props" Condition=" Exists('Custom.Build.props') " /> | ||
26 | </Project> | ||
diff --git a/src/libs/wcautil/Directory.Build.targets b/src/libs/wcautil/Directory.Build.targets new file mode 100644 index 00000000..dac7452a --- /dev/null +++ b/src/libs/wcautil/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>(?<="[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/libs/wcautil/NativeMultiTargeting.Build.props b/src/libs/wcautil/NativeMultiTargeting.Build.props new file mode 100644 index 00000000..1ff46559 --- /dev/null +++ b/src/libs/wcautil/NativeMultiTargeting.Build.props | |||
@@ -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 | <Project> | ||
5 | <!-- Overrides the standard Cpp.Build.props to include the PlatformToolset in the output path. --> | ||
6 | <PropertyGroup> | ||
7 | <IntDir>$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformToolset)\$(PlatformTarget)\</IntDir> | ||
8 | <OutDir>$(OutputPath)$(PlatformToolset)\$(PlatformTarget)\</OutDir> | ||
9 | </PropertyGroup> | ||
10 | </Project> | ||
diff --git a/src/libs/wcautil/README.md b/src/libs/wcautil/README.md new file mode 100644 index 00000000..aa004554 --- /dev/null +++ b/src/libs/wcautil/README.md | |||
@@ -0,0 +1,2 @@ | |||
1 | # wcautil | ||
2 | wcautil.lib - WiX Toolset Custom Action native utility library | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/build/WixToolset.WcaUtil.props b/src/libs/wcautil/WixToolset.WcaUtil/build/WixToolset.WcaUtil.props new file mode 100644 index 00000000..fb73a680 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/build/WixToolset.WcaUtil.props | |||
@@ -0,0 +1,28 @@ | |||
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 ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
5 | <ItemDefinitionGroup> | ||
6 | <ClCompile> | ||
7 | <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)native\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||
8 | </ClCompile> | ||
9 | <ResourceCompile> | ||
10 | <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)native\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||
11 | </ResourceCompile> | ||
12 | </ItemDefinitionGroup> | ||
13 | <ItemDefinitionGroup Condition=" $(PlatformToolset.ToLower().StartsWith('v140')) "> | ||
14 | <Link> | ||
15 | <AdditionalDependencies>$(MSBuildThisFileDirectory)native\v140\$(PlatformTarget)\wcautil.lib;%(AdditionalDependencies)</AdditionalDependencies> | ||
16 | </Link> | ||
17 | </ItemDefinitionGroup> | ||
18 | <ItemDefinitionGroup Condition=" $(PlatformToolset.ToLower().StartsWith('v141')) "> | ||
19 | <Link> | ||
20 | <AdditionalDependencies>$(MSBuildThisFileDirectory)native\v141\$(PlatformTarget)\wcautil.lib;%(AdditionalDependencies)</AdditionalDependencies> | ||
21 | </Link> | ||
22 | </ItemDefinitionGroup> | ||
23 | <ItemDefinitionGroup Condition=" $(PlatformToolset.ToLower().StartsWith('v142')) "> | ||
24 | <Link> | ||
25 | <AdditionalDependencies>$(MSBuildThisFileDirectory)native\v142\$(PlatformTarget)\wcautil.lib;%(AdditionalDependencies)</AdditionalDependencies> | ||
26 | </Link> | ||
27 | </ItemDefinitionGroup> | ||
28 | </Project> | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/custommsierrors.h b/src/libs/wcautil/WixToolset.WcaUtil/custommsierrors.h new file mode 100644 index 00000000..f149fb31 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/custommsierrors.h | |||
@@ -0,0 +1,130 @@ | |||
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 GLOBAL_ERROR_BASE 25501 | ||
6 | |||
7 | #define msierrSecureObjectsFailedCreateSD 25520 | ||
8 | #define msierrSecureObjectsFailedSet 25521 | ||
9 | #define msierrSecureObjectsUnknownType 25522 | ||
10 | |||
11 | #define msierrXmlFileFailedRead 25530 | ||
12 | #define msierrXmlFileFailedOpen 25531 | ||
13 | #define msierrXmlFileFailedSelect 25532 | ||
14 | #define msierrXmlFileFailedSave 25533 | ||
15 | |||
16 | #define msierrXmlConfigFailedRead 25540 | ||
17 | #define msierrXmlConfigFailedOpen 25541 | ||
18 | #define msierrXmlConfigFailedSelect 25542 | ||
19 | #define msierrXmlConfigFailedSave 25543 | ||
20 | |||
21 | #define msierrFirewallCannotConnect 25580 | ||
22 | |||
23 | //--------------------------------------------------------------------------- | ||
24 | // Server CustomAction Errors | ||
25 | // SERVER range: 26001-26100 | ||
26 | #define SERVER_ERROR_BASE 26000 | ||
27 | |||
28 | #define msierrIISCannotConnect 26001 | ||
29 | #define msierrIISFailedReadWebSite 26002 | ||
30 | #define msierrIISFailedReadWebDirs 26003 | ||
31 | #define msierrIISFailedReadVDirs 26004 | ||
32 | #define msierrIISFailedReadFilters 26005 | ||
33 | #define msierrIISFailedReadAppPool 26006 | ||
34 | #define msierrIISFailedReadMimeMap 26007 | ||
35 | #define msierrIISFailedReadProp 26008 | ||
36 | #define msierrIISFailedReadWebSvcExt 26009 | ||
37 | #define msierrIISFailedReadWebError 26010 | ||
38 | #define msierrIISFailedReadHttpHeader 26011 | ||
39 | |||
40 | #define msierrIISFailedSchedTransaction 26031 | ||
41 | #define msierrIISFailedSchedInstallWebs 26032 | ||
42 | #define msierrIISFailedSchedInstallWebDirs 26033 | ||
43 | #define msierrIISFailedSchedInstallVDirs 26034 | ||
44 | #define msierrIISFailedSchedInstallFilters 26035 | ||
45 | #define msierrIISFailedSchedInstallAppPool 26036 | ||
46 | #define msierrIISFailedSchedInstallProp 26037 | ||
47 | #define msierrIISFailedSchedInstallWebSvcExt 26038 | ||
48 | |||
49 | #define msierrIISFailedSchedUninstallWebs 26051 | ||
50 | #define msierrIISFailedSchedUninstallWebDirs 26052 | ||
51 | #define msierrIISFailedSchedUninstallVDirs 26053 | ||
52 | #define msierrIISFailedSchedUninstallFilters 26054 | ||
53 | #define msierrIISFailedSchedUninstallAppPool 26055 | ||
54 | #define msierrIISFailedSchedUninstallProp 26056 | ||
55 | #define msierrIISFailedSchedUninstallWebSvcExt 26057 | ||
56 | |||
57 | #define msierrIISFailedStartTransaction 26101 | ||
58 | #define msierrIISFailedOpenKey 26102 | ||
59 | #define msierrIISFailedCreateKey 26103 | ||
60 | #define msierrIISFailedWriteData 26104 | ||
61 | #define msierrIISFailedCreateApp 26105 | ||
62 | #define msierrIISFailedDeleteKey 26106 | ||
63 | #define msierrIISFailedDeleteApp 26107 | ||
64 | #define msierrIISFailedDeleteValue 26108 | ||
65 | #define msierrIISFailedCommitInUse 26109 | ||
66 | |||
67 | #define msierrSQLFailedCreateDatabase 26201 | ||
68 | #define msierrSQLFailedDropDatabase 26202 | ||
69 | #define msierrSQLFailedConnectDatabase 26203 | ||
70 | #define msierrSQLFailedExecString 26204 | ||
71 | #define msierrSQLDatabaseAlreadyExists 26205 | ||
72 | |||
73 | #define msierrPERFMONFailedRegisterDLL 26251 | ||
74 | #define msierrPERFMONFailedUnregisterDLL 26252 | ||
75 | #define msierrInstallPerfCounterData 26253 | ||
76 | #define msierrUninstallPerfCounterData 26254 | ||
77 | |||
78 | #define msierrSMBFailedCreate 26301 | ||
79 | #define msierrSMBFailedDrop 26302 | ||
80 | |||
81 | #define msierrCERTFailedOpen 26351 | ||
82 | #define msierrCERTFailedAdd 26352 | ||
83 | |||
84 | #define msierrUSRFailedUserCreate 26401 | ||
85 | #define msierrUSRFailedUserCreatePswd 26402 | ||
86 | #define msierrUSRFailedUserGroupAdd 26403 | ||
87 | #define msierrUSRFailedUserCreateExists 26404 | ||
88 | #define msierrUSRFailedGrantLogonAsService 26405 | ||
89 | |||
90 | #define msierrDependencyMissingDependencies 26451 | ||
91 | #define msierrDependencyHasDependents 26452 | ||
92 | |||
93 | //-------------------------------------------------------------------------- | ||
94 | // Managed code CustomAction Errors | ||
95 | // MANAGED range: 27000-27100 | ||
96 | #define MANAGED_ERROR_BASE 27000 | ||
97 | |||
98 | #define msierrDotNetRuntimeRequired 27000 | ||
99 | //--------------------------------------------------------------------------- | ||
100 | // Public CustomAction Errors | ||
101 | // PUBLIC range: 28001-28100 | ||
102 | #define PUBLIC_ERROR_BASE 28000 | ||
103 | |||
104 | #define msierrComPlusCannotConnect 28001 | ||
105 | #define msierrComPlusPartitionReadFailed 28002 | ||
106 | #define msierrComPlusPartitionRoleReadFailed 28003 | ||
107 | #define msierrComPlusUserInPartitionRoleReadFailed 28004 | ||
108 | #define msierrComPlusPartitionUserReadFailed 28005 | ||
109 | #define msierrComPlusApplicationReadFailed 28006 | ||
110 | #define msierrComPlusApplicationRoleReadFailed 28007 | ||
111 | #define msierrComPlusUserInApplicationRoleReadFailed 28008 | ||
112 | #define msierrComPlusAssembliesReadFailed 28009 | ||
113 | #define msierrComPlusSubscriptionReadFailed 28010 | ||
114 | #define msierrComPlusPartitionDependency 28011 | ||
115 | #define msierrComPlusPartitionNotFound 28012 | ||
116 | #define msierrComPlusPartitionIdConflict 28013 | ||
117 | #define msierrComPlusPartitionNameConflict 28014 | ||
118 | #define msierrComPlusApplicationDependency 28015 | ||
119 | #define msierrComPlusApplicationNotFound 28016 | ||
120 | #define msierrComPlusApplicationIdConflict 28017 | ||
121 | #define msierrComPlusApplicationNameConflict 28018 | ||
122 | #define msierrComPlusApplicationRoleDependency 28019 | ||
123 | #define msierrComPlusApplicationRoleNotFound 28020 | ||
124 | #define msierrComPlusApplicationRoleConflict 28021 | ||
125 | #define msierrComPlusAssemblyDependency 28022 | ||
126 | #define msierrComPlusSubscriptionIdConflict 28023 | ||
127 | #define msierrComPlusSubscriptionNameConflict 28024 | ||
128 | #define msierrComPlusFailedLookupNames 28025 | ||
129 | |||
130 | #define msierrMsmqCannotConnect 28101 | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/exbinary.cpp b/src/libs/wcautil/WixToolset.WcaUtil/exbinary.cpp new file mode 100644 index 00000000..5ff24212 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/exbinary.cpp | |||
@@ -0,0 +1,142 @@ | |||
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 | // Extracts the data from the Binary table row with the given ID into a buffer. | ||
7 | // | ||
8 | HRESULT WIXAPI WcaExtractBinaryToBuffer( | ||
9 | __in LPCWSTR wzBinaryId, | ||
10 | __out BYTE** pbData, | ||
11 | __out DWORD* pcbData | ||
12 | ) | ||
13 | { | ||
14 | HRESULT hr = S_OK; | ||
15 | LPWSTR pwzSql = NULL; | ||
16 | PMSIHANDLE hView; | ||
17 | PMSIHANDLE hRec; | ||
18 | |||
19 | // make sure we're not horked from the get-go | ||
20 | hr = WcaTableExists(L"Binary"); | ||
21 | if (S_OK != hr) | ||
22 | { | ||
23 | if (SUCCEEDED(hr)) | ||
24 | { | ||
25 | hr = E_UNEXPECTED; | ||
26 | } | ||
27 | ExitOnFailure(hr, "There is no Binary table."); | ||
28 | } | ||
29 | |||
30 | ExitOnNull(wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be null"); | ||
31 | ExitOnNull(*wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be empty string"); | ||
32 | |||
33 | hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%ls\'", wzBinaryId); | ||
34 | ExitOnFailure(hr, "Failed to allocate Binary table query."); | ||
35 | |||
36 | hr = WcaOpenExecuteView(pwzSql, &hView); | ||
37 | ExitOnFailure(hr, "Failed to open view on Binary table"); | ||
38 | |||
39 | hr = WcaFetchSingleRecord(hView, &hRec); | ||
40 | ExitOnFailure(hr, "Failed to retrieve request from Binary table"); | ||
41 | |||
42 | hr = WcaGetRecordStream(hRec, 1, pbData, pcbData); | ||
43 | ExitOnFailure(hr, "Failed to read Binary.Data."); | ||
44 | |||
45 | LExit: | ||
46 | ReleaseStr(pwzSql); | ||
47 | |||
48 | return hr; | ||
49 | } | ||
50 | |||
51 | // | ||
52 | // Extracts the data from the Binary table row with the given ID into a file. | ||
53 | // | ||
54 | HRESULT WIXAPI WcaExtractBinaryToFile( | ||
55 | __in LPCWSTR wzBinaryId, | ||
56 | __in LPCWSTR wzPath | ||
57 | ) | ||
58 | { | ||
59 | HRESULT hr = S_OK; | ||
60 | BYTE* pbData = NULL; | ||
61 | DWORD cbData = 0; | ||
62 | HANDLE hFile = INVALID_HANDLE_VALUE; | ||
63 | |||
64 | // grab the bits | ||
65 | hr = WcaExtractBinaryToBuffer(wzBinaryId, &pbData, &cbData); | ||
66 | ExitOnFailure(hr, "Failed to extract binary data: %ls", wzBinaryId); | ||
67 | |||
68 | // write 'em to the file | ||
69 | hFile = ::CreateFileW(wzPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | ||
70 | if (INVALID_HANDLE_VALUE == hFile) | ||
71 | { | ||
72 | ExitWithLastError(hr, "Failed to create file: %ls", wzPath); | ||
73 | } | ||
74 | |||
75 | DWORD cbWritten = 0; | ||
76 | if (!::WriteFile(hFile, pbData, cbData, &cbWritten, NULL)) | ||
77 | { | ||
78 | ExitWithLastError(hr, "Failed to write data to file: %ls", wzPath); | ||
79 | } | ||
80 | |||
81 | LExit: | ||
82 | ReleaseFile(hFile); | ||
83 | ReleaseMem(pbData); | ||
84 | |||
85 | return hr; | ||
86 | } | ||
87 | |||
88 | // | ||
89 | // Extracts the data from the Binary table row with the given ID into a string. | ||
90 | // | ||
91 | HRESULT WIXAPI WcaExtractBinaryToString( | ||
92 | __in LPCWSTR wzBinaryId, | ||
93 | __deref_out_z LPWSTR* psczOutput, | ||
94 | __out WCA_ENCODING* encoding | ||
95 | ) | ||
96 | { | ||
97 | HRESULT hr = S_OK; | ||
98 | BYTE* pbData = NULL; | ||
99 | DWORD cbData = 0; | ||
100 | |||
101 | // grab the bits | ||
102 | hr = WcaExtractBinaryToBuffer(wzBinaryId, &pbData, &cbData); | ||
103 | ExitOnFailure(hr, "Failed to extract binary data: %ls", wzBinaryId); | ||
104 | |||
105 | // expand by a NULL character (or two) to make sure the buffer is null-terminated | ||
106 | cbData += 2; | ||
107 | pbData = reinterpret_cast<LPBYTE>(MemReAlloc(pbData, cbData, TRUE)); | ||
108 | ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to expand binary buffer"); | ||
109 | |||
110 | // Check for BOMs. | ||
111 | if (2 < cbData) | ||
112 | { | ||
113 | if ((0xFF == *pbData) && (0xFE == *(pbData + 1))) | ||
114 | { | ||
115 | *encoding = WCA_ENCODING_UTF_16; | ||
116 | hr = StrAllocString(psczOutput, reinterpret_cast<LPWSTR>(pbData), 0); | ||
117 | } | ||
118 | else if ((0xEF == *pbData) && (0xBB == *(pbData + 1)) && (0xBF == *(pbData + 2))) | ||
119 | { | ||
120 | *encoding = WCA_ENCODING_UTF_8; | ||
121 | hr = StrAllocStringAnsi(psczOutput, reinterpret_cast<LPCSTR>(pbData), 0, CP_UTF8); | ||
122 | } | ||
123 | else | ||
124 | { | ||
125 | *encoding = WCA_ENCODING_ANSI; | ||
126 | hr = StrAllocStringAnsi(psczOutput, reinterpret_cast<LPCSTR>(pbData), 0, CP_ACP); | ||
127 | } | ||
128 | ExitOnFailure(hr, "Failed to allocate string for binary buffer."); | ||
129 | } | ||
130 | |||
131 | // Free the byte buffer since it has been converted to a new UNICODE string, one way or another. | ||
132 | if (pbData) | ||
133 | { | ||
134 | WcaFreeStream(pbData); | ||
135 | pbData = NULL; | ||
136 | } | ||
137 | |||
138 | LExit: | ||
139 | ReleaseMem(pbData); | ||
140 | |||
141 | return hr; | ||
142 | } | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/inc/wcalog.h b/src/libs/wcautil/WixToolset.WcaUtil/inc/wcalog.h new file mode 100644 index 00000000..ffa3fa03 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/inc/wcalog.h | |||
@@ -0,0 +1,14 @@ | |||
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 | #ifdef __cplusplus | ||
6 | extern "C" { | ||
7 | #endif | ||
8 | |||
9 | BOOL WIXAPI IsVerboseLogging(); | ||
10 | HRESULT WIXAPI SetVerboseLoggingAtom(BOOL bValue); | ||
11 | |||
12 | #ifdef __cplusplus | ||
13 | } | ||
14 | #endif | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/inc/wcautil.h b/src/libs/wcautil/WixToolset.WcaUtil/inc/wcautil.h new file mode 100644 index 00000000..4d036a9d --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/inc/wcautil.h | |||
@@ -0,0 +1,397 @@ | |||
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 | #ifdef __cplusplus | ||
6 | extern "C" { | ||
7 | #endif | ||
8 | |||
9 | #include "dutilsources.h" | ||
10 | |||
11 | #define WIXAPI __stdcall | ||
12 | #ifndef DUTIL_SOURCE_DEFAULT | ||
13 | #define DUTIL_SOURCE_DEFAULT DUTIL_SOURCE_EXTERNAL | ||
14 | #endif | ||
15 | |||
16 | #include "dutil.h" | ||
17 | |||
18 | #define MessageExitOnLastErrorSource(d, x, e, s, ...) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { ExitTraceSource(d, x, "%s", s, __VA_ARGS__); WcaErrorMessage(e, x, MB_OK, -1, __VA_ARGS__); goto LExit; } } | ||
19 | #define MessageExitOnFailureSource(d, x, e, s, ...) if (FAILED(x)) { ExitTraceSource(d, x, "%s", s, __VA_ARGS__); WcaErrorMessage(e, x, INSTALLMESSAGE_ERROR | MB_OK, -1, __VA_ARGS__); goto LExit; } | ||
20 | #define MessageExitOnNullWithLastErrorSource(d, p, x, e, s, ...) if (NULL == p) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTraceSource(d, x, "%s", s, __VA_ARGS__); WcaErrorMessage(e, x, MB_OK, -1, __VA_ARGS__); goto LExit; } | ||
21 | |||
22 | #define MessageExitOnLastError(x, e, s, ...) MessageExitOnLastErrorSource(DUTIL_SOURCE_DEFAULT, x, e, s, __VA_ARGS__) | ||
23 | #define MessageExitOnFailure(x, e, s, ...) MessageExitOnFailureSource(DUTIL_SOURCE_DEFAULT, x, e, s, __VA_ARGS__) | ||
24 | #define MessageExitOnNullWithLastError(p, x, e, s, ...) MessageExitOnNullWithLastErrorSource(DUTIL_SOURCE_DEFAULT, p, x, e, s, __VA_ARGS__) | ||
25 | |||
26 | // Generic action enum. | ||
27 | typedef enum WCA_ACTION | ||
28 | { | ||
29 | WCA_ACTION_NONE, | ||
30 | WCA_ACTION_INSTALL, | ||
31 | WCA_ACTION_UNINSTALL, | ||
32 | } WCA_ACTION; | ||
33 | |||
34 | typedef enum WCA_CASCRIPT | ||
35 | { | ||
36 | WCA_CASCRIPT_SCHEDULED, | ||
37 | WCA_CASCRIPT_ROLLBACK, | ||
38 | } WCA_CASCRIPT; | ||
39 | |||
40 | typedef enum WCA_CASCRIPT_CLOSE | ||
41 | { | ||
42 | WCA_CASCRIPT_CLOSE_PRESERVE, | ||
43 | WCA_CASCRIPT_CLOSE_DELETE, | ||
44 | } WCA_CASCRIPT_CLOSE; | ||
45 | |||
46 | typedef enum WCA_TODO | ||
47 | { | ||
48 | WCA_TODO_UNKNOWN, | ||
49 | WCA_TODO_INSTALL, | ||
50 | WCA_TODO_UNINSTALL, | ||
51 | WCA_TODO_REINSTALL, | ||
52 | } WCA_TODO; | ||
53 | |||
54 | typedef struct WCA_CASCRIPT_STRUCT | ||
55 | { | ||
56 | LPWSTR pwzScriptPath; | ||
57 | HANDLE hScriptFile; | ||
58 | } *WCA_CASCRIPT_HANDLE; | ||
59 | |||
60 | typedef enum WCA_ENCODING | ||
61 | { | ||
62 | WCA_ENCODING_UNKNOWN, | ||
63 | WCA_ENCODING_UTF_16, | ||
64 | WCA_ENCODING_UTF_8, | ||
65 | WCA_ENCODING_ANSI, | ||
66 | } WCA_ENCODING; | ||
67 | |||
68 | void WIXAPI WcaGlobalInitialize( | ||
69 | __in HINSTANCE hInst | ||
70 | ); | ||
71 | void WIXAPI WcaGlobalFinalize(); | ||
72 | |||
73 | HRESULT WIXAPI WcaInitialize( | ||
74 | __in MSIHANDLE hInstall, | ||
75 | __in_z PCSTR szCustomActionLogName | ||
76 | ); | ||
77 | UINT WIXAPI WcaFinalize( | ||
78 | __in UINT iReturnValue | ||
79 | ); | ||
80 | BOOL WIXAPI WcaIsInitialized(); | ||
81 | |||
82 | MSIHANDLE WIXAPI WcaGetInstallHandle(); | ||
83 | MSIHANDLE WIXAPI WcaGetDatabaseHandle(); | ||
84 | |||
85 | const char* WIXAPI WcaGetLogName(); | ||
86 | |||
87 | void WIXAPI WcaSetReturnValue( | ||
88 | __in UINT iReturnValue | ||
89 | ); | ||
90 | BOOL WIXAPI WcaCancelDetected(); | ||
91 | |||
92 | #define LOG_BUFFER 2048 | ||
93 | typedef enum LOGLEVEL | ||
94 | { | ||
95 | LOGMSG_TRACEONLY, // Never written to the log file (except in DEBUG builds) | ||
96 | LOGMSG_VERBOSE, // Written to log when LOGVERBOSE | ||
97 | LOGMSG_STANDARD // Written to log whenever informational logging is enabled | ||
98 | } LOGLEVEL; | ||
99 | |||
100 | void __cdecl WcaLog( | ||
101 | __in LOGLEVEL llv, | ||
102 | __in_z __format_string PCSTR fmt, ... | ||
103 | ); | ||
104 | BOOL WIXAPI WcaDisplayAssert( | ||
105 | __in LPCSTR sz | ||
106 | ); | ||
107 | void __cdecl WcaLogError( | ||
108 | __in HRESULT hr, | ||
109 | __in LPCSTR szMessage, | ||
110 | ... | ||
111 | ); | ||
112 | void WIXAPI WcaLogErrorArgs( | ||
113 | __in HRESULT hr, | ||
114 | __in LPCSTR szMessage, | ||
115 | __in va_list args | ||
116 | ); | ||
117 | |||
118 | UINT WIXAPI WcaProcessMessage( | ||
119 | __in INSTALLMESSAGE eMessageType, | ||
120 | __in MSIHANDLE hRecord | ||
121 | ); | ||
122 | UINT __cdecl WcaErrorMessage( | ||
123 | __in int iError, | ||
124 | __in HRESULT hrError, | ||
125 | __in UINT uiType, | ||
126 | __in INT cArgs, | ||
127 | ... | ||
128 | ); | ||
129 | HRESULT WIXAPI WcaProgressMessage( | ||
130 | __in UINT uiCost, | ||
131 | __in BOOL fExtendProgressBar | ||
132 | ); | ||
133 | |||
134 | BOOL WIXAPI WcaIsInstalling( | ||
135 | __in INSTALLSTATE isInstalled, | ||
136 | __in INSTALLSTATE isAction | ||
137 | ); | ||
138 | BOOL WIXAPI WcaIsReInstalling( | ||
139 | __in INSTALLSTATE isInstalled, | ||
140 | __in INSTALLSTATE isAction | ||
141 | ); | ||
142 | BOOL WIXAPI WcaIsUninstalling( | ||
143 | __in INSTALLSTATE isInstalled, | ||
144 | __in INSTALLSTATE isAction | ||
145 | ); | ||
146 | |||
147 | HRESULT WIXAPI WcaSetComponentState( | ||
148 | __in_z LPCWSTR wzComponent, | ||
149 | __in INSTALLSTATE isState | ||
150 | ); | ||
151 | |||
152 | HRESULT WIXAPI WcaTableExists( | ||
153 | __in_z LPCWSTR wzTable | ||
154 | ); | ||
155 | |||
156 | HRESULT WIXAPI WcaOpenView( | ||
157 | __in_z LPCWSTR wzSql, | ||
158 | __out MSIHANDLE* phView | ||
159 | ); | ||
160 | HRESULT WIXAPI WcaExecuteView( | ||
161 | __in MSIHANDLE hView, | ||
162 | __in MSIHANDLE hRec | ||
163 | ); | ||
164 | HRESULT WIXAPI WcaOpenExecuteView( | ||
165 | __in_z LPCWSTR wzSql, | ||
166 | __out MSIHANDLE* phView | ||
167 | ); | ||
168 | HRESULT WIXAPI WcaFetchRecord( | ||
169 | __in MSIHANDLE hView, | ||
170 | __out MSIHANDLE* phRec | ||
171 | ); | ||
172 | HRESULT WIXAPI WcaFetchSingleRecord( | ||
173 | __in MSIHANDLE hView, | ||
174 | __out MSIHANDLE* phRec | ||
175 | ); | ||
176 | |||
177 | HRESULT WIXAPI WcaGetProperty( | ||
178 | __in_z LPCWSTR wzProperty, | ||
179 | __inout LPWSTR* ppwzData | ||
180 | ); | ||
181 | HRESULT WIXAPI WcaGetFormattedProperty( | ||
182 | __in_z LPCWSTR wzProperty, | ||
183 | __out LPWSTR* ppwzData | ||
184 | ); | ||
185 | HRESULT WIXAPI WcaGetFormattedString( | ||
186 | __in_z LPCWSTR wzString, | ||
187 | __out LPWSTR* ppwzData | ||
188 | ); | ||
189 | HRESULT WIXAPI WcaGetIntProperty( | ||
190 | __in_z LPCWSTR wzProperty, | ||
191 | __inout int* piData | ||
192 | ); | ||
193 | HRESULT WIXAPI WcaGetTargetPath( | ||
194 | __in_z LPCWSTR wzFolder, | ||
195 | __out LPWSTR* ppwzData | ||
196 | ); | ||
197 | HRESULT WIXAPI WcaSetProperty( | ||
198 | __in_z LPCWSTR wzPropertyName, | ||
199 | __in_z LPCWSTR wzPropertyValue | ||
200 | ); | ||
201 | HRESULT WIXAPI WcaSetIntProperty( | ||
202 | __in_z LPCWSTR wzPropertyName, | ||
203 | __in int nPropertyValue | ||
204 | ); | ||
205 | BOOL WIXAPI WcaIsPropertySet( | ||
206 | __in LPCSTR szProperty | ||
207 | ); | ||
208 | BOOL WIXAPI WcaIsUnicodePropertySet( | ||
209 | __in LPCWSTR wzProperty | ||
210 | ); | ||
211 | |||
212 | HRESULT WIXAPI WcaGetRecordInteger( | ||
213 | __in MSIHANDLE hRec, | ||
214 | __in UINT uiField, | ||
215 | __inout int* piData | ||
216 | ); | ||
217 | HRESULT WIXAPI WcaGetRecordString( | ||
218 | __in MSIHANDLE hRec, | ||
219 | __in UINT uiField, | ||
220 | __inout LPWSTR* ppwzData | ||
221 | ); | ||
222 | HRESULT WIXAPI WcaGetRecordFormattedInteger( | ||
223 | __in MSIHANDLE hRec, | ||
224 | __in UINT uiField, | ||
225 | __out int* piData | ||
226 | ); | ||
227 | HRESULT WIXAPI WcaGetRecordFormattedString( | ||
228 | __in MSIHANDLE hRec, | ||
229 | __in UINT uiField, | ||
230 | __inout LPWSTR* ppwzData | ||
231 | ); | ||
232 | |||
233 | HRESULT WIXAPI WcaAllocStream( | ||
234 | __deref_out_bcount_part(cbData, 0) BYTE** ppbData, | ||
235 | __in SIZE_T cbData | ||
236 | ); | ||
237 | HRESULT WIXAPI WcaFreeStream( | ||
238 | __in BYTE* pbData | ||
239 | ); | ||
240 | |||
241 | HRESULT WIXAPI WcaGetRecordStream( | ||
242 | __in MSIHANDLE hRecBinary, | ||
243 | __in UINT uiField, | ||
244 | __deref_out_bcount_full(*pcbData) BYTE** ppbData, | ||
245 | __out DWORD* pcbData | ||
246 | ); | ||
247 | HRESULT WIXAPI WcaSetRecordString( | ||
248 | __in MSIHANDLE hRec, | ||
249 | __in UINT uiField, | ||
250 | __in_z LPCWSTR wzData | ||
251 | ); | ||
252 | HRESULT WIXAPI WcaSetRecordInteger( | ||
253 | __in MSIHANDLE hRec, | ||
254 | __in UINT uiField, | ||
255 | __in int iValue | ||
256 | ); | ||
257 | |||
258 | HRESULT WIXAPI WcaDoDeferredAction( | ||
259 | __in_z LPCWSTR wzAction, | ||
260 | __in_z LPCWSTR wzCustomActionData, | ||
261 | __in UINT uiCost | ||
262 | ); | ||
263 | DWORD WIXAPI WcaCountOfCustomActionDataRecords( | ||
264 | __in_z LPCWSTR wzData | ||
265 | ); | ||
266 | |||
267 | HRESULT WIXAPI WcaReadStringFromCaData( | ||
268 | __deref_in LPWSTR* ppwzCustomActionData, | ||
269 | __deref_out_z LPWSTR* ppwzString | ||
270 | ); | ||
271 | HRESULT WIXAPI WcaReadIntegerFromCaData( | ||
272 | __deref_in LPWSTR* ppwzCustomActionData, | ||
273 | __out int* piResult | ||
274 | ); | ||
275 | HRESULT WIXAPI WcaReadStreamFromCaData( | ||
276 | __deref_in LPWSTR* ppwzCustomActionData, | ||
277 | __deref_out_bcount(*pcbData) BYTE** ppbData, | ||
278 | __out DWORD_PTR* pcbData | ||
279 | ); | ||
280 | HRESULT WIXAPI WcaWriteStringToCaData( | ||
281 | __in_z LPCWSTR wzString, | ||
282 | __deref_inout_z LPWSTR* ppwzCustomActionData | ||
283 | ); | ||
284 | HRESULT WIXAPI WcaWriteIntegerToCaData( | ||
285 | __in int i, | ||
286 | __deref_out_z_opt LPWSTR* ppwzCustomActionData | ||
287 | ); | ||
288 | HRESULT WIXAPI WcaWriteStreamToCaData( | ||
289 | __in_bcount(cbData) const BYTE* pbData, | ||
290 | __in SIZE_T cbData, | ||
291 | __deref_inout_z_opt LPWSTR* ppwzCustomActionData | ||
292 | ); | ||
293 | |||
294 | HRESULT __cdecl WcaAddTempRecord( | ||
295 | __inout MSIHANDLE* phTableView, | ||
296 | __inout MSIHANDLE* phColumns, | ||
297 | __in_z LPCWSTR wzTable, | ||
298 | __out_opt MSIDBERROR* pdbError, | ||
299 | __in UINT uiUniquifyColumn, | ||
300 | __in UINT cColumns, | ||
301 | ... | ||
302 | ); | ||
303 | |||
304 | HRESULT WIXAPI WcaDumpTable( | ||
305 | __in_z LPCWSTR wzTable | ||
306 | ); | ||
307 | |||
308 | HRESULT WIXAPI WcaDeferredActionRequiresReboot(); | ||
309 | BOOL WIXAPI WcaDidDeferredActionRequireReboot(); | ||
310 | |||
311 | HRESULT WIXAPI WcaCaScriptCreateKey( | ||
312 | __out LPWSTR* ppwzScriptKey | ||
313 | ); | ||
314 | |||
315 | HRESULT WIXAPI WcaCaScriptCreate( | ||
316 | __in WCA_ACTION action, | ||
317 | __in WCA_CASCRIPT script, | ||
318 | __in BOOL fImpersonated, | ||
319 | __in_z LPCWSTR wzScriptKey, | ||
320 | __in BOOL fAppend, | ||
321 | __out WCA_CASCRIPT_HANDLE* phScript | ||
322 | ); | ||
323 | |||
324 | HRESULT WIXAPI WcaCaScriptOpen( | ||
325 | __in WCA_ACTION action, | ||
326 | __in WCA_CASCRIPT script, | ||
327 | __in BOOL fImpersonated, | ||
328 | __in_z LPCWSTR wzScriptKey, | ||
329 | __out WCA_CASCRIPT_HANDLE* phScript | ||
330 | ); | ||
331 | |||
332 | void WIXAPI WcaCaScriptClose( | ||
333 | __in_opt WCA_CASCRIPT_HANDLE hScript, | ||
334 | __in WCA_CASCRIPT_CLOSE closeOperation | ||
335 | ); | ||
336 | |||
337 | HRESULT WIXAPI WcaCaScriptReadAsCustomActionData( | ||
338 | __in WCA_CASCRIPT_HANDLE hScript, | ||
339 | __out LPWSTR* ppwzCustomActionData | ||
340 | ); | ||
341 | |||
342 | HRESULT WIXAPI WcaCaScriptWriteString( | ||
343 | __in WCA_CASCRIPT_HANDLE hScript, | ||
344 | __in_z LPCWSTR wzValue | ||
345 | ); | ||
346 | |||
347 | HRESULT WIXAPI WcaCaScriptWriteNumber( | ||
348 | __in WCA_CASCRIPT_HANDLE hScript, | ||
349 | __in DWORD dwValue | ||
350 | ); | ||
351 | |||
352 | void WIXAPI WcaCaScriptFlush( | ||
353 | __in WCA_CASCRIPT_HANDLE hScript | ||
354 | ); | ||
355 | |||
356 | void WIXAPI WcaCaScriptCleanup( | ||
357 | __in_z LPCWSTR wzProductCode, | ||
358 | __in BOOL fImpersonated | ||
359 | ); | ||
360 | |||
361 | HRESULT WIXAPI QuietExec( | ||
362 | __inout_z LPWSTR wzCommand, | ||
363 | __in DWORD dwTimeout, | ||
364 | __in BOOL fLogCommand, | ||
365 | __in BOOL fLogOutput | ||
366 | ); | ||
367 | |||
368 | HRESULT WIXAPI QuietExecCapture( | ||
369 | __inout_z LPWSTR wzCommand, | ||
370 | __in DWORD dwTimeout, | ||
371 | __in BOOL fLogCommand, | ||
372 | __in BOOL fLogOutput, | ||
373 | __out_z_opt LPWSTR* psczOutput | ||
374 | ); | ||
375 | |||
376 | WCA_TODO WIXAPI WcaGetComponentToDo( | ||
377 | __in_z LPCWSTR wzComponentId | ||
378 | ); | ||
379 | |||
380 | HRESULT WIXAPI WcaExtractBinaryToBuffer( | ||
381 | __in LPCWSTR wzBinaryId, | ||
382 | __out BYTE** pbData, | ||
383 | __out DWORD* pcbData | ||
384 | ); | ||
385 | HRESULT WIXAPI WcaExtractBinaryToFile( | ||
386 | __in LPCWSTR wzBinaryId, | ||
387 | __in LPCWSTR wzPath | ||
388 | ); | ||
389 | HRESULT WIXAPI WcaExtractBinaryToString( | ||
390 | __in LPCWSTR wzBinaryId, | ||
391 | __deref_out_z LPWSTR* psczOutput, | ||
392 | __out WCA_ENCODING* encoding | ||
393 | ); | ||
394 | |||
395 | #ifdef __cplusplus | ||
396 | } | ||
397 | #endif | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/inc/wcawow64.h b/src/libs/wcautil/WixToolset.WcaUtil/inc/wcawow64.h new file mode 100644 index 00000000..dd55f3fd --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/inc/wcawow64.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #pragma once | ||
2 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
3 | |||
4 | |||
5 | #include "wcautil.h" | ||
6 | |||
7 | #ifdef __cplusplus | ||
8 | extern "C" { | ||
9 | #endif | ||
10 | |||
11 | HRESULT WIXAPI WcaInitializeWow64(); | ||
12 | BOOL WIXAPI WcaIsWow64Process(); | ||
13 | BOOL WIXAPI WcaIsWow64Initialized(); | ||
14 | HRESULT WIXAPI WcaDisableWow64FSRedirection(); | ||
15 | HRESULT WIXAPI WcaRevertWow64FSRedirection(); | ||
16 | HRESULT WIXAPI WcaFinalizeWow64(); | ||
17 | |||
18 | #ifdef __cplusplus | ||
19 | } | ||
20 | #endif | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/inc/wcawrapquery.h b/src/libs/wcautil/WixToolset.WcaUtil/inc/wcawrapquery.h new file mode 100644 index 00000000..e08f1c3f --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/inc/wcawrapquery.h | |||
@@ -0,0 +1,130 @@ | |||
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 "wcautil.h" | ||
6 | |||
7 | // Enumerations | ||
8 | typedef enum eWrapQueryAction | ||
9 | { | ||
10 | wqaTableBegin = 1, | ||
11 | wqaTableFinish, | ||
12 | wqaRowBegin, | ||
13 | wqaRowFinish | ||
14 | } eWrapQueryAction; | ||
15 | |||
16 | typedef enum eColumnDataType | ||
17 | { | ||
18 | cdtString = 1, | ||
19 | cdtInt, | ||
20 | cdtStream, | ||
21 | cdtUnknown | ||
22 | } eColumnDataType; | ||
23 | |||
24 | typedef enum eFormatMaskColumn | ||
25 | { | ||
26 | efmcColumn1 = 1, | ||
27 | efmcColumn2 = 1 << 1, | ||
28 | efmcColumn3 = 1 << 2, | ||
29 | efmcColumn4 = 1 << 3, | ||
30 | efmcColumn5 = 1 << 4, | ||
31 | efmcColumn6 = 1 << 5, | ||
32 | efmcColumn7 = 1 << 6, | ||
33 | efmcColumn8 = 1 << 7, | ||
34 | efmcColumn9 = 1 << 8, | ||
35 | efmcColumn10 = 1 << 9, | ||
36 | efmcColumn11 = 1 << 10, | ||
37 | efmcColumn12 = 1 << 11, | ||
38 | efmcColumn13 = 1 << 12, | ||
39 | efmcColumn14 = 1 << 13, | ||
40 | efmcColumn15 = 1 << 14, | ||
41 | efmcColumn16 = 1 << 15, | ||
42 | efmcColumn17 = 1 << 16, | ||
43 | efmcColumn18 = 1 << 17, | ||
44 | efmcColumn19 = 1 << 18, | ||
45 | efmcColumn20 = 1 << 19, | ||
46 | efmcColumn21 = 1 << 20, | ||
47 | efmcColumn22 = 1 << 21, | ||
48 | efmcColumn23 = 1 << 22, | ||
49 | efmcColumn24 = 1 << 23, | ||
50 | efmcColumn25 = 1 << 24, | ||
51 | efmcColumn26 = 1 << 25, | ||
52 | efmcColumn27 = 1 << 26, | ||
53 | efmcColumn28 = 1 << 27, | ||
54 | efmcColumn29 = 1 << 28, | ||
55 | efmcColumn30 = 1 << 29, | ||
56 | efmcColumn31 = 1 << 30, | ||
57 | efmcColumn32 = 1 << 31, | ||
58 | } eFormatMaskColumn; | ||
59 | |||
60 | // Keeps track of the query instance for the reading CA (deferred CA) | ||
61 | typedef struct WCA_WRAPQUERY_STRUCT | ||
62 | { | ||
63 | // These are used to size our dynamic arrays below | ||
64 | DWORD dwColumns, dwRows, dwNextIndex; | ||
65 | |||
66 | // Dynamic arrays of column schema information | ||
67 | eColumnDataType *pcdtColumnType; | ||
68 | LPWSTR *ppwzColumnNames; | ||
69 | |||
70 | // Dynamic array of raw record data | ||
71 | MSIHANDLE *phRecords; | ||
72 | } *WCA_WRAPQUERY_HANDLE; | ||
73 | |||
74 | // Wrap a query | ||
75 | // Setting the pfFormatMask enables control over which fields will be formatted, and which will be left unchanged | ||
76 | // Setting dwComponentColumn to something other than 0xFFFFFFFF tells WcaWrapQuery to add two additional columns to the right side of the table | ||
77 | // - ISInstalled and ISAction - which map to the ComponentState of the component (the component is found in the column specified) | ||
78 | // Note that if a component is NULL, the component state columns will also be left null, and it will be up to the deferred CA to fail or ignore the case appropriately | ||
79 | // Setting dwDirectoryColumn to something other than 0xFFFFFFFF tells WcaWrapQuery to add two more additional columns to the right side of the table | ||
80 | // - SourcePath and TargetPath - which map to the Directory's Source and Target Path (the directory is found in the column specified) | ||
81 | // Note that if a directory is NULL, the directory source/target path columns will also be left null, and it will be up to the deferred CA to fail or ignore the case appropriately | ||
82 | HRESULT WIXAPI WcaWrapQuery( | ||
83 | __in_z LPCWSTR pwzQuery, | ||
84 | __inout LPWSTR * ppwzCustomActionData, | ||
85 | __in_opt DWORD dwFormatMask, | ||
86 | __in_opt DWORD dwComponentColumn, | ||
87 | __in_opt DWORD dwDirectoryColumn | ||
88 | ); | ||
89 | // This wraps an empty table query into the custom action data - this is a way to indicate to the deferred custom action that a necessary table doesn't exist, or its query returned no results | ||
90 | HRESULT WIXAPI WcaWrapEmptyQuery( | ||
91 | __inout LPWSTR * ppwzCustomActionData | ||
92 | ); | ||
93 | |||
94 | // Open a new unwrap query operation, with data from the ppwzCustomActionData string | ||
95 | HRESULT WIXAPI WcaBeginUnwrapQuery( | ||
96 | __out WCA_WRAPQUERY_HANDLE * phWrapQuery, | ||
97 | __inout LPWSTR * ppwzCustomActionData | ||
98 | ); | ||
99 | |||
100 | // Get the number of records in a query being unwrapped | ||
101 | DWORD WIXAPI WcaGetQueryRecords( | ||
102 | __in const WCA_WRAPQUERY_HANDLE hWrapQuery | ||
103 | ); | ||
104 | |||
105 | // This function resets a query back to its first row, so that the next fetch returns the first record | ||
106 | void WIXAPI WcaFetchWrappedReset( | ||
107 | __in WCA_WRAPQUERY_HANDLE hWrapQuery | ||
108 | ); | ||
109 | // Fetch the next record in this query | ||
110 | // NOTE: the MSIHANDLE returned by this function should not be released, as it is the same handle used by the query object to maintain the item. | ||
111 | // so, don't use this function with PMSIHANDLE objects! | ||
112 | HRESULT WIXAPI WcaFetchWrappedRecord( | ||
113 | __in WCA_WRAPQUERY_HANDLE hWrapQuery, | ||
114 | __out MSIHANDLE* phRec | ||
115 | ); | ||
116 | |||
117 | // Fetch the next record in the query where the string value in column dwComparisonColumn equals the value pwzExpectedValue | ||
118 | // NOTE: the MSIHANDLE returned by this function should not be released, as it is the same handle used by the query object to maintain the item. | ||
119 | // so, don't use this function with PMSIHANDLE objects! | ||
120 | HRESULT WIXAPI WcaFetchWrappedRecordWhereString( | ||
121 | __in WCA_WRAPQUERY_HANDLE hWrapQuery, | ||
122 | __in DWORD dwComparisonColumn, | ||
123 | __in_z LPCWSTR pwzExpectedValue, | ||
124 | __out MSIHANDLE* phRec | ||
125 | ); | ||
126 | |||
127 | // Release a query ID (frees memory, and frees the ID for a new query) | ||
128 | void WIXAPI WcaFinishUnwrapQuery( | ||
129 | __in_opt WCA_WRAPQUERY_HANDLE hWrapQuery | ||
130 | ); | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/packages.config b/src/libs/wcautil/WixToolset.WcaUtil/packages.config new file mode 100644 index 00000000..aa8b4077 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/packages.config | |||
@@ -0,0 +1,5 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <packages> | ||
3 | <package id="Nerdbank.GitVersioning" version="2.1.65" developmentDependency="true" targetFramework="net40" /> | ||
4 | <package id="WixToolset.DUtil" version="4.0.72" targetFramework="native" /> | ||
5 | </packages> \ No newline at end of file | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/precomp.h b/src/libs/wcautil/WixToolset.WcaUtil/precomp.h new file mode 100644 index 00000000..1d41337a --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/precomp.h | |||
@@ -0,0 +1,19 @@ | |||
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 <wchar.h> | ||
8 | #include <strsafe.h> | ||
9 | |||
10 | const WCHAR MAGIC_MULTISZ_DELIM = 128; | ||
11 | |||
12 | #include "wcautil.h" | ||
13 | #include "inc\wcalog.h" | ||
14 | #include "inc\wcawow64.h" | ||
15 | #include "inc\wcawrapquery.h" | ||
16 | #include "wiutil.h" | ||
17 | #include "fileutil.h" | ||
18 | #include "memutil.h" | ||
19 | #include "strutil.h" | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/qtexec.cpp b/src/libs/wcautil/WixToolset.WcaUtil/qtexec.cpp new file mode 100644 index 00000000..19abfaf8 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/qtexec.cpp | |||
@@ -0,0 +1,340 @@ | |||
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 | #define OUTPUT_BUFFER 1024 | ||
6 | #define ONEMINUTE 60000 | ||
7 | |||
8 | static HRESULT CreatePipes( | ||
9 | __out HANDLE *phOutRead, | ||
10 | __out HANDLE *phOutWrite, | ||
11 | __out HANDLE *phErrWrite, | ||
12 | __out HANDLE *phInRead, | ||
13 | __out HANDLE *phInWrite | ||
14 | ) | ||
15 | { | ||
16 | Assert(phOutRead); | ||
17 | Assert(phOutWrite); | ||
18 | Assert(phErrWrite); | ||
19 | Assert(phInRead); | ||
20 | Assert(phInWrite); | ||
21 | |||
22 | HRESULT hr = S_OK; | ||
23 | SECURITY_ATTRIBUTES sa; | ||
24 | HANDLE hOutTemp = INVALID_HANDLE_VALUE; | ||
25 | HANDLE hInTemp = INVALID_HANDLE_VALUE; | ||
26 | |||
27 | HANDLE hOutRead = INVALID_HANDLE_VALUE; | ||
28 | HANDLE hOutWrite = INVALID_HANDLE_VALUE; | ||
29 | HANDLE hErrWrite = INVALID_HANDLE_VALUE; | ||
30 | HANDLE hInRead = INVALID_HANDLE_VALUE; | ||
31 | HANDLE hInWrite = INVALID_HANDLE_VALUE; | ||
32 | |||
33 | // Fill out security structure so we can inherit handles | ||
34 | ::ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); | ||
35 | sa.nLength = sizeof(SECURITY_ATTRIBUTES); | ||
36 | sa.bInheritHandle = TRUE; | ||
37 | sa.lpSecurityDescriptor = NULL; | ||
38 | |||
39 | // Create pipes | ||
40 | if (!::CreatePipe(&hOutTemp, &hOutWrite, &sa, 0)) | ||
41 | { | ||
42 | ExitOnLastError(hr, "Failed to create output pipe"); | ||
43 | } | ||
44 | |||
45 | if (!::CreatePipe(&hInRead, &hInTemp, &sa, 0)) | ||
46 | { | ||
47 | ExitOnLastError(hr, "Failed to create input pipe"); | ||
48 | } | ||
49 | |||
50 | |||
51 | // Duplicate output pipe so standard error and standard output write to | ||
52 | // the same pipe | ||
53 | if (!::DuplicateHandle(::GetCurrentProcess(), hOutWrite, ::GetCurrentProcess(), &hErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS)) | ||
54 | { | ||
55 | ExitOnLastError(hr, "Failed to duplicate write handle"); | ||
56 | } | ||
57 | |||
58 | // We need to create new output read and input write handles that are | ||
59 | // non inheritable. Otherwise it creates handles that can't be closed. | ||
60 | if (!::DuplicateHandle(::GetCurrentProcess(), hOutTemp, ::GetCurrentProcess(), &hOutRead, 0, FALSE, DUPLICATE_SAME_ACCESS)) | ||
61 | { | ||
62 | ExitOnLastError(hr, "Failed to duplicate output pipe"); | ||
63 | } | ||
64 | |||
65 | if (!::DuplicateHandle(::GetCurrentProcess(), hInTemp, ::GetCurrentProcess(), &hInWrite, 0, FALSE, DUPLICATE_SAME_ACCESS)) | ||
66 | { | ||
67 | ExitOnLastError(hr, "Failed to duplicate input pipe"); | ||
68 | } | ||
69 | |||
70 | // now that everything has succeeded, assign to the outputs | ||
71 | *phOutRead = hOutRead; | ||
72 | hOutRead = INVALID_HANDLE_VALUE; | ||
73 | |||
74 | *phOutWrite = hOutWrite; | ||
75 | hOutWrite = INVALID_HANDLE_VALUE; | ||
76 | |||
77 | *phErrWrite = hErrWrite; | ||
78 | hErrWrite = INVALID_HANDLE_VALUE; | ||
79 | |||
80 | *phInRead = hInRead; | ||
81 | hInRead = INVALID_HANDLE_VALUE; | ||
82 | |||
83 | *phInWrite = hInWrite; | ||
84 | hInWrite = INVALID_HANDLE_VALUE; | ||
85 | |||
86 | LExit: | ||
87 | ReleaseFile(hOutRead); | ||
88 | ReleaseFile(hOutWrite); | ||
89 | ReleaseFile(hErrWrite); | ||
90 | ReleaseFile(hInRead); | ||
91 | ReleaseFile(hInWrite); | ||
92 | ReleaseFile(hOutTemp); | ||
93 | ReleaseFile(hInTemp); | ||
94 | |||
95 | return hr; | ||
96 | } | ||
97 | |||
98 | static HRESULT HandleOutput( | ||
99 | __in BOOL fLogOutput, | ||
100 | __in HANDLE hRead, | ||
101 | __out_z_opt LPWSTR* psczOutput | ||
102 | ) | ||
103 | { | ||
104 | BYTE* pBuffer = NULL; | ||
105 | LPWSTR szLog = NULL; | ||
106 | LPWSTR szTemp = NULL; | ||
107 | LPWSTR pEnd = NULL; | ||
108 | LPWSTR pNext = NULL; | ||
109 | LPWSTR sczEscaped = NULL; | ||
110 | LPSTR szWrite = NULL; | ||
111 | DWORD dwBytes = OUTPUT_BUFFER; | ||
112 | BOOL bFirst = TRUE; | ||
113 | BOOL bUnicode = TRUE; | ||
114 | HRESULT hr = S_OK; | ||
115 | |||
116 | // Get buffer for output | ||
117 | pBuffer = static_cast<BYTE *>(MemAlloc(OUTPUT_BUFFER, FALSE)); | ||
118 | ExitOnNull(pBuffer, hr, E_OUTOFMEMORY, "Failed to allocate buffer for output."); | ||
119 | |||
120 | while (0 != dwBytes) | ||
121 | { | ||
122 | ::ZeroMemory(pBuffer, OUTPUT_BUFFER); | ||
123 | if (!::ReadFile(hRead, pBuffer, OUTPUT_BUFFER - 1, &dwBytes, NULL) && GetLastError() != ERROR_BROKEN_PIPE) | ||
124 | { | ||
125 | ExitOnLastError(hr, "Failed to read from handle."); | ||
126 | } | ||
127 | |||
128 | if (fLogOutput) | ||
129 | { | ||
130 | // Check for UNICODE or ANSI output | ||
131 | if (bFirst) | ||
132 | { | ||
133 | if ((isgraph(pBuffer[0]) && isgraph(pBuffer[1])) || | ||
134 | (isgraph(pBuffer[0]) && isspace(pBuffer[1])) || | ||
135 | (isspace(pBuffer[0]) && isgraph(pBuffer[1])) || | ||
136 | (isspace(pBuffer[0]) && isspace(pBuffer[1]))) | ||
137 | { | ||
138 | bUnicode = FALSE; | ||
139 | } | ||
140 | |||
141 | bFirst = FALSE; | ||
142 | } | ||
143 | |||
144 | // Keep track of output | ||
145 | if (bUnicode) | ||
146 | { | ||
147 | hr = StrAllocConcat(&szLog, (LPCWSTR)pBuffer, 0); | ||
148 | ExitOnFailure(hr, "Failed to concatenate output strings."); | ||
149 | |||
150 | if (psczOutput) | ||
151 | { | ||
152 | hr = StrAllocConcat(psczOutput, (LPCWSTR)pBuffer, 0); | ||
153 | ExitOnFailure(hr, "Failed to concatenate output to return string."); | ||
154 | } | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | hr = StrAllocStringAnsi(&szTemp, (LPCSTR)pBuffer, 0, CP_OEMCP); | ||
159 | ExitOnFailure(hr, "Failed to allocate output string."); | ||
160 | hr = StrAllocConcat(&szLog, szTemp, 0); | ||
161 | ExitOnFailure(hr, "Failed to concatenate output strings."); | ||
162 | |||
163 | if (psczOutput) | ||
164 | { | ||
165 | hr = StrAllocConcat(psczOutput, szTemp, 0); | ||
166 | ExitOnFailure(hr, "Failed to concatenate output to return string."); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | // Log each line of the output | ||
171 | pNext = szLog; | ||
172 | pEnd = wcschr(szLog, L'\r'); | ||
173 | if (NULL == pEnd) | ||
174 | { | ||
175 | pEnd = wcschr(szLog, L'\n'); | ||
176 | } | ||
177 | while (pEnd && *pEnd) | ||
178 | { | ||
179 | // Find beginning of next line | ||
180 | pEnd[0] = 0; | ||
181 | ++pEnd; | ||
182 | if ((pEnd[0] == L'\r') || (pEnd[0] == L'\n')) | ||
183 | { | ||
184 | ++pEnd; | ||
185 | } | ||
186 | |||
187 | // Log output | ||
188 | hr = StrAllocString(&sczEscaped, pNext, 0); | ||
189 | ExitOnFailure(hr, "Failed to allocate copy of string"); | ||
190 | |||
191 | hr = StrReplaceStringAll(&sczEscaped, L"%", L"%%"); | ||
192 | ExitOnFailure(hr, "Failed to escape percent signs in string"); | ||
193 | |||
194 | hr = StrAnsiAllocString(&szWrite, sczEscaped, 0, CP_OEMCP); | ||
195 | ExitOnFailure(hr, "Failed to convert output to ANSI"); | ||
196 | WcaLog(LOGMSG_STANDARD, szWrite); | ||
197 | |||
198 | // Next line | ||
199 | pNext = pEnd; | ||
200 | pEnd = wcschr(pNext, L'\r'); | ||
201 | if (NULL == pEnd) | ||
202 | { | ||
203 | pEnd = wcschr(pNext, L'\n'); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | hr = StrAllocString(&szTemp, pNext, 0); | ||
208 | ExitOnFailure(hr, "Failed to allocate string"); | ||
209 | |||
210 | hr = StrAllocString(&szLog, szTemp, 0); | ||
211 | ExitOnFailure(hr, "Failed to allocate string"); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | // Print any text that didn't end with a new line | ||
216 | if (szLog && *szLog) | ||
217 | { | ||
218 | hr = StrReplaceStringAll(&szLog, L"%", L"%%"); | ||
219 | ExitOnFailure(hr, "Failed to escape percent signs in string"); | ||
220 | |||
221 | hr = StrAnsiAllocString(&szWrite, szLog, 0, CP_OEMCP); | ||
222 | ExitOnFailure(hr, "Failed to convert output to ANSI"); | ||
223 | |||
224 | WcaLog(LOGMSG_VERBOSE, szWrite); | ||
225 | } | ||
226 | |||
227 | LExit: | ||
228 | ReleaseMem(pBuffer); | ||
229 | |||
230 | ReleaseStr(szLog); | ||
231 | ReleaseStr(szTemp); | ||
232 | ReleaseStr(szWrite); | ||
233 | ReleaseStr(sczEscaped); | ||
234 | |||
235 | return hr; | ||
236 | } | ||
237 | |||
238 | static HRESULT QuietExecImpl( | ||
239 | __inout_z LPWSTR wzCommand, | ||
240 | __in DWORD dwTimeout, | ||
241 | __in BOOL fLogCommand, | ||
242 | __in BOOL fLogOutput, | ||
243 | __out_z_opt LPWSTR* psczOutput | ||
244 | ) | ||
245 | { | ||
246 | HRESULT hr = S_OK; | ||
247 | PROCESS_INFORMATION oProcInfo; | ||
248 | STARTUPINFOW oStartInfo; | ||
249 | DWORD dwExitCode = ERROR_SUCCESS; | ||
250 | HANDLE hOutRead = INVALID_HANDLE_VALUE; | ||
251 | HANDLE hOutWrite = INVALID_HANDLE_VALUE; | ||
252 | HANDLE hErrWrite = INVALID_HANDLE_VALUE; | ||
253 | HANDLE hInRead = INVALID_HANDLE_VALUE; | ||
254 | HANDLE hInWrite = INVALID_HANDLE_VALUE; | ||
255 | |||
256 | memset(&oProcInfo, 0, sizeof(oProcInfo)); | ||
257 | memset(&oStartInfo, 0, sizeof(oStartInfo)); | ||
258 | |||
259 | // Create output redirect pipes | ||
260 | hr = CreatePipes(&hOutRead, &hOutWrite, &hErrWrite, &hInRead, &hInWrite); | ||
261 | ExitOnFailure(hr, "Failed to create output pipes"); | ||
262 | |||
263 | // Set up startup structure | ||
264 | oStartInfo.cb = sizeof(STARTUPINFOW); | ||
265 | oStartInfo.dwFlags = STARTF_USESTDHANDLES; | ||
266 | oStartInfo.hStdInput = hInRead; | ||
267 | oStartInfo.hStdOutput = hOutWrite; | ||
268 | oStartInfo.hStdError = hErrWrite; | ||
269 | |||
270 | // Log command if we were asked to do so | ||
271 | if (fLogCommand) | ||
272 | { | ||
273 | WcaLog(LOGMSG_VERBOSE, "%ls", wzCommand); | ||
274 | } | ||
275 | |||
276 | #pragma prefast(suppress:25028) | ||
277 | if (::CreateProcessW(NULL, | ||
278 | wzCommand, // command line | ||
279 | NULL, // security info | ||
280 | NULL, // thread info | ||
281 | TRUE, // inherit handles | ||
282 | ::GetPriorityClass(::GetCurrentProcess()) | CREATE_NO_WINDOW, // creation flags | ||
283 | NULL, // environment | ||
284 | NULL, // cur dir | ||
285 | &oStartInfo, | ||
286 | &oProcInfo)) | ||
287 | { | ||
288 | ReleaseFile(oProcInfo.hThread); | ||
289 | |||
290 | // Close child output/input handles so it doesn't hang | ||
291 | ReleaseFile(hOutWrite); | ||
292 | ReleaseFile(hErrWrite); | ||
293 | ReleaseFile(hInRead); | ||
294 | |||
295 | // Log output if we were asked to do so; otherwise just read the output handle | ||
296 | HandleOutput(fLogOutput, hOutRead, psczOutput); | ||
297 | |||
298 | // Wait for everything to finish | ||
299 | ::WaitForSingleObject(oProcInfo.hProcess, dwTimeout); | ||
300 | if (!::GetExitCodeProcess(oProcInfo.hProcess, &dwExitCode)) | ||
301 | { | ||
302 | dwExitCode = ERROR_SEM_IS_SET; | ||
303 | } | ||
304 | |||
305 | ReleaseFile(hOutRead); | ||
306 | ReleaseFile(hInWrite); | ||
307 | ReleaseFile(oProcInfo.hProcess); | ||
308 | } | ||
309 | else | ||
310 | { | ||
311 | ExitOnLastError(hr, "Command failed to execute."); | ||
312 | } | ||
313 | |||
314 | ExitOnWin32Error(dwExitCode, hr, "Command line returned an error."); | ||
315 | |||
316 | LExit: | ||
317 | return hr; | ||
318 | } | ||
319 | |||
320 | |||
321 | HRESULT WIXAPI QuietExec( | ||
322 | __inout_z LPWSTR wzCommand, | ||
323 | __in DWORD dwTimeout, | ||
324 | __in BOOL fLogCommand, | ||
325 | __in BOOL fLogOutput | ||
326 | ) | ||
327 | { | ||
328 | return QuietExecImpl(wzCommand, dwTimeout, fLogCommand, fLogOutput, NULL); | ||
329 | } | ||
330 | |||
331 | HRESULT WIXAPI QuietExecCapture( | ||
332 | __inout_z LPWSTR wzCommand, | ||
333 | __in DWORD dwTimeout, | ||
334 | __in BOOL fLogCommand, | ||
335 | __in BOOL fLogOutput, | ||
336 | __out_z_opt LPWSTR* psczOutput | ||
337 | ) | ||
338 | { | ||
339 | return QuietExecImpl(wzCommand, dwTimeout, fLogCommand, fLogOutput, psczOutput); | ||
340 | } | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp new file mode 100644 index 00000000..cc7d1438 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp | |||
@@ -0,0 +1,269 @@ | |||
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 | IsVerboseLoggingPolicy() - internal helper function to detect if | ||
7 | policy is set for verbose logging. Does | ||
8 | not require database access. | ||
9 | ********************************************************************/ | ||
10 | static BOOL IsVerboseLoggingPolicy() | ||
11 | { | ||
12 | BOOL fVerbose = FALSE; | ||
13 | HKEY hkey = NULL; | ||
14 | WCHAR rgwc[16] = { 0 }; | ||
15 | DWORD cb = sizeof(rgwc); | ||
16 | if (ERROR_SUCCESS == ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Policies\\Microsoft\\Windows\\Installer", 0, KEY_QUERY_VALUE, &hkey)) | ||
17 | { | ||
18 | if (ERROR_SUCCESS == ::RegQueryValueExW(hkey, L"Logging", 0, NULL, reinterpret_cast<BYTE*>(rgwc), &cb)) | ||
19 | { | ||
20 | for (LPCWSTR pwc = rgwc; (cb / sizeof(WCHAR)) > static_cast<DWORD>(pwc - rgwc) && *pwc; pwc++) | ||
21 | { | ||
22 | if (L'v' == *pwc || L'V' == *pwc) | ||
23 | { | ||
24 | fVerbose = TRUE; | ||
25 | break; | ||
26 | } | ||
27 | } | ||
28 | } | ||
29 | |||
30 | ::RegCloseKey(hkey); | ||
31 | } | ||
32 | return fVerbose; | ||
33 | } | ||
34 | |||
35 | /******************************************************************** | ||
36 | IsVerboseLogging() - internal helper function to detect if doing | ||
37 | verbose logging. Checks: | ||
38 | 1. LOGVERBOSE property. | ||
39 | 2. MsiLogging property contains 'v' | ||
40 | 3. Policy from registry. | ||
41 | |||
42 | Requires database access. | ||
43 | ********************************************************************/ | ||
44 | BOOL WIXAPI IsVerboseLogging() | ||
45 | { | ||
46 | static int iVerbose = -1; | ||
47 | LPWSTR pwzMsiLogging = NULL; | ||
48 | |||
49 | if (0 > iVerbose) | ||
50 | { | ||
51 | iVerbose = WcaIsPropertySet("LOGVERBOSE"); | ||
52 | if (0 == iVerbose) | ||
53 | { | ||
54 | // if the property wasn't set, check the MsiLogging property (MSI 4.0+) | ||
55 | HRESULT hr = WcaGetProperty(L"MsiLogging", &pwzMsiLogging); | ||
56 | ExitOnFailure(hr, "failed to get MsiLogging property"); | ||
57 | |||
58 | if (pwzMsiLogging) | ||
59 | { | ||
60 | for (int i = 0; pwzMsiLogging[i]; i++) | ||
61 | { | ||
62 | if (L'v' == pwzMsiLogging[i] || L'V' == pwzMsiLogging[i]) | ||
63 | { | ||
64 | iVerbose = 1; | ||
65 | break; | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // last chance: Check the registry to see if the logging policy was turned on | ||
71 | if (0 == iVerbose && IsVerboseLoggingPolicy()) | ||
72 | { | ||
73 | iVerbose = 1; | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | LExit: | ||
79 | ReleaseStr(pwzMsiLogging); | ||
80 | Assert(iVerbose >= 0); | ||
81 | return (BOOL)iVerbose; | ||
82 | } | ||
83 | |||
84 | /******************************************************************** | ||
85 | SetVerboseLoggingAtom() - Sets one of two global Atoms to specify | ||
86 | if the install should do verbose logging. | ||
87 | Communicates the verbose setting to | ||
88 | deferred CAs. | ||
89 | Set a negative case atom so that we can | ||
90 | distinguish between an unset atom and the | ||
91 | non-verbose case. This helps prevent the | ||
92 | expensive regkey lookup for non-verbose. | ||
93 | ********************************************************************/ | ||
94 | HRESULT WIXAPI SetVerboseLoggingAtom(BOOL bValue) | ||
95 | { | ||
96 | HRESULT hr = S_OK; | ||
97 | ATOM atomVerbose = 0; | ||
98 | |||
99 | atomVerbose = ::GlobalFindAtomW(L"WcaVerboseLogging"); | ||
100 | if (0 == atomVerbose && bValue) | ||
101 | { | ||
102 | atomVerbose = ::GlobalAddAtomW(L"WcaVerboseLogging"); | ||
103 | ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaVerboseLogging global atom."); | ||
104 | } | ||
105 | else if (0 != atomVerbose && !bValue) | ||
106 | { | ||
107 | ::SetLastError(ERROR_SUCCESS); | ||
108 | ::GlobalDeleteAtom(atomVerbose); | ||
109 | ExitOnLastError(hr, "Failed to delete WcaVerboseLogging global atom."); | ||
110 | } | ||
111 | |||
112 | atomVerbose = ::GlobalFindAtomW(L"WcaNotVerboseLogging"); | ||
113 | if (0 == atomVerbose && !bValue) | ||
114 | { | ||
115 | atomVerbose = ::GlobalAddAtomW(L"WcaNotVerboseLogging"); | ||
116 | ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaNotVerboseLogging global atom."); | ||
117 | } | ||
118 | else if (0 != atomVerbose && bValue) | ||
119 | { | ||
120 | ::SetLastError(ERROR_SUCCESS); | ||
121 | ::GlobalDeleteAtom(atomVerbose); | ||
122 | ExitOnLastError(hr, "Failed to delete WcaNotVerboseLogging global atom."); | ||
123 | } | ||
124 | |||
125 | LExit: | ||
126 | return hr; | ||
127 | } | ||
128 | |||
129 | /******************************************************************** | ||
130 | IsVerboseLoggingLite() - internal helper function to detect if atom was | ||
131 | previously set to specify verbose logging. | ||
132 | Falls back on policy for an installer that is | ||
133 | unable to set the atom (no immediate CAs). | ||
134 | |||
135 | Does not require database access. | ||
136 | ********************************************************************/ | ||
137 | static BOOL IsVerboseLoggingLite() | ||
138 | { | ||
139 | ATOM atomVerbose = ::GlobalFindAtomW(L"WcaVerboseLogging"); | ||
140 | if (0 != atomVerbose) | ||
141 | { | ||
142 | return TRUE; | ||
143 | } | ||
144 | |||
145 | atomVerbose = ::GlobalFindAtomW(L"WcaNotVerboseLogging"); | ||
146 | if (0 != atomVerbose) | ||
147 | { | ||
148 | return FALSE; | ||
149 | } | ||
150 | |||
151 | return IsVerboseLoggingPolicy(); | ||
152 | } | ||
153 | |||
154 | /******************************************************************** | ||
155 | WcaLog() - outputs trace and log info | ||
156 | |||
157 | *******************************************************************/ | ||
158 | extern "C" void __cdecl WcaLog( | ||
159 | __in LOGLEVEL llv, | ||
160 | __in_z __format_string PCSTR fmt, | ||
161 | ... | ||
162 | ) | ||
163 | { | ||
164 | static char szFmt[LOG_BUFFER]; | ||
165 | static char szBuf[LOG_BUFFER]; | ||
166 | static bool fInLogPrint = false; | ||
167 | |||
168 | // prevent re-entrant logprints. (recursion issues between assert/logging code) | ||
169 | if (fInLogPrint) | ||
170 | return; | ||
171 | fInLogPrint = true; | ||
172 | |||
173 | if (LOGMSG_STANDARD == llv || | ||
174 | (LOGMSG_VERBOSE == llv && IsVerboseLoggingLite()) | ||
175 | #ifdef DEBUG | ||
176 | || LOGMSG_TRACEONLY == llv | ||
177 | #endif | ||
178 | ) | ||
179 | { | ||
180 | va_list args; | ||
181 | va_start(args, fmt); | ||
182 | |||
183 | LPCSTR szLogName = WcaGetLogName(); | ||
184 | if (szLogName[0] != 0) | ||
185 | StringCchPrintfA(szFmt, countof(szFmt), "%s: %s", szLogName, fmt); | ||
186 | else | ||
187 | StringCchCopyA(szFmt, countof(szFmt), fmt); | ||
188 | |||
189 | StringCchVPrintfA(szBuf, countof(szBuf), szFmt, args); | ||
190 | va_end(args); | ||
191 | |||
192 | #ifdef DEBUG | ||
193 | // always write to the log in debug | ||
194 | #else | ||
195 | if (llv == LOGMSG_STANDARD || (llv == LOGMSG_VERBOSE && IsVerboseLoggingLite())) | ||
196 | #endif | ||
197 | { | ||
198 | PMSIHANDLE hrec = MsiCreateRecord(1); | ||
199 | |||
200 | ::MsiRecordSetStringA(hrec, 0, szBuf); | ||
201 | // TODO: Recursion on failure. May not be safe to assert from here. | ||
202 | WcaProcessMessage(INSTALLMESSAGE_INFO, hrec); | ||
203 | } | ||
204 | |||
205 | #if DEBUG | ||
206 | StringCchCatA(szBuf, countof(szBuf), "\n"); | ||
207 | OutputDebugStringA(szBuf); | ||
208 | #endif | ||
209 | } | ||
210 | |||
211 | fInLogPrint = false; | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | |||
216 | /******************************************************************** | ||
217 | WcaDisplayAssert() - called before Assert() dialog shows | ||
218 | |||
219 | NOTE: writes the assert string to the MSI log | ||
220 | ********************************************************************/ | ||
221 | extern "C" BOOL WIXAPI WcaDisplayAssert( | ||
222 | __in LPCSTR sz | ||
223 | ) | ||
224 | { | ||
225 | WcaLog(LOGMSG_STANDARD, "Debug Assert Message: %s", sz); | ||
226 | return TRUE; | ||
227 | } | ||
228 | |||
229 | |||
230 | /******************************************************************** | ||
231 | WcaLogError() - called before ExitOnXXX() macro exits the function | ||
232 | |||
233 | NOTE: writes the hresult and error string to the MSI log | ||
234 | ********************************************************************/ | ||
235 | extern "C" void WcaLogError( | ||
236 | __in HRESULT hr, | ||
237 | __in LPCSTR szMessage, | ||
238 | ... | ||
239 | ) | ||
240 | { | ||
241 | va_list dots; | ||
242 | |||
243 | va_start(dots, szMessage); | ||
244 | WcaLogErrorArgs(hr, szMessage, dots); | ||
245 | va_end(dots); | ||
246 | } | ||
247 | |||
248 | |||
249 | /******************************************************************** | ||
250 | WcaLogErrorArgs() - called before ExitOnXXX() macro exits the function | ||
251 | |||
252 | NOTE: writes the hresult and error string to the MSI log | ||
253 | ********************************************************************/ | ||
254 | extern "C" void WcaLogErrorArgs( | ||
255 | __in HRESULT hr, | ||
256 | __in LPCSTR szMessage, | ||
257 | __in va_list args | ||
258 | ) | ||
259 | { | ||
260 | char szBuffer[LOG_BUFFER]; | ||
261 | |||
262 | StringCchVPrintfA(szBuffer, countof(szBuffer), szMessage, args); | ||
263 | |||
264 | // log the message if using Wca common layer | ||
265 | if (WcaIsInitialized()) | ||
266 | { | ||
267 | WcaLog(LOGMSG_STANDARD, "Error 0x%x: %s", hr, szBuffer); | ||
268 | } | ||
269 | } | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp new file mode 100644 index 00000000..a7e98491 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp | |||
@@ -0,0 +1,429 @@ | |||
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 | static HRESULT CaScriptFileName( | ||
7 | __in WCA_ACTION action, | ||
8 | __in WCA_CASCRIPT script, | ||
9 | __in BOOL fImpersonated, | ||
10 | __in_z LPCWSTR wzScriptKey, | ||
11 | __out LPWSTR* pwzScriptName | ||
12 | ); | ||
13 | |||
14 | |||
15 | /******************************************************************** | ||
16 | WcaCaScriptCreateKey() - creates a unique script key for this | ||
17 | CustomAction. | ||
18 | |||
19 | ********************************************************************/ | ||
20 | extern "C" HRESULT WIXAPI WcaCaScriptCreateKey( | ||
21 | __out LPWSTR* ppwzScriptKey | ||
22 | ) | ||
23 | { | ||
24 | AssertSz(WcaIsInitialized(), "WcaInitialize() should have been called before calling this function."); | ||
25 | HRESULT hr = S_OK; | ||
26 | |||
27 | hr = StrAllocStringAnsi(ppwzScriptKey, WcaGetLogName(), 0, CP_ACP); | ||
28 | ExitOnFailure(hr, "Failed to create script key."); | ||
29 | |||
30 | LExit: | ||
31 | return hr; | ||
32 | } | ||
33 | |||
34 | |||
35 | /******************************************************************** | ||
36 | WcaCaScriptCreate() - creates the appropriate script for this | ||
37 | CustomAction Script Key. | ||
38 | |||
39 | ********************************************************************/ | ||
40 | extern "C" HRESULT WIXAPI WcaCaScriptCreate( | ||
41 | __in WCA_ACTION action, | ||
42 | __in WCA_CASCRIPT script, | ||
43 | __in BOOL fImpersonated, | ||
44 | __in_z LPCWSTR wzScriptKey, | ||
45 | __in BOOL fAppend, | ||
46 | __out WCA_CASCRIPT_HANDLE* phScript | ||
47 | ) | ||
48 | { | ||
49 | HRESULT hr = S_OK; | ||
50 | LPWSTR pwzScriptPath = NULL; | ||
51 | HANDLE hScriptFile = INVALID_HANDLE_VALUE; | ||
52 | |||
53 | hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath); | ||
54 | ExitOnFailure(hr, "Failed to calculate script file name."); | ||
55 | |||
56 | hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, fAppend ? OPEN_ALWAYS : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); | ||
57 | if (INVALID_HANDLE_VALUE == hScriptFile) | ||
58 | { | ||
59 | ExitWithLastError(hr, "Failed to open CaScript: %ls", pwzScriptPath); | ||
60 | } | ||
61 | |||
62 | if (fAppend && INVALID_SET_FILE_POINTER == ::SetFilePointer(hScriptFile, 0, NULL, FILE_END)) | ||
63 | { | ||
64 | ExitWithLastError(hr, "Failed to seek to end of file."); | ||
65 | } | ||
66 | |||
67 | *phScript = static_cast<WCA_CASCRIPT_HANDLE>(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE)); | ||
68 | ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle."); | ||
69 | |||
70 | (*phScript)->pwzScriptPath = pwzScriptPath; | ||
71 | pwzScriptPath = NULL; | ||
72 | (*phScript)->hScriptFile = hScriptFile; | ||
73 | hScriptFile = INVALID_HANDLE_VALUE; | ||
74 | |||
75 | LExit: | ||
76 | if (INVALID_HANDLE_VALUE != hScriptFile) | ||
77 | { | ||
78 | ::CloseHandle(hScriptFile); | ||
79 | } | ||
80 | |||
81 | ReleaseStr(pwzScriptPath); | ||
82 | return hr; | ||
83 | } | ||
84 | |||
85 | |||
86 | /******************************************************************** | ||
87 | WcaCaScriptOpen() - opens the appropriate script for this CustomAction | ||
88 | Script Key. | ||
89 | |||
90 | ********************************************************************/ | ||
91 | extern "C" HRESULT WIXAPI WcaCaScriptOpen( | ||
92 | __in WCA_ACTION action, | ||
93 | __in WCA_CASCRIPT script, | ||
94 | __in BOOL fImpersonated, | ||
95 | __in_z LPCWSTR wzScriptKey, | ||
96 | __out WCA_CASCRIPT_HANDLE* phScript | ||
97 | ) | ||
98 | { | ||
99 | HRESULT hr = S_OK; | ||
100 | LPWSTR pwzScriptPath = NULL; | ||
101 | HANDLE hScriptFile = INVALID_HANDLE_VALUE; | ||
102 | |||
103 | hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath); | ||
104 | ExitOnFailure(hr, "Failed to calculate script file name."); | ||
105 | |||
106 | hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); | ||
107 | if (INVALID_HANDLE_VALUE == hScriptFile) | ||
108 | { | ||
109 | ExitWithLastError(hr, "Failed to open CaScript: %ls", pwzScriptPath); | ||
110 | } | ||
111 | |||
112 | *phScript = static_cast<WCA_CASCRIPT_HANDLE>(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE)); | ||
113 | ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle."); | ||
114 | |||
115 | (*phScript)->pwzScriptPath = pwzScriptPath; | ||
116 | pwzScriptPath = NULL; | ||
117 | (*phScript)->hScriptFile = hScriptFile; | ||
118 | hScriptFile = INVALID_HANDLE_VALUE; | ||
119 | |||
120 | LExit: | ||
121 | if (INVALID_HANDLE_VALUE != hScriptFile) | ||
122 | { | ||
123 | ::CloseHandle(hScriptFile); | ||
124 | } | ||
125 | |||
126 | ReleaseStr(pwzScriptPath); | ||
127 | return hr; | ||
128 | } | ||
129 | |||
130 | |||
131 | /******************************************************************** | ||
132 | WcaCaScriptClose() - closes an open script handle. | ||
133 | |||
134 | ********************************************************************/ | ||
135 | extern "C" void WIXAPI WcaCaScriptClose( | ||
136 | __in_opt WCA_CASCRIPT_HANDLE hScript, | ||
137 | __in WCA_CASCRIPT_CLOSE closeOperation | ||
138 | ) | ||
139 | { | ||
140 | if (hScript) | ||
141 | { | ||
142 | if (INVALID_HANDLE_VALUE != hScript->hScriptFile) | ||
143 | { | ||
144 | ::CloseHandle(hScript->hScriptFile); | ||
145 | } | ||
146 | |||
147 | if (hScript->pwzScriptPath) | ||
148 | { | ||
149 | if (WCA_CASCRIPT_CLOSE_DELETE == closeOperation) | ||
150 | { | ||
151 | ::DeleteFileW(hScript->pwzScriptPath); | ||
152 | } | ||
153 | |||
154 | StrFree(hScript->pwzScriptPath); | ||
155 | } | ||
156 | |||
157 | MemFree(hScript); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | |||
162 | /******************************************************************** | ||
163 | WcaCaScriptReadAsCustomActionData() - read the ca script into a format | ||
164 | that is useable by other CA data | ||
165 | functions. | ||
166 | |||
167 | ********************************************************************/ | ||
168 | extern "C" HRESULT WIXAPI WcaCaScriptReadAsCustomActionData( | ||
169 | __in WCA_CASCRIPT_HANDLE hScript, | ||
170 | __out LPWSTR* ppwzCustomActionData | ||
171 | ) | ||
172 | { | ||
173 | HRESULT hr = S_OK; | ||
174 | LARGE_INTEGER liScriptSize = { 0 }; | ||
175 | BYTE* pbData = NULL; | ||
176 | DWORD cbData = 0; | ||
177 | |||
178 | if (!::GetFileSizeEx(hScript->hScriptFile, &liScriptSize)) | ||
179 | { | ||
180 | ExitWithLastError(hr, "Failed to get size of ca script file."); | ||
181 | } | ||
182 | |||
183 | if (0 != liScriptSize.HighPart || 0 != (liScriptSize.LowPart % sizeof(WCHAR))) | ||
184 | { | ||
185 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); | ||
186 | ExitOnRootFailure(hr, "Invalid data read from ca script."); | ||
187 | } | ||
188 | |||
189 | cbData = liScriptSize.LowPart; | ||
190 | if (cbData) | ||
191 | { | ||
192 | pbData = static_cast<BYTE*>(MemAlloc(cbData, TRUE)); | ||
193 | ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate memory to read in ca script."); | ||
194 | |||
195 | if (INVALID_SET_FILE_POINTER == ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_BEGIN)) | ||
196 | { | ||
197 | ExitWithLastError(hr, "Failed to reset to beginning of ca script."); | ||
198 | } | ||
199 | |||
200 | DWORD cbTotalRead = 0; | ||
201 | DWORD cbRead = 0; | ||
202 | do | ||
203 | { | ||
204 | if (!::ReadFile(hScript->hScriptFile, pbData + cbTotalRead, cbData - cbTotalRead, &cbRead, NULL)) | ||
205 | { | ||
206 | ExitWithLastError(hr, "Failed to read from ca script."); | ||
207 | } | ||
208 | |||
209 | cbTotalRead += cbRead; | ||
210 | } while (cbRead && cbTotalRead < cbData); | ||
211 | |||
212 | if (cbTotalRead != cbData) | ||
213 | { | ||
214 | hr = E_UNEXPECTED; | ||
215 | ExitOnFailure(hr, "Failed to completely read ca script."); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | // Add one to the allocated space because the data stored in the script is not | ||
220 | // null terminated. After copying the memory over, we'll ensure the string is | ||
221 | // null terminated. | ||
222 | DWORD cchData = cbData / sizeof(WCHAR) + 1; | ||
223 | hr = StrAlloc(ppwzCustomActionData, cchData); | ||
224 | ExitOnFailure(hr, "Failed to copy ca script."); | ||
225 | |||
226 | if (cbData) | ||
227 | { | ||
228 | CopyMemory(*ppwzCustomActionData, pbData, cbData); | ||
229 | } | ||
230 | |||
231 | (*ppwzCustomActionData)[cchData - 1] = L'\0'; | ||
232 | |||
233 | LExit: | ||
234 | ReleaseMem(pbData); | ||
235 | return hr; | ||
236 | } | ||
237 | |||
238 | |||
239 | /******************************************************************** | ||
240 | WcaCaScriptWriteString() - writes a string to the ca script. | ||
241 | |||
242 | ********************************************************************/ | ||
243 | extern "C" HRESULT WIXAPI WcaCaScriptWriteString( | ||
244 | __in WCA_CASCRIPT_HANDLE hScript, | ||
245 | __in_z LPCWSTR wzValue | ||
246 | ) | ||
247 | { | ||
248 | HRESULT hr = S_OK; | ||
249 | DWORD cbFile = 0; | ||
250 | WCHAR delim[] = { MAGIC_MULTISZ_DELIM }; // magic char followed by NULL terminator | ||
251 | SIZE_T cch = 0; | ||
252 | |||
253 | cbFile = ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_END); | ||
254 | if (INVALID_SET_FILE_POINTER == cbFile) | ||
255 | { | ||
256 | ExitWithLastError(hr, "Failed to move file pointer to end of file."); | ||
257 | } | ||
258 | |||
259 | // If there is existing data in the file, append on the magic delimeter | ||
260 | // before adding our new data on the end of the file. | ||
261 | if (0 < cbFile) | ||
262 | { | ||
263 | hr = FileWriteHandle(hScript->hScriptFile, reinterpret_cast<LPCBYTE>(delim), sizeof(delim)); | ||
264 | ExitOnFailure(hr, "Failed to write data to ca script."); | ||
265 | } | ||
266 | |||
267 | hr = ::StringCchLengthW(wzValue, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cch)); | ||
268 | ExitOnRootFailure(hr, "Failed to get length of ca script string."); | ||
269 | |||
270 | hr = FileWriteHandle(hScript->hScriptFile, reinterpret_cast<LPCBYTE>(wzValue), static_cast<DWORD>(cch) * sizeof(WCHAR)); | ||
271 | ExitOnFailure(hr, "Failed to write data to ca script."); | ||
272 | |||
273 | LExit: | ||
274 | return hr; | ||
275 | } | ||
276 | |||
277 | |||
278 | /******************************************************************** | ||
279 | WcaCaScriptWriteNumber() - writes a number to the ca script. | ||
280 | |||
281 | ********************************************************************/ | ||
282 | extern "C" HRESULT WIXAPI WcaCaScriptWriteNumber( | ||
283 | __in WCA_CASCRIPT_HANDLE hScript, | ||
284 | __in DWORD dwValue | ||
285 | ) | ||
286 | { | ||
287 | HRESULT hr = S_OK; | ||
288 | WCHAR wzBuffer[13] = { 0 }; | ||
289 | |||
290 | hr = ::StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%u", dwValue); | ||
291 | ExitOnFailure(hr, "Failed to convert number into string."); | ||
292 | |||
293 | hr = WcaCaScriptWriteString(hScript, wzBuffer); | ||
294 | ExitOnFailure(hr, "Failed to write number to script."); | ||
295 | |||
296 | LExit: | ||
297 | return hr; | ||
298 | } | ||
299 | |||
300 | |||
301 | /******************************************************************** | ||
302 | WcaCaScriptFlush() - best effort function to get script written to | ||
303 | disk. | ||
304 | |||
305 | ********************************************************************/ | ||
306 | extern "C" void WIXAPI WcaCaScriptFlush( | ||
307 | __in WCA_CASCRIPT_HANDLE hScript | ||
308 | ) | ||
309 | { | ||
310 | ::FlushFileBuffers(hScript->hScriptFile); | ||
311 | } | ||
312 | |||
313 | |||
314 | /******************************************************************** | ||
315 | WcaCaScriptCleanup() - best effort clean-up of any cascripts left | ||
316 | over from this install/uninstall. | ||
317 | |||
318 | ********************************************************************/ | ||
319 | extern "C" void WIXAPI WcaCaScriptCleanup( | ||
320 | __in_z LPCWSTR wzProductCode, | ||
321 | __in BOOL fImpersonated | ||
322 | ) | ||
323 | { | ||
324 | HRESULT hr = S_OK; | ||
325 | WCHAR wzTempPath[MAX_PATH]; | ||
326 | LPWSTR pwzWildCardPath = NULL; | ||
327 | WIN32_FIND_DATAW fd = { 0 }; | ||
328 | HANDLE hff = INVALID_HANDLE_VALUE; | ||
329 | LPWSTR pwzDeletePath = NULL; | ||
330 | |||
331 | if (fImpersonated) | ||
332 | { | ||
333 | if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) | ||
334 | { | ||
335 | ExitWithLastError(hr, "Failed to get temp path."); | ||
336 | } | ||
337 | } | ||
338 | else | ||
339 | { | ||
340 | if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath))) | ||
341 | { | ||
342 | ExitWithLastError(hr, "Failed to get windows path."); | ||
343 | } | ||
344 | |||
345 | hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\"); | ||
346 | ExitOnFailure(hr, "Failed to concat Installer directory on windows path string."); | ||
347 | } | ||
348 | |||
349 | hr = StrAllocFormatted(&pwzWildCardPath, L"%swix%s.*.???", wzTempPath, wzProductCode); | ||
350 | ExitOnFailure(hr, "Failed to allocate wildcard path to ca scripts."); | ||
351 | |||
352 | hff = ::FindFirstFileW(pwzWildCardPath, &fd); | ||
353 | if (INVALID_HANDLE_VALUE == hff) | ||
354 | { | ||
355 | ExitWithLastError(hr, "Failed to find files with pattern: %ls", pwzWildCardPath); | ||
356 | } | ||
357 | |||
358 | do | ||
359 | { | ||
360 | hr = StrAllocFormatted(&pwzDeletePath, L"%s%s", wzTempPath, fd.cFileName); | ||
361 | if (SUCCEEDED(hr)) | ||
362 | { | ||
363 | if (!::DeleteFileW(pwzDeletePath)) | ||
364 | { | ||
365 | DWORD er = ::GetLastError(); | ||
366 | WcaLog(LOGMSG_VERBOSE, "Failed to clean up CAScript file: %ls, er: %d", fd.cFileName, er); | ||
367 | } | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | WcaLog(LOGMSG_VERBOSE, "Failed to allocate path to clean up CAScript file: %ls, hr: 0x%x", fd.cFileName, hr); | ||
372 | } | ||
373 | } while(::FindNextFileW(hff, &fd)); | ||
374 | |||
375 | LExit: | ||
376 | if (INVALID_HANDLE_VALUE == hff) | ||
377 | { | ||
378 | ::FindClose(hff); | ||
379 | } | ||
380 | |||
381 | ReleaseStr(pwzDeletePath); | ||
382 | ReleaseStr(pwzWildCardPath); | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | |||
387 | static HRESULT CaScriptFileName( | ||
388 | __in WCA_ACTION action, | ||
389 | __in WCA_CASCRIPT script, | ||
390 | __in BOOL fImpersonated, | ||
391 | __in_z LPCWSTR wzScriptKey, | ||
392 | __out LPWSTR* ppwzScriptName | ||
393 | ) | ||
394 | { | ||
395 | HRESULT hr = S_OK; | ||
396 | WCHAR wzTempPath[MAX_PATH]; | ||
397 | LPWSTR pwzProductCode = NULL; | ||
398 | WCHAR chInstallOrUninstall = action == WCA_ACTION_INSTALL ? L'i' : L'u'; | ||
399 | WCHAR chScheduledOrRollback = script == WCA_CASCRIPT_SCHEDULED ? L's' : L'r'; | ||
400 | WCHAR chUserOrMachine = fImpersonated ? L'u' : L'm'; | ||
401 | |||
402 | if (fImpersonated) | ||
403 | { | ||
404 | if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) | ||
405 | { | ||
406 | ExitWithLastError(hr, "Failed to get temp path."); | ||
407 | } | ||
408 | } | ||
409 | else | ||
410 | { | ||
411 | if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath))) | ||
412 | { | ||
413 | ExitWithLastError(hr, "Failed to get windows path."); | ||
414 | } | ||
415 | |||
416 | hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\"); | ||
417 | ExitOnFailure(hr, "Failed to concat Installer directory on windows path string."); | ||
418 | } | ||
419 | |||
420 | hr = WcaGetProperty(L"ProductCode", &pwzProductCode); | ||
421 | ExitOnFailure(hr, "Failed to get ProductCode."); | ||
422 | |||
423 | hr = StrAllocFormatted(ppwzScriptName, L"%swix%s.%s.%c%c%c", wzTempPath, pwzProductCode, wzScriptKey, chScheduledOrRollback, chUserOrMachine, chInstallOrUninstall); | ||
424 | ExitOnFailure(hr, "Failed to allocate path to ca script."); | ||
425 | |||
426 | LExit: | ||
427 | ReleaseStr(pwzProductCode); | ||
428 | return hr; | ||
429 | } | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcautil.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcautil.cpp new file mode 100644 index 00000000..11867d10 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcautil.cpp | |||
@@ -0,0 +1,243 @@ | |||
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 | // globals | ||
6 | HMODULE g_hInstCADLL; | ||
7 | |||
8 | // statics | ||
9 | static BOOL s_fInitialized; | ||
10 | static MSIHANDLE s_hInstall; | ||
11 | static MSIHANDLE s_hDatabase; | ||
12 | static char s_szCustomActionLogName[32]; | ||
13 | static UINT s_iRetVal; | ||
14 | |||
15 | static void CALLBACK WcaTraceError( | ||
16 | __in_z LPCSTR szFile, | ||
17 | __in int iLine, | ||
18 | __in REPORT_LEVEL rl, | ||
19 | __in UINT source, | ||
20 | __in HRESULT hrError, | ||
21 | __in_z __format_string LPCSTR szFormat, | ||
22 | __in va_list args | ||
23 | ); | ||
24 | |||
25 | /******************************************************************** | ||
26 | WcaGlobalInitialize() - initializes the Wca library, should be | ||
27 | called once per custom action Dll during | ||
28 | DllMain on DLL_PROCESS_ATTACH | ||
29 | |||
30 | ********************************************************************/ | ||
31 | extern "C" void WIXAPI WcaGlobalInitialize( | ||
32 | __in HINSTANCE hInst | ||
33 | ) | ||
34 | { | ||
35 | g_hInstCADLL = hInst; | ||
36 | DutilInitialize(&WcaTraceError); | ||
37 | MemInitialize(); | ||
38 | |||
39 | AssertSetModule(g_hInstCADLL); | ||
40 | AssertSetDisplayFunction(WcaDisplayAssert); | ||
41 | } | ||
42 | |||
43 | |||
44 | /******************************************************************** | ||
45 | WcaGlobalFinalize() - finalizes the Wca library, should be the | ||
46 | called once per custom action Dll during | ||
47 | DllMain on DLL_PROCESS_DETACH | ||
48 | |||
49 | ********************************************************************/ | ||
50 | extern "C" void WIXAPI WcaGlobalFinalize() | ||
51 | { | ||
52 | #ifdef DEBUG | ||
53 | if (WcaIsInitialized()) | ||
54 | { | ||
55 | CHAR szBuf[2048]; | ||
56 | StringCchPrintfA(szBuf, countof(szBuf), "CustomAction %s called WcaInitialize() but not WcaFinalize()", WcaGetLogName()); | ||
57 | |||
58 | AssertSz(FALSE, szBuf); | ||
59 | } | ||
60 | #endif | ||
61 | MemUninitialize(); | ||
62 | DutilUninitialize(); | ||
63 | g_hInstCADLL = NULL; | ||
64 | } | ||
65 | |||
66 | |||
67 | /******************************************************************** | ||
68 | WcaInitialize() - initializes the Wca framework, should be the first | ||
69 | thing called by all CustomActions | ||
70 | |||
71 | ********************************************************************/ | ||
72 | extern "C" HRESULT WIXAPI WcaInitialize( | ||
73 | __in MSIHANDLE hInstall, | ||
74 | __in_z PCSTR szCustomActionLogName | ||
75 | ) | ||
76 | { | ||
77 | WCHAR wzCAFileName[MAX_PATH] = {0}; | ||
78 | DWORD dwMajorVersion = 0; | ||
79 | DWORD dwMinorVersion = 0; | ||
80 | |||
81 | // these statics should be called once per CustomAction invocation. | ||
82 | // Darwin does doesn't preserve DLL state across CustomAction calls so | ||
83 | // these should always be initialized to NULL. If that behavior changes | ||
84 | // we would need to do a careful review of all of our module/global data. | ||
85 | AssertSz(!s_fInitialized, "WcaInitialize() should only be called once per CustomAction"); | ||
86 | Assert(NULL == s_hInstall); | ||
87 | Assert(NULL == s_hDatabase); | ||
88 | Assert(0 == *s_szCustomActionLogName); | ||
89 | |||
90 | HRESULT hr = S_OK; | ||
91 | |||
92 | s_fInitialized = TRUE; | ||
93 | s_iRetVal = ERROR_SUCCESS; // assume all will go well | ||
94 | |||
95 | s_hInstall = hInstall; | ||
96 | s_hDatabase = ::MsiGetActiveDatabase(s_hInstall); // may return null if deferred CustomAction | ||
97 | |||
98 | hr = ::StringCchCopy(s_szCustomActionLogName, countof(s_szCustomActionLogName), szCustomActionLogName); | ||
99 | ExitOnFailure(hr, "Failed to copy CustomAction log name: %s", szCustomActionLogName); | ||
100 | |||
101 | // If we got the database handle IE: immediate CA | ||
102 | if (s_hDatabase) | ||
103 | { | ||
104 | hr = SetVerboseLoggingAtom(IsVerboseLogging()); | ||
105 | ExitOnFailure(hr, "Failed to set verbose logging global atom"); | ||
106 | } | ||
107 | |||
108 | if (!::GetModuleFileNameW(g_hInstCADLL, wzCAFileName, countof(wzCAFileName))) | ||
109 | { | ||
110 | ExitWithLastError(hr, "Failed to get module filename"); | ||
111 | } | ||
112 | |||
113 | FileVersion(wzCAFileName, &dwMajorVersion, &dwMinorVersion); // Ignore failure, just log 0.0.0.0 | ||
114 | |||
115 | WcaLog(LOGMSG_VERBOSE, "Entering %s in %ls, version %u.%u.%u.%u", szCustomActionLogName, wzCAFileName, (DWORD)HIWORD(dwMajorVersion), (DWORD)LOWORD(dwMajorVersion), (DWORD)HIWORD(dwMinorVersion), (DWORD)LOWORD(dwMinorVersion)); | ||
116 | |||
117 | Assert(s_hInstall); | ||
118 | LExit: | ||
119 | if (FAILED(hr)) | ||
120 | { | ||
121 | if (s_hDatabase) | ||
122 | { | ||
123 | ::MsiCloseHandle(s_hDatabase); | ||
124 | s_hDatabase = NULL; | ||
125 | } | ||
126 | |||
127 | s_hInstall = NULL; | ||
128 | s_fInitialized = FALSE; | ||
129 | } | ||
130 | |||
131 | return hr; | ||
132 | } | ||
133 | |||
134 | |||
135 | /******************************************************************** | ||
136 | WcaFinalize() - cleans up after the Wca framework, should be the last | ||
137 | thing called by all CustomActions | ||
138 | |||
139 | ********************************************************************/ | ||
140 | extern "C" UINT WIXAPI WcaFinalize( | ||
141 | __in UINT iReturnValue | ||
142 | ) | ||
143 | { | ||
144 | AssertSz(!WcaIsWow64Initialized(), "WcaFinalizeWow64() should be called before calling WcaFinalize()"); | ||
145 | |||
146 | // clean up after our initialization | ||
147 | if (s_hDatabase) | ||
148 | { | ||
149 | ::MsiCloseHandle(s_hDatabase); | ||
150 | s_hDatabase = NULL; | ||
151 | } | ||
152 | |||
153 | s_hInstall = NULL; | ||
154 | s_fInitialized = FALSE; | ||
155 | |||
156 | // if no error occurred during the processing of the CusotmAction return the passed in return value | ||
157 | // otherwise return the previous failure | ||
158 | return (ERROR_SUCCESS == s_iRetVal) ? iReturnValue : s_iRetVal; | ||
159 | } | ||
160 | |||
161 | |||
162 | /******************************************************************** | ||
163 | WcaIsInitialized() - determines if WcaInitialize() has been called | ||
164 | |||
165 | ********************************************************************/ | ||
166 | extern "C" BOOL WIXAPI WcaIsInitialized() | ||
167 | { | ||
168 | return s_fInitialized; | ||
169 | } | ||
170 | |||
171 | |||
172 | /******************************************************************** | ||
173 | WcaGetInstallHandle() - gets the handle to the active install session | ||
174 | |||
175 | ********************************************************************/ | ||
176 | extern "C" MSIHANDLE WIXAPI WcaGetInstallHandle() | ||
177 | { | ||
178 | AssertSz(s_hInstall, "WcaInitialize() should be called before attempting to access the install handle."); | ||
179 | return s_hInstall; | ||
180 | } | ||
181 | |||
182 | |||
183 | /******************************************************************** | ||
184 | WcaGetDatabaseHandle() - gets the handle to the active database | ||
185 | |||
186 | NOTE: this function can only be used in immediate CustomActions. | ||
187 | Deferred CustomActions do not have access to the active | ||
188 | database. | ||
189 | ********************************************************************/ | ||
190 | extern "C" MSIHANDLE WIXAPI WcaGetDatabaseHandle() | ||
191 | { | ||
192 | AssertSz(s_hDatabase, "WcaInitialize() should be called before attempting to access the install handle. Also note that deferred CustomActions do not have access to the active database."); | ||
193 | return s_hDatabase; | ||
194 | } | ||
195 | |||
196 | |||
197 | /******************************************************************** | ||
198 | WcaGetLogName() - gets the name of the CustomAction used in logging | ||
199 | |||
200 | ********************************************************************/ | ||
201 | extern "C" const char* WIXAPI WcaGetLogName() | ||
202 | { | ||
203 | return s_szCustomActionLogName; | ||
204 | } | ||
205 | |||
206 | |||
207 | /******************************************************************** | ||
208 | WcaSetReturnValue() - sets the value to return from the CustomAction | ||
209 | |||
210 | ********************************************************************/ | ||
211 | extern "C" void WIXAPI WcaSetReturnValue( | ||
212 | __in UINT iReturnValue | ||
213 | ) | ||
214 | { | ||
215 | s_iRetVal = iReturnValue; | ||
216 | } | ||
217 | |||
218 | |||
219 | /******************************************************************** | ||
220 | WcaCancelDetected() - determines if the user has canceled yet | ||
221 | |||
222 | NOTE: returns true when WcaSetReturnValue() is set to ERROR_INSTALL_USEREXIT | ||
223 | ********************************************************************/ | ||
224 | extern "C" BOOL WIXAPI WcaCancelDetected() | ||
225 | { | ||
226 | return ERROR_INSTALL_USEREXIT == s_iRetVal; | ||
227 | } | ||
228 | |||
229 | static void CALLBACK WcaTraceError( | ||
230 | __in_z LPCSTR /*szFile*/, | ||
231 | __in int /*iLine*/, | ||
232 | __in REPORT_LEVEL /*rl*/, | ||
233 | __in UINT source, | ||
234 | __in HRESULT hrError, | ||
235 | __in_z __format_string LPCSTR szFormat, | ||
236 | __in va_list args | ||
237 | ) | ||
238 | { | ||
239 | if (DUTIL_SOURCE_DEFAULT == source) | ||
240 | { | ||
241 | WcaLogErrorArgs(hrError, szFormat, args); | ||
242 | } | ||
243 | } | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcautil.nuspec b/src/libs/wcautil/WixToolset.WcaUtil/wcautil.nuspec new file mode 100644 index 00000000..a57a5749 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcautil.nuspec | |||
@@ -0,0 +1,30 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <package > | ||
3 | <metadata> | ||
4 | <id>$id$</id> | ||
5 | <version>$version$</version> | ||
6 | <authors>$authors$</authors> | ||
7 | <owners>$authors$</owners> | ||
8 | <license type="expression">MS-RL</license> | ||
9 | <projectUrl>https://github.com/wixtoolset/wcautil</projectUrl> | ||
10 | <requireLicenseAcceptance>false</requireLicenseAcceptance> | ||
11 | <description>$description$</description> | ||
12 | <copyright>$copyright$</copyright> | ||
13 | <dependencies> | ||
14 | <dependency id="WixToolset.DUtil" version="[4,5)" /> | ||
15 | </dependencies> | ||
16 | </metadata> | ||
17 | |||
18 | <files> | ||
19 | <file src="build\$id$.props" target="build\" /> | ||
20 | <file src="inc\*" target="build\native\include" /> | ||
21 | <file src="..\..\build\$configuration$\v140\x64\wcautil.lib" target="build\native\v140\x64" /> | ||
22 | <file src="..\..\build\$configuration$\v140\x86\wcautil.lib" target="build\native\v140\x86" /> | ||
23 | <file src="..\..\build\$configuration$\v141\x64\wcautil.lib" target="build\native\v141\x64" /> | ||
24 | <file src="..\..\build\$configuration$\v141\x86\wcautil.lib" target="build\native\v141\x86" /> | ||
25 | <file src="..\..\build\$configuration$\v141\ARM64\wcautil.lib" target="build\native\v141\ARM64" /> | ||
26 | <file src="..\..\build\$configuration$\v142\x64\wcautil.lib" target="build\native\v142\x64" /> | ||
27 | <file src="..\..\build\$configuration$\v142\x86\wcautil.lib" target="build\native\v142\x86" /> | ||
28 | <file src="..\..\build\$configuration$\v142\ARM64\wcautil.lib" target="build\native\v142\ARM64" /> | ||
29 | </files> | ||
30 | </package> | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcautil.vcxproj b/src/libs/wcautil/WixToolset.WcaUtil/wcautil.vcxproj new file mode 100644 index 00000000..6876bd5b --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcautil.vcxproj | |||
@@ -0,0 +1,94 @@ | |||
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 | <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
4 | <Import Project="..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" /> | ||
5 | <ItemGroup Label="ProjectConfigurations"> | ||
6 | <ProjectConfiguration Include="Debug|ARM64"> | ||
7 | <Configuration>Debug</Configuration> | ||
8 | <Platform>ARM64</Platform> | ||
9 | </ProjectConfiguration> | ||
10 | <ProjectConfiguration Include="Debug|x64"> | ||
11 | <Configuration>Debug</Configuration> | ||
12 | <Platform>x64</Platform> | ||
13 | </ProjectConfiguration> | ||
14 | <ProjectConfiguration Include="Debug|Win32"> | ||
15 | <Configuration>Debug</Configuration> | ||
16 | <Platform>Win32</Platform> | ||
17 | </ProjectConfiguration> | ||
18 | <ProjectConfiguration Include="Release|ARM64"> | ||
19 | <Configuration>Release</Configuration> | ||
20 | <Platform>ARM64</Platform> | ||
21 | </ProjectConfiguration> | ||
22 | <ProjectConfiguration Include="Release|Win32"> | ||
23 | <Configuration>Release</Configuration> | ||
24 | <Platform>Win32</Platform> | ||
25 | </ProjectConfiguration> | ||
26 | <ProjectConfiguration Include="Release|x64"> | ||
27 | <Configuration>Release</Configuration> | ||
28 | <Platform>x64</Platform> | ||
29 | </ProjectConfiguration> | ||
30 | </ItemGroup> | ||
31 | <PropertyGroup Label="Globals"> | ||
32 | <ProjectGuid>{5B3714B6-3A76-463E-8595-D48DA276C512}</ProjectGuid> | ||
33 | <ConfigurationType>StaticLibrary</ConfigurationType> | ||
34 | <TargetName>wcautil</TargetName> | ||
35 | <MultiTargetLibrary>true</MultiTargetLibrary> | ||
36 | <PlatformToolset>v142</PlatformToolset> | ||
37 | <CharacterSet>MultiByte</CharacterSet> | ||
38 | <Description>WiX Toolset Custom Action native utility library</Description> | ||
39 | </PropertyGroup> | ||
40 | |||
41 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||
42 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | ||
43 | <ImportGroup Label="Shared"> | ||
44 | <Import Project="..\..\packages\Nerdbank.GitVersioning.2.1.65\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\..\packages\Nerdbank.GitVersioning.2.1.65\build\Nerdbank.GitVersioning.targets')" /> | ||
45 | </ImportGroup> | ||
46 | <Import Project="..\NativeMultiTargeting.Build.props" /> | ||
47 | |||
48 | <ItemGroup> | ||
49 | <ClCompile Include="exbinary.cpp" /> | ||
50 | <ClCompile Include="wcalog.cpp" /> | ||
51 | <ClCompile Include="wcascript.cpp" /> | ||
52 | <ClCompile Include="wcautil.cpp"> | ||
53 | <PrecompiledHeader>Create</PrecompiledHeader> | ||
54 | </ClCompile> | ||
55 | <ClCompile Include="wcawrapquery.cpp" /> | ||
56 | <ClCompile Include="wcawow64.cpp" /> | ||
57 | <ClCompile Include="wcawrap.cpp" /> | ||
58 | <ClCompile Include="qtexec.cpp" /> | ||
59 | </ItemGroup> | ||
60 | |||
61 | <ItemGroup Condition="'$(Platform)' == 'Win32'"> | ||
62 | <ClInclude Include="custommsierrors.h"> | ||
63 | <GenerateWixInclude>caerr.wxi</GenerateWixInclude> | ||
64 | </ClInclude> | ||
65 | </ItemGroup> | ||
66 | <ItemGroup Condition="'$(Platform)' != 'Win32'"> | ||
67 | <ClInclude Include="custommsierrors.h" /> | ||
68 | </ItemGroup> | ||
69 | <ItemGroup> | ||
70 | <ClInclude Include="precomp.h" /> | ||
71 | <ClInclude Include="inc\wcalog.h" /> | ||
72 | <ClInclude Include="inc\wcautil.h" /> | ||
73 | <ClInclude Include="inc\wcawow64.h" /> | ||
74 | <ClInclude Include="inc\wcawrapquery.h" /> | ||
75 | </ItemGroup> | ||
76 | |||
77 | <ItemGroup> | ||
78 | <None Include="packages.config" /> | ||
79 | </ItemGroup> | ||
80 | |||
81 | <Target Name="PackNativeNuget" | ||
82 | DependsOnTargets="GetBuildVersion"> | ||
83 | <Exec Command='nuget pack wcautil.nuspec -OutputDirectory "$(BaseOutputPath)$(Configuration)" -Properties Configuration=$(Configuration);Id=WixToolset.WcaUtil;Version="$(BuildVersionSimple)";Authors="$(Authors)";Copyright="$(Copyright)";Description="$(Description)";Title="$(Title)"' /> | ||
84 | </Target> | ||
85 | |||
86 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||
87 | <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> | ||
88 | <PropertyGroup> | ||
89 | <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> | ||
90 | </PropertyGroup> | ||
91 | <Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.2.1.65\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.2.1.65\build\Nerdbank.GitVersioning.targets'))" /> | ||
92 | <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props'))" /> | ||
93 | </Target> | ||
94 | </Project> \ No newline at end of file | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcawow64.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcawow64.cpp new file mode 100644 index 00000000..8174c43e --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcawow64.cpp | |||
@@ -0,0 +1,169 @@ | |||
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 | static HMODULE s_hKernel32; | ||
6 | static BOOL s_fWow64Initialized; | ||
7 | static BOOL (*s_pfnDisableWow64)(__out PVOID* ); | ||
8 | static BOOL (*s_pfnRevertWow64)(__in PVOID ); | ||
9 | static BOOL (*s_pfnIsWow64Process) (HANDLE, PBOOL); | ||
10 | static PVOID s_Wow64FSRevertState; | ||
11 | static BOOL s_fWow64FSDisabled; | ||
12 | |||
13 | /******************************************************************** | ||
14 | WcaInitializeWow64() - Initializes the Wow64 API | ||
15 | |||
16 | ********************************************************************/ | ||
17 | extern "C" HRESULT WIXAPI WcaInitializeWow64() | ||
18 | { | ||
19 | AssertSz(WcaIsInitialized(), "WcaInitialize() should be called before calling WcaInitializeWow64()"); | ||
20 | AssertSz(!WcaIsWow64Initialized(), "WcaInitializeWow64() should not be called twice without calling WcaFinalizeWow64()"); | ||
21 | |||
22 | s_fWow64Initialized = FALSE; | ||
23 | HRESULT hr = S_OK; | ||
24 | s_Wow64FSRevertState = NULL; | ||
25 | s_fWow64FSDisabled = false; | ||
26 | |||
27 | // Test if we have access to the Wow64 API, and store the result in bWow64APIPresent | ||
28 | s_hKernel32 = ::GetModuleHandleW(L"kernel32.dll"); | ||
29 | if (!s_hKernel32) | ||
30 | { | ||
31 | ExitWithLastError(hr, "failed to get handle to kernel32.dll"); | ||
32 | } | ||
33 | |||
34 | // This will test if we have access to the Wow64 API | ||
35 | s_pfnIsWow64Process = (BOOL (*)(HANDLE, PBOOL))::GetProcAddress(s_hKernel32, "IsWow64Process"); | ||
36 | if (NULL != s_pfnIsWow64Process) | ||
37 | { | ||
38 | s_pfnDisableWow64 = (BOOL (*)(PVOID *))::GetProcAddress(s_hKernel32, "Wow64DisableWow64FsRedirection"); | ||
39 | // If we fail, log the error but proceed, because we may not need a particular function, or the Wow64 API at all | ||
40 | if (!s_pfnDisableWow64) | ||
41 | { | ||
42 | return S_FALSE; | ||
43 | } | ||
44 | |||
45 | s_pfnRevertWow64 = (BOOL (*)(PVOID))::GetProcAddress(s_hKernel32, "Wow64RevertWow64FsRedirection"); | ||
46 | if (!s_pfnRevertWow64) | ||
47 | { | ||
48 | return S_FALSE; | ||
49 | } | ||
50 | |||
51 | if (s_pfnDisableWow64 && s_pfnRevertWow64) | ||
52 | { | ||
53 | s_fWow64Initialized = TRUE; | ||
54 | } | ||
55 | } | ||
56 | else | ||
57 | { | ||
58 | return S_FALSE; | ||
59 | } | ||
60 | |||
61 | LExit: | ||
62 | |||
63 | return hr; | ||
64 | } | ||
65 | |||
66 | /******************************************************************** | ||
67 | WcaIsWow64Process() - determines if the current process is running | ||
68 | in WOW | ||
69 | |||
70 | ********************************************************************/ | ||
71 | extern "C" BOOL WIXAPI WcaIsWow64Process() | ||
72 | { | ||
73 | BOOL fIsWow64Process = FALSE; | ||
74 | if (s_fWow64Initialized) | ||
75 | { | ||
76 | if (!s_pfnIsWow64Process(GetCurrentProcess(), &fIsWow64Process)) | ||
77 | { | ||
78 | // clear out the value since call failed | ||
79 | fIsWow64Process = FALSE; | ||
80 | } | ||
81 | } | ||
82 | return fIsWow64Process; | ||
83 | } | ||
84 | |||
85 | /******************************************************************** | ||
86 | WcaIsWow64Initialized() - determines if WcaInitializeWow64() has | ||
87 | been successfully called | ||
88 | |||
89 | ********************************************************************/ | ||
90 | extern "C" BOOL WIXAPI WcaIsWow64Initialized() | ||
91 | { | ||
92 | return s_fWow64Initialized; | ||
93 | } | ||
94 | |||
95 | /******************************************************************** | ||
96 | WcaDisableWow64FSRedirection() - Disables Wow64 FS Redirection | ||
97 | |||
98 | ********************************************************************/ | ||
99 | extern "C" HRESULT WIXAPI WcaDisableWow64FSRedirection() | ||
100 | { | ||
101 | AssertSz(s_fWow64Initialized && s_pfnDisableWow64 != NULL, "WcaDisableWow64FSRedirection() called, but Wow64 API was not initialized"); | ||
102 | |||
103 | #ifdef DEBUG | ||
104 | AssertSz(!s_fWow64FSDisabled, "You must call WcaRevertWow64FSRedirection() before calling WcaDisableWow64FSRedirection() again"); | ||
105 | #endif | ||
106 | |||
107 | HRESULT hr = S_OK; | ||
108 | if (s_pfnDisableWow64(&s_Wow64FSRevertState)) | ||
109 | { | ||
110 | s_fWow64FSDisabled = TRUE; | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | ExitWithLastError(hr, "Failed to disable WOW64."); | ||
115 | } | ||
116 | |||
117 | LExit: | ||
118 | return hr; | ||
119 | } | ||
120 | |||
121 | /******************************************************************** | ||
122 | WcaRevertWow64FSRedirection() - Reverts Wow64 FS Redirection to its | ||
123 | pre-disabled state | ||
124 | |||
125 | ********************************************************************/ | ||
126 | extern "C" HRESULT WIXAPI WcaRevertWow64FSRedirection() | ||
127 | { | ||
128 | AssertSz(s_fWow64Initialized && s_pfnDisableWow64 != NULL, "WcaRevertWow64FSRedirection() called, but Wow64 API was not initialized"); | ||
129 | |||
130 | #ifdef DEBUG | ||
131 | AssertSz(s_fWow64FSDisabled, "You must call WcaDisableWow64FSRedirection() before calling WcaRevertWow64FSRedirection()"); | ||
132 | #endif | ||
133 | |||
134 | HRESULT hr = S_OK; | ||
135 | if (s_pfnRevertWow64(s_Wow64FSRevertState)) | ||
136 | { | ||
137 | s_fWow64FSDisabled = FALSE; | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | ExitWithLastError(hr, "Failed to revert WOW64."); | ||
142 | } | ||
143 | |||
144 | LExit: | ||
145 | return hr; | ||
146 | } | ||
147 | |||
148 | /******************************************************************** | ||
149 | WcaFinalizeWow64() - Cleans up after Wow64 API Initialization | ||
150 | |||
151 | ********************************************************************/ | ||
152 | extern "C" HRESULT WIXAPI WcaFinalizeWow64() | ||
153 | { | ||
154 | if (s_fWow64FSDisabled) | ||
155 | { | ||
156 | #ifdef DEBUG | ||
157 | AssertSz(FALSE, "WcaFinalizeWow64() called while Filesystem redirection was disabled."); | ||
158 | #else | ||
159 | // If we aren't in debug mode, let's do our best to recover gracefully | ||
160 | WcaRevertWow64FSRedirection(); | ||
161 | #endif | ||
162 | } | ||
163 | |||
164 | s_fWow64Initialized = FALSE; | ||
165 | s_pfnDisableWow64 = NULL; | ||
166 | s_pfnRevertWow64 = NULL; | ||
167 | |||
168 | return S_OK; | ||
169 | } | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcawrap.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcawrap.cpp new file mode 100644 index 00000000..2b68f36f --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcawrap.cpp | |||
@@ -0,0 +1,1668 @@ | |||
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 | WcaProcessMessage() - sends a message from the CustomAction | ||
8 | |||
9 | ********************************************************************/ | ||
10 | extern "C" UINT WIXAPI WcaProcessMessage( | ||
11 | __in INSTALLMESSAGE eMessageType, | ||
12 | __in MSIHANDLE hRecord | ||
13 | ) | ||
14 | { | ||
15 | UINT er = ::MsiProcessMessage(WcaGetInstallHandle(), eMessageType, hRecord); | ||
16 | if (ERROR_INSTALL_USEREXIT == er || IDCANCEL == er) | ||
17 | { | ||
18 | WcaSetReturnValue(ERROR_INSTALL_USEREXIT); | ||
19 | } | ||
20 | |||
21 | return er; | ||
22 | } | ||
23 | |||
24 | |||
25 | /******************************************************************** | ||
26 | WcaErrorMessage() - sends an error message from the CustomAction using | ||
27 | the Error table | ||
28 | |||
29 | NOTE: Any and all var_args (...) must be WCHAR* | ||
30 | If you pass -1 to cArgs the count will be determined | ||
31 | ********************************************************************/ | ||
32 | extern "C" UINT __cdecl WcaErrorMessage( | ||
33 | __in int iError, | ||
34 | __in HRESULT hrError, | ||
35 | __in UINT uiType, | ||
36 | __in INT cArgs, | ||
37 | ... | ||
38 | ) | ||
39 | { | ||
40 | UINT er; | ||
41 | MSIHANDLE hRec = NULL; | ||
42 | va_list args = NULL; | ||
43 | |||
44 | uiType |= INSTALLMESSAGE_ERROR; // ensure error type is set | ||
45 | hRec = ::MsiCreateRecord(cArgs + 2); | ||
46 | if (!hRec) | ||
47 | { | ||
48 | er = ERROR_OUTOFMEMORY; | ||
49 | ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to create record when sending error message"); | ||
50 | } | ||
51 | |||
52 | er = ::MsiRecordSetInteger(hRec, 1, iError); | ||
53 | ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set error code into error message"); | ||
54 | |||
55 | er = ::MsiRecordSetInteger(hRec, 2, hrError); | ||
56 | ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set hresult code into error message"); | ||
57 | |||
58 | va_start(args, cArgs); | ||
59 | if (-1 == cArgs) | ||
60 | { | ||
61 | LPCWSTR wzArg = NULL; | ||
62 | va_list iter = args; | ||
63 | cArgs = 0; | ||
64 | |||
65 | while (NULL != (wzArg = va_arg(iter, WCHAR*)) && L'\0' != *wzArg) | ||
66 | { | ||
67 | ++cArgs; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | for (INT i = 0; i < cArgs; i++) | ||
72 | { | ||
73 | er = ::MsiRecordSetStringW(hRec, i + 3, va_arg(args, WCHAR*)); | ||
74 | ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set string string into error message"); | ||
75 | } | ||
76 | va_end(args); | ||
77 | |||
78 | er = WcaProcessMessage(static_cast<INSTALLMESSAGE>(uiType), hRec); | ||
79 | LExit: | ||
80 | if (args) | ||
81 | { | ||
82 | va_end(args); | ||
83 | } | ||
84 | |||
85 | if (hRec) | ||
86 | { | ||
87 | ::MsiCloseHandle(hRec); | ||
88 | } | ||
89 | |||
90 | return er; | ||
91 | } | ||
92 | |||
93 | |||
94 | /******************************************************************** | ||
95 | WcaProgressMessage() - extends the progress bar or sends a progress | ||
96 | update from the CustomAction | ||
97 | |||
98 | ********************************************************************/ | ||
99 | extern "C" HRESULT WIXAPI WcaProgressMessage( | ||
100 | __in UINT uiCost, | ||
101 | __in BOOL fExtendProgressBar | ||
102 | ) | ||
103 | { | ||
104 | static BOOL fExplicitProgressMessages = FALSE; | ||
105 | |||
106 | HRESULT hr = S_OK; | ||
107 | UINT er = ERROR_SUCCESS; | ||
108 | MSIHANDLE hRec = ::MsiCreateRecord(3); | ||
109 | |||
110 | // if aren't extending the progress bar and we haven't switched into explicit message mode | ||
111 | if (!fExtendProgressBar && !fExplicitProgressMessages) | ||
112 | { | ||
113 | AssertSz(::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED) || | ||
114 | ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_COMMIT) || | ||
115 | ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK), "can only send progress bar messages in a deferred CustomAction"); | ||
116 | |||
117 | // tell Darwin to use explicit progress messages | ||
118 | ::MsiRecordSetInteger(hRec, 1, 1); | ||
119 | ::MsiRecordSetInteger(hRec, 2, 1); | ||
120 | ::MsiRecordSetInteger(hRec, 3, 0); | ||
121 | |||
122 | er = WcaProcessMessage(INSTALLMESSAGE_PROGRESS, hRec); | ||
123 | if (0 == er || IDOK == er || IDYES == er) | ||
124 | { | ||
125 | hr = S_OK; | ||
126 | } | ||
127 | else if (IDABORT == er || IDCANCEL == er) | ||
128 | { | ||
129 | WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit | ||
130 | ExitFunction1(hr = S_FALSE); | ||
131 | } | ||
132 | else | ||
133 | { | ||
134 | hr = E_UNEXPECTED; | ||
135 | } | ||
136 | ExitOnFailure(hr, "failed to tell Darwin to use explicit progress messages"); | ||
137 | |||
138 | fExplicitProgressMessages = TRUE; | ||
139 | } | ||
140 | #if DEBUG | ||
141 | else if (fExtendProgressBar) // if we are extending the progress bar, make sure we're not deferred | ||
142 | { | ||
143 | AssertSz(!::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED), "cannot add ticks to progress bar length from deferred CustomAction"); | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | // send the progress message | ||
148 | ::MsiRecordSetInteger(hRec, 1, (fExtendProgressBar) ? 3 : 2); | ||
149 | ::MsiRecordSetInteger(hRec, 2, uiCost); | ||
150 | ::MsiRecordSetInteger(hRec, 3, 0); | ||
151 | |||
152 | er = WcaProcessMessage(INSTALLMESSAGE_PROGRESS, hRec); | ||
153 | if (0 == er || IDOK == er || IDYES == er) | ||
154 | { | ||
155 | hr = S_OK; | ||
156 | } | ||
157 | else if (IDABORT == er || IDCANCEL == er) | ||
158 | { | ||
159 | WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit | ||
160 | hr = S_FALSE; | ||
161 | } | ||
162 | else | ||
163 | { | ||
164 | hr = E_UNEXPECTED; | ||
165 | } | ||
166 | |||
167 | LExit: | ||
168 | if (hRec) | ||
169 | { | ||
170 | ::MsiCloseHandle(hRec); | ||
171 | } | ||
172 | |||
173 | return hr; | ||
174 | } | ||
175 | |||
176 | |||
177 | /******************************************************************** | ||
178 | WcaIsInstalling() - determines if a pair of installstates means install | ||
179 | |||
180 | ********************************************************************/ | ||
181 | extern "C" BOOL WIXAPI WcaIsInstalling( | ||
182 | __in INSTALLSTATE isInstalled, | ||
183 | __in INSTALLSTATE isAction | ||
184 | ) | ||
185 | { | ||
186 | return (INSTALLSTATE_LOCAL == isAction || | ||
187 | INSTALLSTATE_SOURCE == isAction || | ||
188 | (INSTALLSTATE_DEFAULT == isAction && | ||
189 | (INSTALLSTATE_LOCAL == isInstalled || | ||
190 | INSTALLSTATE_SOURCE == isInstalled))); | ||
191 | } | ||
192 | |||
193 | /******************************************************************** | ||
194 | WcaIsReInstalling() - determines if a pair of installstates means reinstall | ||
195 | |||
196 | ********************************************************************/ | ||
197 | extern "C" BOOL WIXAPI WcaIsReInstalling( | ||
198 | __in INSTALLSTATE isInstalled, | ||
199 | __in INSTALLSTATE isAction | ||
200 | ) | ||
201 | { | ||
202 | return ((INSTALLSTATE_LOCAL == isAction || | ||
203 | INSTALLSTATE_SOURCE == isAction || | ||
204 | INSTALLSTATE_DEFAULT == isAction) && | ||
205 | (INSTALLSTATE_LOCAL == isInstalled || | ||
206 | INSTALLSTATE_SOURCE == isInstalled)); | ||
207 | } | ||
208 | |||
209 | |||
210 | /******************************************************************** | ||
211 | WcaIsUninstalling() - determines if a pair of installstates means uninstall | ||
212 | |||
213 | ********************************************************************/ | ||
214 | extern "C" BOOL WIXAPI WcaIsUninstalling( | ||
215 | __in INSTALLSTATE isInstalled, | ||
216 | __in INSTALLSTATE isAction | ||
217 | ) | ||
218 | { | ||
219 | return ((INSTALLSTATE_ABSENT == isAction || | ||
220 | INSTALLSTATE_REMOVED == isAction) && | ||
221 | (INSTALLSTATE_LOCAL == isInstalled || | ||
222 | INSTALLSTATE_SOURCE == isInstalled)); | ||
223 | } | ||
224 | |||
225 | |||
226 | /******************************************************************** | ||
227 | WcaGetComponentToDo() - gets a component's install states and | ||
228 | determines if they mean install, uninstall, or reinstall. | ||
229 | ********************************************************************/ | ||
230 | extern "C" WCA_TODO WIXAPI WcaGetComponentToDo( | ||
231 | __in_z LPCWSTR wzComponentId | ||
232 | ) | ||
233 | { | ||
234 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
235 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
236 | if (ERROR_SUCCESS != ::MsiGetComponentStateW(WcaGetInstallHandle(), wzComponentId, &isInstalled, &isAction)) | ||
237 | { | ||
238 | return WCA_TODO_UNKNOWN; | ||
239 | } | ||
240 | |||
241 | if (WcaIsReInstalling(isInstalled, isAction)) | ||
242 | { | ||
243 | return WCA_TODO_REINSTALL; | ||
244 | } | ||
245 | else if (WcaIsUninstalling(isInstalled, isAction)) | ||
246 | { | ||
247 | return WCA_TODO_UNINSTALL; | ||
248 | } | ||
249 | else if (WcaIsInstalling(isInstalled, isAction)) | ||
250 | { | ||
251 | return WCA_TODO_INSTALL; | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | return WCA_TODO_UNKNOWN; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | |||
260 | /******************************************************************** | ||
261 | WcaSetComponentState() - sets the install state of a Component | ||
262 | |||
263 | ********************************************************************/ | ||
264 | extern "C" HRESULT WIXAPI WcaSetComponentState( | ||
265 | __in_z LPCWSTR wzComponent, | ||
266 | __in INSTALLSTATE isState | ||
267 | ) | ||
268 | { | ||
269 | UINT er = ::MsiSetComponentStateW(WcaGetInstallHandle(), wzComponent, isState); | ||
270 | if (ERROR_INSTALL_USEREXIT == er) | ||
271 | { | ||
272 | WcaSetReturnValue(er); | ||
273 | } | ||
274 | |||
275 | return HRESULT_FROM_WIN32(er); | ||
276 | } | ||
277 | |||
278 | |||
279 | /******************************************************************** | ||
280 | WcaTableExists() - determines if installing database contains a table | ||
281 | |||
282 | ********************************************************************/ | ||
283 | extern "C" HRESULT WIXAPI WcaTableExists( | ||
284 | __in_z LPCWSTR wzTable | ||
285 | ) | ||
286 | { | ||
287 | HRESULT hr = S_OK; | ||
288 | UINT er = ERROR_SUCCESS; | ||
289 | |||
290 | // NOTE: The following line of commented out code should work in a | ||
291 | // CustomAction but does not in Windows Installer v1.1 | ||
292 | // er = ::MsiDatabaseIsTablePersistentW(hDatabase, wzTable); | ||
293 | |||
294 | // a "most elegant" workaround a Darwin v1.1 bug | ||
295 | PMSIHANDLE hRec; | ||
296 | er = ::MsiDatabaseGetPrimaryKeysW(WcaGetDatabaseHandle(), wzTable, &hRec); | ||
297 | |||
298 | if (ERROR_SUCCESS == er) | ||
299 | { | ||
300 | hr = S_OK; | ||
301 | } | ||
302 | else if (ERROR_INVALID_TABLE == er) | ||
303 | { | ||
304 | hr = S_FALSE; | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | hr = E_FAIL; | ||
309 | } | ||
310 | Assert(SUCCEEDED(hr)); | ||
311 | |||
312 | return hr; | ||
313 | } | ||
314 | |||
315 | |||
316 | /******************************************************************** | ||
317 | WcaOpenView() - opens a view on the installing database | ||
318 | |||
319 | ********************************************************************/ | ||
320 | extern "C" HRESULT WIXAPI WcaOpenView( | ||
321 | __in_z LPCWSTR wzSql, | ||
322 | __out MSIHANDLE* phView | ||
323 | ) | ||
324 | { | ||
325 | if (!wzSql || !*wzSql|| !phView) | ||
326 | { | ||
327 | return E_INVALIDARG; | ||
328 | } | ||
329 | |||
330 | HRESULT hr = S_OK; | ||
331 | UINT er = ::MsiDatabaseOpenViewW(WcaGetDatabaseHandle(), wzSql, phView); | ||
332 | ExitOnWin32Error(er, hr, "failed to open view on database with SQL: %ls", wzSql); | ||
333 | |||
334 | LExit: | ||
335 | return hr; | ||
336 | } | ||
337 | |||
338 | |||
339 | /******************************************************************** | ||
340 | WcaExecuteView() - executes a parameterized open view on the installing database | ||
341 | |||
342 | ********************************************************************/ | ||
343 | extern "C" HRESULT WIXAPI WcaExecuteView( | ||
344 | __in MSIHANDLE hView, | ||
345 | __in MSIHANDLE hRec | ||
346 | ) | ||
347 | { | ||
348 | if (!hView) | ||
349 | { | ||
350 | return E_INVALIDARG; | ||
351 | } | ||
352 | AssertSz(hRec, "Use WcaOpenExecuteView() if you don't need to pass in a record"); | ||
353 | |||
354 | HRESULT hr = S_OK; | ||
355 | UINT er = ::MsiViewExecute(hView, hRec); | ||
356 | ExitOnWin32Error(er, hr, "failed to execute view"); | ||
357 | |||
358 | LExit: | ||
359 | return hr; | ||
360 | } | ||
361 | |||
362 | |||
363 | /******************************************************************** | ||
364 | WcaOpenExecuteView() - opens and executes a view on the installing database | ||
365 | |||
366 | ********************************************************************/ | ||
367 | extern "C" HRESULT WIXAPI WcaOpenExecuteView( | ||
368 | __in_z LPCWSTR wzSql, | ||
369 | __out MSIHANDLE* phView | ||
370 | ) | ||
371 | { | ||
372 | if (!wzSql || !*wzSql|| !phView) | ||
373 | { | ||
374 | return E_INVALIDARG; | ||
375 | } | ||
376 | |||
377 | HRESULT hr = S_OK; | ||
378 | UINT er = ::MsiDatabaseOpenViewW(WcaGetDatabaseHandle(), wzSql, phView); | ||
379 | ExitOnWin32Error(er, hr, "failed to open view on database"); | ||
380 | |||
381 | er = ::MsiViewExecute(*phView, NULL); | ||
382 | ExitOnWin32Error(er, hr, "failed to execute view"); | ||
383 | |||
384 | LExit: | ||
385 | return hr; | ||
386 | } | ||
387 | |||
388 | |||
389 | /******************************************************************** | ||
390 | WcaFetchRecord() - gets the next record from a view on the installing database | ||
391 | |||
392 | ********************************************************************/ | ||
393 | extern "C" HRESULT WIXAPI WcaFetchRecord( | ||
394 | __in MSIHANDLE hView, | ||
395 | __out MSIHANDLE* phRec | ||
396 | ) | ||
397 | { | ||
398 | if (!hView|| !phRec) | ||
399 | { | ||
400 | return E_INVALIDARG; | ||
401 | } | ||
402 | |||
403 | HRESULT hr = S_OK; | ||
404 | UINT er = ::MsiViewFetch(hView, phRec); | ||
405 | hr = HRESULT_FROM_WIN32(er); | ||
406 | if (FAILED(hr) && E_NOMOREITEMS != hr) | ||
407 | { | ||
408 | ExitOnFailure(hr, "failed to fetch record from view"); | ||
409 | } | ||
410 | |||
411 | LExit: | ||
412 | return hr; | ||
413 | } | ||
414 | |||
415 | |||
416 | /******************************************************************** | ||
417 | WcaFetchSingleRecord() - gets a single record from a view on the installing database | ||
418 | |||
419 | ********************************************************************/ | ||
420 | extern "C" HRESULT WIXAPI WcaFetchSingleRecord( | ||
421 | __in MSIHANDLE hView, | ||
422 | __out MSIHANDLE* phRec | ||
423 | ) | ||
424 | { | ||
425 | if (!hView|| !phRec) | ||
426 | { | ||
427 | return E_INVALIDARG; | ||
428 | } | ||
429 | |||
430 | HRESULT hr = S_OK; | ||
431 | UINT er = ::MsiViewFetch(hView, phRec); | ||
432 | if (ERROR_NO_MORE_ITEMS == er) | ||
433 | { | ||
434 | hr = S_FALSE; | ||
435 | } | ||
436 | else | ||
437 | { | ||
438 | hr = HRESULT_FROM_WIN32(er); | ||
439 | } | ||
440 | ExitOnFailure(hr, "failed to fetch single record from view"); | ||
441 | |||
442 | #ifdef DEBUG // only do this in debug to verify that a single record was returned | ||
443 | MSIHANDLE hRecTest; | ||
444 | er = ::MsiViewFetch(hView, &hRecTest); | ||
445 | AssertSz(ERROR_NO_MORE_ITEMS == er && NULL == hRecTest, "WcaSingleFetch() did not fetch a single record"); | ||
446 | ::MsiCloseHandle(hRecTest); | ||
447 | #endif | ||
448 | |||
449 | LExit: | ||
450 | return hr; | ||
451 | } | ||
452 | |||
453 | |||
454 | /******************************************************************** | ||
455 | WcaGetProperty - gets a string property value from the active install | ||
456 | |||
457 | ********************************************************************/ | ||
458 | extern "C" HRESULT WIXAPI WcaGetProperty( | ||
459 | __in_z LPCWSTR wzProperty, | ||
460 | __inout LPWSTR* ppwzData | ||
461 | ) | ||
462 | { | ||
463 | if (!wzProperty || !*wzProperty || !ppwzData) | ||
464 | { | ||
465 | return E_INVALIDARG; | ||
466 | } | ||
467 | |||
468 | HRESULT hr = S_OK; | ||
469 | UINT er = ERROR_SUCCESS; | ||
470 | DWORD cch = 0; | ||
471 | SIZE_T cchMax = 0; | ||
472 | |||
473 | if (!*ppwzData) | ||
474 | { | ||
475 | WCHAR szEmpty[1] = L""; | ||
476 | er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, szEmpty, &cch); | ||
477 | if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) | ||
478 | { | ||
479 | hr = StrAlloc(ppwzData, ++cch); | ||
480 | } | ||
481 | else | ||
482 | { | ||
483 | hr = HRESULT_FROM_WIN32(er); | ||
484 | } | ||
485 | ExitOnRootFailure(hr, "Failed to allocate string for Property '%ls'", wzProperty); | ||
486 | } | ||
487 | else | ||
488 | { | ||
489 | hr = StrMaxLength(*ppwzData, &cchMax); | ||
490 | ExitOnFailure(hr, "Failed to get previous size of property data string."); | ||
491 | |||
492 | cch = (DWORD)min(MAXDWORD, cchMax); | ||
493 | } | ||
494 | |||
495 | er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, *ppwzData, &cch); | ||
496 | if (ERROR_MORE_DATA == er) | ||
497 | { | ||
498 | Assert(*ppwzData); | ||
499 | hr = StrAlloc(ppwzData, ++cch); | ||
500 | ExitOnFailure(hr, "Failed to allocate string for Property '%ls'", wzProperty); | ||
501 | |||
502 | er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, *ppwzData, &cch); | ||
503 | } | ||
504 | ExitOnWin32Error(er, hr, "Failed to get data for property '%ls'", wzProperty); | ||
505 | |||
506 | LExit: | ||
507 | return hr; | ||
508 | } | ||
509 | |||
510 | |||
511 | /******************************************************************** | ||
512 | WcaGetFormattedProperty - gets a formatted string property value from | ||
513 | the active install | ||
514 | |||
515 | ********************************************************************/ | ||
516 | extern "C" HRESULT WIXAPI WcaGetFormattedProperty( | ||
517 | __in_z LPCWSTR wzProperty, | ||
518 | __out LPWSTR* ppwzData | ||
519 | ) | ||
520 | { | ||
521 | if (!wzProperty || !*wzProperty || !ppwzData) | ||
522 | { | ||
523 | return E_INVALIDARG; | ||
524 | } | ||
525 | |||
526 | HRESULT hr = S_OK; | ||
527 | LPWSTR pwzPropertyValue = NULL; | ||
528 | |||
529 | hr = WcaGetProperty(wzProperty, &pwzPropertyValue); | ||
530 | ExitOnFailure(hr, "failed to get %ls", wzProperty); | ||
531 | |||
532 | hr = WcaGetFormattedString(pwzPropertyValue, ppwzData); | ||
533 | ExitOnFailure(hr, "failed to get formatted value for property: '%ls' with value: '%ls'", wzProperty, pwzPropertyValue); | ||
534 | |||
535 | LExit: | ||
536 | ReleaseStr(pwzPropertyValue); | ||
537 | |||
538 | return hr; | ||
539 | } | ||
540 | |||
541 | |||
542 | /******************************************************************** | ||
543 | WcaGetFormattedString - gets a formatted string value from | ||
544 | the active install | ||
545 | |||
546 | ********************************************************************/ | ||
547 | extern "C" HRESULT WIXAPI WcaGetFormattedString( | ||
548 | __in_z LPCWSTR wzString, | ||
549 | __out LPWSTR* ppwzData | ||
550 | ) | ||
551 | { | ||
552 | if (!wzString || !*wzString || !ppwzData) | ||
553 | { | ||
554 | return E_INVALIDARG; | ||
555 | } | ||
556 | |||
557 | HRESULT hr = S_OK; | ||
558 | UINT er = ERROR_SUCCESS; | ||
559 | PMSIHANDLE hRecord = ::MsiCreateRecord(1); | ||
560 | DWORD cch = 0; | ||
561 | SIZE_T cchMax = 0; | ||
562 | |||
563 | er = ::MsiRecordSetStringW(hRecord, 0, wzString); | ||
564 | ExitOnWin32Error(er, hr, "Failed to set record field 0 with '%ls'", wzString); | ||
565 | |||
566 | if (!*ppwzData) | ||
567 | { | ||
568 | WCHAR szEmpty[1] = L""; | ||
569 | er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, szEmpty, &cch); | ||
570 | if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) | ||
571 | { | ||
572 | hr = StrAlloc(ppwzData, ++cch); | ||
573 | } | ||
574 | else | ||
575 | { | ||
576 | hr = HRESULT_FROM_WIN32(er); | ||
577 | } | ||
578 | ExitOnFailure(hr, "Failed to allocate string for formatted string: '%ls'", wzString); | ||
579 | } | ||
580 | else | ||
581 | { | ||
582 | hr = StrMaxLength(*ppwzData, &cchMax); | ||
583 | ExitOnFailure(hr, "Failed to get previous size of property data string"); | ||
584 | |||
585 | cch = (DWORD)min(MAXDWORD, cchMax); | ||
586 | } | ||
587 | |||
588 | er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, *ppwzData, &cch); | ||
589 | if (ERROR_MORE_DATA == er) | ||
590 | { | ||
591 | hr = StrAlloc(ppwzData, ++cch); | ||
592 | ExitOnFailure(hr, "Failed to allocate string for formatted string: '%ls'", wzString); | ||
593 | |||
594 | er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, *ppwzData, &cch); | ||
595 | } | ||
596 | ExitOnWin32Error(er, hr, "Failed to get formatted string: '%ls'", wzString); | ||
597 | |||
598 | LExit: | ||
599 | return hr; | ||
600 | } | ||
601 | |||
602 | |||
603 | /******************************************************************** | ||
604 | WcaGetIntProperty - gets an integer property value from the active install | ||
605 | |||
606 | ********************************************************************/ | ||
607 | extern "C" HRESULT WIXAPI WcaGetIntProperty( | ||
608 | __in_z LPCWSTR wzProperty, | ||
609 | __inout int* piData | ||
610 | ) | ||
611 | { | ||
612 | if (!piData) | ||
613 | return E_INVALIDARG; | ||
614 | |||
615 | HRESULT hr = S_OK; | ||
616 | UINT er; | ||
617 | |||
618 | WCHAR wzValue[32]; | ||
619 | DWORD cch = countof(wzValue) - 1; | ||
620 | |||
621 | er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, wzValue, &cch); | ||
622 | ExitOnWin32Error(er, hr, "Failed to get data for property '%ls'", wzProperty); | ||
623 | |||
624 | *piData = wcstol(wzValue, NULL, 10); | ||
625 | |||
626 | LExit: | ||
627 | return hr; | ||
628 | } | ||
629 | |||
630 | |||
631 | /******************************************************************** | ||
632 | WcaGetTargetPath - gets the target path for a specified folder | ||
633 | |||
634 | ********************************************************************/ | ||
635 | extern "C" HRESULT WIXAPI WcaGetTargetPath( | ||
636 | __in_z LPCWSTR wzFolder, | ||
637 | __out LPWSTR* ppwzData | ||
638 | ) | ||
639 | { | ||
640 | if (!wzFolder || !*wzFolder || !ppwzData) | ||
641 | return E_INVALIDARG; | ||
642 | |||
643 | HRESULT hr = S_OK; | ||
644 | |||
645 | UINT er = ERROR_SUCCESS; | ||
646 | DWORD cch = 0; | ||
647 | SIZE_T cchMax = 0; | ||
648 | |||
649 | if (!*ppwzData) | ||
650 | { | ||
651 | WCHAR szEmpty[1] = L""; | ||
652 | er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, szEmpty, &cch); | ||
653 | if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) | ||
654 | { | ||
655 | ++cch; //Add one for the null terminator | ||
656 | hr = StrAlloc(ppwzData, cch); | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | hr = HRESULT_FROM_WIN32(er); | ||
661 | } | ||
662 | ExitOnFailure(hr, "Failed to allocate string for target path of folder: '%ls'", wzFolder); | ||
663 | } | ||
664 | else | ||
665 | { | ||
666 | hr = StrMaxLength(*ppwzData, &cchMax); | ||
667 | ExitOnFailure(hr, "Failed to get previous size of string"); | ||
668 | |||
669 | cch = (DWORD)min(MAXDWORD, cchMax); | ||
670 | } | ||
671 | |||
672 | er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, *ppwzData, &cch); | ||
673 | if (ERROR_MORE_DATA == er) | ||
674 | { | ||
675 | ++cch; | ||
676 | hr = StrAlloc(ppwzData, cch); | ||
677 | ExitOnFailure(hr, "Failed to allocate string for target path of folder: '%ls'", wzFolder); | ||
678 | |||
679 | er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, *ppwzData, &cch); | ||
680 | } | ||
681 | ExitOnWin32Error(er, hr, "Failed to get target path for folder '%ls'", wzFolder); | ||
682 | |||
683 | LExit: | ||
684 | return hr; | ||
685 | } | ||
686 | |||
687 | |||
688 | /******************************************************************** | ||
689 | WcaSetProperty - sets a string property value in the active install | ||
690 | |||
691 | ********************************************************************/ | ||
692 | extern "C" HRESULT WIXAPI WcaSetProperty( | ||
693 | __in_z LPCWSTR wzPropertyName, | ||
694 | __in_z LPCWSTR wzPropertyValue | ||
695 | ) | ||
696 | { | ||
697 | HRESULT hr = S_OK; | ||
698 | |||
699 | if (!wzPropertyName || !*wzPropertyName || !wzPropertyValue) | ||
700 | return E_INVALIDARG; | ||
701 | |||
702 | UINT er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzPropertyName, wzPropertyValue); | ||
703 | ExitOnWin32Error(er, hr, "failed to set property: %ls", wzPropertyName); | ||
704 | |||
705 | LExit: | ||
706 | return hr; | ||
707 | } | ||
708 | |||
709 | |||
710 | /******************************************************************** | ||
711 | WcaSetIntProperty - sets a integer property value in the active install | ||
712 | |||
713 | ********************************************************************/ | ||
714 | extern "C" HRESULT WIXAPI WcaSetIntProperty( | ||
715 | __in_z LPCWSTR wzPropertyName, | ||
716 | __in int nPropertyValue | ||
717 | ) | ||
718 | { | ||
719 | if (!wzPropertyName || !*wzPropertyName) | ||
720 | return E_INVALIDARG; | ||
721 | |||
722 | // 12 characters should be enough for a 32-bit int: 10 digits, 1 sign, 1 null | ||
723 | WCHAR wzPropertyValue[13]; | ||
724 | HRESULT hr = StringCchPrintfW(wzPropertyValue, countof(wzPropertyValue), L"%d", nPropertyValue); | ||
725 | ExitOnFailure(hr, "failed to convert into string property value: %d", nPropertyValue); | ||
726 | |||
727 | UINT er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzPropertyName, wzPropertyValue); | ||
728 | ExitOnWin32Error(er, hr, "failed to set property: %ls", wzPropertyName); | ||
729 | |||
730 | LExit: | ||
731 | return hr; | ||
732 | } | ||
733 | |||
734 | |||
735 | /******************************************************************** | ||
736 | WcaIsPropertySet() - returns TRUE if property is set | ||
737 | |||
738 | ********************************************************************/ | ||
739 | extern "C" BOOL WIXAPI WcaIsPropertySet( | ||
740 | __in LPCSTR szProperty | ||
741 | ) | ||
742 | { | ||
743 | DWORD cchProperty = 0; | ||
744 | char szEmpty[1] = ""; | ||
745 | #ifdef DEBUG | ||
746 | UINT er = | ||
747 | #endif | ||
748 | ::MsiGetPropertyA(WcaGetInstallHandle(), szProperty, szEmpty, &cchProperty); | ||
749 | AssertSz(ERROR_INVALID_PARAMETER != er && ERROR_INVALID_HANDLE != er, "Unexpected return value from ::MsiGetProperty()"); | ||
750 | |||
751 | return 0 < cchProperty; // property is set if the length is greater than zero | ||
752 | } | ||
753 | |||
754 | |||
755 | /******************************************************************** | ||
756 | WcaIsUnicodePropertySet() - returns TRUE if property is set | ||
757 | |||
758 | ********************************************************************/ | ||
759 | extern "C" BOOL WIXAPI WcaIsUnicodePropertySet( | ||
760 | __in LPCWSTR wzProperty | ||
761 | ) | ||
762 | { | ||
763 | DWORD cchProperty = 0; | ||
764 | wchar_t wzEmpty[1] = L""; | ||
765 | #ifdef DEBUG | ||
766 | UINT er = | ||
767 | #endif | ||
768 | ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, wzEmpty, &cchProperty); | ||
769 | AssertSz(ERROR_INVALID_PARAMETER != er && ERROR_INVALID_HANDLE != er, "Unexpected return value from ::MsiGetProperty()"); | ||
770 | |||
771 | return 0 < cchProperty; // property is set if the length is greater than zero | ||
772 | } | ||
773 | |||
774 | |||
775 | /******************************************************************** | ||
776 | WcaGetRecordInteger() - gets an integer field out of a record | ||
777 | |||
778 | NOTE: returns S_FALSE if the field was null | ||
779 | ********************************************************************/ | ||
780 | extern "C" HRESULT WIXAPI WcaGetRecordInteger( | ||
781 | __in MSIHANDLE hRec, | ||
782 | __in UINT uiField, | ||
783 | __inout int* piData | ||
784 | ) | ||
785 | { | ||
786 | if (!hRec || !piData) | ||
787 | return E_INVALIDARG; | ||
788 | |||
789 | HRESULT hr = S_OK; | ||
790 | *piData = ::MsiRecordGetInteger(hRec, uiField); | ||
791 | if (MSI_NULL_INTEGER == *piData) | ||
792 | hr = S_FALSE; | ||
793 | |||
794 | //LExit: | ||
795 | return hr; | ||
796 | } | ||
797 | |||
798 | |||
799 | /******************************************************************** | ||
800 | WcaGetRecordString() - gets a string field out of a record | ||
801 | |||
802 | ********************************************************************/ | ||
803 | extern "C" HRESULT WIXAPI WcaGetRecordString( | ||
804 | __in MSIHANDLE hRec, | ||
805 | __in UINT uiField, | ||
806 | __inout LPWSTR* ppwzData | ||
807 | ) | ||
808 | { | ||
809 | if (!hRec || !ppwzData) | ||
810 | return E_INVALIDARG; | ||
811 | |||
812 | HRESULT hr = S_OK; | ||
813 | UINT er; | ||
814 | DWORD cch = 0; | ||
815 | SIZE_T cchMax = 0; | ||
816 | |||
817 | if (!*ppwzData) | ||
818 | { | ||
819 | WCHAR szEmpty[1] = L""; | ||
820 | er = ::MsiRecordGetStringW(hRec, uiField, szEmpty, &cch); | ||
821 | if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) | ||
822 | { | ||
823 | hr = StrAlloc(ppwzData, ++cch); | ||
824 | } | ||
825 | else | ||
826 | { | ||
827 | hr = HRESULT_FROM_WIN32(er); | ||
828 | } | ||
829 | ExitOnFailure(hr, "Failed to allocate memory for record string"); | ||
830 | } | ||
831 | else | ||
832 | { | ||
833 | hr = StrMaxLength(*ppwzData, &cchMax); | ||
834 | ExitOnFailure(hr, "Failed to get previous size of string"); | ||
835 | |||
836 | cch = (DWORD)min(MAXDWORD, cchMax); | ||
837 | } | ||
838 | |||
839 | er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, &cch); | ||
840 | if (ERROR_MORE_DATA == er) | ||
841 | { | ||
842 | hr = StrAlloc(ppwzData, ++cch); | ||
843 | ExitOnFailure(hr, "Failed to allocate memory for record string"); | ||
844 | |||
845 | er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, &cch); | ||
846 | } | ||
847 | ExitOnWin32Error(er, hr, "Failed to get string from record"); | ||
848 | |||
849 | LExit: | ||
850 | return hr; | ||
851 | } | ||
852 | |||
853 | |||
854 | /******************************************************************** | ||
855 | HideNulls() - internal helper function to escape [~] in formatted strings | ||
856 | |||
857 | ********************************************************************/ | ||
858 | static void HideNulls( | ||
859 | __inout_z LPWSTR wzData | ||
860 | ) | ||
861 | { | ||
862 | LPWSTR pwz = wzData; | ||
863 | |||
864 | while(*pwz) | ||
865 | { | ||
866 | if (pwz[0] == L'[' && pwz[1] == L'~' && pwz[2] == L']') // found a null [~] | ||
867 | { | ||
868 | pwz[0] = L'!'; // turn it into !$! | ||
869 | pwz[1] = L'$'; | ||
870 | pwz[2] = L'!'; | ||
871 | pwz += 3; | ||
872 | } | ||
873 | else | ||
874 | { | ||
875 | ++pwz; | ||
876 | } | ||
877 | } | ||
878 | } | ||
879 | |||
880 | |||
881 | /******************************************************************** | ||
882 | RevealNulls() - internal helper function to unescape !$! in formatted strings | ||
883 | |||
884 | ********************************************************************/ | ||
885 | static void RevealNulls( | ||
886 | __inout_z LPWSTR wzData | ||
887 | ) | ||
888 | { | ||
889 | LPWSTR pwz = wzData; | ||
890 | |||
891 | while(*pwz) | ||
892 | { | ||
893 | if (pwz[0] == L'!' && pwz[1] == L'$' && pwz[2] == L'!') // found the fake null !$! | ||
894 | { | ||
895 | pwz[0] = L'['; // turn it back into [~] | ||
896 | pwz[1] = L'~'; | ||
897 | pwz[2] = L']'; | ||
898 | pwz += 3; | ||
899 | } | ||
900 | else | ||
901 | { | ||
902 | ++pwz; | ||
903 | } | ||
904 | } | ||
905 | } | ||
906 | |||
907 | |||
908 | /******************************************************************** | ||
909 | WcaGetRecordFormattedString() - gets formatted string filed from record | ||
910 | |||
911 | ********************************************************************/ | ||
912 | extern "C" HRESULT WIXAPI WcaGetRecordFormattedString( | ||
913 | __in MSIHANDLE hRec, | ||
914 | __in UINT uiField, | ||
915 | __inout LPWSTR* ppwzData | ||
916 | ) | ||
917 | { | ||
918 | if (!hRec || !ppwzData) | ||
919 | { | ||
920 | return E_INVALIDARG; | ||
921 | } | ||
922 | |||
923 | HRESULT hr = S_OK; | ||
924 | UINT er; | ||
925 | DWORD cch = 0; | ||
926 | SIZE_T cchMax = 0; | ||
927 | PMSIHANDLE hRecFormat; | ||
928 | |||
929 | // get the format string | ||
930 | hr = WcaGetRecordString(hRec, uiField, ppwzData); | ||
931 | ExitOnFailure(hr, "failed to get string from record"); | ||
932 | |||
933 | if (!**ppwzData) | ||
934 | { | ||
935 | ExitFunction(); | ||
936 | } | ||
937 | |||
938 | // hide the nulls '[~]' so we can get them back after formatting | ||
939 | HideNulls(*ppwzData); | ||
940 | |||
941 | // set up the format record | ||
942 | hRecFormat = ::MsiCreateRecord(1); | ||
943 | ExitOnNull(hRecFormat, hr, E_UNEXPECTED, "Failed to create record to format string"); | ||
944 | hr = WcaSetRecordString(hRecFormat, 0, *ppwzData); | ||
945 | ExitOnFailure(hr, "failed to set string to format record"); | ||
946 | |||
947 | // format the string | ||
948 | hr = StrMaxLength(*ppwzData, &cchMax); | ||
949 | ExitOnFailure(hr, "failed to get max length of string"); | ||
950 | |||
951 | cch = (DWORD)min(MAXDWORD, cchMax); | ||
952 | |||
953 | er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, &cch); | ||
954 | if (ERROR_MORE_DATA == er) | ||
955 | { | ||
956 | hr = StrAlloc(ppwzData, ++cch); | ||
957 | ExitOnFailure(hr, "Failed to allocate memory for record string"); | ||
958 | |||
959 | er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, &cch); | ||
960 | } | ||
961 | ExitOnWin32Error(er, hr, "Failed to format string"); | ||
962 | |||
963 | // put the nulls back | ||
964 | RevealNulls(*ppwzData); | ||
965 | |||
966 | LExit: | ||
967 | return hr; | ||
968 | } | ||
969 | |||
970 | |||
971 | /******************************************************************** | ||
972 | WcaGetRecordFormattedInteger() - gets formatted integer from record | ||
973 | |||
974 | ********************************************************************/ | ||
975 | extern "C" HRESULT WIXAPI WcaGetRecordFormattedInteger( | ||
976 | __in MSIHANDLE hRec, | ||
977 | __in UINT uiField, | ||
978 | __out int* piData | ||
979 | ) | ||
980 | { | ||
981 | if (!hRec || !piData) | ||
982 | { | ||
983 | return E_INVALIDARG; | ||
984 | } | ||
985 | |||
986 | HRESULT hr = S_OK; | ||
987 | LPWSTR pwzData = NULL; | ||
988 | |||
989 | hr = WcaGetRecordFormattedString(hRec, uiField, &pwzData); | ||
990 | ExitOnFailure(hr, "failed to get record field: %u", uiField); | ||
991 | if (pwzData && *pwzData) | ||
992 | { | ||
993 | LPWSTR wz = NULL; | ||
994 | *piData = wcstol(pwzData, &wz, 10); | ||
995 | if (wz && *wz) | ||
996 | { | ||
997 | hr = E_INVALIDARG; | ||
998 | ExitOnFailure(hr, "failed to parse record field: %u as number: %ls", uiField, pwzData); | ||
999 | } | ||
1000 | } | ||
1001 | else | ||
1002 | { | ||
1003 | *piData = MSI_NULL_INTEGER; | ||
1004 | } | ||
1005 | |||
1006 | LExit: | ||
1007 | return hr; | ||
1008 | } | ||
1009 | |||
1010 | |||
1011 | /******************************************************************** | ||
1012 | WcaAllocStream() - creates a byte stream of the specified size | ||
1013 | |||
1014 | NOTE: Use WcaFreeStream() to release the byte stream | ||
1015 | ********************************************************************/ | ||
1016 | extern "C" HRESULT WIXAPI WcaAllocStream( | ||
1017 | __deref_out_bcount_part(cbData, 0) BYTE** ppbData, | ||
1018 | __in SIZE_T cbData | ||
1019 | ) | ||
1020 | { | ||
1021 | Assert(ppbData); | ||
1022 | HRESULT hr; | ||
1023 | BYTE* pbNewData; | ||
1024 | |||
1025 | if (*ppbData) | ||
1026 | pbNewData = static_cast<BYTE*>(MemReAlloc(*ppbData, cbData, TRUE)); | ||
1027 | else | ||
1028 | pbNewData = static_cast<BYTE*>(MemAlloc(cbData, TRUE)); | ||
1029 | |||
1030 | if (!pbNewData) | ||
1031 | { | ||
1032 | ExitOnLastError(hr, "Failed to allocate string"); | ||
1033 | } | ||
1034 | |||
1035 | *ppbData = pbNewData; | ||
1036 | pbNewData = NULL; | ||
1037 | |||
1038 | hr = S_OK; | ||
1039 | LExit: | ||
1040 | ReleaseMem(pbNewData); | ||
1041 | |||
1042 | return hr; | ||
1043 | } | ||
1044 | |||
1045 | |||
1046 | /******************************************************************** | ||
1047 | WcaFreeStream() - frees a byte stream | ||
1048 | |||
1049 | ********************************************************************/ | ||
1050 | extern "C" HRESULT WIXAPI WcaFreeStream( | ||
1051 | __in BYTE* pbData | ||
1052 | ) | ||
1053 | { | ||
1054 | if (!pbData) | ||
1055 | return E_INVALIDARG; | ||
1056 | |||
1057 | HRESULT hr = MemFree(pbData); | ||
1058 | return hr; | ||
1059 | } | ||
1060 | |||
1061 | |||
1062 | /******************************************************************** | ||
1063 | WcaGetRecordStream() - gets a byte stream field from record | ||
1064 | |||
1065 | ********************************************************************/ | ||
1066 | extern "C" HRESULT WIXAPI WcaGetRecordStream( | ||
1067 | __in MSIHANDLE hRecBinary, | ||
1068 | __in UINT uiField, | ||
1069 | __deref_out_bcount_full(*pcbData) BYTE** ppbData, | ||
1070 | __out DWORD* pcbData | ||
1071 | ) | ||
1072 | { | ||
1073 | HRESULT hr = S_OK; | ||
1074 | UINT er = ERROR_SUCCESS; | ||
1075 | |||
1076 | if (!hRecBinary || !ppbData || !pcbData) | ||
1077 | return E_INVALIDARG; | ||
1078 | |||
1079 | *pcbData = 0; | ||
1080 | er = ::MsiRecordReadStream(hRecBinary, uiField, NULL, pcbData); | ||
1081 | ExitOnWin32Error(er, hr, "failed to get size of stream"); | ||
1082 | |||
1083 | hr = WcaAllocStream(ppbData, *pcbData); | ||
1084 | ExitOnFailure(hr, "failed to allocate data for stream"); | ||
1085 | |||
1086 | er = ::MsiRecordReadStream(hRecBinary, uiField, (char*)*ppbData, pcbData); | ||
1087 | ExitOnWin32Error(er, hr, "failed to read from stream"); | ||
1088 | |||
1089 | LExit: | ||
1090 | return hr; | ||
1091 | } | ||
1092 | |||
1093 | |||
1094 | /******************************************************************** | ||
1095 | WcaSetRecordString() - set a string field in record | ||
1096 | |||
1097 | ********************************************************************/ | ||
1098 | extern "C" HRESULT WIXAPI WcaSetRecordString( | ||
1099 | __in MSIHANDLE hRec, | ||
1100 | __in UINT uiField, | ||
1101 | __in_z LPCWSTR wzData | ||
1102 | ) | ||
1103 | { | ||
1104 | if (!hRec || !wzData) | ||
1105 | return E_INVALIDARG; | ||
1106 | |||
1107 | HRESULT hr = S_OK; | ||
1108 | UINT er = ::MsiRecordSetStringW(hRec, uiField, wzData); | ||
1109 | ExitOnWin32Error(er, hr, "failed to set string in record"); | ||
1110 | |||
1111 | LExit: | ||
1112 | return hr; | ||
1113 | } | ||
1114 | |||
1115 | |||
1116 | /******************************************************************** | ||
1117 | WcaSetRecordInteger() - set a integer field in record | ||
1118 | |||
1119 | ********************************************************************/ | ||
1120 | extern "C" HRESULT WIXAPI WcaSetRecordInteger( | ||
1121 | __in MSIHANDLE hRec, | ||
1122 | __in UINT uiField, | ||
1123 | __in int iValue | ||
1124 | ) | ||
1125 | { | ||
1126 | if (!hRec) | ||
1127 | return E_INVALIDARG; | ||
1128 | |||
1129 | HRESULT hr = S_OK; | ||
1130 | UINT er = ::MsiRecordSetInteger(hRec, uiField, iValue); | ||
1131 | ExitOnWin32Error(er, hr, "failed to set integer in record"); | ||
1132 | |||
1133 | LExit: | ||
1134 | return hr; | ||
1135 | } | ||
1136 | |||
1137 | |||
1138 | /******************************************************************** | ||
1139 | |||
1140 | WcaDoDeferredAction() - schedules an action at this point in the script | ||
1141 | |||
1142 | ********************************************************************/ | ||
1143 | extern "C" HRESULT WIXAPI WcaDoDeferredAction( | ||
1144 | __in_z LPCWSTR wzAction, | ||
1145 | __in_z LPCWSTR wzCustomActionData, | ||
1146 | __in UINT uiCost | ||
1147 | ) | ||
1148 | { | ||
1149 | HRESULT hr = S_OK; | ||
1150 | UINT er; | ||
1151 | |||
1152 | if (wzCustomActionData && *wzCustomActionData) | ||
1153 | { | ||
1154 | er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzAction, wzCustomActionData); | ||
1155 | ExitOnWin32Error(er, hr, "Failed to set CustomActionData for deferred action"); | ||
1156 | } | ||
1157 | |||
1158 | if (0 < uiCost) | ||
1159 | { | ||
1160 | hr = WcaProgressMessage(uiCost, TRUE); // add ticks to the progress bar | ||
1161 | // TODO: handle the return codes correctly | ||
1162 | } | ||
1163 | |||
1164 | er = ::MsiDoActionW(WcaGetInstallHandle(), wzAction); | ||
1165 | if (ERROR_INSTALL_USEREXIT == er) | ||
1166 | { | ||
1167 | WcaSetReturnValue(er); | ||
1168 | } | ||
1169 | ExitOnWin32Error(er, hr, "Failed MsiDoAction on deferred action"); | ||
1170 | |||
1171 | LExit: | ||
1172 | return hr; | ||
1173 | } | ||
1174 | |||
1175 | |||
1176 | /******************************************************************** | ||
1177 | WcaCountOfCustomActionDataRecords() - counts the number of records | ||
1178 | passed to a deferred CustomAction | ||
1179 | |||
1180 | ********************************************************************/ | ||
1181 | extern "C" DWORD WIXAPI WcaCountOfCustomActionDataRecords( | ||
1182 | __in_z LPCWSTR wzData | ||
1183 | ) | ||
1184 | { | ||
1185 | WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by NULL terminator | ||
1186 | DWORD dwCount = 0; | ||
1187 | |||
1188 | // Loop through until there are no delimiters, we are at the end of the string, or the delimiter is the last character in the string | ||
1189 | for (LPCWSTR pwzCurrent = wzData; pwzCurrent && *pwzCurrent && *(pwzCurrent + 1); pwzCurrent = wcsstr(pwzCurrent, delim)) | ||
1190 | { | ||
1191 | ++dwCount; | ||
1192 | ++pwzCurrent; | ||
1193 | } | ||
1194 | |||
1195 | return dwCount; | ||
1196 | } | ||
1197 | |||
1198 | |||
1199 | /******************************************************************** | ||
1200 | BreakDownCustomActionData() - internal helper to chop up CustomActionData | ||
1201 | |||
1202 | NOTE: this modifies the passed in data | ||
1203 | ********************************************************************/ | ||
1204 | static LPWSTR BreakDownCustomActionData( | ||
1205 | __inout LPWSTR* ppwzData | ||
1206 | ) | ||
1207 | { | ||
1208 | if (!ppwzData) | ||
1209 | return NULL; | ||
1210 | if (0 == *ppwzData) | ||
1211 | return NULL; | ||
1212 | |||
1213 | WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by Null terminator | ||
1214 | |||
1215 | LPWSTR pwzReturn = *ppwzData; | ||
1216 | LPWSTR pwz = wcsstr(pwzReturn, delim); | ||
1217 | if (pwz) | ||
1218 | { | ||
1219 | *pwz = 0; | ||
1220 | *ppwzData = pwz + 1; | ||
1221 | } | ||
1222 | else | ||
1223 | *ppwzData = 0; | ||
1224 | |||
1225 | return pwzReturn; | ||
1226 | } | ||
1227 | |||
1228 | |||
1229 | /******************************************************************** | ||
1230 | RevertCustomActionData() - Reverts custom action data changes made | ||
1231 | by BreakDownCustomActionData; | ||
1232 | |||
1233 | NOTE: this modifies the passed in data | ||
1234 | ********************************************************************/ | ||
1235 | extern "C" void WIXAPI RevertCustomActionData( | ||
1236 | __in LPWSTR wzRevertTo, | ||
1237 | __in LPCWSTR wzRevertFrom | ||
1238 | ) | ||
1239 | { | ||
1240 | if (!wzRevertTo) | ||
1241 | return; | ||
1242 | if (!wzRevertFrom) | ||
1243 | return; | ||
1244 | // start at the revert point and replace all \0 with MAGIC_MULTISZ_DELIM | ||
1245 | for(LPWSTR wzIndex = wzRevertTo; wzIndex < wzRevertFrom; wzIndex++) | ||
1246 | { | ||
1247 | if (0 == *wzIndex) | ||
1248 | { | ||
1249 | *wzIndex = MAGIC_MULTISZ_DELIM; | ||
1250 | } | ||
1251 | } | ||
1252 | return; | ||
1253 | } | ||
1254 | |||
1255 | /******************************************************************** | ||
1256 | WcaReadStringFromCaData() - reads a string out of the CustomActionData | ||
1257 | |||
1258 | NOTE: this modifies the passed in ppwzCustomActionData variable | ||
1259 | ********************************************************************/ | ||
1260 | extern "C" HRESULT WIXAPI WcaReadStringFromCaData( | ||
1261 | __deref_in LPWSTR* ppwzCustomActionData, | ||
1262 | __deref_out_z LPWSTR* ppwzString | ||
1263 | ) | ||
1264 | { | ||
1265 | HRESULT hr = S_OK; | ||
1266 | |||
1267 | LPCWSTR pwz = BreakDownCustomActionData(ppwzCustomActionData); | ||
1268 | if (!pwz) | ||
1269 | return E_NOMOREITEMS; | ||
1270 | |||
1271 | hr = StrAllocString(ppwzString, pwz, 0); | ||
1272 | ExitOnFailure(hr, "failed to allocate memory for string"); | ||
1273 | |||
1274 | hr = S_OK; | ||
1275 | LExit: | ||
1276 | return hr; | ||
1277 | } | ||
1278 | |||
1279 | |||
1280 | /******************************************************************** | ||
1281 | WcaReadIntegerFromCaData() - reads an integer out of the CustomActionData | ||
1282 | |||
1283 | NOTE: this modifies the passed in ppwzCustomActionData variable | ||
1284 | ********************************************************************/ | ||
1285 | extern "C" HRESULT WIXAPI WcaReadIntegerFromCaData( | ||
1286 | __deref_in LPWSTR* ppwzCustomActionData, | ||
1287 | __out int* piResult | ||
1288 | ) | ||
1289 | { | ||
1290 | LPCWSTR pwz = BreakDownCustomActionData(ppwzCustomActionData); | ||
1291 | if (!pwz || !*pwz) | ||
1292 | return E_NOMOREITEMS; | ||
1293 | |||
1294 | *piResult = wcstol(pwz, NULL, 10); | ||
1295 | return S_OK; | ||
1296 | } | ||
1297 | |||
1298 | |||
1299 | /******************************************************************** | ||
1300 | WcaReadStreamFromCaData() - reads a stream out of the CustomActionData | ||
1301 | |||
1302 | NOTE: this modifies the passed in ppwzCustomActionData variable | ||
1303 | NOTE: returned stream should be freed with WcaFreeStream() | ||
1304 | ********************************************************************/ | ||
1305 | extern "C" HRESULT WIXAPI WcaReadStreamFromCaData( | ||
1306 | __deref_in LPWSTR* ppwzCustomActionData, | ||
1307 | __deref_out_bcount(*pcbData) BYTE** ppbData, | ||
1308 | __out DWORD_PTR* pcbData | ||
1309 | ) | ||
1310 | { | ||
1311 | HRESULT hr; | ||
1312 | |||
1313 | LPCWSTR pwz = BreakDownCustomActionData(ppwzCustomActionData); | ||
1314 | if (!pwz) | ||
1315 | return E_NOMOREITEMS; | ||
1316 | |||
1317 | hr = StrAllocBase85Decode(pwz, ppbData, pcbData); | ||
1318 | ExitOnFailure(hr, "failed to decode string into stream"); | ||
1319 | |||
1320 | LExit: | ||
1321 | return hr; | ||
1322 | } | ||
1323 | |||
1324 | |||
1325 | /******************************************************************** | ||
1326 | WcaWriteStringToCaData() - adds a string to the CustomActionData to | ||
1327 | feed a deferred CustomAction | ||
1328 | |||
1329 | ********************************************************************/ | ||
1330 | extern "C" HRESULT WIXAPI WcaWriteStringToCaData( | ||
1331 | __in_z LPCWSTR wzString, | ||
1332 | __deref_inout_z_opt LPWSTR* ppwzCustomActionData | ||
1333 | ) | ||
1334 | { | ||
1335 | HRESULT hr = S_OK; | ||
1336 | WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by NULL terminator | ||
1337 | SIZE_T cchString = 0; | ||
1338 | SIZE_T cchCustomActionData = 0; | ||
1339 | SIZE_T cchMax = 0; | ||
1340 | |||
1341 | if (!ppwzCustomActionData) | ||
1342 | { | ||
1343 | ExitFunction1(hr = E_INVALIDARG); | ||
1344 | } | ||
1345 | |||
1346 | hr = ::StringCchLengthW(wzString, STRSAFE_MAX_LENGTH, reinterpret_cast<size_t*>(&cchString)); | ||
1347 | ExitOnRootFailure(hr, "failed to get length of ca data string"); | ||
1348 | |||
1349 | ++cchString; // assume we'll be adding the delim | ||
1350 | |||
1351 | if (*ppwzCustomActionData) | ||
1352 | { | ||
1353 | hr = StrMaxLength(*ppwzCustomActionData, &cchCustomActionData); | ||
1354 | ExitOnFailure(hr, "failed to get max length of custom action data"); | ||
1355 | |||
1356 | hr = ::StringCchLengthW(*ppwzCustomActionData, STRSAFE_MAX_LENGTH, reinterpret_cast<size_t*>(&cchMax)); | ||
1357 | ExitOnRootFailure(hr, "failed to get length of custom action data"); | ||
1358 | } | ||
1359 | |||
1360 | if ((cchCustomActionData - cchMax) < cchString + 1) | ||
1361 | { | ||
1362 | cchCustomActionData += cchString + 1 + 255; // add 255 for good measure | ||
1363 | cchCustomActionData = min(STRSAFE_MAX_LENGTH, cchCustomActionData); | ||
1364 | |||
1365 | hr = StrAlloc(ppwzCustomActionData, cchCustomActionData); | ||
1366 | ExitOnFailure(hr, "Failed to allocate memory for CustomActionData string"); | ||
1367 | } | ||
1368 | |||
1369 | if (**ppwzCustomActionData) // if data exists toss the delimiter on before adding more to the end | ||
1370 | { | ||
1371 | hr = ::StringCchCatW(*ppwzCustomActionData, cchCustomActionData, delim); | ||
1372 | ExitOnRootFailure(hr, "Failed to concatenate CustomActionData string"); | ||
1373 | } | ||
1374 | |||
1375 | hr = ::StringCchCatW(*ppwzCustomActionData, cchCustomActionData, wzString); | ||
1376 | ExitOnRootFailure(hr, "Failed to concatenate CustomActionData string"); | ||
1377 | |||
1378 | LExit: | ||
1379 | return hr; | ||
1380 | } | ||
1381 | |||
1382 | |||
1383 | /******************************************************************** | ||
1384 | WcaWriteIntegerToCaData() - adds an integer to the CustomActionData to | ||
1385 | feed a deferred CustomAction | ||
1386 | |||
1387 | ********************************************************************/ | ||
1388 | extern "C" HRESULT WIXAPI WcaWriteIntegerToCaData( | ||
1389 | __in int i, | ||
1390 | __deref_out_z_opt LPWSTR* ppwzCustomActionData | ||
1391 | ) | ||
1392 | { | ||
1393 | WCHAR wzBuffer[13]; | ||
1394 | StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%d", i); | ||
1395 | |||
1396 | return WcaWriteStringToCaData(wzBuffer, ppwzCustomActionData); | ||
1397 | } | ||
1398 | |||
1399 | |||
1400 | /******************************************************************** | ||
1401 | WcaWriteStreamToCaData() - adds a byte stream to the CustomActionData to | ||
1402 | feed a deferred CustomAction | ||
1403 | |||
1404 | ********************************************************************/ | ||
1405 | extern "C" HRESULT WIXAPI WcaWriteStreamToCaData( | ||
1406 | __in_bcount(cbData) const BYTE* pbData, | ||
1407 | __in SIZE_T cbData, | ||
1408 | __deref_inout_z_opt LPWSTR* ppwzCustomActionData | ||
1409 | ) | ||
1410 | { | ||
1411 | HRESULT hr; | ||
1412 | LPWSTR pwzData = NULL; | ||
1413 | |||
1414 | hr = StrAllocBase85Encode(pbData, cbData, &pwzData); | ||
1415 | ExitOnFailure(hr, "failed to encode data into string"); | ||
1416 | |||
1417 | hr = WcaWriteStringToCaData(pwzData, ppwzCustomActionData); | ||
1418 | |||
1419 | LExit: | ||
1420 | ReleaseStr(pwzData); | ||
1421 | return hr; | ||
1422 | } | ||
1423 | |||
1424 | |||
1425 | /******************************************************************** | ||
1426 | WcaAddTempRecord - adds a temporary record to the active database | ||
1427 | |||
1428 | NOTE: you cannot use PMSIHANDLEs for the __in/__out parameters | ||
1429 | NOTE: uiUniquifyColumn can be 0 if no column needs to be made unique | ||
1430 | ********************************************************************/ | ||
1431 | extern "C" HRESULT __cdecl WcaAddTempRecord( | ||
1432 | __inout MSIHANDLE* phTableView, | ||
1433 | __inout MSIHANDLE* phColumns, | ||
1434 | __in_z LPCWSTR wzTable, | ||
1435 | __out_opt MSIDBERROR* pdbError, | ||
1436 | __in UINT uiUniquifyColumn, | ||
1437 | __in UINT cColumns, | ||
1438 | ... | ||
1439 | ) | ||
1440 | { | ||
1441 | Assert(phTableView && phColumns); | ||
1442 | |||
1443 | static DWORD dwUniquifyValue = ::GetTickCount(); | ||
1444 | |||
1445 | HRESULT hr = S_OK; | ||
1446 | UINT er = ERROR_SUCCESS; | ||
1447 | |||
1448 | LPWSTR pwzQuery = NULL; | ||
1449 | PMSIHANDLE hTempRec; | ||
1450 | DWORD i; | ||
1451 | va_list args; | ||
1452 | |||
1453 | LPWSTR pwzData = NULL; | ||
1454 | LPWSTR pwzUniquify = NULL; | ||
1455 | |||
1456 | // | ||
1457 | // if we don't have a table and its columns already | ||
1458 | // | ||
1459 | if (NULL == *phTableView) | ||
1460 | { | ||
1461 | // set the query | ||
1462 | hr = StrAllocFormatted(&pwzQuery, L"SELECT * FROM `%s`",wzTable); | ||
1463 | ExitOnFailure(hr, "failed to allocate string for query"); | ||
1464 | |||
1465 | // Open and Execute the temp View | ||
1466 | hr = WcaOpenExecuteView(pwzQuery, phTableView); | ||
1467 | ExitOnFailure(hr, "failed to openexecute temp view with query %ls", pwzQuery); | ||
1468 | } | ||
1469 | |||
1470 | if (NULL == *phColumns) | ||
1471 | { | ||
1472 | // use GetColumnInfo to populate the datatype record | ||
1473 | er = ::MsiViewGetColumnInfo(*phTableView, MSICOLINFO_TYPES, phColumns); | ||
1474 | ExitOnWin32Error(er, hr, "failed to columns for table: %ls", wzTable); | ||
1475 | } | ||
1476 | AssertSz(::MsiRecordGetFieldCount(*phColumns) == cColumns, "passed in argument does not match number of columns in table"); | ||
1477 | |||
1478 | // | ||
1479 | // create the temp record | ||
1480 | // | ||
1481 | hTempRec = ::MsiCreateRecord(cColumns); | ||
1482 | ExitOnNull(hTempRec, hr, E_UNEXPECTED, "could not create temp record for table: %ls", wzTable); | ||
1483 | |||
1484 | // | ||
1485 | // loop through all the columns filling in the data | ||
1486 | // | ||
1487 | va_start(args, cColumns); | ||
1488 | for (i = 1; i <= cColumns; i++) | ||
1489 | { | ||
1490 | hr = WcaGetRecordString(*phColumns, i, &pwzData); | ||
1491 | ExitOnFailure(hr, "failed to get the data type for %d", i); | ||
1492 | |||
1493 | // if data type is string write string | ||
1494 | if (L's' == *pwzData || L'S' == *pwzData || L'g' == *pwzData || L'G' == *pwzData || L'l' == *pwzData || L'L' == *pwzData) | ||
1495 | { | ||
1496 | LPCWSTR wz = va_arg(args, WCHAR*); | ||
1497 | |||
1498 | // if this is the column that is supposed to be unique add the time stamp on the end | ||
1499 | if (uiUniquifyColumn == i) | ||
1500 | { | ||
1501 | hr = StrAllocFormatted(&pwzUniquify, L"%s%u", wz, ++dwUniquifyValue); // up the count so we have no collisions on the unique name | ||
1502 | ExitOnFailure(hr, "failed to allocate string for unique column: %d", uiUniquifyColumn); | ||
1503 | |||
1504 | wz = pwzUniquify; | ||
1505 | } | ||
1506 | |||
1507 | er = ::MsiRecordSetStringW(hTempRec, i, wz); | ||
1508 | ExitOnWin32Error(er, hr, "failed to set string value at position %d", i); | ||
1509 | } | ||
1510 | // if data type is integer write integer | ||
1511 | else if (L'i' == *pwzData || L'I' == *pwzData || L'j' == *pwzData || L'J' == *pwzData) | ||
1512 | { | ||
1513 | AssertSz(uiUniquifyColumn != i, "Cannot uniquify an integer column"); | ||
1514 | int iData = va_arg(args, int); | ||
1515 | |||
1516 | er = ::MsiRecordSetInteger(hTempRec, i, iData); | ||
1517 | ExitOnWin32Error(er, hr, "failed to set integer value at position %d", i); | ||
1518 | } | ||
1519 | else | ||
1520 | { | ||
1521 | // not supporting binary streams so error out | ||
1522 | hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); | ||
1523 | ExitOnRootFailure(hr, "unsupported data type '%ls' in column: %d", pwzData, i); | ||
1524 | } | ||
1525 | } | ||
1526 | va_end(args); | ||
1527 | |||
1528 | // | ||
1529 | // add the temporary record to the MSI | ||
1530 | // | ||
1531 | er = ::MsiViewModify(*phTableView, MSIMODIFY_INSERT_TEMPORARY, hTempRec); | ||
1532 | hr = HRESULT_FROM_WIN32(er); | ||
1533 | if (FAILED(hr)) | ||
1534 | { | ||
1535 | if (pdbError) | ||
1536 | { | ||
1537 | // MSI provides only a generic ERROR_FUNCTION_FAILED if a temporary row | ||
1538 | // can't be inserted; if we're being asked to provide the detailed error, | ||
1539 | // get it using the MSIMODIFY_VALIDATE_NEW flag | ||
1540 | er = ::MsiViewModify(*phTableView, MSIMODIFY_VALIDATE_NEW, hTempRec); | ||
1541 | hr = HRESULT_FROM_WIN32(er); | ||
1542 | } | ||
1543 | |||
1544 | WCHAR wzBuf[MAX_PATH]; | ||
1545 | DWORD cchBuf = countof(wzBuf); | ||
1546 | MSIDBERROR dbErr = ::MsiViewGetErrorW(*phTableView, wzBuf, &cchBuf); | ||
1547 | if (pdbError) | ||
1548 | { | ||
1549 | *pdbError = dbErr; | ||
1550 | } | ||
1551 | ExitOnFailure(hr, "failed to add temporary row, dberr: %d, err: %ls", dbErr, wzBuf); | ||
1552 | } | ||
1553 | |||
1554 | LExit: | ||
1555 | ReleaseStr(pwzUniquify); | ||
1556 | ReleaseStr(pwzData); | ||
1557 | ReleaseStr(pwzQuery); | ||
1558 | |||
1559 | return hr; | ||
1560 | } | ||
1561 | |||
1562 | |||
1563 | /******************************************************************** | ||
1564 | WcaDumpTable - dumps a table to the log file | ||
1565 | |||
1566 | ********************************************************************/ | ||
1567 | extern "C" HRESULT WIXAPI WcaDumpTable( | ||
1568 | __in_z LPCWSTR wzTable | ||
1569 | ) | ||
1570 | { | ||
1571 | HRESULT hr = S_OK; | ||
1572 | UINT er = ERROR_SUCCESS; | ||
1573 | |||
1574 | LPWSTR pwzQuery = NULL; | ||
1575 | PMSIHANDLE hView; | ||
1576 | PMSIHANDLE hColumns; | ||
1577 | DWORD cColumns = 0; | ||
1578 | PMSIHANDLE hRec; | ||
1579 | |||
1580 | LPWSTR pwzData = NULL; | ||
1581 | LPWSTR pwzPrint = NULL; | ||
1582 | |||
1583 | hr = StrAllocFormatted(&pwzQuery, L"SELECT * FROM `%s`",wzTable); | ||
1584 | ExitOnFailure(hr, "failed to allocate string for query"); | ||
1585 | |||
1586 | // Open and Execute the temp View | ||
1587 | hr = WcaOpenExecuteView(pwzQuery, &hView); | ||
1588 | ExitOnFailure(hr, "failed to openexecute temp view with query %ls", pwzQuery); | ||
1589 | |||
1590 | // Use GetColumnInfo to populate the names of the columns. | ||
1591 | er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_NAMES, &hColumns); | ||
1592 | hr = HRESULT_FROM_WIN32(er); | ||
1593 | ExitOnFailure(hr, "failed to get column info for table: %ls", wzTable); | ||
1594 | |||
1595 | cColumns = ::MsiRecordGetFieldCount(hColumns); | ||
1596 | |||
1597 | WcaLog(LOGMSG_STANDARD, "--- Begin Table Dump %ls ---", wzTable); | ||
1598 | |||
1599 | // Loop through all the columns filling in the data. | ||
1600 | for (DWORD i = 1; i <= cColumns; i++) | ||
1601 | { | ||
1602 | hr = WcaGetRecordString(hColumns, i, &pwzData); | ||
1603 | ExitOnFailure(hr, "failed to get the column name for %d", i); | ||
1604 | |||
1605 | hr = StrAllocConcat(&pwzPrint, pwzData, 0); | ||
1606 | ExitOnFailure(hr, "Failed to add column name."); | ||
1607 | |||
1608 | hr = StrAllocConcat(&pwzPrint, L"\t", 1); | ||
1609 | ExitOnFailure(hr, "Failed to add column name."); | ||
1610 | } | ||
1611 | |||
1612 | WcaLog(LOGMSG_STANDARD, "%ls", pwzPrint); | ||
1613 | |||
1614 | // Now dump the actual rows. | ||
1615 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
1616 | { | ||
1617 | if (pwzPrint && *pwzPrint) | ||
1618 | { | ||
1619 | *pwzPrint = L'\0'; | ||
1620 | } | ||
1621 | |||
1622 | for (DWORD i = 1; i <= cColumns; i++) | ||
1623 | { | ||
1624 | hr = WcaGetRecordString(hRec, i, &pwzData); | ||
1625 | ExitOnFailure(hr, "failed to get the column name for %d", i); | ||
1626 | |||
1627 | hr = StrAllocConcat(&pwzPrint, pwzData, 0); | ||
1628 | ExitOnFailure(hr, "Failed to add column name."); | ||
1629 | |||
1630 | hr = StrAllocConcat(&pwzPrint, L"\t", 1); | ||
1631 | ExitOnFailure(hr, "Failed to add column name."); | ||
1632 | } | ||
1633 | |||
1634 | WcaLog(LOGMSG_STANDARD, "%ls", pwzPrint); | ||
1635 | } | ||
1636 | |||
1637 | WcaLog(LOGMSG_STANDARD, "--- End Table Dump %ls ---", wzTable); | ||
1638 | |||
1639 | LExit: | ||
1640 | ReleaseStr(pwzPrint); | ||
1641 | ReleaseStr(pwzData); | ||
1642 | ReleaseStr(pwzQuery); | ||
1643 | |||
1644 | return hr; | ||
1645 | } | ||
1646 | |||
1647 | |||
1648 | HRESULT WIXAPI WcaDeferredActionRequiresReboot() | ||
1649 | { | ||
1650 | HRESULT hr = S_OK; | ||
1651 | ATOM atomReboot = 0; | ||
1652 | |||
1653 | atomReboot = ::GlobalAddAtomW(L"WcaDeferredActionRequiresReboot"); | ||
1654 | ExitOnNullWithLastError(atomReboot, hr, "Failed to create WcaDeferredActionRequiresReboot global atom."); | ||
1655 | |||
1656 | LExit: | ||
1657 | return hr; | ||
1658 | } | ||
1659 | |||
1660 | |||
1661 | BOOL WIXAPI WcaDidDeferredActionRequireReboot() | ||
1662 | { | ||
1663 | // NOTE: This function does not delete the global atom. That is done | ||
1664 | // purposefully so that any other installs that occur after this point also | ||
1665 | // require a reboot. | ||
1666 | ATOM atomReboot = ::GlobalFindAtomW(L"WcaDeferredActionRequiresReboot"); | ||
1667 | return 0 != atomReboot; | ||
1668 | } | ||
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp new file mode 100644 index 00000000..a3b593fd --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcawrapquery.cpp | |||
@@ -0,0 +1,717 @@ | |||
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 | #include "wcawrapquery.h" | ||
5 | |||
6 | static const LPWSTR ISINSTALLEDCOLUMNNAME = L"ISInstalled"; | ||
7 | static const LPWSTR ISACTIONCOLUMNNAME = L"ISAction"; | ||
8 | static const LPWSTR SOURCEPATHCOLUMNNAME = L"SourcePath"; | ||
9 | static const LPWSTR TARGETPATHCOLUMNNAME = L"TargetPath"; | ||
10 | |||
11 | // This instantiates a new query object in the deferred CA, and returns the handle to the query | ||
12 | WCA_WRAPQUERY_HANDLE WIXAPI GetNewQueryInstance( | ||
13 | DWORD dwInColumns, | ||
14 | DWORD dwInRows | ||
15 | ) | ||
16 | { | ||
17 | HRESULT hr = S_OK; | ||
18 | |||
19 | WCA_WRAPQUERY_HANDLE hNewHandle = NULL; | ||
20 | |||
21 | hNewHandle = static_cast<WCA_WRAPQUERY_HANDLE>(MemAlloc(sizeof(WCA_WRAPQUERY_STRUCT), TRUE)); | ||
22 | if (NULL == hNewHandle) | ||
23 | { | ||
24 | hr = E_OUTOFMEMORY; | ||
25 | ExitOnFailure(hr, "Failed to allocate Query Instance"); | ||
26 | } | ||
27 | |||
28 | // Initialize non-array members | ||
29 | hNewHandle->dwColumns = dwInColumns; | ||
30 | hNewHandle->dwRows = dwInRows; | ||
31 | hNewHandle->dwNextIndex = 0; | ||
32 | |||
33 | // Initialize arrays | ||
34 | if (0 != hNewHandle->dwColumns) | ||
35 | { | ||
36 | hNewHandle->pcdtColumnType = static_cast<eColumnDataType *>(MemAlloc(hNewHandle->dwColumns * sizeof(eColumnDataType), TRUE)); | ||
37 | if (NULL == hNewHandle->pcdtColumnType) | ||
38 | { | ||
39 | hr = E_OUTOFMEMORY; | ||
40 | ExitOnFailure(hr, "Failed to allocate column type array"); | ||
41 | } | ||
42 | |||
43 | hNewHandle->ppwzColumnNames = static_cast<LPWSTR *>(MemAlloc(hNewHandle->dwColumns * sizeof(LPWSTR), TRUE)); | ||
44 | if (NULL == hNewHandle->ppwzColumnNames) | ||
45 | { | ||
46 | hr = E_OUTOFMEMORY; | ||
47 | ExitOnFailure(hr, "Failed to allocate column names array"); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | for (DWORD i=0;i<hNewHandle->dwColumns;i++) | ||
52 | { | ||
53 | hNewHandle->pcdtColumnType[i] = cdtUnknown; | ||
54 | hNewHandle->ppwzColumnNames[i] = NULL; | ||
55 | } | ||
56 | |||
57 | if (0 != hNewHandle->dwRows) | ||
58 | { | ||
59 | hNewHandle->phRecords = static_cast<MSIHANDLE *>(MemAlloc(hNewHandle->dwRows * sizeof(MSIHANDLE), TRUE)); | ||
60 | if (NULL == hNewHandle->phRecords) | ||
61 | { | ||
62 | hr = E_OUTOFMEMORY; | ||
63 | ExitOnFailure(hr, "Failed to allocate records array"); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | for (DWORD i=0;i<hNewHandle->dwRows;i++) | ||
68 | { | ||
69 | hNewHandle->phRecords[i] = NULL; | ||
70 | } | ||
71 | |||
72 | return hNewHandle; | ||
73 | |||
74 | LExit: | ||
75 | // The handle isn't complete, so destroy any memory it allocated before returning NULL | ||
76 | if (NULL != hNewHandle) | ||
77 | { | ||
78 | WcaFinishUnwrapQuery(hNewHandle); | ||
79 | } | ||
80 | |||
81 | return NULL; | ||
82 | } | ||
83 | |||
84 | // This function takes in the column type string from MsiViewGetColumnInfo, and returns | ||
85 | // whether the column stores strings, ints, binary streams, or | ||
86 | // cdtUnknown if this information couldn't be determined. | ||
87 | eColumnDataType WIXAPI GetDataTypeFromString( | ||
88 | LPCWSTR pwzTypeString | ||
89 | ) | ||
90 | { | ||
91 | if (!pwzTypeString || !*pwzTypeString) | ||
92 | { | ||
93 | return cdtUnknown; | ||
94 | } | ||
95 | |||
96 | switch (pwzTypeString[0]) | ||
97 | { | ||
98 | case 'v': | ||
99 | case 'V': | ||
100 | case 'o': | ||
101 | case 'O': | ||
102 | return cdtStream; | ||
103 | |||
104 | case 'g': | ||
105 | case 'G': | ||
106 | case 's': | ||
107 | case 'S': | ||
108 | case 'l': | ||
109 | case 'L': | ||
110 | return cdtString; | ||
111 | |||
112 | case 'i': | ||
113 | case 'I': | ||
114 | case 'j': | ||
115 | case 'J': | ||
116 | return cdtInt; | ||
117 | |||
118 | default: | ||
119 | return cdtUnknown; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | HRESULT WIXAPI WcaWrapEmptyQuery( | ||
124 | __inout LPWSTR * ppwzCustomActionData | ||
125 | ) | ||
126 | { | ||
127 | HRESULT hr = S_OK; | ||
128 | |||
129 | WcaLog(LOGMSG_TRACEONLY, "Wrapping result of empty query"); | ||
130 | |||
131 | hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableBegin), ppwzCustomActionData); | ||
132 | ExitOnFailure(hr, "Failed to write table begin marker to custom action data"); | ||
133 | |||
134 | hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData); | ||
135 | ExitOnFailure(hr, "Failed to write number of columns to custom action data"); | ||
136 | |||
137 | hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData); | ||
138 | ExitOnFailure(hr, "Failed to write number of rows to custom action data"); | ||
139 | |||
140 | hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableFinish), ppwzCustomActionData); | ||
141 | ExitOnFailure(hr, "Failed to write table finish marker to custom action data"); | ||
142 | |||
143 | // WcaLog(LOGMSG_TRACEONLY, "Finished wrapping result of empty query"); | ||
144 | |||
145 | LExit: | ||
146 | return hr; | ||
147 | } | ||
148 | |||
149 | /******************************************************************** | ||
150 | WcaWrapQuery() - wraps a view and transmits it through the | ||
151 | CustomActionData property | ||
152 | |||
153 | ********************************************************************/ | ||
154 | HRESULT WIXAPI WcaWrapQuery( | ||
155 | __in_z LPCWSTR pwzQuery, | ||
156 | __inout LPWSTR * ppwzCustomActionData, | ||
157 | __in_opt DWORD dwFormatMask, | ||
158 | __in_opt DWORD dwComponentColumn, | ||
159 | __in_opt DWORD dwDirectoryColumn | ||
160 | ) | ||
161 | { | ||
162 | HRESULT hr = S_OK; | ||
163 | HRESULT hrTemp = S_OK; | ||
164 | UINT er = ERROR_SUCCESS; | ||
165 | UINT cViewColumns; | ||
166 | eColumnDataType *pcdtColumnTypeList = NULL; | ||
167 | LPWSTR pwzData = NULL; | ||
168 | LPWSTR pwzColumnData = NULL; | ||
169 | LPWSTR pwzRecordData = NULL; | ||
170 | BYTE* pbData = NULL; | ||
171 | DWORD dwNumRecords = 0; | ||
172 | BOOL fAddComponentState = FALSE; // Add two integer columns to the right side of the query - ISInstalled, and ISAction | ||
173 | BOOL fAddDirectoryPath = FALSE; // Add two string columns to the right side of the query - SourcePath, and TargetPath | ||
174 | int iTempInteger = 0; | ||
175 | |||
176 | WCHAR wzPath[MAX_PATH + 1]; | ||
177 | DWORD dwLen; | ||
178 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
179 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
180 | |||
181 | PMSIHANDLE hColumnTypes, hColumnNames; | ||
182 | PMSIHANDLE hView, hRec; | ||
183 | |||
184 | WcaLog(LOGMSG_TRACEONLY, "Wrapping result of query: \"%ls\"", pwzQuery); | ||
185 | |||
186 | // open the view | ||
187 | hr = WcaOpenExecuteView(pwzQuery, &hView); | ||
188 | ExitOnFailure(hr, "Failed to execute view"); | ||
189 | |||
190 | hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableBegin), ppwzCustomActionData); | ||
191 | ExitOnFailure(hr, "Failed to write table begin marker to custom action data"); | ||
192 | |||
193 | // WcaLog(LOGMSG_TRACEONLY, "Starting to wrap table's column information", pwzQuery); | ||
194 | |||
195 | // Use GetColumnInfo to populate the names of the columns. | ||
196 | er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_TYPES, &hColumnTypes); | ||
197 | ExitOnWin32Error(er, hr, "Failed to get column types"); | ||
198 | |||
199 | er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_NAMES, &hColumnNames); | ||
200 | ExitOnWin32Error(er, hr, "Failed to get column names"); | ||
201 | |||
202 | cViewColumns = ::MsiRecordGetFieldCount(hColumnTypes); | ||
203 | |||
204 | if (0xFFFFFFFF == cViewColumns) | ||
205 | { | ||
206 | // According to MSDN, this return value only happens when the handle is invalid | ||
207 | hr = E_HANDLE; | ||
208 | ExitOnFailure(hr, "Failed to get number of fields in record"); | ||
209 | } | ||
210 | |||
211 | if (cViewColumns >= dwComponentColumn) | ||
212 | { | ||
213 | fAddComponentState = TRUE; | ||
214 | } | ||
215 | else if (0xFFFFFFFF != dwComponentColumn) | ||
216 | { | ||
217 | hr = E_INVALIDARG; | ||
218 | ExitOnFailure(hr, "Component column %d out of range", dwComponentColumn); | ||
219 | } | ||
220 | |||
221 | if (cViewColumns >= dwDirectoryColumn) | ||
222 | { | ||
223 | fAddDirectoryPath = TRUE; | ||
224 | } | ||
225 | else if (0xFFFFFFFF != dwDirectoryColumn) | ||
226 | { | ||
227 | hr = E_INVALIDARG; | ||
228 | ExitOnFailure(hr, "Directory column %d out of range", dwDirectoryColumn); | ||
229 | } | ||
230 | |||
231 | hr = WcaWriteIntegerToCaData(static_cast<int>(cViewColumns) + 2 * static_cast<int>(fAddComponentState) + 2 * static_cast<int>(fAddDirectoryPath), ppwzCustomActionData); | ||
232 | ExitOnFailure(hr, "Failed to write number of columns to custom action data"); | ||
233 | |||
234 | pcdtColumnTypeList = new eColumnDataType[cViewColumns]; | ||
235 | ExitOnNull(pcdtColumnTypeList, hr, E_OUTOFMEMORY, "Failed to allocate memory to store column info types"); | ||
236 | |||
237 | // Loop through all the columns reporting information about each one | ||
238 | for (DWORD i = 0; i < cViewColumns; i++) | ||
239 | { | ||
240 | hr = WcaGetRecordString(hColumnNames, i+1, &pwzData); | ||
241 | ExitOnFailure(hr, "Failed to get the column %d name", i+1); | ||
242 | |||
243 | hr = WcaWriteStringToCaData(pwzData, &pwzColumnData); | ||
244 | ExitOnFailure(hr, "Failed to write column %d name %ls to custom action data", i+1, pwzData); | ||
245 | |||
246 | hr = WcaGetRecordString(hColumnTypes, i+1, &pwzData); | ||
247 | ExitOnFailure(hr, "Failed to get the column type string for column %d", i+1); | ||
248 | |||
249 | pcdtColumnTypeList[i] = GetDataTypeFromString(pwzData); | ||
250 | |||
251 | if (cdtUnknown == pcdtColumnTypeList[i]) | ||
252 | { | ||
253 | hr = E_INVALIDARG; | ||
254 | ExitOnFailure(hr, "Failed to recognize column %d type string: %ls", i+1, pwzData); | ||
255 | } | ||
256 | |||
257 | hr = WcaWriteIntegerToCaData(pcdtColumnTypeList[i], &pwzColumnData); | ||
258 | ExitOnFailure(hr, "Failed to write column %d type enumeration to custom action data", i+1); | ||
259 | } | ||
260 | |||
261 | // Add two integer columns to the right side of the query - ISInstalled, and ISAction | ||
262 | if (fAddComponentState) | ||
263 | { | ||
264 | hr = WcaWriteStringToCaData(ISINSTALLEDCOLUMNNAME, &pwzColumnData); | ||
265 | ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, ISINSTALLEDCOLUMNNAME); | ||
266 | |||
267 | hr = WcaWriteIntegerToCaData(cdtInt, &pwzColumnData); | ||
268 | ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1); | ||
269 | |||
270 | hr = WcaWriteStringToCaData(ISACTIONCOLUMNNAME, &pwzColumnData); | ||
271 | ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, ISACTIONCOLUMNNAME); | ||
272 | |||
273 | hr = WcaWriteIntegerToCaData(cdtInt, &pwzColumnData); | ||
274 | ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1); | ||
275 | } | ||
276 | |||
277 | if (fAddDirectoryPath) | ||
278 | { | ||
279 | hr = WcaWriteStringToCaData(SOURCEPATHCOLUMNNAME, &pwzColumnData); | ||
280 | ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, SOURCEPATHCOLUMNNAME); | ||
281 | |||
282 | hr = WcaWriteIntegerToCaData(cdtString, &pwzColumnData); | ||
283 | ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1); | ||
284 | |||
285 | hr = WcaWriteStringToCaData(TARGETPATHCOLUMNNAME, &pwzColumnData); | ||
286 | ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, TARGETPATHCOLUMNNAME); | ||
287 | |||
288 | hr = WcaWriteIntegerToCaData(cdtString, &pwzColumnData); | ||
289 | ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1); | ||
290 | } | ||
291 | |||
292 | // Begin wrapping actual table data | ||
293 | //WcaLog(LOGMSG_TRACEONLY, "Starting to wrap table data", pwzQuery); | ||
294 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
295 | { | ||
296 | hr = WcaWriteIntegerToCaData(static_cast<int>(wqaRowBegin), &pwzRecordData); | ||
297 | ExitOnFailure(hr, "Failed to write row begin marker to custom action data"); | ||
298 | |||
299 | for (DWORD i = 0; i < cViewColumns; i++) | ||
300 | { | ||
301 | switch (pcdtColumnTypeList[i]) | ||
302 | { | ||
303 | case cdtString: | ||
304 | // If we were given a format mask, we're not past the index, and it's set to true for this column, then format the string | ||
305 | if (i < (sizeof(dwFormatMask) * 8) && (dwFormatMask & (1 << i))) | ||
306 | { | ||
307 | hr = WcaGetRecordFormattedString(hRec, i + 1, &pwzData); | ||
308 | } | ||
309 | else | ||
310 | { | ||
311 | hr = WcaGetRecordString(hRec, i + 1, &pwzData); | ||
312 | } | ||
313 | ExitOnFailure(hr, "Failed to get string for column %d", i + 1); | ||
314 | |||
315 | hr = WcaWriteStringToCaData(pwzData, &pwzRecordData); | ||
316 | ExitOnFailure(hr, "Failed to write string to temporary record custom action data for column %d", i + 1); | ||
317 | break; | ||
318 | |||
319 | case cdtInt: | ||
320 | if (i < (sizeof(dwFormatMask) * 8) && (dwFormatMask & (1 << i))) | ||
321 | { | ||
322 | hr = WcaGetRecordFormattedInteger(hRec, i + 1, &iTempInteger); | ||
323 | } | ||
324 | else | ||
325 | { | ||
326 | hr = WcaGetRecordInteger(hRec, i + 1, &iTempInteger); | ||
327 | } | ||
328 | ExitOnFailure(hr, "Failed to get integer for column %d", i + 1); | ||
329 | |||
330 | hr = WcaWriteIntegerToCaData(iTempInteger, &pwzRecordData); | ||
331 | ExitOnFailure(hr, "Failed to write integer to temporary record custom action data for column %d", i + 1); | ||
332 | break; | ||
333 | |||
334 | case cdtStream: | ||
335 | hr = E_NOTIMPL; | ||
336 | ExitOnFailure(hr, "A query was wrapped which contained a binary stream data field in column %d - however, the ability to wrap stream data fields is not implemented at this time", i); | ||
337 | break; | ||
338 | |||
339 | case cdtUnknown: | ||
340 | default: | ||
341 | hr = E_INVALIDARG; | ||
342 | ExitOnFailure(hr, "Failed to recognize column type enumeration %d for column %d", pcdtColumnTypeList[i], i + 1); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | // Add two integer columns to the right side of the query - ISInstalled, and ISAction | ||
347 | if (fAddComponentState) | ||
348 | { | ||
349 | // Get the component ID | ||
350 | hr = WcaGetRecordString(hRec, dwComponentColumn, &pwzData); | ||
351 | ExitOnFailure(hr, "Failed to get component from column %d while adding extra columns", dwComponentColumn); | ||
352 | |||
353 | if (!pwzData || !*pwzData) | ||
354 | { | ||
355 | // If no component was provided, set these both to zero as though a structure to store them were allocated with memory zero'd out | ||
356 | isInstalled = (INSTALLSTATE)0; | ||
357 | isAction = (INSTALLSTATE)0; | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction); | ||
362 | // If we don't get the component state, that may be because the component ID was invalid, but isn't necessarily an error, so write NULL's | ||
363 | if (FAILED(HRESULT_FROM_WIN32(er))) | ||
364 | { | ||
365 | ExitOnFailure(hr, "Failed to get component state for component %ls", pwzData); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | hr = WcaWriteIntegerToCaData(isInstalled, &pwzRecordData); | ||
370 | ExitOnFailure(hr, "Failed to write extra ISInstalled column to custom action data"); | ||
371 | |||
372 | hr = WcaWriteIntegerToCaData(isAction, &pwzRecordData); | ||
373 | ExitOnFailure(hr, "Failed to write extra ISAction column to custom action data"); | ||
374 | } | ||
375 | |||
376 | // Add two string columns to the right side of the query - SourcePath, and TargetPath | ||
377 | if (fAddDirectoryPath) | ||
378 | { | ||
379 | hr = WcaGetRecordString(hRec, dwDirectoryColumn, &pwzData); | ||
380 | // If this fails, ignore it, and just leave those columns blank | ||
381 | if (SUCCEEDED(hr)) | ||
382 | { | ||
383 | // Only get source path if the component state is INSTALLSTATE_SOURCE, or if we have no component to check the installstate of | ||
384 | if (INSTALLSTATE_SOURCE == isAction || !fAddComponentState) | ||
385 | { | ||
386 | dwLen = countof(wzPath); | ||
387 | er = ::MsiGetSourcePathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen); | ||
388 | hrTemp = HRESULT_FROM_WIN32(er); | ||
389 | if (dwLen > countof(wzPath)) | ||
390 | { | ||
391 | hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | ||
392 | ExitOnRootFailure(hr, "Failed to record entire Source Path for Directory %ls because its length was greater than MAX_PATH.", pwzData); | ||
393 | } | ||
394 | |||
395 | if (SUCCEEDED(hrTemp)) | ||
396 | { | ||
397 | hr = WcaWriteStringToCaData(wzPath, &pwzRecordData); | ||
398 | ExitOnFailure(hr, "Failed to write source path string to record data string"); | ||
399 | } | ||
400 | else | ||
401 | { | ||
402 | hr = WcaWriteStringToCaData(L"", &pwzRecordData); | ||
403 | ExitOnFailure(hr, "Failed to write empty source path string to record data string"); | ||
404 | } | ||
405 | } | ||
406 | else | ||
407 | { | ||
408 | hr = WcaWriteStringToCaData(L"", &pwzRecordData); | ||
409 | ExitOnFailure(hr, "Failed to write empty source path string before writing target path string to record data string"); | ||
410 | } | ||
411 | |||
412 | dwLen = countof(wzPath); | ||
413 | er = ::MsiGetTargetPathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen); | ||
414 | hrTemp = HRESULT_FROM_WIN32(er); | ||
415 | if (dwLen > countof(wzPath)) | ||
416 | { | ||
417 | hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | ||
418 | ExitOnRootFailure(hr, "Failed to record entire Source Path for Directory %ls because its length was greater than MAX_PATH.", pwzData); | ||
419 | } | ||
420 | if (SUCCEEDED(hrTemp)) | ||
421 | { | ||
422 | hr = WcaWriteStringToCaData(wzPath, &pwzRecordData); | ||
423 | ExitOnFailure(hr, "Failed to write target path string to record data string"); | ||
424 | } | ||
425 | else | ||
426 | { | ||
427 | hr = WcaWriteStringToCaData(L"", &pwzRecordData); | ||
428 | ExitOnFailure(hr, "Failed to write empty target path string to record data string"); | ||
429 | } | ||
430 | } | ||
431 | else | ||
432 | { | ||
433 | // Write both fields as blank | ||
434 | hr = WcaWriteStringToCaData(L"", &pwzRecordData); | ||
435 | hr = WcaWriteStringToCaData(L"", &pwzRecordData); | ||
436 | } | ||
437 | } | ||
438 | |||
439 | hr = WcaWriteIntegerToCaData(static_cast<int>(wqaRowFinish), &pwzRecordData); | ||
440 | ExitOnFailure(hr, "Failed to write row finish marker to custom action data"); | ||
441 | |||
442 | ++dwNumRecords; | ||
443 | } | ||
444 | |||
445 | hr = WcaWriteIntegerToCaData(dwNumRecords, ppwzCustomActionData); | ||
446 | ExitOnFailure(hr, "Failed to write number of records to custom action data"); | ||
447 | |||
448 | if (NULL != pwzColumnData) | ||
449 | { | ||
450 | hr = WcaWriteStringToCaData(pwzColumnData, ppwzCustomActionData); | ||
451 | ExitOnFailure(hr, "Failed to write column data to custom action data"); | ||
452 | } | ||
453 | |||
454 | if (NULL != pwzRecordData) | ||
455 | { | ||
456 | hr = WcaWriteStringToCaData(pwzRecordData, ppwzCustomActionData); | ||
457 | ExitOnFailure(hr, "Failed to write record data to custom action data"); | ||
458 | } | ||
459 | |||
460 | hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableFinish), ppwzCustomActionData); | ||
461 | ExitOnFailure(hr, "Failed to write table finish marker to custom action data"); | ||
462 | |||
463 | // WcaLog(LOGMSG_TRACEONLY, "Finished wrapping result of query: \"%ls\"", pwzQuery); | ||
464 | |||
465 | LExit: | ||
466 | ReleaseStr(pwzData); | ||
467 | ReleaseStr(pwzColumnData); | ||
468 | ReleaseStr(pwzRecordData); | ||
469 | |||
470 | ReleaseMem(pbData); | ||
471 | |||
472 | return hr; | ||
473 | } | ||
474 | |||
475 | |||
476 | /******************************************************************** | ||
477 | WcaBeginUnwrapQuery() - unwraps a view for direct access from the | ||
478 | CustomActionData property | ||
479 | |||
480 | ********************************************************************/ | ||
481 | HRESULT WIXAPI WcaBeginUnwrapQuery( | ||
482 | __out WCA_WRAPQUERY_HANDLE * phWrapQuery, | ||
483 | __inout LPWSTR * ppwzCustomActionData | ||
484 | ) | ||
485 | { | ||
486 | HRESULT hr = S_OK; | ||
487 | int iTempInteger = 0; | ||
488 | int iColumns = 0; | ||
489 | int iRows = 0; | ||
490 | BYTE* pbData = NULL; | ||
491 | LPWSTR pwzData = NULL; | ||
492 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
493 | |||
494 | WcaLog(LOGMSG_TRACEONLY, "Unwrapping a query from custom action data"); | ||
495 | |||
496 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger); | ||
497 | if (wqaTableBegin != iTempInteger) | ||
498 | { | ||
499 | hr = E_INVALIDARG; | ||
500 | } | ||
501 | ExitOnFailure(hr, "Failed to read table begin marker from custom action data (read %d instead)", iTempInteger); | ||
502 | |||
503 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iColumns); | ||
504 | ExitOnFailure(hr, "Failed to read number of columns from custom action data"); | ||
505 | |||
506 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iRows); | ||
507 | ExitOnFailure(hr, "Failed to read number of rows from custom action data"); | ||
508 | |||
509 | hWrapQuery = GetNewQueryInstance(iColumns, iRows); | ||
510 | if (NULL == hWrapQuery) | ||
511 | { | ||
512 | hr = E_POINTER; | ||
513 | } | ||
514 | ExitOnFailure(hr, "Failed to get a query instance with %d columns and %d rows", iColumns, iRows); | ||
515 | |||
516 | for (int i = 0; i < iColumns; i++) | ||
517 | { | ||
518 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &(hWrapQuery->ppwzColumnNames[i])); | ||
519 | ExitOnFailure(hr, "Failed to read column %d's name from custom action data", i+1); | ||
520 | |||
521 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger); | ||
522 | if (cdtString != iTempInteger && cdtInt != iTempInteger && cdtStream != iTempInteger) | ||
523 | { | ||
524 | hr = E_INVALIDARG; | ||
525 | } | ||
526 | ExitOnFailure(hr, "Failed to read column %d's type from custom action data", i+1); | ||
527 | |||
528 | // Set the column type into the actual data structure | ||
529 | hWrapQuery->pcdtColumnType[i] = (eColumnDataType)iTempInteger; | ||
530 | } | ||
531 | |||
532 | for (int i = 0; i < iRows; i++) | ||
533 | { | ||
534 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger); | ||
535 | if (wqaRowBegin != iTempInteger) | ||
536 | { | ||
537 | hr = E_INVALIDARG; | ||
538 | } | ||
539 | ExitOnFailure(hr, "Failed to read begin row marker from custom action data (read %d instead)", iTempInteger); | ||
540 | |||
541 | hWrapQuery->phRecords[i] = ::MsiCreateRecord((unsigned int)iColumns); | ||
542 | |||
543 | for (int j = 0; j < iColumns; j++) | ||
544 | { | ||
545 | switch (hWrapQuery->pcdtColumnType[j]) | ||
546 | { | ||
547 | case cdtString: | ||
548 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
549 | ExitOnFailure(hr, "Failed to read string from custom action data"); | ||
550 | |||
551 | hr = WcaSetRecordString(hWrapQuery->phRecords[i], j+1, pwzData); | ||
552 | ExitOnFailure(hr, "Failed to write string %ls to record in column %d", pwzData, j+1); | ||
553 | break; | ||
554 | |||
555 | case cdtInt: | ||
556 | WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger); | ||
557 | ExitOnFailure(hr, "Failed to read integer from custom action data"); | ||
558 | |||
559 | WcaSetRecordInteger(hWrapQuery->phRecords[i], j+1, iTempInteger); | ||
560 | ExitOnFailure(hr, "Failed to write integer %d to record in column %d", iTempInteger, j+1); | ||
561 | break; | ||
562 | |||
563 | case cdtStream: | ||
564 | hr = E_NOTIMPL; | ||
565 | ExitOnFailure(hr, "A query was wrapped which contained a stream data field - however, the ability to wrap stream data fields is not implemented at this time"); | ||
566 | break; | ||
567 | |||
568 | case cdtUnknown: | ||
569 | default: | ||
570 | hr = E_INVALIDARG; | ||
571 | ExitOnFailure(hr, "Failed to recognize column type enumeration %d for column %d", hWrapQuery->pcdtColumnType[j+1], i+1); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger); | ||
576 | if (wqaRowFinish != iTempInteger) | ||
577 | { | ||
578 | hr = E_INVALIDARG; | ||
579 | } | ||
580 | ExitOnFailure(hr, "Failed to read row finish marker from custom action data (read %d instead)", iTempInteger); | ||
581 | } | ||
582 | |||
583 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger); | ||
584 | if (wqaTableFinish != iTempInteger) | ||
585 | { | ||
586 | hr = E_INVALIDARG; | ||
587 | } | ||
588 | ExitOnFailure(hr, "Failed to read table finish marker from custom action data (read %d instead)", iTempInteger); | ||
589 | |||
590 | *phWrapQuery = hWrapQuery; | ||
591 | |||
592 | // WcaLog(LOGMSG_TRACEONLY, "Successfully finished unwrapping a query from custom action data"); | ||
593 | |||
594 | LExit: | ||
595 | ReleaseStr(pwzData); | ||
596 | ReleaseMem(pbData); | ||
597 | |||
598 | return hr; | ||
599 | } | ||
600 | |||
601 | // This function returns the total number of records in a query | ||
602 | DWORD WIXAPI WcaGetQueryRecords( | ||
603 | __in const WCA_WRAPQUERY_HANDLE hWrapQuery | ||
604 | ) | ||
605 | { | ||
606 | return hWrapQuery->dwRows; | ||
607 | } | ||
608 | |||
609 | // This function resets a query back to its first row, so that the next fetch returns the first record | ||
610 | void WIXAPI WcaFetchWrappedReset( | ||
611 | __in WCA_WRAPQUERY_HANDLE hWrapQuery | ||
612 | ) | ||
613 | { | ||
614 | hWrapQuery->dwNextIndex = 0; | ||
615 | } | ||
616 | |||
617 | // Fetches the next record in the query | ||
618 | // NOTE: the MSIHANDLE returned by this function should not be released, as it is the same handle used by the query object to maintain the item. | ||
619 | // so, don't use this function with PMSIHANDLE objects! | ||
620 | HRESULT WIXAPI WcaFetchWrappedRecord( | ||
621 | __in WCA_WRAPQUERY_HANDLE hWrapQuery, | ||
622 | __out MSIHANDLE* phRec | ||
623 | ) | ||
624 | { | ||
625 | DWORD dwNextIndex = hWrapQuery->dwNextIndex; | ||
626 | |||
627 | if (dwNextIndex >= hWrapQuery->dwRows) | ||
628 | { | ||
629 | return E_NOMOREITEMS; | ||
630 | } | ||
631 | |||
632 | if (NULL == hWrapQuery->phRecords[dwNextIndex]) | ||
633 | { | ||
634 | return E_HANDLE; | ||
635 | } | ||
636 | |||
637 | *phRec = hWrapQuery->phRecords[hWrapQuery->dwNextIndex]; | ||
638 | |||
639 | // Increment our next index variable | ||
640 | ++hWrapQuery->dwNextIndex; | ||
641 | |||
642 | return S_OK; | ||
643 | } | ||
644 | |||
645 | // Fetch the next record in the query where the string value in column dwComparisonColumn equals the value pwzExpectedValue | ||
646 | // NOTE: the MSIHANDLE returned by this function should not be released, as it is the same handle used by the query object to maintain the item. | ||
647 | // so, don't use this function with PMSIHANDLE objects! | ||
648 | HRESULT WIXAPI WcaFetchWrappedRecordWhereString( | ||
649 | __in WCA_WRAPQUERY_HANDLE hWrapQuery, | ||
650 | __in DWORD dwComparisonColumn, | ||
651 | __in_z LPCWSTR pwzExpectedValue, | ||
652 | __out MSIHANDLE* phRec | ||
653 | ) | ||
654 | { | ||
655 | HRESULT hr = S_OK; | ||
656 | MSIHANDLE hRec = NULL; | ||
657 | LPWSTR pwzData = NULL; | ||
658 | |||
659 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
660 | { | ||
661 | ExitOnFailure(hr, "Failed to fetch a wrapped record"); | ||
662 | |||
663 | hr = WcaGetRecordString(hRec, dwComparisonColumn, &pwzData); | ||
664 | ExitOnFailure(hr, "Failed to get record string in column %d", dwComparisonColumn); | ||
665 | |||
666 | if (0 == lstrcmpW(pwzData, pwzExpectedValue)) | ||
667 | { | ||
668 | *phRec = hRec; | ||
669 | ExitFunction1(hr = S_OK); | ||
670 | } | ||
671 | } | ||
672 | // If we errored here but not because there were no records left, write an error to the log | ||
673 | if (hr != E_NOMOREITEMS) | ||
674 | { | ||
675 | ExitOnFailure(hr, "Failed while searching for a wrapped record where column %d is set to %ls", dwComparisonColumn, pwzExpectedValue); | ||
676 | } | ||
677 | |||
678 | LExit: | ||
679 | ReleaseStr(pwzData); | ||
680 | |||
681 | return hr; | ||
682 | } | ||
683 | |||
684 | /******************************************************************** | ||
685 | WcaBeginUnwrapQuery() - Finishes unwrapping a view for direct access | ||
686 | from the CustomActionData property | ||
687 | |||
688 | ********************************************************************/ | ||
689 | void WIXAPI WcaFinishUnwrapQuery( | ||
690 | __in_opt WCA_WRAPQUERY_HANDLE hWrapQuery | ||
691 | ) | ||
692 | { | ||
693 | if (NULL == hWrapQuery) | ||
694 | { | ||
695 | WcaLog(LOGMSG_TRACEONLY, "Failed to finish an unwrap query - ignoring"); | ||
696 | return; | ||
697 | } | ||
698 | |||
699 | ReleaseMem(hWrapQuery->pcdtColumnType); | ||
700 | |||
701 | for (DWORD i=0;i<hWrapQuery->dwColumns;i++) | ||
702 | { | ||
703 | ReleaseStr(hWrapQuery->ppwzColumnNames[i]); | ||
704 | } | ||
705 | ReleaseMem(hWrapQuery->ppwzColumnNames); | ||
706 | |||
707 | for (DWORD i=0;i<hWrapQuery->dwRows;i++) | ||
708 | { | ||
709 | if (NULL != hWrapQuery->phRecords[i]) | ||
710 | { | ||
711 | ::MsiCloseHandle(hWrapQuery->phRecords[i]); | ||
712 | } | ||
713 | } | ||
714 | ReleaseMem(hWrapQuery->phRecords); | ||
715 | |||
716 | ReleaseMem(hWrapQuery); | ||
717 | } | ||
diff --git a/src/libs/wcautil/appveyor.cmd b/src/libs/wcautil/appveyor.cmd new file mode 100644 index 00000000..a2596256 --- /dev/null +++ b/src/libs/wcautil/appveyor.cmd | |||
@@ -0,0 +1,20 @@ | |||
1 | @setlocal | ||
2 | @pushd %~dp0 | ||
3 | |||
4 | nuget restore || exit /b | ||
5 | |||
6 | msbuild -p:Configuration=Release;Platform=x86;PlatformToolset=v140 || exit /b | ||
7 | msbuild -p:Configuration=Release;Platform=x64;PlatformToolset=v140 || exit /b | ||
8 | |||
9 | msbuild -p:Configuration=Release;Platform=x86;PlatformToolset=v141 || exit /b | ||
10 | msbuild -p:Configuration=Release;Platform=x64;PlatformToolset=v141 || exit /b | ||
11 | msbuild -p:Configuration=Release;Platform=ARM64;PlatformToolset=v141 || exit /b | ||
12 | |||
13 | msbuild -p:Configuration=Release;Platform=x86;PlatformToolset=v142 || exit /b | ||
14 | msbuild -p:Configuration=Release;Platform=x64;PlatformToolset=v142 || exit /b | ||
15 | msbuild -p:Configuration=Release;Platform=ARM64;PlatformToolset=v142 || exit /b | ||
16 | |||
17 | msbuild -p:Configuration=Release -t:PackNativeNuget src\wcautil\wcautil.vcxproj || exit /b | ||
18 | |||
19 | @popd | ||
20 | @endlocal \ No newline at end of file | ||
diff --git a/src/libs/wcautil/appveyor.yml b/src/libs/wcautil/appveyor.yml new file mode 100644 index 00000000..bbf880f0 --- /dev/null +++ b/src/libs/wcautil/appveyor.yml | |||
@@ -0,0 +1,35 @@ | |||
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 | |||
6 | image: Visual Studio 2019 | ||
7 | |||
8 | version: 0.0.0.{build} | ||
9 | configuration: Release | ||
10 | |||
11 | environment: | ||
12 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true | ||
13 | DOTNET_CLI_TELEMETRY_OPTOUT: 1 | ||
14 | NUGET_XMLDOC_MODE: skip | ||
15 | |||
16 | build_script: | ||
17 | - appveyor.cmd | ||
18 | |||
19 | pull_requests: | ||
20 | do_not_increment_build_number: true | ||
21 | |||
22 | nuget: | ||
23 | disable_publish_on_pr: true | ||
24 | |||
25 | skip_branch_with_pr: true | ||
26 | skip_tags: true | ||
27 | |||
28 | artifacts: | ||
29 | - path: build\Release\**\*.nupkg | ||
30 | name: nuget | ||
31 | |||
32 | notifications: | ||
33 | - provider: Slack | ||
34 | incoming_webhook: | ||
35 | secure: p5xuu+4x2JHfwGDMDe5KcG1k7gZxqYc4jWVwvyNZv5cvkubPD2waJs5yXMAXZNN7Z63/3PWHb7q4KoY/99AjauYa1nZ4c5qYqRPFRBKTHfA= | ||
diff --git a/src/libs/wcautil/nuget.config b/src/libs/wcautil/nuget.config new file mode 100644 index 00000000..790be2b0 --- /dev/null +++ b/src/libs/wcautil/nuget.config | |||
@@ -0,0 +1,8 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <configuration> | ||
3 | <packageSources> | ||
4 | <clear /> | ||
5 | <add key="wixtoolset-dutil" value="https://ci.appveyor.com/nuget/wixtoolset-dutil" /> | ||
6 | <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" /> | ||
7 | </packageSources> | ||
8 | </configuration> \ No newline at end of file | ||
diff --git a/src/libs/wcautil/wcautil.sln b/src/libs/wcautil/wcautil.sln new file mode 100644 index 00000000..5682f1f7 --- /dev/null +++ b/src/libs/wcautil/wcautil.sln | |||
@@ -0,0 +1,37 @@ | |||
1 | | ||
2 | Microsoft Visual Studio Solution File, Format Version 12.00 | ||
3 | # Visual Studio Version 16 | ||
4 | VisualStudioVersion = 16.0.31005.135 | ||
5 | MinimumVisualStudioVersion = 15.0.26124.0 | ||
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wcautil", "src\wcautil\wcautil.vcxproj", "{5B3714B6-3A76-463E-8595-D48DA276C512}" | ||
7 | EndProject | ||
8 | Global | ||
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
10 | Debug|ARM64 = Debug|ARM64 | ||
11 | Debug|x64 = Debug|x64 | ||
12 | Debug|x86 = Debug|x86 | ||
13 | Release|ARM64 = Release|ARM64 | ||
14 | Release|x64 = Release|x64 | ||
15 | Release|x86 = Release|x86 | ||
16 | EndGlobalSection | ||
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
18 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Debug|ARM64.ActiveCfg = Debug|ARM64 | ||
19 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Debug|ARM64.Build.0 = Debug|ARM64 | ||
20 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Debug|x64.ActiveCfg = Debug|x64 | ||
21 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Debug|x64.Build.0 = Debug|x64 | ||
22 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Debug|x86.ActiveCfg = Debug|Win32 | ||
23 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Debug|x86.Build.0 = Debug|Win32 | ||
24 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Release|ARM64.ActiveCfg = Release|ARM64 | ||
25 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Release|ARM64.Build.0 = Release|ARM64 | ||
26 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Release|x64.ActiveCfg = Release|x64 | ||
27 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Release|x64.Build.0 = Release|x64 | ||
28 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Release|x86.ActiveCfg = Release|Win32 | ||
29 | {5B3714B6-3A76-463E-8595-D48DA276C512}.Release|x86.Build.0 = Release|Win32 | ||
30 | EndGlobalSection | ||
31 | GlobalSection(SolutionProperties) = preSolution | ||
32 | HideSolutionNode = FALSE | ||
33 | EndGlobalSection | ||
34 | GlobalSection(ExtensibilityGlobals) = postSolution | ||
35 | SolutionGuid = {DD209744-C40E-4C34-8CB4-BC6B71F9A133} | ||
36 | EndGlobalSection | ||
37 | EndGlobal | ||