diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-05-11 07:38:50 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-05-11 07:38:50 -0700 |
| commit | cb49308d18e998e96bbe9e259e815128f7fc2abc (patch) | |
| tree | a5203b99de14ec36862f00e1b40ee71e53add911 /src | |
| parent | 0c6aea2de8db1258949a741b1c504307a81bf579 (diff) | |
| parent | 30827588eb0c189b7e2d04693d116080d333200e (diff) | |
| download | wix-cb49308d18e998e96bbe9e259e815128f7fc2abc.tar.gz wix-cb49308d18e998e96bbe9e259e815128f7fc2abc.tar.bz2 wix-cb49308d18e998e96bbe9e259e815128f7fc2abc.zip | |
Merge wcautil
Diffstat (limited to 'src')
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 | ||
