This commit is contained in:
Sean Hall 2017-09-03 17:25:02 -05:00
Родитель a3073f2da5
Коммит 7df142a458
29 изменённых файлов: 5298 добавлений и 0 удалений

2
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

295
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,295 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

28
LICENSE.TXT Normal file
Просмотреть файл

@ -0,0 +1,28 @@
Copyright (c) .NET Foundation and contributors.
This software is released under the Microsoft Reciprocal License (MS-RL) (the "License"); you may not use the software except in compliance with the License.
The text of the Microsoft Reciprocal License (MS-RL) can be found online at:
http://opensource.org/licenses/ms-rl
Microsoft Reciprocal License (MS-RL)
This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
1. Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
A "contribution" is the original software, or any additions or changes to the software.
A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
2. Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
3. Conditions and Limitations
(A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose.
(B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
(C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
(D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
(E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
(F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.

13
appveyor.cmd Normal file
Просмотреть файл

@ -0,0 +1,13 @@
@setlocal
@pushd %~dp0
msbuild -p:Configuration=Release;Platform=x86;PlatformToolset=v140_xp
msbuild -p:Configuration=Release;Platform=x64;PlatformToolset=v140_xp
msbuild -p:Configuration=Release;Platform=x86;PlatformToolset=v141_xp
msbuild -p:Configuration=Release;Platform=x64;PlatformToolset=v141_xp
msbuild -p:Configuration=Release -t:PackNativeNuget src\wcautil\wcautil.vcxproj
@popd
@endlocal

27
appveyor.yml Normal file
Просмотреть файл

@ -0,0 +1,27 @@
image: Visual Studio 2017
version: 0.0.0.{build}
configuration: Release
environment:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: 1
NUGET_XMLDOC_MODE: skip
before_build:
- nuget restore
build_script:
- appveyor.cmd
pull_requests:
do_not_increment_build_number: true
nuget:
disable_publish_on_pr: true
skip_tags: true
artifacts:
- path: build\Release\**\*.nupkg
name: nuget

8
nuget.config Normal file
Просмотреть файл

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="wixtoolset-dutil" value="https://ci.appveyor.com/nuget/wixtoolset-dutil" />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>

100
src/Cpp.Build.props Normal file
Просмотреть файл

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<Project>
<PropertyGroup>
<BaseOutputPath>$(OutputPath)</BaseOutputPath>
<IntDir>$(BaseIntermediateOutputPath)$(Platform)\</IntDir>
<OutDir>$(OutputPath)$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<DisableSpecificWarnings>$(DisableSpecificCompilerWarnings)</DisableSpecificWarnings>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
<CallingConvention>StdCall</CallingConvention>
<TreatWarningAsError>true</TreatWarningAsError>
<ExceptionHandling>false</ExceptionHandling>
<AdditionalOptions>-YlprecompDefine</AdditionalOptions>
<AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
<MultiProcessorCompilation Condition=" $(NUMBER_OF_PROCESSORS) &gt; 4 ">true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>$(ArmPreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Lib>
<AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Lib>
<Link>
<SubSystem>$(ProjectSubSystem)</SubSystem>
<ModuleDefinitionFile>$(ProjectModuleDefinitionFile)</ModuleDefinitionFile>
<NoEntryPoint>$(ResourceOnlyDll)</NoEntryPoint>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/IGNORE:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" '$(Platform)'=='Win32' and '$(PlatformToolset)'!='v100'">
<ClCompile>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" '$(Platform)'=='arm' ">
<ClCompile>
<CallingConvention>CDecl</CallingConvention>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" '$(ConfigurationType)'=='StaticLibrary' ">
<ClCompile>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<OmitDefaultLibName>true</OmitDefaultLibName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" '$(Configuration)'=='Debug' ">
<ClCompile>
<Optimization>Disabled</Optimization>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<PreprocessorDefinitions>_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" '$(Configuration)'=='Debug' and '$(CLRSupport)'=='true' ">
<ClCompile>
<BasicRuntimeChecks></BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDll</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' ">
<ClCompile>
<Optimization>MinSpace</Optimization>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' and '$(CLRSupport)'=='true' ">
<ClCompile>
<BasicRuntimeChecks></BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDll</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" '$(CLRSupport)'=='true' ">
<Link>
<KeyFile>$(LinkKeyFile)</KeyFile>
<DelaySign>$(LinkDelaySign)</DelaySign>
</Link>
</ItemDefinitionGroup>
</Project>

21
src/Directory.Build.props Normal file
Просмотреть файл

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<Project>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory)..\build\obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
<OutputPath>$(MSBuildThisFileDirectory)..\build\$(Configuration)\</OutputPath>
<Authors>WiX Toolset Team</Authors>
<Company>WiX Toolset</Company>
<Copyright>Copyright (c) .NET Foundation and contributors. All rights reserved.</Copyright>
</PropertyGroup>
<PropertyGroup>
<WixToolsetRootFolder>$(MSBuildThisFileDirectory)..\..\</WixToolsetRootFolder>
</PropertyGroup>
<Import Project="Cpp.Build.props" Condition=" '$(MSBuildProjectExtension)'=='.vcxproj' " />
<Import Project="Custom.Build.props" Condition=" Exists('Custom.Build.props') " />
</Project>

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<Project>
<!-- Overrides the standard Cpp.Build.props to include the PlatformToolset in the output path. -->
<PropertyGroup>
<IntDir>$(BaseIntermediateOutputPath)$(PlatformToolset)\$(PlatformTarget)\</IntDir>
<OutDir>$(OutputPath)$(PlatformToolset)\$(PlatformTarget)\</OutDir>
</PropertyGroup>
</Project>

Просмотреть файл

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)native\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)native\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" $(PlatformToolset.ToLower().StartsWith('v140')) ">
<Link>
<AdditionalDependencies>$(MSBuildThisFileDirectory)native\lib\v140\$(PlatformTarget)\wcautil.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition=" $(PlatformToolset.ToLower().StartsWith('v141')) ">
<Link>
<AdditionalDependencies>$(MSBuildThisFileDirectory)native\lib\v141\$(PlatformTarget)\wcautil.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
</Project>

Просмотреть файл

@ -0,0 +1,130 @@
#pragma once
// 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.
#define GLOBAL_ERROR_BASE 25501
#define msierrSecureObjectsFailedCreateSD 25520
#define msierrSecureObjectsFailedSet 25521
#define msierrSecureObjectsUnknownType 25522
#define msierrXmlFileFailedRead 25530
#define msierrXmlFileFailedOpen 25531
#define msierrXmlFileFailedSelect 25532
#define msierrXmlFileFailedSave 25533
#define msierrXmlConfigFailedRead 25540
#define msierrXmlConfigFailedOpen 25541
#define msierrXmlConfigFailedSelect 25542
#define msierrXmlConfigFailedSave 25543
#define msierrFirewallCannotConnect 25580
//---------------------------------------------------------------------------
// Server CustomAction Errors
// SERVER range: 26001-26100
#define SERVER_ERROR_BASE 26000
#define msierrIISCannotConnect 26001
#define msierrIISFailedReadWebSite 26002
#define msierrIISFailedReadWebDirs 26003
#define msierrIISFailedReadVDirs 26004
#define msierrIISFailedReadFilters 26005
#define msierrIISFailedReadAppPool 26006
#define msierrIISFailedReadMimeMap 26007
#define msierrIISFailedReadProp 26008
#define msierrIISFailedReadWebSvcExt 26009
#define msierrIISFailedReadWebError 26010
#define msierrIISFailedReadHttpHeader 26011
#define msierrIISFailedSchedTransaction 26031
#define msierrIISFailedSchedInstallWebs 26032
#define msierrIISFailedSchedInstallWebDirs 26033
#define msierrIISFailedSchedInstallVDirs 26034
#define msierrIISFailedSchedInstallFilters 26035
#define msierrIISFailedSchedInstallAppPool 26036
#define msierrIISFailedSchedInstallProp 26037
#define msierrIISFailedSchedInstallWebSvcExt 26038
#define msierrIISFailedSchedUninstallWebs 26051
#define msierrIISFailedSchedUninstallWebDirs 26052
#define msierrIISFailedSchedUninstallVDirs 26053
#define msierrIISFailedSchedUninstallFilters 26054
#define msierrIISFailedSchedUninstallAppPool 26055
#define msierrIISFailedSchedUninstallProp 26056
#define msierrIISFailedSchedUninstallWebSvcExt 26057
#define msierrIISFailedStartTransaction 26101
#define msierrIISFailedOpenKey 26102
#define msierrIISFailedCreateKey 26103
#define msierrIISFailedWriteData 26104
#define msierrIISFailedCreateApp 26105
#define msierrIISFailedDeleteKey 26106
#define msierrIISFailedDeleteApp 26107
#define msierrIISFailedDeleteValue 26108
#define msierrIISFailedCommitInUse 26109
#define msierrSQLFailedCreateDatabase 26201
#define msierrSQLFailedDropDatabase 26202
#define msierrSQLFailedConnectDatabase 26203
#define msierrSQLFailedExecString 26204
#define msierrSQLDatabaseAlreadyExists 26205
#define msierrPERFMONFailedRegisterDLL 26251
#define msierrPERFMONFailedUnregisterDLL 26252
#define msierrInstallPerfCounterData 26253
#define msierrUninstallPerfCounterData 26254
#define msierrSMBFailedCreate 26301
#define msierrSMBFailedDrop 26302
#define msierrCERTFailedOpen 26351
#define msierrCERTFailedAdd 26352
#define msierrUSRFailedUserCreate 26401
#define msierrUSRFailedUserCreatePswd 26402
#define msierrUSRFailedUserGroupAdd 26403
#define msierrUSRFailedUserCreateExists 26404
#define msierrUSRFailedGrantLogonAsService 26405
#define msierrDependencyMissingDependencies 26451
#define msierrDependencyHasDependents 26452
//--------------------------------------------------------------------------
// Managed code CustomAction Errors
// MANAGED range: 27000-27100
#define MANAGED_ERROR_BASE 27000
#define msierrDotNetRuntimeRequired 27000
//---------------------------------------------------------------------------
// Public CustomAction Errors
// PUBLIC range: 28001-28100
#define PUBLIC_ERROR_BASE 28000
#define msierrComPlusCannotConnect 28001
#define msierrComPlusPartitionReadFailed 28002
#define msierrComPlusPartitionRoleReadFailed 28003
#define msierrComPlusUserInPartitionRoleReadFailed 28004
#define msierrComPlusPartitionUserReadFailed 28005
#define msierrComPlusApplicationReadFailed 28006
#define msierrComPlusApplicationRoleReadFailed 28007
#define msierrComPlusUserInApplicationRoleReadFailed 28008
#define msierrComPlusAssembliesReadFailed 28009
#define msierrComPlusSubscriptionReadFailed 28010
#define msierrComPlusPartitionDependency 28011
#define msierrComPlusPartitionNotFound 28012
#define msierrComPlusPartitionIdConflict 28013
#define msierrComPlusPartitionNameConflict 28014
#define msierrComPlusApplicationDependency 28015
#define msierrComPlusApplicationNotFound 28016
#define msierrComPlusApplicationIdConflict 28017
#define msierrComPlusApplicationNameConflict 28018
#define msierrComPlusApplicationRoleDependency 28019
#define msierrComPlusApplicationRoleNotFound 28020
#define msierrComPlusApplicationRoleConflict 28021
#define msierrComPlusAssemblyDependency 28022
#define msierrComPlusSubscriptionIdConflict 28023
#define msierrComPlusSubscriptionNameConflict 28024
#define msierrComPlusFailedLookupNames 28025
#define msierrMsmqCannotConnect 28101

142
src/wcautil/exbinary.cpp Normal file
Просмотреть файл

@ -0,0 +1,142 @@
// 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.
#include "precomp.h"
//
// Extracts the data from the Binary table row with the given ID into a buffer.
//
HRESULT WIXAPI WcaExtractBinaryToBuffer(
__in LPCWSTR wzBinaryId,
__out BYTE** pbData,
__out DWORD* pcbData
)
{
HRESULT hr = S_OK;
LPWSTR pwzSql = NULL;
PMSIHANDLE hView;
PMSIHANDLE hRec;
// make sure we're not horked from the get-go
hr = WcaTableExists(L"Binary");
if (S_OK != hr)
{
if (SUCCEEDED(hr))
{
hr = E_UNEXPECTED;
}
ExitOnFailure(hr, "There is no Binary table.");
}
ExitOnNull(wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be null");
ExitOnNull(*wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be empty string");
hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%ls\'", wzBinaryId);
ExitOnFailure(hr, "Failed to allocate Binary table query.");
hr = WcaOpenExecuteView(pwzSql, &hView);
ExitOnFailure(hr, "Failed to open view on Binary table");
hr = WcaFetchSingleRecord(hView, &hRec);
ExitOnFailure(hr, "Failed to retrieve request from Binary table");
hr = WcaGetRecordStream(hRec, 1, pbData, pcbData);
ExitOnFailure(hr, "Failed to read Binary.Data.");
LExit:
ReleaseStr(pwzSql);
return hr;
}
//
// Extracts the data from the Binary table row with the given ID into a file.
//
HRESULT WIXAPI WcaExtractBinaryToFile(
__in LPCWSTR wzBinaryId,
__in LPCWSTR wzPath
)
{
HRESULT hr = S_OK;
BYTE* pbData = NULL;
DWORD cbData = 0;
HANDLE hFile = INVALID_HANDLE_VALUE;
// grab the bits
hr = WcaExtractBinaryToBuffer(wzBinaryId, &pbData, &cbData);
ExitOnFailure(hr, "Failed to extract binary data: %ls", wzBinaryId);
// write 'em to the file
hFile = ::CreateFileW(wzPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
ExitWithLastError(hr, "Failed to create file: %ls", wzPath);
}
DWORD cbWritten = 0;
if (!::WriteFile(hFile, pbData, cbData, &cbWritten, NULL))
{
ExitWithLastError(hr, "Failed to write data to file: %ls", wzPath);
}
LExit:
ReleaseFile(hFile);
ReleaseMem(pbData);
return hr;
}
//
// Extracts the data from the Binary table row with the given ID into a string.
//
HRESULT WIXAPI WcaExtractBinaryToString(
__in LPCWSTR wzBinaryId,
__deref_out_z LPWSTR* psczOutput,
__out WCA_ENCODING* encoding
)
{
HRESULT hr = S_OK;
BYTE* pbData = NULL;
DWORD cbData = 0;
// grab the bits
hr = WcaExtractBinaryToBuffer(wzBinaryId, &pbData, &cbData);
ExitOnFailure(hr, "Failed to extract binary data: %ls", wzBinaryId);
// expand by a NULL character (or two) to make sure the buffer is null-terminated
cbData += 2;
pbData = reinterpret_cast<LPBYTE>(MemReAlloc(pbData, cbData, TRUE));
ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to expand binary buffer");
// Check for BOMs.
if (2 < cbData)
{
if ((0xFF == *pbData) && (0xFE == *(pbData + 1)))
{
*encoding = WCA_ENCODING_UTF_16;
hr = StrAllocString(psczOutput, reinterpret_cast<LPWSTR>(pbData), 0);
}
else if ((0xEF == *pbData) && (0xBB == *(pbData + 1)) && (0xBF == *(pbData + 2)))
{
*encoding = WCA_ENCODING_UTF_8;
hr = StrAllocStringAnsi(psczOutput, reinterpret_cast<LPCSTR>(pbData), 0, CP_UTF8);
}
else
{
*encoding = WCA_ENCODING_ANSI;
hr = StrAllocStringAnsi(psczOutput, reinterpret_cast<LPCSTR>(pbData), 0, CP_ACP);
}
ExitOnFailure(hr, "Failed to allocate string for binary buffer.");
}
// Free the byte buffer since it has been converted to a new UNICODE string, one way or another.
if (pbData)
{
WcaFreeStream(pbData);
pbData = NULL;
}
LExit:
ReleaseMem(pbData);
return hr;
}

14
src/wcautil/inc/wcalog.h Normal file
Просмотреть файл

@ -0,0 +1,14 @@
#pragma once
// 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.
#ifdef __cplusplus
extern "C" {
#endif
BOOL WIXAPI IsVerboseLogging();
HRESULT WIXAPI SetVerboseLoggingAtom(BOOL bValue);
#ifdef __cplusplus
}
#endif

384
src/wcautil/inc/wcautil.h Normal file
Просмотреть файл

@ -0,0 +1,384 @@
#pragma once
// 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.
#ifdef __cplusplus
extern "C" {
#endif
#define WIXAPI __stdcall
#define ExitTrace WcaLogError
#include "dutil.h"
#define MessageExitOnLastError(x, e, s, ...) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { ExitTrace(x, "%s", s, __VA_ARGS__); WcaErrorMessage(e, x, MB_OK, -1, __VA_ARGS__); goto LExit; } }
#define MessageExitOnFailure(x, e, s, ...) if (FAILED(x)) { ExitTrace(x, "%s", s, __VA_ARGS__); WcaErrorMessage(e, x, INSTALLMESSAGE_ERROR | MB_OK, -1, __VA_ARGS__); goto LExit; }
#define MessageExitOnNullWithLastError(p, x, e, s, ...) if (NULL == p) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace(x, "%s", s, __VA_ARGS__); WcaErrorMessage(e, x, MB_OK, -1, __VA_ARGS__); goto LExit; }
// Generic action enum.
typedef enum WCA_ACTION
{
WCA_ACTION_NONE,
WCA_ACTION_INSTALL,
WCA_ACTION_UNINSTALL,
} WCA_ACTION;
typedef enum WCA_CASCRIPT
{
WCA_CASCRIPT_SCHEDULED,
WCA_CASCRIPT_ROLLBACK,
} WCA_CASCRIPT;
typedef enum WCA_CASCRIPT_CLOSE
{
WCA_CASCRIPT_CLOSE_PRESERVE,
WCA_CASCRIPT_CLOSE_DELETE,
} WCA_CASCRIPT_CLOSE;
typedef enum WCA_TODO
{
WCA_TODO_UNKNOWN,
WCA_TODO_INSTALL,
WCA_TODO_UNINSTALL,
WCA_TODO_REINSTALL,
} WCA_TODO;
typedef struct WCA_CASCRIPT_STRUCT
{
LPWSTR pwzScriptPath;
HANDLE hScriptFile;
} *WCA_CASCRIPT_HANDLE;
typedef enum WCA_ENCODING
{
WCA_ENCODING_UNKNOWN,
WCA_ENCODING_UTF_16,
WCA_ENCODING_UTF_8,
WCA_ENCODING_ANSI,
} WCA_ENCODING;
void WIXAPI WcaGlobalInitialize(
__in HINSTANCE hInst
);
void WIXAPI WcaGlobalFinalize();
HRESULT WIXAPI WcaInitialize(
__in MSIHANDLE hInstall,
__in_z PCSTR szCustomActionLogName
);
UINT WIXAPI WcaFinalize(
__in UINT iReturnValue
);
BOOL WIXAPI WcaIsInitialized();
MSIHANDLE WIXAPI WcaGetInstallHandle();
MSIHANDLE WIXAPI WcaGetDatabaseHandle();
const char* WIXAPI WcaGetLogName();
void WIXAPI WcaSetReturnValue(
__in UINT iReturnValue
);
BOOL WIXAPI WcaCancelDetected();
#define LOG_BUFFER 2048
typedef enum LOGLEVEL
{
LOGMSG_TRACEONLY, // Never written to the log file (except in DEBUG builds)
LOGMSG_VERBOSE, // Written to log when LOGVERBOSE
LOGMSG_STANDARD // Written to log whenever informational logging is enabled
} LOGLEVEL;
void __cdecl WcaLog(
__in LOGLEVEL llv,
__in_z __format_string PCSTR fmt, ...
);
BOOL WIXAPI WcaDisplayAssert(
__in LPCSTR sz
);
void __cdecl WcaLogError(
__in HRESULT hr,
__in LPCSTR szMessage,
...
);
UINT WIXAPI WcaProcessMessage(
__in INSTALLMESSAGE eMessageType,
__in MSIHANDLE hRecord
);
UINT __cdecl WcaErrorMessage(
__in int iError,
__in HRESULT hrError,
__in UINT uiType,
__in INT cArgs,
...
);
HRESULT WIXAPI WcaProgressMessage(
__in UINT uiCost,
__in BOOL fExtendProgressBar
);
BOOL WIXAPI WcaIsInstalling(
__in INSTALLSTATE isInstalled,
__in INSTALLSTATE isAction
);
BOOL WIXAPI WcaIsReInstalling(
__in INSTALLSTATE isInstalled,
__in INSTALLSTATE isAction
);
BOOL WIXAPI WcaIsUninstalling(
__in INSTALLSTATE isInstalled,
__in INSTALLSTATE isAction
);
HRESULT WIXAPI WcaSetComponentState(
__in_z LPCWSTR wzComponent,
__in INSTALLSTATE isState
);
HRESULT WIXAPI WcaTableExists(
__in_z LPCWSTR wzTable
);
HRESULT WIXAPI WcaOpenView(
__in_z LPCWSTR wzSql,
__out MSIHANDLE* phView
);
HRESULT WIXAPI WcaExecuteView(
__in MSIHANDLE hView,
__in MSIHANDLE hRec
);
HRESULT WIXAPI WcaOpenExecuteView(
__in_z LPCWSTR wzSql,
__out MSIHANDLE* phView
);
HRESULT WIXAPI WcaFetchRecord(
__in MSIHANDLE hView,
__out MSIHANDLE* phRec
);
HRESULT WIXAPI WcaFetchSingleRecord(
__in MSIHANDLE hView,
__out MSIHANDLE* phRec
);
HRESULT WIXAPI WcaGetProperty(
__in_z LPCWSTR wzProperty,
__inout LPWSTR* ppwzData
);
HRESULT WIXAPI WcaGetFormattedProperty(
__in_z LPCWSTR wzProperty,
__out LPWSTR* ppwzData
);
HRESULT WIXAPI WcaGetFormattedString(
__in_z LPCWSTR wzString,
__out LPWSTR* ppwzData
);
HRESULT WIXAPI WcaGetIntProperty(
__in_z LPCWSTR wzProperty,
__inout int* piData
);
HRESULT WIXAPI WcaGetTargetPath(
__in_z LPCWSTR wzFolder,
__out LPWSTR* ppwzData
);
HRESULT WIXAPI WcaSetProperty(
__in_z LPCWSTR wzPropertyName,
__in_z LPCWSTR wzPropertyValue
);
HRESULT WIXAPI WcaSetIntProperty(
__in_z LPCWSTR wzPropertyName,
__in int nPropertyValue
);
BOOL WIXAPI WcaIsPropertySet(
__in LPCSTR szProperty
);
BOOL WIXAPI WcaIsUnicodePropertySet(
__in LPCWSTR wzProperty
);
HRESULT WIXAPI WcaGetRecordInteger(
__in MSIHANDLE hRec,
__in UINT uiField,
__inout int* piData
);
HRESULT WIXAPI WcaGetRecordString(
__in MSIHANDLE hRec,
__in UINT uiField,
__inout LPWSTR* ppwzData
);
HRESULT WIXAPI WcaGetRecordFormattedInteger(
__in MSIHANDLE hRec,
__in UINT uiField,
__out int* piData
);
HRESULT WIXAPI WcaGetRecordFormattedString(
__in MSIHANDLE hRec,
__in UINT uiField,
__inout LPWSTR* ppwzData
);
HRESULT WIXAPI WcaAllocStream(
__deref_out_bcount_part(cbData, 0) BYTE** ppbData,
__in DWORD cbData
);
HRESULT WIXAPI WcaFreeStream(
__in BYTE* pbData
);
HRESULT WIXAPI WcaGetRecordStream(
__in MSIHANDLE hRecBinary,
__in UINT uiField,
__deref_out_bcount_full(*pcbData) BYTE** ppbData,
__out DWORD* pcbData
);
HRESULT WIXAPI WcaSetRecordString(
__in MSIHANDLE hRec,
__in UINT uiField,
__in_z LPCWSTR wzData
);
HRESULT WIXAPI WcaSetRecordInteger(
__in MSIHANDLE hRec,
__in UINT uiField,
__in int iValue
);
HRESULT WIXAPI WcaDoDeferredAction(
__in_z LPCWSTR wzAction,
__in_z LPCWSTR wzCustomActionData,
__in UINT uiCost
);
DWORD WIXAPI WcaCountOfCustomActionDataRecords(
__in_z LPCWSTR wzData
);
HRESULT WIXAPI WcaReadStringFromCaData(
__deref_in LPWSTR* ppwzCustomActionData,
__deref_out_z LPWSTR* ppwzString
);
HRESULT WIXAPI WcaReadIntegerFromCaData(
__deref_in LPWSTR* ppwzCustomActionData,
__out int* piResult
);
HRESULT WIXAPI WcaReadStreamFromCaData(
__deref_in LPWSTR* ppwzCustomActionData,
__deref_out_bcount(*pcbData) BYTE** ppbData,
__out DWORD_PTR* pcbData
);
HRESULT WIXAPI WcaWriteStringToCaData(
__in_z LPCWSTR wzString,
__deref_inout_z LPWSTR* ppwzCustomActionData
);
HRESULT WIXAPI WcaWriteIntegerToCaData(
__in int i,
__deref_out_z_opt LPWSTR* ppwzCustomActionData
);
HRESULT WIXAPI WcaWriteStreamToCaData(
__in_bcount(cbData) const BYTE* pbData,
__in DWORD cbData,
__deref_inout_z_opt LPWSTR* ppwzCustomActionData
);
HRESULT __cdecl WcaAddTempRecord(
__inout MSIHANDLE* phTableView,
__inout MSIHANDLE* phColumns,
__in_z LPCWSTR wzTable,
__out_opt MSIDBERROR* pdbError,
__in UINT uiUniquifyColumn,
__in UINT cColumns,
...
);
HRESULT WIXAPI WcaDumpTable(
__in_z LPCWSTR wzTable
);
HRESULT WIXAPI WcaDeferredActionRequiresReboot();
BOOL WIXAPI WcaDidDeferredActionRequireReboot();
HRESULT WIXAPI WcaCaScriptCreateKey(
__out LPWSTR* ppwzScriptKey
);
HRESULT WIXAPI WcaCaScriptCreate(
__in WCA_ACTION action,
__in WCA_CASCRIPT script,
__in BOOL fImpersonated,
__in_z LPCWSTR wzScriptKey,
__in BOOL fAppend,
__out WCA_CASCRIPT_HANDLE* phScript
);
HRESULT WIXAPI WcaCaScriptOpen(
__in WCA_ACTION action,
__in WCA_CASCRIPT script,
__in BOOL fImpersonated,
__in_z LPCWSTR wzScriptKey,
__out WCA_CASCRIPT_HANDLE* phScript
);
void WIXAPI WcaCaScriptClose(
__in_opt WCA_CASCRIPT_HANDLE hScript,
__in WCA_CASCRIPT_CLOSE closeOperation
);
HRESULT WIXAPI WcaCaScriptReadAsCustomActionData(
__in WCA_CASCRIPT_HANDLE hScript,
__out LPWSTR* ppwzCustomActionData
);
HRESULT WIXAPI WcaCaScriptWriteString(
__in WCA_CASCRIPT_HANDLE hScript,
__in_z LPCWSTR wzValue
);
HRESULT WIXAPI WcaCaScriptWriteNumber(
__in WCA_CASCRIPT_HANDLE hScript,
__in DWORD dwValue
);
void WIXAPI WcaCaScriptFlush(
__in WCA_CASCRIPT_HANDLE hScript
);
void WIXAPI WcaCaScriptCleanup(
__in_z LPCWSTR wzProductCode,
__in BOOL fImpersonated
);
HRESULT WIXAPI QuietExec(
__inout_z LPWSTR wzCommand,
__in DWORD dwTimeout,
__in BOOL fLogCommand,
__in BOOL fLogOutput
);
HRESULT WIXAPI QuietExecCapture(
__inout_z LPWSTR wzCommand,
__in DWORD dwTimeout,
__in BOOL fLogCommand,
__in BOOL fLogOutput,
__out_z_opt LPWSTR* psczOutput
);
WCA_TODO WIXAPI WcaGetComponentToDo(
__in_z LPCWSTR wzComponentId
);
HRESULT WIXAPI WcaExtractBinaryToBuffer(
__in LPCWSTR wzBinaryId,
__out BYTE** pbData,
__out DWORD* pcbData
);
HRESULT WIXAPI WcaExtractBinaryToFile(
__in LPCWSTR wzBinaryId,
__in LPCWSTR wzPath
);
HRESULT WIXAPI WcaExtractBinaryToString(
__in LPCWSTR wzBinaryId,
__deref_out_z LPWSTR* psczOutput,
__out WCA_ENCODING* encoding
);
#ifdef __cplusplus
}
#endif

Просмотреть файл

@ -0,0 +1,20 @@
#pragma once
// 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.
#include "wcautil.h"
#ifdef __cplusplus
extern "C" {
#endif
HRESULT WIXAPI WcaInitializeWow64();
BOOL WIXAPI WcaIsWow64Process();
BOOL WIXAPI WcaIsWow64Initialized();
HRESULT WIXAPI WcaDisableWow64FSRedirection();
HRESULT WIXAPI WcaRevertWow64FSRedirection();
HRESULT WIXAPI WcaFinalizeWow64();
#ifdef __cplusplus
}
#endif

Просмотреть файл

@ -0,0 +1,130 @@
#pragma once
// 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.
#include "wcautil.h"
// Enumerations
typedef enum eWrapQueryAction
{
wqaTableBegin = 1,
wqaTableFinish,
wqaRowBegin,
wqaRowFinish
} eWrapQueryAction;
typedef enum eColumnDataType
{
cdtString = 1,
cdtInt,
cdtStream,
cdtUnknown
} eColumnDataType;
typedef enum eFormatMaskColumn
{
efmcColumn1 = 1,
efmcColumn2 = 1 << 1,
efmcColumn3 = 1 << 2,
efmcColumn4 = 1 << 3,
efmcColumn5 = 1 << 4,
efmcColumn6 = 1 << 5,
efmcColumn7 = 1 << 6,
efmcColumn8 = 1 << 7,
efmcColumn9 = 1 << 8,
efmcColumn10 = 1 << 9,
efmcColumn11 = 1 << 10,
efmcColumn12 = 1 << 11,
efmcColumn13 = 1 << 12,
efmcColumn14 = 1 << 13,
efmcColumn15 = 1 << 14,
efmcColumn16 = 1 << 15,
efmcColumn17 = 1 << 16,
efmcColumn18 = 1 << 17,
efmcColumn19 = 1 << 18,
efmcColumn20 = 1 << 19,
efmcColumn21 = 1 << 20,
efmcColumn22 = 1 << 21,
efmcColumn23 = 1 << 22,
efmcColumn24 = 1 << 23,
efmcColumn25 = 1 << 24,
efmcColumn26 = 1 << 25,
efmcColumn27 = 1 << 26,
efmcColumn28 = 1 << 27,
efmcColumn29 = 1 << 28,
efmcColumn30 = 1 << 29,
efmcColumn31 = 1 << 30,
efmcColumn32 = 1 << 31,
} eFormatMaskColumn;
// Keeps track of the query instance for the reading CA (deferred CA)
typedef struct WCA_WRAPQUERY_STRUCT
{
// These are used to size our dynamic arrays below
DWORD dwColumns, dwRows, dwNextIndex;
// Dynamic arrays of column schema information
eColumnDataType *pcdtColumnType;
LPWSTR *ppwzColumnNames;
// Dynamic array of raw record data
MSIHANDLE *phRecords;
} *WCA_WRAPQUERY_HANDLE;
// Wrap a query
// Setting the pfFormatMask enables control over which fields will be formatted, and which will be left unchanged
// Setting dwComponentColumn to something other than 0xFFFFFFFF tells WcaWrapQuery to add two additional columns to the right side of the table
// - ISInstalled and ISAction - which map to the ComponentState of the component (the component is found in the column specified)
// 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
// Setting dwDirectoryColumn to something other than 0xFFFFFFFF tells WcaWrapQuery to add two more additional columns to the right side of the table
// - SourcePath and TargetPath - which map to the Directory's Source and Target Path (the directory is found in the column specified)
// 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
HRESULT WIXAPI WcaWrapQuery(
__in_z LPCWSTR pwzQuery,
__inout LPWSTR * ppwzCustomActionData,
__in_opt DWORD dwFormatMask,
__in_opt DWORD dwComponentColumn,
__in_opt DWORD dwDirectoryColumn
);
// 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
HRESULT WIXAPI WcaWrapEmptyQuery(
__inout LPWSTR * ppwzCustomActionData
);
// Open a new unwrap query operation, with data from the ppwzCustomActionData string
HRESULT WIXAPI WcaBeginUnwrapQuery(
__out WCA_WRAPQUERY_HANDLE * phWrapQuery,
__inout LPWSTR * ppwzCustomActionData
);
// Get the number of records in a query being unwrapped
DWORD WIXAPI WcaGetQueryRecords(
__in const WCA_WRAPQUERY_HANDLE hWrapQuery
);
// This function resets a query back to its first row, so that the next fetch returns the first record
void WIXAPI WcaFetchWrappedReset(
__in WCA_WRAPQUERY_HANDLE hWrapQuery
);
// Fetch the next record in this query
// 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.
// so, don't use this function with PMSIHANDLE objects!
HRESULT WIXAPI WcaFetchWrappedRecord(
__in WCA_WRAPQUERY_HANDLE hWrapQuery,
__out MSIHANDLE* phRec
);
// Fetch the next record in the query where the string value in column dwComparisonColumn equals the value pwzExpectedValue
// 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.
// so, don't use this function with PMSIHANDLE objects!
HRESULT WIXAPI WcaFetchWrappedRecordWhereString(
__in WCA_WRAPQUERY_HANDLE hWrapQuery,
__in DWORD dwComparisonColumn,
__in_z LPCWSTR pwzExpectedValue,
__out MSIHANDLE* phRec
);
// Release a query ID (frees memory, and frees the ID for a new query)
void WIXAPI WcaFinishUnwrapQuery(
__in_opt WCA_WRAPQUERY_HANDLE hWrapQuery
);

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Nerdbank.GitVersioning" version="2.0.37-beta" targetFramework="native" developmentDependency="true" />
<package id="WixToolset.DUtil" version="4.0.3" targetFramework="native" />
</packages>

19
src/wcautil/precomp.h Normal file
Просмотреть файл

@ -0,0 +1,19 @@
#pragma once
// 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.
#include <windows.h>
#include <msiquery.h>
#include <wchar.h>
#include <strsafe.h>
const WCHAR MAGIC_MULTISZ_DELIM = 128;
#include "wcautil.h"
#include "inc\wcalog.h"
#include "inc\wcawow64.h"
#include "inc\wcawrapquery.h"
#include "wiutil.h"
#include "fileutil.h"
#include "memutil.h"
#include "strutil.h"

340
src/wcautil/qtexec.cpp Normal file
Просмотреть файл

@ -0,0 +1,340 @@
// 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.
#include "precomp.h"
#define OUTPUT_BUFFER 1024
#define ONEMINUTE 60000
static HRESULT CreatePipes(
__out HANDLE *phOutRead,
__out HANDLE *phOutWrite,
__out HANDLE *phErrWrite,
__out HANDLE *phInRead,
__out HANDLE *phInWrite
)
{
Assert(phOutRead);
Assert(phOutWrite);
Assert(phErrWrite);
Assert(phInRead);
Assert(phInWrite);
HRESULT hr = S_OK;
SECURITY_ATTRIBUTES sa;
HANDLE hOutTemp = INVALID_HANDLE_VALUE;
HANDLE hInTemp = INVALID_HANDLE_VALUE;
HANDLE hOutRead = INVALID_HANDLE_VALUE;
HANDLE hOutWrite = INVALID_HANDLE_VALUE;
HANDLE hErrWrite = INVALID_HANDLE_VALUE;
HANDLE hInRead = INVALID_HANDLE_VALUE;
HANDLE hInWrite = INVALID_HANDLE_VALUE;
// Fill out security structure so we can inherit handles
::ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
// Create pipes
if (!::CreatePipe(&hOutTemp, &hOutWrite, &sa, 0))
{
ExitOnLastError(hr, "Failed to create output pipe");
}
if (!::CreatePipe(&hInRead, &hInTemp, &sa, 0))
{
ExitOnLastError(hr, "Failed to create input pipe");
}
// Duplicate output pipe so standard error and standard output write to
// the same pipe
if (!::DuplicateHandle(::GetCurrentProcess(), hOutWrite, ::GetCurrentProcess(), &hErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
ExitOnLastError(hr, "Failed to duplicate write handle");
}
// We need to create new output read and input write handles that are
// non inheritable. Otherwise it creates handles that can't be closed.
if (!::DuplicateHandle(::GetCurrentProcess(), hOutTemp, ::GetCurrentProcess(), &hOutRead, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
ExitOnLastError(hr, "Failed to duplicate output pipe");
}
if (!::DuplicateHandle(::GetCurrentProcess(), hInTemp, ::GetCurrentProcess(), &hInWrite, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
ExitOnLastError(hr, "Failed to duplicate input pipe");
}
// now that everything has succeeded, assign to the outputs
*phOutRead = hOutRead;
hOutRead = INVALID_HANDLE_VALUE;
*phOutWrite = hOutWrite;
hOutWrite = INVALID_HANDLE_VALUE;
*phErrWrite = hErrWrite;
hErrWrite = INVALID_HANDLE_VALUE;
*phInRead = hInRead;
hInRead = INVALID_HANDLE_VALUE;
*phInWrite = hInWrite;
hInWrite = INVALID_HANDLE_VALUE;
LExit:
ReleaseFile(hOutRead);
ReleaseFile(hOutWrite);
ReleaseFile(hErrWrite);
ReleaseFile(hInRead);
ReleaseFile(hInWrite);
ReleaseFile(hOutTemp);
ReleaseFile(hInTemp);
return hr;
}
static HRESULT HandleOutput(
__in BOOL fLogOutput,
__in HANDLE hRead,
__out_z_opt LPWSTR* psczOutput
)
{
BYTE* pBuffer = NULL;
LPWSTR szLog = NULL;
LPWSTR szTemp = NULL;
LPWSTR pEnd = NULL;
LPWSTR pNext = NULL;
LPWSTR sczEscaped = NULL;
LPSTR szWrite = NULL;
DWORD dwBytes = OUTPUT_BUFFER;
BOOL bFirst = TRUE;
BOOL bUnicode = TRUE;
HRESULT hr = S_OK;
// Get buffer for output
pBuffer = static_cast<BYTE *>(MemAlloc(OUTPUT_BUFFER, FALSE));
ExitOnNull(pBuffer, hr, E_OUTOFMEMORY, "Failed to allocate buffer for output.");
while (0 != dwBytes)
{
::ZeroMemory(pBuffer, OUTPUT_BUFFER);
if (!::ReadFile(hRead, pBuffer, OUTPUT_BUFFER - 1, &dwBytes, NULL) && GetLastError() != ERROR_BROKEN_PIPE)
{
ExitOnLastError(hr, "Failed to read from handle.");
}
if (fLogOutput)
{
// Check for UNICODE or ANSI output
if (bFirst)
{
if ((isgraph(pBuffer[0]) && isgraph(pBuffer[1])) ||
(isgraph(pBuffer[0]) && isspace(pBuffer[1])) ||
(isspace(pBuffer[0]) && isgraph(pBuffer[1])) ||
(isspace(pBuffer[0]) && isspace(pBuffer[1])))
{
bUnicode = FALSE;
}
bFirst = FALSE;
}
// Keep track of output
if (bUnicode)
{
hr = StrAllocConcat(&szLog, (LPCWSTR)pBuffer, 0);
ExitOnFailure(hr, "Failed to concatenate output strings.");
if (psczOutput)
{
hr = StrAllocConcat(psczOutput, (LPCWSTR)pBuffer, 0);
ExitOnFailure(hr, "Failed to concatenate output to return string.");
}
}
else
{
hr = StrAllocStringAnsi(&szTemp, (LPCSTR)pBuffer, 0, CP_OEMCP);
ExitOnFailure(hr, "Failed to allocate output string.");
hr = StrAllocConcat(&szLog, szTemp, 0);
ExitOnFailure(hr, "Failed to concatenate output strings.");
if (psczOutput)
{
hr = StrAllocConcat(psczOutput, szTemp, 0);
ExitOnFailure(hr, "Failed to concatenate output to return string.");
}
}
// Log each line of the output
pNext = szLog;
pEnd = wcschr(szLog, L'\r');
if (NULL == pEnd)
{
pEnd = wcschr(szLog, L'\n');
}
while (pEnd && *pEnd)
{
// Find beginning of next line
pEnd[0] = 0;
++pEnd;
if ((pEnd[0] == L'\r') || (pEnd[0] == L'\n'))
{
++pEnd;
}
// Log output
hr = StrAllocString(&sczEscaped, pNext, 0);
ExitOnFailure(hr, "Failed to allocate copy of string");
hr = StrReplaceStringAll(&sczEscaped, L"%", L"%%");
ExitOnFailure(hr, "Failed to escape percent signs in string");
hr = StrAnsiAllocString(&szWrite, sczEscaped, 0, CP_OEMCP);
ExitOnFailure(hr, "Failed to convert output to ANSI");
WcaLog(LOGMSG_STANDARD, szWrite);
// Next line
pNext = pEnd;
pEnd = wcschr(pNext, L'\r');
if (NULL == pEnd)
{
pEnd = wcschr(pNext, L'\n');
}
}
hr = StrAllocString(&szTemp, pNext, 0);
ExitOnFailure(hr, "Failed to allocate string");
hr = StrAllocString(&szLog, szTemp, 0);
ExitOnFailure(hr, "Failed to allocate string");
}
}
// Print any text that didn't end with a new line
if (szLog && *szLog)
{
hr = StrReplaceStringAll(&szLog, L"%", L"%%");
ExitOnFailure(hr, "Failed to escape percent signs in string");
hr = StrAnsiAllocString(&szWrite, szLog, 0, CP_OEMCP);
ExitOnFailure(hr, "Failed to convert output to ANSI");
WcaLog(LOGMSG_VERBOSE, szWrite);
}
LExit:
ReleaseMem(pBuffer);
ReleaseStr(szLog);
ReleaseStr(szTemp);
ReleaseStr(szWrite);
ReleaseStr(sczEscaped);
return hr;
}
static HRESULT QuietExecImpl(
__inout_z LPWSTR wzCommand,
__in DWORD dwTimeout,
__in BOOL fLogCommand,
__in BOOL fLogOutput,
__out_z_opt LPWSTR* psczOutput
)
{
HRESULT hr = S_OK;
PROCESS_INFORMATION oProcInfo;
STARTUPINFOW oStartInfo;
DWORD dwExitCode = ERROR_SUCCESS;
HANDLE hOutRead = INVALID_HANDLE_VALUE;
HANDLE hOutWrite = INVALID_HANDLE_VALUE;
HANDLE hErrWrite = INVALID_HANDLE_VALUE;
HANDLE hInRead = INVALID_HANDLE_VALUE;
HANDLE hInWrite = INVALID_HANDLE_VALUE;
memset(&oProcInfo, 0, sizeof(oProcInfo));
memset(&oStartInfo, 0, sizeof(oStartInfo));
// Create output redirect pipes
hr = CreatePipes(&hOutRead, &hOutWrite, &hErrWrite, &hInRead, &hInWrite);
ExitOnFailure(hr, "Failed to create output pipes");
// Set up startup structure
oStartInfo.cb = sizeof(STARTUPINFOW);
oStartInfo.dwFlags = STARTF_USESTDHANDLES;
oStartInfo.hStdInput = hInRead;
oStartInfo.hStdOutput = hOutWrite;
oStartInfo.hStdError = hErrWrite;
// Log command if we were asked to do so
if (fLogCommand)
{
WcaLog(LOGMSG_VERBOSE, "%ls", wzCommand);
}
#pragma prefast(suppress:25028)
if (::CreateProcessW(NULL,
wzCommand, // command line
NULL, // security info
NULL, // thread info
TRUE, // inherit handles
::GetPriorityClass(::GetCurrentProcess()) | CREATE_NO_WINDOW, // creation flags
NULL, // environment
NULL, // cur dir
&oStartInfo,
&oProcInfo))
{
ReleaseFile(oProcInfo.hThread);
// Close child output/input handles so it doesn't hang
ReleaseFile(hOutWrite);
ReleaseFile(hErrWrite);
ReleaseFile(hInRead);
// Log output if we were asked to do so; otherwise just read the output handle
HandleOutput(fLogOutput, hOutRead, psczOutput);
// Wait for everything to finish
::WaitForSingleObject(oProcInfo.hProcess, dwTimeout);
if (!::GetExitCodeProcess(oProcInfo.hProcess, &dwExitCode))
{
dwExitCode = ERROR_SEM_IS_SET;
}
ReleaseFile(hOutRead);
ReleaseFile(hInWrite);
ReleaseFile(oProcInfo.hProcess);
}
else
{
ExitOnLastError(hr, "Command failed to execute.");
}
ExitOnWin32Error(dwExitCode, hr, "Command line returned an error.");
LExit:
return hr;
}
HRESULT WIXAPI QuietExec(
__inout_z LPWSTR wzCommand,
__in DWORD dwTimeout,
__in BOOL fLogCommand,
__in BOOL fLogOutput
)
{
return QuietExecImpl(wzCommand, dwTimeout, fLogCommand, fLogOutput, NULL);
}
HRESULT WIXAPI QuietExecCapture(
__inout_z LPWSTR wzCommand,
__in DWORD dwTimeout,
__in BOOL fLogCommand,
__in BOOL fLogOutput,
__out_z_opt LPWSTR* psczOutput
)
{
return QuietExecImpl(wzCommand, dwTimeout, fLogCommand, fLogOutput, psczOutput);
}

251
src/wcautil/wcalog.cpp Normal file
Просмотреть файл

@ -0,0 +1,251 @@
// 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.
#include "precomp.h"
/********************************************************************
IsVerboseLoggingPolicy() - internal helper function to detect if
policy is set for verbose logging. Does
not require database access.
********************************************************************/
static BOOL IsVerboseLoggingPolicy()
{
BOOL fVerbose = FALSE;
HKEY hkey = NULL;
WCHAR rgwc[16] = { 0 };
DWORD cb = sizeof(rgwc);
if (ERROR_SUCCESS == ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Policies\\Microsoft\\Windows\\Installer", 0, KEY_QUERY_VALUE, &hkey))
{
if (ERROR_SUCCESS == ::RegQueryValueExW(hkey, L"Logging", 0, NULL, reinterpret_cast<BYTE*>(rgwc), &cb))
{
for (LPCWSTR pwc = rgwc; (cb / sizeof(WCHAR)) > static_cast<DWORD>(pwc - rgwc) && *pwc; pwc++)
{
if (L'v' == *pwc || L'V' == *pwc)
{
fVerbose = TRUE;
break;
}
}
}
::RegCloseKey(hkey);
}
return fVerbose;
}
/********************************************************************
IsVerboseLogging() - internal helper function to detect if doing
verbose logging. Checks:
1. LOGVERBOSE property.
2. MsiLogging property contains 'v'
3. Policy from registry.
Requires database access.
********************************************************************/
BOOL WIXAPI IsVerboseLogging()
{
static int iVerbose = -1;
LPWSTR pwzMsiLogging = NULL;
if (0 > iVerbose)
{
iVerbose = WcaIsPropertySet("LOGVERBOSE");
if (0 == iVerbose)
{
// if the property wasn't set, check the MsiLogging property (MSI 4.0+)
HRESULT hr = WcaGetProperty(L"MsiLogging", &pwzMsiLogging);
ExitOnFailure(hr, "failed to get MsiLogging property");
int cchMsiLogging = lstrlenW(pwzMsiLogging);
if (0 < cchMsiLogging)
{
for (int i = 0; i < cchMsiLogging; i++)
{
if (L'v' == pwzMsiLogging[i] || L'V' == pwzMsiLogging[i])
{
iVerbose = 1;
break;
}
}
}
// last chance: Check the registry to see if the logging policy was turned on
if (0 == iVerbose && IsVerboseLoggingPolicy())
{
iVerbose = 1;
}
}
}
LExit:
ReleaseStr(pwzMsiLogging);
Assert(iVerbose >= 0);
return (BOOL)iVerbose;
}
/********************************************************************
SetVerboseLoggingAtom() - Sets one of two global Atoms to specify
if the install should do verbose logging.
Communicates the verbose setting to
deferred CAs.
Set a negative case atom so that we can
distinguish between an unset atom and the
non-verbose case. This helps prevent the
expensive regkey lookup for non-verbose.
********************************************************************/
HRESULT WIXAPI SetVerboseLoggingAtom(BOOL bValue)
{
HRESULT hr = S_OK;
ATOM atomVerbose = 0;
atomVerbose = ::GlobalFindAtomW(L"WcaVerboseLogging");
if (0 == atomVerbose && bValue)
{
atomVerbose = ::GlobalAddAtomW(L"WcaVerboseLogging");
ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaVerboseLogging global atom.");
}
else if (0 != atomVerbose && !bValue)
{
::SetLastError(ERROR_SUCCESS);
::GlobalDeleteAtom(atomVerbose);
ExitOnLastError(hr, "Failed to delete WcaVerboseLogging global atom.");
}
atomVerbose = ::GlobalFindAtomW(L"WcaNotVerboseLogging");
if (0 == atomVerbose && !bValue)
{
atomVerbose = ::GlobalAddAtomW(L"WcaNotVerboseLogging");
ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaNotVerboseLogging global atom.");
}
else if (0 != atomVerbose && bValue)
{
::SetLastError(ERROR_SUCCESS);
::GlobalDeleteAtom(atomVerbose);
ExitOnLastError(hr, "Failed to delete WcaNotVerboseLogging global atom.");
}
LExit:
return hr;
}
/********************************************************************
IsVerboseLoggingLite() - internal helper function to detect if atom was
previously set to specify verbose logging.
Falls back on policy for an installer that is
unable to set the atom (no immediate CAs).
Does not require database access.
********************************************************************/
static BOOL IsVerboseLoggingLite()
{
ATOM atomVerbose = ::GlobalFindAtomW(L"WcaVerboseLogging");
if (0 != atomVerbose)
{
return TRUE;
}
atomVerbose = ::GlobalFindAtomW(L"WcaNotVerboseLogging");
if (0 != atomVerbose)
{
return FALSE;
}
return IsVerboseLoggingPolicy();
}
/********************************************************************
WcaLog() - outputs trace and log info
*******************************************************************/
extern "C" void __cdecl WcaLog(
__in LOGLEVEL llv,
__in_z __format_string PCSTR fmt,
...
)
{
static char szFmt[LOG_BUFFER];
static char szBuf[LOG_BUFFER];
static bool fInLogPrint = false;
// prevent re-entrant logprints. (recursion issues between assert/logging code)
if (fInLogPrint)
return;
fInLogPrint = true;
if (LOGMSG_STANDARD == llv ||
(LOGMSG_VERBOSE == llv && IsVerboseLoggingLite())
#ifdef DEBUG
|| LOGMSG_TRACEONLY == llv
#endif
)
{
va_list args;
va_start(args, fmt);
LPCSTR szLogName = WcaGetLogName();
if (szLogName[0] != 0)
StringCchPrintfA(szFmt, countof(szFmt), "%s: %s", szLogName, fmt);
else
StringCchCopyA(szFmt, countof(szFmt), fmt);
StringCchVPrintfA(szBuf, countof(szBuf), szFmt, args);
va_end(args);
#ifdef DEBUG
// always write to the log in debug
#else
if (llv == LOGMSG_STANDARD || (llv == LOGMSG_VERBOSE && IsVerboseLoggingLite()))
#endif
{
PMSIHANDLE hrec = MsiCreateRecord(1);
::MsiRecordSetStringA(hrec, 0, szBuf);
// TODO: Recursion on failure. May not be safe to assert from here.
WcaProcessMessage(INSTALLMESSAGE_INFO, hrec);
}
#if DEBUG
StringCchCatA(szBuf, countof(szBuf), "\n");
OutputDebugStringA(szBuf);
#endif
}
fInLogPrint = false;
return;
}
/********************************************************************
WcaDisplayAssert() - called before Assert() dialog shows
NOTE: writes the assert string to the MSI log
********************************************************************/
extern "C" BOOL WIXAPI WcaDisplayAssert(
__in LPCSTR sz
)
{
WcaLog(LOGMSG_STANDARD, "Debug Assert Message: %s", sz);
return TRUE;
}
/********************************************************************
WcaLogError() - called before ExitOnXXX() macro exists the function
NOTE: writes the hresult and error string to the MSI log
********************************************************************/
extern "C" void WcaLogError(
__in HRESULT hr,
__in LPCSTR szMessage,
...
)
{
char szBuffer[LOG_BUFFER];
va_list dots;
va_start(dots, szMessage);
StringCchVPrintfA(szBuffer, countof(szBuffer), szMessage, dots);
va_end(dots);
// log the message if using Wca common layer
if (WcaIsInitialized())
WcaLog(LOGMSG_STANDARD, "Error 0x%x: %s", hr, szBuffer);
}

447
src/wcautil/wcascript.cpp Normal file
Просмотреть файл

@ -0,0 +1,447 @@
// 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.
#include "precomp.h"
static HRESULT CaScriptFileName(
__in WCA_ACTION action,
__in WCA_CASCRIPT script,
__in BOOL fImpersonated,
__in_z LPCWSTR wzScriptKey,
__out LPWSTR* pwzScriptName
);
/********************************************************************
WcaCaScriptCreateKey() - creates a unique script key for this
CustomAction.
********************************************************************/
extern "C" HRESULT WIXAPI WcaCaScriptCreateKey(
__out LPWSTR* ppwzScriptKey
)
{
AssertSz(WcaIsInitialized(), "WcaInitialize() should have been called before calling this function.");
HRESULT hr = S_OK;
hr = StrAllocStringAnsi(ppwzScriptKey, WcaGetLogName(), 0, CP_ACP);
ExitOnFailure(hr, "Failed to create script key.");
LExit:
return hr;
}
/********************************************************************
WcaCaScriptCreate() - creates the appropriate script for this
CustomAction Script Key.
********************************************************************/
extern "C" HRESULT WIXAPI WcaCaScriptCreate(
__in WCA_ACTION action,
__in WCA_CASCRIPT script,
__in BOOL fImpersonated,
__in_z LPCWSTR wzScriptKey,
__in BOOL fAppend,
__out WCA_CASCRIPT_HANDLE* phScript
)
{
HRESULT hr = S_OK;
LPWSTR pwzScriptPath = NULL;
HANDLE hScriptFile = INVALID_HANDLE_VALUE;
hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath);
ExitOnFailure(hr, "Failed to calculate script file name.");
hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, fAppend ? OPEN_ALWAYS : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE == hScriptFile)
{
ExitWithLastError(hr, "Failed to open CaScript: %ls", pwzScriptPath);
}
if (fAppend && INVALID_SET_FILE_POINTER == ::SetFilePointer(hScriptFile, 0, NULL, FILE_END))
{
ExitWithLastError(hr, "Failed to seek to end of file.");
}
*phScript = static_cast<WCA_CASCRIPT_HANDLE>(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE));
ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle.");
(*phScript)->pwzScriptPath = pwzScriptPath;
pwzScriptPath = NULL;
(*phScript)->hScriptFile = hScriptFile;
hScriptFile = INVALID_HANDLE_VALUE;
LExit:
if (INVALID_HANDLE_VALUE != hScriptFile)
{
::CloseHandle(hScriptFile);
}
ReleaseStr(pwzScriptPath);
return hr;
}
/********************************************************************
WcaCaScriptOpen() - opens the appropriate script for this CustomAction
Script Key.
********************************************************************/
extern "C" HRESULT WIXAPI WcaCaScriptOpen(
__in WCA_ACTION action,
__in WCA_CASCRIPT script,
__in BOOL fImpersonated,
__in_z LPCWSTR wzScriptKey,
__out WCA_CASCRIPT_HANDLE* phScript
)
{
HRESULT hr = S_OK;
LPWSTR pwzScriptPath = NULL;
HANDLE hScriptFile = INVALID_HANDLE_VALUE;
hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath);
ExitOnFailure(hr, "Failed to calculate script file name.");
hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE == hScriptFile)
{
ExitWithLastError(hr, "Failed to open CaScript: %ls", pwzScriptPath);
}
*phScript = static_cast<WCA_CASCRIPT_HANDLE>(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE));
ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle.");
(*phScript)->pwzScriptPath = pwzScriptPath;
pwzScriptPath = NULL;
(*phScript)->hScriptFile = hScriptFile;
hScriptFile = INVALID_HANDLE_VALUE;
LExit:
if (INVALID_HANDLE_VALUE != hScriptFile)
{
::CloseHandle(hScriptFile);
}
ReleaseStr(pwzScriptPath);
return hr;
}
/********************************************************************
WcaCaScriptClose() - closes an open script handle.
********************************************************************/
extern "C" void WIXAPI WcaCaScriptClose(
__in_opt WCA_CASCRIPT_HANDLE hScript,
__in WCA_CASCRIPT_CLOSE closeOperation
)
{
if (hScript)
{
if (INVALID_HANDLE_VALUE != hScript->hScriptFile)
{
::CloseHandle(hScript->hScriptFile);
}
if (hScript->pwzScriptPath)
{
if (WCA_CASCRIPT_CLOSE_DELETE == closeOperation)
{
::DeleteFileW(hScript->pwzScriptPath);
}
StrFree(hScript->pwzScriptPath);
}
MemFree(hScript);
}
}
/********************************************************************
WcaCaScriptReadAsCustomActionData() - read the ca script into a format
that is useable by other CA data
functions.
********************************************************************/
extern "C" HRESULT WIXAPI WcaCaScriptReadAsCustomActionData(
__in WCA_CASCRIPT_HANDLE hScript,
__out LPWSTR* ppwzCustomActionData
)
{
HRESULT hr = S_OK;
LARGE_INTEGER liScriptSize = { 0 };
BYTE* pbData = NULL;
DWORD cbData = 0;
if (!::GetFileSizeEx(hScript->hScriptFile, &liScriptSize))
{
ExitWithLastError(hr, "Failed to get size of ca script file.");
}
if (0 != liScriptSize.HighPart || 0 != (liScriptSize.LowPart % sizeof(WCHAR)))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
ExitOnRootFailure(hr, "Invalid data read from ca script.");
}
cbData = liScriptSize.LowPart;
if (cbData)
{
pbData = static_cast<BYTE*>(MemAlloc(cbData, TRUE));
ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate memory to read in ca script.");
if (INVALID_SET_FILE_POINTER == ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_BEGIN))
{
ExitWithLastError(hr, "Failed to reset to beginning of ca script.");
}
DWORD cbTotalRead = 0;
DWORD cbRead = 0;
do
{
if (!::ReadFile(hScript->hScriptFile, pbData + cbTotalRead, cbData - cbTotalRead, &cbRead, NULL))
{
ExitWithLastError(hr, "Failed to read from ca script.");
}
cbTotalRead += cbRead;
} while (cbRead && cbTotalRead < cbData);
if (cbTotalRead != cbData)
{
hr = E_UNEXPECTED;
ExitOnFailure(hr, "Failed to completely read ca script.");
}
}
// Add one to the allocated space because the data stored in the script is not
// null terminated. After copying the memory over, we'll ensure the string is
// null terminated.
DWORD cchData = cbData / sizeof(WCHAR) + 1;
hr = StrAlloc(ppwzCustomActionData, cchData);
ExitOnFailure(hr, "Failed to copy ca script.");
if (cbData)
{
CopyMemory(*ppwzCustomActionData, pbData, cbData);
}
(*ppwzCustomActionData)[cchData - 1] = L'\0';
LExit:
ReleaseMem(pbData);
return hr;
}
/********************************************************************
WcaCaScriptWriteString() - writes a string to the ca script.
********************************************************************/
extern "C" HRESULT WIXAPI WcaCaScriptWriteString(
__in WCA_CASCRIPT_HANDLE hScript,
__in_z LPCWSTR wzValue
)
{
HRESULT hr = S_OK;
DWORD cbFile = 0;
DWORD cbWrite = 0;
DWORD cbTotalWritten = 0;
WCHAR delim[] = { MAGIC_MULTISZ_DELIM }; // magic char followed by NULL terminator
cbFile = ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_END);
if (INVALID_SET_FILE_POINTER == cbFile)
{
ExitWithLastError(hr, "Failed to move file pointer to end of file.");
}
// If there is existing data in the file, append on the magic delimeter
// before adding our new data on the end of the file.
if (0 < cbFile)
{
cbWrite = sizeof(delim);
cbTotalWritten = 0;
while (cbTotalWritten < cbWrite)
{
DWORD cbWritten = 0;
if (!::WriteFile(hScript->hScriptFile, reinterpret_cast<BYTE*>(delim) + cbTotalWritten, cbWrite - cbTotalWritten, &cbWritten, NULL))
{
ExitWithLastError(hr, "Failed to write data to ca script.");
}
cbTotalWritten += cbWritten;
}
}
cbWrite = lstrlenW(wzValue) * sizeof(WCHAR);
cbTotalWritten = 0;
while (cbTotalWritten < cbWrite)
{
DWORD cbWritten = 0;
if (!::WriteFile(hScript->hScriptFile, reinterpret_cast<const BYTE*>(wzValue) + cbTotalWritten, cbWrite - cbTotalWritten, &cbWritten, NULL))
{
ExitWithLastError(hr, "Failed to write data to ca script.");
}
cbTotalWritten += cbWritten;
}
LExit:
return hr;
}
/********************************************************************
WcaCaScriptWriteNumber() - writes a number to the ca script.
********************************************************************/
extern "C" HRESULT WIXAPI WcaCaScriptWriteNumber(
__in WCA_CASCRIPT_HANDLE hScript,
__in DWORD dwValue
)
{
HRESULT hr = S_OK;
WCHAR wzBuffer[13] = { 0 };
hr = ::StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%u", dwValue);
ExitOnFailure(hr, "Failed to convert number into string.");
hr = WcaCaScriptWriteString(hScript, wzBuffer);
ExitOnFailure(hr, "Failed to write number to script.");
LExit:
return hr;
}
/********************************************************************
WcaCaScriptFlush() - best effort function to get script written to
disk.
********************************************************************/
extern "C" void WIXAPI WcaCaScriptFlush(
__in WCA_CASCRIPT_HANDLE hScript
)
{
::FlushFileBuffers(hScript->hScriptFile);
}
/********************************************************************
WcaCaScriptCleanup() - best effort clean-up of any cascripts left
over from this install/uninstall.
********************************************************************/
extern "C" void WIXAPI WcaCaScriptCleanup(
__in_z LPCWSTR wzProductCode,
__in BOOL fImpersonated
)
{
HRESULT hr = S_OK;
WCHAR wzTempPath[MAX_PATH];
LPWSTR pwzWildCardPath = NULL;
WIN32_FIND_DATAW fd = { 0 };
HANDLE hff = INVALID_HANDLE_VALUE;
LPWSTR pwzDeletePath = NULL;
if (fImpersonated)
{
if (!::GetTempPathW(countof(wzTempPath), wzTempPath))
{
ExitWithLastError(hr, "Failed to get temp path.");
}
}
else
{
if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath)))
{
ExitWithLastError(hr, "Failed to get windows path.");
}
hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\");
ExitOnFailure(hr, "Failed to concat Installer directory on windows path string.");
}
hr = StrAllocFormatted(&pwzWildCardPath, L"%swix%s.*.???", wzTempPath, wzProductCode);
ExitOnFailure(hr, "Failed to allocate wildcard path to ca scripts.");
hff = ::FindFirstFileW(pwzWildCardPath, &fd);
if (INVALID_HANDLE_VALUE == hff)
{
ExitWithLastError(hr, "Failed to find files with pattern: %ls", pwzWildCardPath);
}
do
{
hr = StrAllocFormatted(&pwzDeletePath, L"%s%s", wzTempPath, fd.cFileName);
if (SUCCEEDED(hr))
{
if (!::DeleteFileW(pwzDeletePath))
{
DWORD er = ::GetLastError();
WcaLog(LOGMSG_VERBOSE, "Failed to clean up CAScript file: %ls, er: %d", fd.cFileName, er);
}
}
else
{
WcaLog(LOGMSG_VERBOSE, "Failed to allocate path to clean up CAScript file: %ls, hr: 0x%x", fd.cFileName, hr);
}
} while(::FindNextFileW(hff, &fd));
LExit:
if (INVALID_HANDLE_VALUE == hff)
{
::FindClose(hff);
}
ReleaseStr(pwzDeletePath);
ReleaseStr(pwzWildCardPath);
return;
}
static HRESULT CaScriptFileName(
__in WCA_ACTION action,
__in WCA_CASCRIPT script,
__in BOOL fImpersonated,
__in_z LPCWSTR wzScriptKey,
__out LPWSTR* ppwzScriptName
)
{
HRESULT hr = S_OK;
WCHAR wzTempPath[MAX_PATH];
LPWSTR pwzProductCode = NULL;
WCHAR chInstallOrUninstall = action == WCA_ACTION_INSTALL ? L'i' : L'u';
WCHAR chScheduledOrRollback = script == WCA_CASCRIPT_SCHEDULED ? L's' : L'r';
WCHAR chUserOrMachine = fImpersonated ? L'u' : L'm';
if (fImpersonated)
{
if (!::GetTempPathW(countof(wzTempPath), wzTempPath))
{
ExitWithLastError(hr, "Failed to get temp path.");
}
}
else
{
if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath)))
{
ExitWithLastError(hr, "Failed to get windows path.");
}
hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\");
ExitOnFailure(hr, "Failed to concat Installer directory on windows path string.");
}
hr = WcaGetProperty(L"ProductCode", &pwzProductCode);
ExitOnFailure(hr, "Failed to get ProductCode.");
hr = StrAllocFormatted(ppwzScriptName, L"%swix%s.%s.%c%c%c", wzTempPath, pwzProductCode, wzScriptKey, chScheduledOrRollback, chUserOrMachine, chInstallOrUninstall);
ExitOnFailure(hr, "Failed to allocate path to ca script.");
LExit:
ReleaseStr(pwzProductCode);
return hr;
}

216
src/wcautil/wcautil.cpp Normal file
Просмотреть файл

@ -0,0 +1,216 @@
// 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.
#include "precomp.h"
// globals
HMODULE g_hInstCADLL;
// statics
static BOOL s_fInitialized;
static MSIHANDLE s_hInstall;
static MSIHANDLE s_hDatabase;
static char s_szCustomActionLogName[32];
static UINT s_iRetVal;
/********************************************************************
WcaGlobalInitialize() - initializes the Wca library, should be
called once per custom action Dll during
DllMain on DLL_PROCESS_ATTACH
********************************************************************/
extern "C" void WIXAPI WcaGlobalInitialize(
__in HINSTANCE hInst
)
{
g_hInstCADLL = hInst;
MemInitialize();
AssertSetModule(g_hInstCADLL);
AssertSetDisplayFunction(WcaDisplayAssert);
}
/********************************************************************
WcaGlobalFinalize() - finalizes the Wca library, should be the
called once per custom action Dll during
DllMain on DLL_PROCESS_DETACH
********************************************************************/
extern "C" void WIXAPI WcaGlobalFinalize()
{
#ifdef DEBUG
if (WcaIsInitialized())
{
CHAR szBuf[2048];
StringCchPrintfA(szBuf, countof(szBuf), "CustomAction %s called WcaInitialize() but not WcaFinalize()", WcaGetLogName());
AssertSz(FALSE, szBuf);
}
#endif
MemUninitialize();
g_hInstCADLL = NULL;
}
/********************************************************************
WcaInitialize() - initializes the Wca framework, should be the first
thing called by all CustomActions
********************************************************************/
extern "C" HRESULT WIXAPI WcaInitialize(
__in MSIHANDLE hInstall,
__in_z PCSTR szCustomActionLogName
)
{
WCHAR wzCAFileName[MAX_PATH] = {0};
DWORD dwMajorVersion = 0;
DWORD dwMinorVersion = 0;
// these statics should be called once per CustomAction invocation.
// Darwin does doesn't preserve DLL state across CustomAction calls so
// these should always be initialized to NULL. If that behavior changes
// we would need to do a careful review of all of our module/global data.
AssertSz(!s_fInitialized, "WcaInitialize() should only be called once per CustomAction");
Assert(NULL == s_hInstall);
Assert(NULL == s_hDatabase);
Assert(0 == *s_szCustomActionLogName);
HRESULT hr = S_OK;
s_fInitialized = TRUE;
s_iRetVal = ERROR_SUCCESS; // assume all will go well
s_hInstall = hInstall;
s_hDatabase = ::MsiGetActiveDatabase(s_hInstall); // may return null if deferred CustomAction
hr = ::StringCchCopy(s_szCustomActionLogName, countof(s_szCustomActionLogName), szCustomActionLogName);
ExitOnFailure(hr, "Failed to copy CustomAction log name: %s", szCustomActionLogName);
// If we got the database handle IE: immediate CA
if (s_hDatabase)
{
hr = SetVerboseLoggingAtom(IsVerboseLogging());
ExitOnFailure(hr, "Failed to set verbose logging global atom");
}
if (!::GetModuleFileNameW(g_hInstCADLL, wzCAFileName, countof(wzCAFileName)))
{
ExitWithLastError(hr, "Failed to get module filename");
}
FileVersion(wzCAFileName, &dwMajorVersion, &dwMinorVersion); // Ignore failure, just log 0.0.0.0
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));
Assert(s_hInstall);
LExit:
if (FAILED(hr))
{
if (s_hDatabase)
{
::MsiCloseHandle(s_hDatabase);
s_hDatabase = NULL;
}
s_hInstall = NULL;
s_fInitialized = FALSE;
}
return hr;
}
/********************************************************************
WcaFinalize() - cleans up after the Wca framework, should be the last
thing called by all CustomActions
********************************************************************/
extern "C" UINT WIXAPI WcaFinalize(
__in UINT iReturnValue
)
{
AssertSz(!WcaIsWow64Initialized(), "WcaFinalizeWow64() should be called before calling WcaFinalize()");
// clean up after our initialization
if (s_hDatabase)
{
::MsiCloseHandle(s_hDatabase);
s_hDatabase = NULL;
}
s_hInstall = NULL;
s_fInitialized = FALSE;
// if no error occurred during the processing of the CusotmAction return the passed in return value
// otherwise return the previous failure
return (ERROR_SUCCESS == s_iRetVal) ? iReturnValue : s_iRetVal;
}
/********************************************************************
WcaIsInitialized() - determines if WcaInitialize() has been called
********************************************************************/
extern "C" BOOL WIXAPI WcaIsInitialized()
{
return s_fInitialized;
}
/********************************************************************
WcaGetInstallHandle() - gets the handle to the active install session
********************************************************************/
extern "C" MSIHANDLE WIXAPI WcaGetInstallHandle()
{
AssertSz(s_hInstall, "WcaInitialize() should be called before attempting to access the install handle.");
return s_hInstall;
}
/********************************************************************
WcaGetDatabaseHandle() - gets the handle to the active database
NOTE: this function can only be used in immediate CustomActions.
Deferred CustomActions do not have access to the active
database.
********************************************************************/
extern "C" MSIHANDLE WIXAPI WcaGetDatabaseHandle()
{
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.");
return s_hDatabase;
}
/********************************************************************
WcaGetLogName() - gets the name of the CustomAction used in logging
********************************************************************/
extern "C" const char* WIXAPI WcaGetLogName()
{
return s_szCustomActionLogName;
}
/********************************************************************
WcaSetReturnValue() - sets the value to return from the CustomAction
********************************************************************/
extern "C" void WIXAPI WcaSetReturnValue(
__in UINT iReturnValue
)
{
s_iRetVal = iReturnValue;
}
/********************************************************************
WcaCancelDetected() - determines if the user has canceled yet
NOTE: returns true when WcaSetReturnValue() is set to ERROR_INSTALL_USEREXIT
********************************************************************/
extern "C" BOOL WIXAPI WcaCancelDetected()
{
return ERROR_INSTALL_USEREXIT == s_iRetVal;
}

Просмотреть файл

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$version$</version>
<authors>$authors$</authors>
<owners>$authors$</owners>
<licenseUrl>https://github.com/wixtoolset/wcautil/blob/master/LICENSE.TXT</licenseUrl>
<projectUrl>https://github.com/wixtoolset/wcautil</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<copyright>$copyright$</copyright>
</metadata>
<files>
<file src="build\$id$.props" target="build\" />
<file src="inc\*" target="build\native\include" />
<file src="..\..\build\$configuration$\v140_xp\x64\wcautil.lib" target="build\native\lib\v140\x64" />
<file src="..\..\build\$configuration$\v140_xp\x86\wcautil.lib" target="build\native\lib\v140\x86" />
<file src="..\..\build\$configuration$\v141_xp\x64\wcautil.lib" target="build\native\lib\v141\x64" />
<file src="..\..\build\$configuration$\v141_xp\x86\wcautil.lib" target="build\native\lib\v141\x86" />
</files>
</package>

Просмотреть файл

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\WixToolset.DUtil.4.0.3\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.3\build\WixToolset.DUtil.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{5B3714B6-3A76-463E-8595-D48DA276C512}</ProjectGuid>
<ConfigurationType>StaticLibrary</ConfigurationType>
<TargetName>wcautil</TargetName>
<MultiTargetLibrary>true</MultiTargetLibrary>
<PlatformToolset>v141_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<Description>WiX Toolset Custom Action native utility library</Description>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="Shared">
<Import Project="..\..\packages\Nerdbank.GitVersioning.2.0.37-beta\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\..\packages\Nerdbank.GitVersioning.2.0.37-beta\build\Nerdbank.GitVersioning.targets')" />
</ImportGroup>
<Import Project="..\NativeMultiTargeting.Build.props" />
<ItemGroup>
<ClCompile Include="exbinary.cpp" />
<ClCompile Include="wcalog.cpp" />
<ClCompile Include="wcascript.cpp" />
<ClCompile Include="wcautil.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="wcawrapquery.cpp" />
<ClCompile Include="wcawow64.cpp" />
<ClCompile Include="wcawrap.cpp" />
<ClCompile Include="qtexec.cpp" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'Win32'">
<ClInclude Include="custommsierrors.h">
<GenerateWixInclude>caerr.wxi</GenerateWixInclude>
</ClInclude>
</ItemGroup>
<ItemGroup Condition="'$(Platform)' != 'Win32'">
<ClInclude Include="custommsierrors.h" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="precomp.h" />
<ClInclude Include="inc\wcalog.h" />
<ClInclude Include="inc\wcautil.h" />
<ClInclude Include="inc\wcawow64.h" />
<ClInclude Include="inc\wcawrapquery.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Target Name="PackNativeNuget" DependsOnTargets="GetBuildVersion">
<Exec Command="nuget pack wcautil.nuspec -OutputDirectory $(BaseOutputPath) -Properties Configuration=$(Configuration);Id=WixToolset.WcaUtil;Version=&quot;$(BuildVersionSimple)&quot;;Authors=&quot;$(Authors)&quot;;Copyright=&quot;$(Copyright)&quot;;Description=&quot;$(Description)&quot;;Title=&quot;$(Title)&quot;" />
</Target>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<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>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.2.0.37-beta\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.2.0.37-beta\build\Nerdbank.GitVersioning.targets'))" />
<Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.3\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.3\build\WixToolset.DUtil.props'))" />
</Target>
</Project>

169
src/wcautil/wcawow64.cpp Normal file
Просмотреть файл

@ -0,0 +1,169 @@
// 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.
#include "precomp.h"
static HMODULE s_hKernel32;
static BOOL s_fWow64Initialized;
static BOOL (*s_pfnDisableWow64)(__out PVOID* );
static BOOL (*s_pfnRevertWow64)(__in PVOID );
static BOOL (*s_pfnIsWow64Process) (HANDLE, PBOOL);
static PVOID s_Wow64FSRevertState;
static BOOL s_fWow64FSDisabled;
/********************************************************************
WcaInitializeWow64() - Initializes the Wow64 API
********************************************************************/
extern "C" HRESULT WIXAPI WcaInitializeWow64()
{
AssertSz(WcaIsInitialized(), "WcaInitialize() should be called before calling WcaInitializeWow64()");
AssertSz(!WcaIsWow64Initialized(), "WcaInitializeWow64() should not be called twice without calling WcaFinalizeWow64()");
s_fWow64Initialized = FALSE;
HRESULT hr = S_OK;
s_Wow64FSRevertState = NULL;
s_fWow64FSDisabled = false;
// Test if we have access to the Wow64 API, and store the result in bWow64APIPresent
s_hKernel32 = ::GetModuleHandleW(L"kernel32.dll");
if (!s_hKernel32)
{
ExitWithLastError(hr, "failed to get handle to kernel32.dll");
}
// This will test if we have access to the Wow64 API
s_pfnIsWow64Process = (BOOL (*)(HANDLE, PBOOL))::GetProcAddress(s_hKernel32, "IsWow64Process");
if (NULL != s_pfnIsWow64Process)
{
s_pfnDisableWow64 = (BOOL (*)(PVOID *))::GetProcAddress(s_hKernel32, "Wow64DisableWow64FsRedirection");
// If we fail, log the error but proceed, because we may not need a particular function, or the Wow64 API at all
if (!s_pfnDisableWow64)
{
return S_FALSE;
}
s_pfnRevertWow64 = (BOOL (*)(PVOID))::GetProcAddress(s_hKernel32, "Wow64RevertWow64FsRedirection");
if (!s_pfnRevertWow64)
{
return S_FALSE;
}
if (s_pfnDisableWow64 && s_pfnRevertWow64)
{
s_fWow64Initialized = TRUE;
}
}
else
{
return S_FALSE;
}
LExit:
return hr;
}
/********************************************************************
WcaIsWow64Process() - determines if the current process is running
in WOW
********************************************************************/
extern "C" BOOL WIXAPI WcaIsWow64Process()
{
BOOL fIsWow64Process = FALSE;
if (s_fWow64Initialized)
{
if (!s_pfnIsWow64Process(GetCurrentProcess(), &fIsWow64Process))
{
// clear out the value since call failed
fIsWow64Process = FALSE;
}
}
return fIsWow64Process;
}
/********************************************************************
WcaIsWow64Initialized() - determines if WcaInitializeWow64() has
been successfully called
********************************************************************/
extern "C" BOOL WIXAPI WcaIsWow64Initialized()
{
return s_fWow64Initialized;
}
/********************************************************************
WcaDisableWow64FSRedirection() - Disables Wow64 FS Redirection
********************************************************************/
extern "C" HRESULT WIXAPI WcaDisableWow64FSRedirection()
{
AssertSz(s_fWow64Initialized && s_pfnDisableWow64 != NULL, "WcaDisableWow64FSRedirection() called, but Wow64 API was not initialized");
#ifdef DEBUG
AssertSz(!s_fWow64FSDisabled, "You must call WcaRevertWow64FSRedirection() before calling WcaDisableWow64FSRedirection() again");
#endif
HRESULT hr = S_OK;
if (s_pfnDisableWow64(&s_Wow64FSRevertState))
{
s_fWow64FSDisabled = TRUE;
}
else
{
ExitWithLastError(hr, "Failed to disable WOW64.");
}
LExit:
return hr;
}
/********************************************************************
WcaRevertWow64FSRedirection() - Reverts Wow64 FS Redirection to its
pre-disabled state
********************************************************************/
extern "C" HRESULT WIXAPI WcaRevertWow64FSRedirection()
{
AssertSz(s_fWow64Initialized && s_pfnDisableWow64 != NULL, "WcaRevertWow64FSRedirection() called, but Wow64 API was not initialized");
#ifdef DEBUG
AssertSz(s_fWow64FSDisabled, "You must call WcaDisableWow64FSRedirection() before calling WcaRevertWow64FSRedirection()");
#endif
HRESULT hr = S_OK;
if (s_pfnRevertWow64(s_Wow64FSRevertState))
{
s_fWow64FSDisabled = FALSE;
}
else
{
ExitWithLastError(hr, "Failed to revert WOW64.");
}
LExit:
return hr;
}
/********************************************************************
WcaFinalizeWow64() - Cleans up after Wow64 API Initialization
********************************************************************/
extern "C" HRESULT WIXAPI WcaFinalizeWow64()
{
if (s_fWow64FSDisabled)
{
#ifdef DEBUG
AssertSz(FALSE, "WcaFinalizeWow64() called while Filesystem redirection was disabled.");
#else
// If we aren't in debug mode, let's do our best to recover gracefully
WcaRevertWow64FSRedirection();
#endif
}
s_fWow64Initialized = FALSE;
s_pfnDisableWow64 = NULL;
s_pfnRevertWow64 = NULL;
return S_OK;
}

1643
src/wcautil/wcawrap.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,717 @@
// 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.
#include "precomp.h"
#include "wcawrapquery.h"
static const LPWSTR ISINSTALLEDCOLUMNNAME = L"ISInstalled";
static const LPWSTR ISACTIONCOLUMNNAME = L"ISAction";
static const LPWSTR SOURCEPATHCOLUMNNAME = L"SourcePath";
static const LPWSTR TARGETPATHCOLUMNNAME = L"TargetPath";
// This instantiates a new query object in the deferred CA, and returns the handle to the query
WCA_WRAPQUERY_HANDLE WIXAPI GetNewQueryInstance(
DWORD dwInColumns,
DWORD dwInRows
)
{
HRESULT hr = S_OK;
WCA_WRAPQUERY_HANDLE hNewHandle = NULL;
hNewHandle = static_cast<WCA_WRAPQUERY_HANDLE>(MemAlloc(sizeof(WCA_WRAPQUERY_STRUCT), TRUE));
if (NULL == hNewHandle)
{
hr = E_OUTOFMEMORY;
ExitOnFailure(hr, "Failed to allocate Query Instance");
}
// Initialize non-array members
hNewHandle->dwColumns = dwInColumns;
hNewHandle->dwRows = dwInRows;
hNewHandle->dwNextIndex = 0;
// Initialize arrays
if (0 != hNewHandle->dwColumns)
{
hNewHandle->pcdtColumnType = static_cast<eColumnDataType *>(MemAlloc(hNewHandle->dwColumns * sizeof(eColumnDataType), TRUE));
if (NULL == hNewHandle->pcdtColumnType)
{
hr = E_OUTOFMEMORY;
ExitOnFailure(hr, "Failed to allocate column type array");
}
hNewHandle->ppwzColumnNames = static_cast<LPWSTR *>(MemAlloc(hNewHandle->dwColumns * sizeof(LPWSTR), TRUE));
if (NULL == hNewHandle->ppwzColumnNames)
{
hr = E_OUTOFMEMORY;
ExitOnFailure(hr, "Failed to allocate column names array");
}
}
for (DWORD i=0;i<hNewHandle->dwColumns;i++)
{
hNewHandle->pcdtColumnType[i] = cdtUnknown;
hNewHandle->ppwzColumnNames[i] = NULL;
}
if (0 != hNewHandle->dwRows)
{
hNewHandle->phRecords = static_cast<MSIHANDLE *>(MemAlloc(hNewHandle->dwRows * sizeof(MSIHANDLE), TRUE));
if (NULL == hNewHandle->phRecords)
{
hr = E_OUTOFMEMORY;
ExitOnFailure(hr, "Failed to allocate records array");
}
}
for (DWORD i=0;i<hNewHandle->dwRows;i++)
{
hNewHandle->phRecords[i] = NULL;
}
return hNewHandle;
LExit:
// The handle isn't complete, so destroy any memory it allocated before returning NULL
if (NULL != hNewHandle)
{
WcaFinishUnwrapQuery(hNewHandle);
}
return NULL;
}
// This function takes in the column type string from MsiViewGetColumnInfo, and returns
// whether the column stores strings, ints, binary streams, or
// cdtUnknown if this information couldn't be determined.
eColumnDataType WIXAPI GetDataTypeFromString(
LPCWSTR pwzTypeString
)
{
if (NULL == pwzTypeString || 0 == wcslen(pwzTypeString))
{
return cdtUnknown;
}
switch (pwzTypeString[0])
{
case 'v':
case 'V':
case 'o':
case 'O':
return cdtStream;
case 'g':
case 'G':
case 's':
case 'S':
case 'l':
case 'L':
return cdtString;
case 'i':
case 'I':
case 'j':
case 'J':
return cdtInt;
default:
return cdtUnknown;
}
}
HRESULT WIXAPI WcaWrapEmptyQuery(
__inout LPWSTR * ppwzCustomActionData
)
{
HRESULT hr = S_OK;
WcaLog(LOGMSG_TRACEONLY, "Wrapping result of empty query");
hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableBegin), ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write table begin marker to custom action data");
hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write number of columns to custom action data");
hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write number of rows to custom action data");
hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableFinish), ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write table finish marker to custom action data");
// WcaLog(LOGMSG_TRACEONLY, "Finished wrapping result of empty query");
LExit:
return hr;
}
/********************************************************************
WcaWrapQuery() - wraps a view and transmits it through the
CustomActionData property
********************************************************************/
HRESULT WIXAPI WcaWrapQuery(
__in_z LPCWSTR pwzQuery,
__inout LPWSTR * ppwzCustomActionData,
__in_opt DWORD dwFormatMask,
__in_opt DWORD dwComponentColumn,
__in_opt DWORD dwDirectoryColumn
)
{
HRESULT hr = S_OK;
HRESULT hrTemp = S_OK;
UINT er = ERROR_SUCCESS;
UINT cViewColumns;
eColumnDataType *pcdtColumnTypeList = NULL;
LPWSTR pwzData = NULL;
LPWSTR pwzColumnData = NULL;
LPWSTR pwzRecordData = NULL;
BYTE* pbData = NULL;
DWORD dwNumRecords = 0;
BOOL fAddComponentState = FALSE; // Add two integer columns to the right side of the query - ISInstalled, and ISAction
BOOL fAddDirectoryPath = FALSE; // Add two string columns to the right side of the query - SourcePath, and TargetPath
int iTempInteger = 0;
WCHAR wzPath[MAX_PATH + 1];
DWORD dwLen;
INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
PMSIHANDLE hColumnTypes, hColumnNames;
PMSIHANDLE hView, hRec;
WcaLog(LOGMSG_TRACEONLY, "Wrapping result of query: \"%ls\"", pwzQuery);
// open the view
hr = WcaOpenExecuteView(pwzQuery, &hView);
ExitOnFailure(hr, "Failed to execute view");
hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableBegin), ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write table begin marker to custom action data");
// WcaLog(LOGMSG_TRACEONLY, "Starting to wrap table's column information", pwzQuery);
// Use GetColumnInfo to populate the names of the columns.
er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_TYPES, &hColumnTypes);
ExitOnWin32Error(er, hr, "Failed to get column types");
er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_NAMES, &hColumnNames);
ExitOnWin32Error(er, hr, "Failed to get column names");
cViewColumns = ::MsiRecordGetFieldCount(hColumnTypes);
if (0xFFFFFFFF == cViewColumns)
{
// According to MSDN, this return value only happens when the handle is invalid
hr = E_HANDLE;
ExitOnFailure(hr, "Failed to get number of fields in record");
}
if (cViewColumns >= dwComponentColumn)
{
fAddComponentState = TRUE;
}
else if (0xFFFFFFFF != dwComponentColumn)
{
hr = E_INVALIDARG;
ExitOnFailure(hr, "Component column %d out of range", dwComponentColumn);
}
if (cViewColumns >= dwDirectoryColumn)
{
fAddDirectoryPath = TRUE;
}
else if (0xFFFFFFFF != dwDirectoryColumn)
{
hr = E_INVALIDARG;
ExitOnFailure(hr, "Directory column %d out of range", dwDirectoryColumn);
}
hr = WcaWriteIntegerToCaData(static_cast<int>(cViewColumns) + 2 * static_cast<int>(fAddComponentState) + 2 * static_cast<int>(fAddDirectoryPath), ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write number of columns to custom action data");
pcdtColumnTypeList = new eColumnDataType[cViewColumns];
ExitOnNull(pcdtColumnTypeList, hr, E_OUTOFMEMORY, "Failed to allocate memory to store column info types");
// Loop through all the columns reporting information about each one
for (DWORD i = 0; i < cViewColumns; i++)
{
hr = WcaGetRecordString(hColumnNames, i+1, &pwzData);
ExitOnFailure(hr, "Failed to get the column %d name", i+1);
hr = WcaWriteStringToCaData(pwzData, &pwzColumnData);
ExitOnFailure(hr, "Failed to write column %d name %ls to custom action data", i+1, pwzData);
hr = WcaGetRecordString(hColumnTypes, i+1, &pwzData);
ExitOnFailure(hr, "Failed to get the column type string for column %d", i+1);
pcdtColumnTypeList[i] = GetDataTypeFromString(pwzData);
if (cdtUnknown == pcdtColumnTypeList[i])
{
hr = E_INVALIDARG;
ExitOnFailure(hr, "Failed to recognize column %d type string: %ls", i+1, pwzData);
}
hr = WcaWriteIntegerToCaData(pcdtColumnTypeList[i], &pwzColumnData);
ExitOnFailure(hr, "Failed to write column %d type enumeration to custom action data", i+1);
}
// Add two integer columns to the right side of the query - ISInstalled, and ISAction
if (fAddComponentState)
{
hr = WcaWriteStringToCaData(ISINSTALLEDCOLUMNNAME, &pwzColumnData);
ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, ISINSTALLEDCOLUMNNAME);
hr = WcaWriteIntegerToCaData(cdtInt, &pwzColumnData);
ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1);
hr = WcaWriteStringToCaData(ISACTIONCOLUMNNAME, &pwzColumnData);
ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, ISACTIONCOLUMNNAME);
hr = WcaWriteIntegerToCaData(cdtInt, &pwzColumnData);
ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1);
}
if (fAddDirectoryPath)
{
hr = WcaWriteStringToCaData(SOURCEPATHCOLUMNNAME, &pwzColumnData);
ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, SOURCEPATHCOLUMNNAME);
hr = WcaWriteIntegerToCaData(cdtString, &pwzColumnData);
ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1);
hr = WcaWriteStringToCaData(TARGETPATHCOLUMNNAME, &pwzColumnData);
ExitOnFailure(hr, "Failed to write extra column %d name %ls to custom action data", cViewColumns + 1, TARGETPATHCOLUMNNAME);
hr = WcaWriteIntegerToCaData(cdtString, &pwzColumnData);
ExitOnFailure(hr, "Failed to write extra column %d type to custom action data", cViewColumns + 1);
}
// Begin wrapping actual table data
//WcaLog(LOGMSG_TRACEONLY, "Starting to wrap table data", pwzQuery);
while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
{
hr = WcaWriteIntegerToCaData(static_cast<int>(wqaRowBegin), &pwzRecordData);
ExitOnFailure(hr, "Failed to write row begin marker to custom action data");
for (DWORD i = 0; i < cViewColumns; i++)
{
switch (pcdtColumnTypeList[i])
{
case cdtString:
// 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
if (i < (sizeof(dwFormatMask) * 8) && (dwFormatMask & (1 << i)))
{
hr = WcaGetRecordFormattedString(hRec, i + 1, &pwzData);
}
else
{
hr = WcaGetRecordString(hRec, i + 1, &pwzData);
}
ExitOnFailure(hr, "Failed to get string for column %d", i + 1);
hr = WcaWriteStringToCaData(pwzData, &pwzRecordData);
ExitOnFailure(hr, "Failed to write string to temporary record custom action data for column %d", i + 1);
break;
case cdtInt:
if (i < (sizeof(dwFormatMask) * 8) && (dwFormatMask & (1 << i)))
{
hr = WcaGetRecordFormattedInteger(hRec, i + 1, &iTempInteger);
}
else
{
hr = WcaGetRecordInteger(hRec, i + 1, &iTempInteger);
}
ExitOnFailure(hr, "Failed to get integer for column %d", i + 1);
hr = WcaWriteIntegerToCaData(iTempInteger, &pwzRecordData);
ExitOnFailure(hr, "Failed to write integer to temporary record custom action data for column %d", i + 1);
break;
case cdtStream:
hr = E_NOTIMPL;
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);
break;
case cdtUnknown:
default:
hr = E_INVALIDARG;
ExitOnFailure(hr, "Failed to recognize column type enumeration %d for column %d", pcdtColumnTypeList[i], i + 1);
}
}
// Add two integer columns to the right side of the query - ISInstalled, and ISAction
if (fAddComponentState)
{
// Get the component ID
hr = WcaGetRecordString(hRec, dwComponentColumn, &pwzData);
ExitOnFailure(hr, "Failed to get component from column %d while adding extra columns", dwComponentColumn);
if (0 == lstrlenW(pwzData))
{
// If no component was provided, set these both to zero as though a structure to store them were allocated with memory zero'd out
isInstalled = (INSTALLSTATE)0;
isAction = (INSTALLSTATE)0;
}
else
{
er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction);
// 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
if (FAILED(HRESULT_FROM_WIN32(er)))
{
ExitOnFailure(hr, "Failed to get component state for component %ls", pwzData);
}
}
hr = WcaWriteIntegerToCaData(isInstalled, &pwzRecordData);
ExitOnFailure(hr, "Failed to write extra ISInstalled column to custom action data");
hr = WcaWriteIntegerToCaData(isAction, &pwzRecordData);
ExitOnFailure(hr, "Failed to write extra ISAction column to custom action data");
}
// Add two string columns to the right side of the query - SourcePath, and TargetPath
if (fAddDirectoryPath)
{
hr = WcaGetRecordString(hRec, dwDirectoryColumn, &pwzData);
// If this fails, ignore it, and just leave those columns blank
if (SUCCEEDED(hr))
{
// Only get source path if the component state is INSTALLSTATE_SOURCE, or if we have no component to check the installstate of
if (INSTALLSTATE_SOURCE == isAction || !fAddComponentState)
{
dwLen = countof(wzPath);
er = ::MsiGetSourcePathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
hrTemp = HRESULT_FROM_WIN32(er);
if (dwLen > countof(wzPath))
{
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
ExitOnRootFailure(hr, "Failed to record entire Source Path for Directory %ls because its length was greater than MAX_PATH.", pwzData);
}
if (SUCCEEDED(hrTemp))
{
hr = WcaWriteStringToCaData(wzPath, &pwzRecordData);
ExitOnFailure(hr, "Failed to write source path string to record data string");
}
else
{
hr = WcaWriteStringToCaData(L"", &pwzRecordData);
ExitOnFailure(hr, "Failed to write empty source path string to record data string");
}
}
else
{
hr = WcaWriteStringToCaData(L"", &pwzRecordData);
ExitOnFailure(hr, "Failed to write empty source path string before writing target path string to record data string");
}
dwLen = countof(wzPath);
er = ::MsiGetTargetPathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
hrTemp = HRESULT_FROM_WIN32(er);
if (dwLen > countof(wzPath))
{
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
ExitOnRootFailure(hr, "Failed to record entire Source Path for Directory %ls because its length was greater than MAX_PATH.", pwzData);
}
if (SUCCEEDED(hrTemp))
{
hr = WcaWriteStringToCaData(wzPath, &pwzRecordData);
ExitOnFailure(hr, "Failed to write target path string to record data string");
}
else
{
hr = WcaWriteStringToCaData(L"", &pwzRecordData);
ExitOnFailure(hr, "Failed to write empty target path string to record data string");
}
}
else
{
// Write both fields as blank
hr = WcaWriteStringToCaData(L"", &pwzRecordData);
hr = WcaWriteStringToCaData(L"", &pwzRecordData);
}
}
hr = WcaWriteIntegerToCaData(static_cast<int>(wqaRowFinish), &pwzRecordData);
ExitOnFailure(hr, "Failed to write row finish marker to custom action data");
++dwNumRecords;
}
hr = WcaWriteIntegerToCaData(dwNumRecords, ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write number of records to custom action data");
if (NULL != pwzColumnData)
{
hr = WcaWriteStringToCaData(pwzColumnData, ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write column data to custom action data");
}
if (NULL != pwzRecordData)
{
hr = WcaWriteStringToCaData(pwzRecordData, ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write record data to custom action data");
}
hr = WcaWriteIntegerToCaData(static_cast<int>(wqaTableFinish), ppwzCustomActionData);
ExitOnFailure(hr, "Failed to write table finish marker to custom action data");
// WcaLog(LOGMSG_TRACEONLY, "Finished wrapping result of query: \"%ls\"", pwzQuery);
LExit:
ReleaseStr(pwzData);
ReleaseStr(pwzColumnData);
ReleaseStr(pwzRecordData);
ReleaseMem(pbData);
return hr;
}
/********************************************************************
WcaBeginUnwrapQuery() - unwraps a view for direct access from the
CustomActionData property
********************************************************************/
HRESULT WIXAPI WcaBeginUnwrapQuery(
__out WCA_WRAPQUERY_HANDLE * phWrapQuery,
__inout LPWSTR * ppwzCustomActionData
)
{
HRESULT hr = S_OK;
int iTempInteger = 0;
int iColumns = 0;
int iRows = 0;
BYTE* pbData = NULL;
LPWSTR pwzData = NULL;
WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
WcaLog(LOGMSG_TRACEONLY, "Unwrapping a query from custom action data");
hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
if (wqaTableBegin != iTempInteger)
{
hr = E_INVALIDARG;
}
ExitOnFailure(hr, "Failed to read table begin marker from custom action data (read %d instead)", iTempInteger);
hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iColumns);
ExitOnFailure(hr, "Failed to read number of columns from custom action data");
hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iRows);
ExitOnFailure(hr, "Failed to read number of rows from custom action data");
hWrapQuery = GetNewQueryInstance(iColumns, iRows);
if (NULL == hWrapQuery)
{
hr = E_POINTER;
}
ExitOnFailure(hr, "Failed to get a query instance with %d columns and %d rows", iColumns, iRows);
for (int i = 0; i < iColumns; i++)
{
hr = WcaReadStringFromCaData(ppwzCustomActionData, &(hWrapQuery->ppwzColumnNames[i]));
ExitOnFailure(hr, "Failed to read column %d's name from custom action data", i+1);
hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
if (cdtString != iTempInteger && cdtInt != iTempInteger && cdtStream != iTempInteger)
{
hr = E_INVALIDARG;
}
ExitOnFailure(hr, "Failed to read column %d's type from custom action data", i+1);
// Set the column type into the actual data structure
hWrapQuery->pcdtColumnType[i] = (eColumnDataType)iTempInteger;
}
for (int i = 0; i < iRows; i++)
{
hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
if (wqaRowBegin != iTempInteger)
{
hr = E_INVALIDARG;
}
ExitOnFailure(hr, "Failed to read begin row marker from custom action data (read %d instead)", iTempInteger);
hWrapQuery->phRecords[i] = ::MsiCreateRecord((unsigned int)iColumns);
for (int j = 0; j < iColumns; j++)
{
switch (hWrapQuery->pcdtColumnType[j])
{
case cdtString:
hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
ExitOnFailure(hr, "Failed to read string from custom action data");
hr = WcaSetRecordString(hWrapQuery->phRecords[i], j+1, pwzData);
ExitOnFailure(hr, "Failed to write string %ls to record in column %d", pwzData, j+1);
break;
case cdtInt:
WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
ExitOnFailure(hr, "Failed to read integer from custom action data");
WcaSetRecordInteger(hWrapQuery->phRecords[i], j+1, iTempInteger);
ExitOnFailure(hr, "Failed to write integer %d to record in column %d", iTempInteger, j+1);
break;
case cdtStream:
hr = E_NOTIMPL;
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");
break;
case cdtUnknown:
default:
hr = E_INVALIDARG;
ExitOnFailure(hr, "Failed to recognize column type enumeration %d for column %d", hWrapQuery->pcdtColumnType[j+1], i+1);
}
}
hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
if (wqaRowFinish != iTempInteger)
{
hr = E_INVALIDARG;
}
ExitOnFailure(hr, "Failed to read row finish marker from custom action data (read %d instead)", iTempInteger);
}
hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iTempInteger);
if (wqaTableFinish != iTempInteger)
{
hr = E_INVALIDARG;
}
ExitOnFailure(hr, "Failed to read table finish marker from custom action data (read %d instead)", iTempInteger);
*phWrapQuery = hWrapQuery;
// WcaLog(LOGMSG_TRACEONLY, "Successfully finished unwrapping a query from custom action data");
LExit:
ReleaseStr(pwzData);
ReleaseMem(pbData);
return hr;
}
// This function returns the total number of records in a query
DWORD WIXAPI WcaGetQueryRecords(
__in const WCA_WRAPQUERY_HANDLE hWrapQuery
)
{
return hWrapQuery->dwRows;
}
// This function resets a query back to its first row, so that the next fetch returns the first record
void WIXAPI WcaFetchWrappedReset(
__in WCA_WRAPQUERY_HANDLE hWrapQuery
)
{
hWrapQuery->dwNextIndex = 0;
}
// Fetches the next record in the query
// 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.
// so, don't use this function with PMSIHANDLE objects!
HRESULT WIXAPI WcaFetchWrappedRecord(
__in WCA_WRAPQUERY_HANDLE hWrapQuery,
__out MSIHANDLE* phRec
)
{
DWORD dwNextIndex = hWrapQuery->dwNextIndex;
if (dwNextIndex >= hWrapQuery->dwRows)
{
return E_NOMOREITEMS;
}
if (NULL == hWrapQuery->phRecords[dwNextIndex])
{
return E_HANDLE;
}
*phRec = hWrapQuery->phRecords[hWrapQuery->dwNextIndex];
// Increment our next index variable
++hWrapQuery->dwNextIndex;
return S_OK;
}
// Fetch the next record in the query where the string value in column dwComparisonColumn equals the value pwzExpectedValue
// 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.
// so, don't use this function with PMSIHANDLE objects!
HRESULT WIXAPI WcaFetchWrappedRecordWhereString(
__in WCA_WRAPQUERY_HANDLE hWrapQuery,
__in DWORD dwComparisonColumn,
__in_z LPCWSTR pwzExpectedValue,
__out MSIHANDLE* phRec
)
{
HRESULT hr = S_OK;
MSIHANDLE hRec = NULL;
LPWSTR pwzData = NULL;
while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
{
ExitOnFailure(hr, "Failed to fetch a wrapped record");
hr = WcaGetRecordString(hRec, dwComparisonColumn, &pwzData);
ExitOnFailure(hr, "Failed to get record string in column %d", dwComparisonColumn);
if (0 == lstrcmpW(pwzData, pwzExpectedValue))
{
*phRec = hRec;
ExitFunction1(hr = S_OK);
}
}
// If we errored here but not because there were no records left, write an error to the log
if (hr != E_NOMOREITEMS)
{
ExitOnFailure(hr, "Failed while searching for a wrapped record where column %d is set to %ls", dwComparisonColumn, pwzExpectedValue);
}
LExit:
ReleaseStr(pwzData);
return hr;
}
/********************************************************************
WcaBeginUnwrapQuery() - Finishes unwrapping a view for direct access
from the CustomActionData property
********************************************************************/
void WIXAPI WcaFinishUnwrapQuery(
__in_opt WCA_WRAPQUERY_HANDLE hWrapQuery
)
{
if (NULL == hWrapQuery)
{
WcaLog(LOGMSG_TRACEONLY, "Failed to finish an unwrap query - ignoring");
return;
}
ReleaseMem(hWrapQuery->pcdtColumnType);
for (DWORD i=0;i<hWrapQuery->dwColumns;i++)
{
ReleaseStr(hWrapQuery->ppwzColumnNames[i]);
}
ReleaseMem(hWrapQuery->ppwzColumnNames);
for (DWORD i=0;i<hWrapQuery->dwRows;i++)
{
if (NULL != hWrapQuery->phRecords[i])
{
::MsiCloseHandle(hWrapQuery->phRecords[i]);
}
}
ReleaseMem(hWrapQuery->phRecords);
ReleaseMem(hWrapQuery);
}

11
version.json Normal file
Просмотреть файл

@ -0,0 +1,11 @@
{
"version": "4.0",
"publicReleaseRefSpec": [
"^refs/heads/master$"
],
"cloudBuild": {
"buildNumber": {
"enabled": true
}
}
}

31
wcautil.sln Normal file
Просмотреть файл

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 15.0.26124.0
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wcautil", "src\wcautil\wcautil.vcxproj", "{1244E671-F108-4334-BA52-8A7517F26ECD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1244E671-F108-4334-BA52-8A7517F26ECD}.Debug|x64.ActiveCfg = Debug|x64
{1244E671-F108-4334-BA52-8A7517F26ECD}.Debug|x64.Build.0 = Debug|x64
{1244E671-F108-4334-BA52-8A7517F26ECD}.Debug|x86.ActiveCfg = Debug|Win32
{1244E671-F108-4334-BA52-8A7517F26ECD}.Debug|x86.Build.0 = Debug|Win32
{1244E671-F108-4334-BA52-8A7517F26ECD}.Release|x64.ActiveCfg = Release|x64
{1244E671-F108-4334-BA52-8A7517F26ECD}.Release|x64.Build.0 = Release|x64
{1244E671-F108-4334-BA52-8A7517F26ECD}.Release|x86.ActiveCfg = Release|Win32
{1244E671-F108-4334-BA52-8A7517F26ECD}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DD209744-C40E-4C34-8CB4-BC6B71F9A133}
EndGlobalSection
EndGlobal