Author: Matti Picus <[email protected]>
Branch: wininstaller_py2
Changeset: r98023:eab10f6abe32
Date: 2019-11-11 07:37 -0500
http://bitbucket.org/pypy/pypy/changeset/eab10f6abe32/

Log:    backport wininstaller, PCbuild directories from windowsinstaller

diff too long, truncating to 2000 out of 6290 lines

diff --git a/PCbuild/find_msbuild.bat b/PCbuild/find_msbuild.bat
new file mode 100644
--- /dev/null
+++ b/PCbuild/find_msbuild.bat
@@ -0,0 +1,60 @@
+@rem
+@rem Searches for MSBuild.exe. This is the only tool we need to initiate
+@rem a build, so we no longer search for the full VC toolset.
+@rem
+@rem This file is supposed to modify the state of the caller (specifically
+@rem the MSBUILD variable), so we do not use setlocal or echo, and avoid
+@rem changing any other persistent state.
+@rem
+
+@rem No arguments provided means do full search
+@if '%1' EQU '' goto :begin_search
+
+@rem One argument may be the full path. Use a goto so we don't try to
+@rem parse the next if statement - incorrect quoting in the multi-arg
+@rem case can cause us to break immediately.
+@if '%2' EQU '' goto :one_arg
+
+@rem Entire command line may represent the full path if quoting failed.
+@if exist "%*" (set MSBUILD="%*") & (set _Py_MSBuild_Source=environment) & 
goto :found
+@goto :begin_search
+
+:one_arg
+@if exist "%~1" (set MSBUILD="%~1") & (set _Py_MSBuild_Source=environment) & 
goto :found
+
+:begin_search
+@set MSBUILD=
+
+@rem If msbuild.exe is on the PATH, assume that the user wants that one.
+@where msbuild > "%TEMP%\msbuild.loc" 2> nul && set /P MSBUILD= < 
"%TEMP%\msbuild.loc" & del "%TEMP%\msbuild.loc"
+@if exist "%MSBUILD%" set MSBUILD="%MSBUILD%" & (set _Py_MSBuild_Source=PATH) 
& goto :found
+
+@rem VS 2017 sets exactly one install as the "main" install, so we may find 
MSBuild in there.
+@reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v 
15.0 /reg:32 >nul 2>nul
+@if NOT ERRORLEVEL 1 @for /F "tokens=1,2*" %%i in ('reg query 
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v 15.0 /reg:32') 
DO @(
+    @if "%%i"=="15.0" @if exist "%%k\MSBuild\15.0\Bin\msbuild.exe" @(set 
MSBUILD="%%k\MSBuild\15.0\Bin\msbuild.exe")
+)
+@if exist %MSBUILD% (set _Py_MSBuild_Source=Visual Studio 2017 registry) & 
goto :found
+
+@rem VS 2015 and earlier register MSBuild separately, so we can find it.
+@reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" 
/v MSBuildToolsPath /reg:32 >nul 2>nul
+@if NOT ERRORLEVEL 1 @for /F "tokens=1,2*" %%i in ('reg query 
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v 
MSBuildToolsPath /reg:32') DO @(
+    @if "%%i"=="MSBuildToolsPath" @if exist "%%k\msbuild.exe" @(set 
MSBUILD="%%k\msbuild.exe")
+)
+@if exist %MSBUILD% (set _Py_MSBuild_Source=registry) & goto :found
+
+
+@exit /b 1
+
+:found
+@pushd %MSBUILD% >nul 2>nul
+@if not ERRORLEVEL 1 @(
+  @if exist msbuild.exe @(set MSBUILD="%CD%\msbuild.exe") else @(set MSBUILD=)
+  @popd
+)
+
+@if defined MSBUILD @echo Using %MSBUILD% (found in the %_Py_MSBuild_Source%)
+@if not defined MSBUILD @echo Failed to find MSBuild
+@set _Py_MSBuild_Source=
+@if not defined MSBUILD @exit /b 1
+@exit /b 0
diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props
new file mode 100644
--- /dev/null
+++ b/PCbuild/pyproject.props
@@ -0,0 +1,197 @@
+&#65279;<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"; 
TreatAsLocalProperty="Py_IntDir">
+  <PropertyGroup Label="Globals">
+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == 
''">10.0</VisualStudioVersion>
+    <OutDir>$(BuildPath)</OutDir>
+    <OutDir Condition="!HasTrailingSlash($(OutDir))">$(OutDir)\</OutDir>
+    <Py_IntDir Condition="'$(Py_IntDir)' == 
''">$(MSBuildThisFileDirectory)obj\</Py_IntDir>
+    
<IntDir>$(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)$(ArchName)_$(Configuration)\$(ProjectName)\</IntDir>
+    <IntDir>$(IntDir.Replace(`\\`, `\`))</IntDir>
+    <TargetName Condition="'$(TargetName)' == ''">$(ProjectName)</TargetName>
+    <TargetName>$(TargetName)$(PyDebugExt)</TargetName>
+    <GenerateManifest>false</GenerateManifest>
+    <EmbedManifest>false</EmbedManifest>
+    <SupportPGO Condition="'$(SupportPGO)' == ''">true</SupportPGO>
+    <SupportSigning Condition="'$(SupportSigning)' == ''">true</SupportSigning>
+    <SupportSigning Condition="'$(Configuration)' == 
'Debug'">false</SupportSigning>
+    <SupportSigning Condition="'$(ConfigurationType)' == 
'StaticLibrary'">false</SupportSigning>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <_DebugPreprocessorDefinition>NDEBUG;</_DebugPreprocessorDefinition>
+    <_DebugPreprocessorDefinition Condition="$(Configuration) == 
'Debug'">_DEBUG;</_DebugPreprocessorDefinition>
+    <_PlatformPreprocessorDefinition>_WIN32;</_PlatformPreprocessorDefinition>
+    <_PlatformPreprocessorDefinition Condition="$(Platform) == 
'x64'">_WIN64;_M_X64;</_PlatformPreprocessorDefinition>
+    <_PydPreprocessorDefinition Condition="$(TargetExt) == 
'.pyd'">Py_BUILD_CORE_MODULE;</_PydPreprocessorDefinition>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      
<AdditionalIncludeDirectories>$(PySourcePath)Include;$(PySourcePath)Include\internal;$(PySourcePath)PC;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      
<PreprocessorDefinitions>WIN32;$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PydPreprocessorDefinition)%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <StringPooling>true</StringPooling>
+      <ExceptionHandling></ExceptionHandling>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <CompileAs>Default</CompileAs>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <EnableEnhancedInstructionSet 
Condition="'$(Platform)'=='Win32'">NoExtensions</EnableEnhancedInstructionSet>
+      <InlineFunctionExpansion 
Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OnlyExplicitInline</InlineFunctionExpansion>
+      <InlineFunctionExpansion 
Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OnlyExplicitInline</InlineFunctionExpansion>
+    </ClCompile>
+    <ClCompile Condition="$(Configuration) == 'Debug'">
+      <Optimization>Disabled</Optimization>
+      <WholeProgramOptimization>false</WholeProgramOptimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <ClCompile Condition="$(ICCBuild) == 'true'">
+      <FloatingPointModel>Strict</FloatingPointModel>
+    </ClCompile>
+    <Link>
+      
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
+      <SubSystem>Windows</SubSystem>
+      <RandomizedBaseAddress>true</RandomizedBaseAddress>
+      <DataExecutionPrevention>true</DataExecutionPrevention>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      
<IgnoreSpecificDefaultLibraries>LIBC;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+      <TargetMachine>MachineX86</TargetMachine>
+      <TargetMachine Condition="'$(Platform)' == 
'x64'">MachineX64</TargetMachine>
+      <ProfileGuidedDatabase 
Condition="$(SupportPGO)">$(OutDir)$(TargetName).pgd</ProfileGuidedDatabase>
+      <LinkTimeCodeGeneration Condition="$(Configuration) == 
'Release'">UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+      <LinkTimeCodeGeneration Condition="$(SupportPGO) and $(Configuration) == 
'PGInstrument'">PGInstrument</LinkTimeCodeGeneration>
+      <LinkTimeCodeGeneration Condition="$(SupportPGO) and $(Configuration) == 
'PGUpdate'">PGUpdate</LinkTimeCodeGeneration>
+    </Link>
+    <Lib>
+      <LinkTimeCodeGeneration Condition="$(Configuration) == 
'Release'">true</LinkTimeCodeGeneration>
+      <LinkTimeCodeGeneration Condition="$(SupportPGO) and $(Configuration) == 
'PGInstrument'">true</LinkTimeCodeGeneration>
+      <LinkTimeCodeGeneration Condition="$(SupportPGO) and $(Configuration) == 
'PGUpdate'">true</LinkTimeCodeGeneration>
+    </Lib>
+    <ResourceCompile>
+      
<AdditionalIncludeDirectories>$(PySourcePath)PC;$(PySourcePath)Include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      
<PreprocessorDefinitions>$(_DebugPreprocessorDefinition)%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <Culture>0x0409</Culture>
+    </ResourceCompile>
+    <Midl>
+      
<PreprocessorDefinitions>$(_DebugPreprocessorDefinition)%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MkTypLibCompatible>true</MkTypLibCompatible>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TargetEnvironment>Win32</TargetEnvironment>
+      <TargetEnvironment Condition="'$(Platform)' == 
'x64'">X64</TargetEnvironment>
+      <OutputDirectory>$(IntDir)</OutputDirectory>
+      
<InterfaceIdentifierFileName>$(MSBuildProjectName)_i.c</InterfaceIdentifierFileName>
+      <ProxyFileName>$(MSBuildProjectName)_p.c</ProxyFileName>
+    </Midl>
+  </ItemDefinitionGroup>
+
+  <Target Name="GeneratePythonNtRcH"
+          BeforeTargets="ClCompile"
+          Inputs="$(PySourcePath)Include\patchlevel.h"
+          Outputs="$(IntDir)pythonnt_rc.h">
+    <WriteLinesToFile File="$(IntDir)pythonnt_rc.h" Overwrite="true" 
Encoding="ascii"
+                      Lines='/* This file created by pyproject.props 
/t:GeneratePythonNtRcH */
+#define FIELD3 $(Field3Value)
+#define MS_DLL_ID "$(SysWinVer)"
+#define PYTHON_DLL_NAME "$(TargetName)$(TargetExt)"
+' />
+    <ItemGroup>
+        <FileWrites Include="$(IntDir)pythonnt_rc.h" />
+    </ItemGroup>
+  </Target>
+
+  <UsingTask TaskName="KillPython" TaskFactory="CodeTaskFactory" 
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
+    <ParameterGroup>
+      <FileName Required="true" />
+    </ParameterGroup>
+    <Task>
+      <Using Namespace="System.Diagnostics"/>
+      <Using Namespace="System.IO"/>
+      <Using Namespace="System.Runtime.InteropServices"/>
+      <Using Namespace="System.Text"/>
+      <Code Type="Method" Language="cs">
+<![CDATA[
+[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
+public static extern bool QueryFullProcessImageName([In]IntPtr hProcess, 
[In]int dwFlags,
+                                                    [Out]StringBuilder 
lpExeName, ref int lpdwSize);
+public override bool Execute() {
+    string fullPath = Path.GetFullPath(FileName);
+    Log.LogMessage("Looking for " + fullPath, MessageImportance.Normal);
+    foreach (Process p in Process.GetProcesses()) {
+        try {
+            int pathLength = 32768;
+            StringBuilder pathBuilder = new StringBuilder(pathLength);
+            if (QueryFullProcessImageName(p.Handle, 0, pathBuilder, ref 
pathLength)) {
+                string exeName = Path.GetFullPath(pathBuilder.ToString());
+                Log.LogMessage("Found running process: " + exeName, 
MessageImportance.Low);
+                if (fullPath.Equals(exeName, 
StringComparison.OrdinalIgnoreCase)) {
+                    Log.LogMessage("Terminating " + exeName, 
MessageImportance.High);
+                    p.Kill();
+                }
+            }
+        } catch {
+        }
+    }
+    return true;
+}
+]]>
+      </Code>
+    </Task>
+  </UsingTask>
+  
+  <Target Name="KillPython" BeforeTargets="PrepareForBuild" 
Condition="'$(KillPython)' == 'true'">
+    <Message Text="Killing any running python$(PyDebugExt)$(PyTestExt).exe 
instances..." Importance="high" />
+    <KillPython FileName="$(OutDir)python$(PyDebugExt)$(PyTestExt).exe" />
+  </Target>
+  
+  <!--
+  A default target to handle msbuild pcbuild.proj /t:CleanAll.
+  
+  Some externals projects don't respond to /t:Clean, so we invoke
+  CleanAll on them when we really want to clean up.
+  -->
+  <Target Name="CleanAll" DependsOnTargets="Clean">
+    <MSBuild Projects="@(ProjectReference->'%(FullPath)')"
+             Properties="Configuration=$(Configuration);Platform=$(Platform)"
+             BuildInParallel="true"
+             StopOnFirstFailure="false"
+             Condition="Exists(%(FullPath))"
+             Targets="CleanAll" />
+  </Target>
+
+  <Target Name="CopyPGCFiles" BeforeTargets="PrepareForBuild" 
Condition="$(Configuration) == 'PGUpdate'">
+    <ItemGroup>
+      <_PGCFiles Include="$(OutDir)instrumented\$(TargetName)!*.pgc" />
+      <_PGDFile Include="$(OutDir)instrumented\$(TargetName).pgd" />
+      <_CopyFiles Include="@(_PGCFiles);@(_PGDFile)" 
Condition="Exists(%(FullPath))" />
+    </ItemGroup>
+    <Delete Files="@(_CopyFiles->'$(OutDir)%(Filename)%(Extension)')" />
+    <Error Text="PGO run did not succeed (no $(TargetName)!*.pgc files) and 
there is no data to merge"
+           Condition="$(RequirePGCFiles) == 'true' and @(_PGCFiles) == ''" />
+    <Copy SourceFiles="@(_CopyFiles)"
+          DestinationFolder="$(OutDir)"
+          UseHardLinksIfPossible="true"
+          OverwriteReadOnlyFiles="true" />
+  </Target>
+
+  <PropertyGroup>
+    <SdkBinPath Condition="'$(SdkBinPath)' == '' or 
!Exists($(SdkBinPath))">$(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
 Kits\Installed 
Roots@KitsRoot10)\bin\$(DefaultWindowsSDKVersion)\x86</SdkBinPath>
+    <SdkBinPath 
Condition="!Exists($(SdkBinPath))">$(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
 Kits\Installed Roots@KitsRoot10)\bin\x86</SdkBinPath>
+    <SdkBinPath 
Condition="!Exists($(SdkBinPath))">$(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
 Kits\Installed Roots@KitsRoot81)\bin\x86</SdkBinPath>
+    <SdkBinPath 
Condition="!Exists($(SdkBinPath))">$(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
 Kits\Installed Roots@KitsRoot)\bin\x86</SdkBinPath>
+    <SdkBinPath 
Condition="!Exists($(SdkBinPath))">$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft
 SDKs\Windows\v7.1A@InstallationFolder)\Bin\</SdkBinPath>
+    <_SignCommand Condition="Exists($(SdkBinPath)) and '$(SigningCertificate)' 
!= '' and $(SupportSigning)">"$(SdkBinPath)\signtool.exe" sign /q /a /n 
"$(SigningCertificate)" /fd sha256 /t 
http://timestamp.verisign.com/scripts/timestamp.dll /d "Python 
$(PythonVersion)"</_SignCommand>
+    <_MakeCatCommand 
Condition="Exists($(SdkBinPath))">"$(SdkBinPath)\makecat.exe"</_MakeCatCommand>
+  </PropertyGroup>
+  
+  <Target Name="_SignBuild" AfterTargets="AfterBuild" 
Condition="'$(SigningCertificate)' != '' and $(SupportSigning)">
+    <Error Text="Unable to locate signtool.exe. Set /p:SignToolPath and 
rebuild" Condition="'$(_SignCommand)' == ''" />
+    <Exec Command='$(_SignCommand) "$(TargetPath)" || $(_SignCommand) 
"$(TargetPath)" || $(_SignCommand) "$(TargetPath)"' ContinueOnError="false" />
+  </Target>
+</Project>
diff --git a/PCbuild/python.props b/PCbuild/python.props
new file mode 100644
--- /dev/null
+++ b/PCbuild/python.props
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <PropertyGroup>
+    <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+    <Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
+    <!--
+    Use the latest available version of Visual Studio to build. To override
+    this and build with an earlier version, pass "/p:PlatformToolset=v100"
+    (for example) when building.
+
+    We set BasePlatformToolset for ICC's benefit, it's otherwise ignored.
+    -->
+    <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and 
('$(MSBuildToolsVersion)' == '15.0' or '$(VisualStudioVersion)' == 
'15.0')">v141</BasePlatformToolset>
+    <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and 
'$(VCTargetsPath14)' != ''">v140</BasePlatformToolset>
+    <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and 
'$(VCTargetsPath12)' != ''">v120</BasePlatformToolset>
+    <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and 
'$(VCTargetsPath11)' != ''">v110</BasePlatformToolset>
+    <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and 
'$(VCTargetsPath10)' != ''">v100</BasePlatformToolset>
+
+    <PlatformToolset Condition="'$(PlatformToolset)' == 
''">$(BasePlatformToolset)</PlatformToolset>
+    <ICCBuild>false</ICCBuild>
+    <ICCBuild Condition="$(PlatformToolset.StartsWith(`Intel C++ 
Compiler`))">true</ICCBuild>
+
+    <!--
+    Convincing MSVC/MSBuild to prefer our platform names is too difficult,
+    so we define our own constant ArchName and use wherever we need it.
+    -->
+    <ArchName Condition="'$(ArchName)' == '' and $(Platform) == 
'x64'">amd64</ArchName>
+    <ArchName Condition="'$(ArchName)' == ''">win32</ArchName>
+    
+    <!-- Root directory of the repository -->
+    <PySourcePath Condition="'$(PySourcePath)' == 
''">$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\))</PySourcePath>
+    <PySourcePath 
Condition="!HasTrailingSlash($(PySourcePath))">$(PySourcePath)\</PySourcePath>
+    
+       <!-- Directory containing the translated python interpretter -->
+       <InterpreterPath Condition="'$(InterpreterPath)' == 
''">$(PySourcePath)pypy\goal\</InterpreterPath>
+    
+       <!-- Directory where msi build outputs are put -->
+       <BuildPath32 Condition="'$(Py_OutDir)' == 
''">$(PySourcePath)PCbuild\win32\</BuildPath32>
+    <BuildPath32 Condition="'$(Py_OutDir)' != 
''">$(Py_OutDir)\win32\</BuildPath32>
+    <BuildPath Condition="'$(BuildPath)' == ''">$(BuildPath32)</BuildPath>
+    <BuildPath 
Condition="!HasTrailingSlash($(BuildPath))">$(BuildPath)\</BuildPath>
+    <BuildPath Condition="$(Configuration) == 
'PGInstrument'">$(BuildPath)instrumented\</BuildPath>
+        
+    <!-- Directories of external projects. tcltk is handled in tcltk.props -->
+    <ExternalsDir>$(EXTERNALS_DIR)</ExternalsDir>
+    <ExternalsDir Condition="$(ExternalsDir) == 
''">$([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`))</ExternalsDir>
+    <ExternalsDir 
Condition="!HasTrailingSlash($(ExternalsDir))">$(ExternalsDir)\</ExternalsDir>
+    <sqlite3Dir>$(ExternalsDir)sqlite-3.21.0.0\</sqlite3Dir>
+    <bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir>
+    <lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir>
+    <opensslDir>$(ExternalsDir)openssl-1.1.0i\</opensslDir>
+    
<opensslOutDir>$(ExternalsDir)openssl-bin-1.1.0i\$(ArchName)\</opensslOutDir>
+    <opensslIncludeDir>$(opensslOutDir)include</opensslIncludeDir>
+    <nasmDir>$(ExternalsDir)\nasm-2.11.06\</nasmDir>
+    <zlibDir>$(ExternalsDir)\zlib-1.2.11\</zlibDir>
+    
+    <!-- Suffix for all binaries when building for debug -->
+    <PyDebugExt Condition="'$(PyDebugExt)' == '' and $(Configuration) == 
'Debug'">_d</PyDebugExt>
+    
+    <!-- Suffix for versions/keys when building with test markers -->
+    <PyTestExt Condition="$(UseTestMarker) == 'true'">-test</PyTestExt>
+    
+    <!-- Suffix for versions/keys when building for particular platforms -->
+    <PyArchExt Condition="'$(ArchName)' == 'win32'">-32</PyArchExt>
+    
+    <!-- Full path of the resulting python.exe binary -->
+    <PythonExe Condition="'$(PythonExe)' == 
''">$(InterpreterPath)pypy3-c$(PyDebugExt).exe</PythonExe>
+  </PropertyGroup>
+  
+  <PropertyGroup Condition="$(DefaultWindowsSDKVersion) == ''">
+    <!--
+    Attempt to select the latest installed WinSDK. If we don't find any, then 
we will
+    let the MSBuild targets determine which one it wants to use (typically the 
earliest
+    possible version). Since we limit WINVER to Windows 7 anyway, it doesn't 
really
+    matter which WinSDK version we use.
+    -->
+    
<_RegistryVersion>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft 
SDKs\Windows\v10.0@ProductVersion)</_RegistryVersion>
+    <_RegistryVersion Condition="$(_RegistryVersion) == 
''">$(Registry:HKEY_LOCAL_MACHINE\WOW6432Node\SOFTWARE\Microsoft\Microsoft 
SDKs\Windows\v10.0@ProductVersion)</_RegistryVersion>
+    <DefaultWindowsSDKVersion>10.0.17134.0</DefaultWindowsSDKVersion>
+    <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == 
'10.0.16299'">10.0.16299.0</DefaultWindowsSDKVersion>
+    <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == 
'10.0.15063'">10.0.15063.0</DefaultWindowsSDKVersion>
+    <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == 
'10.0.14393'">10.0.14393.0</DefaultWindowsSDKVersion>
+    <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == 
'10.0.10586'">10.0.10586.0</DefaultWindowsSDKVersion>
+    <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == 
'10.0.10240'">10.0.10240.0</DefaultWindowsSDKVersion>
+  </PropertyGroup>
+  
+  <PropertyGroup Condition="'$(OverrideVersion)' == ''">
+    <!--
+    Read version information from Include\patchlevel.h. The following 
properties are set:
+    
+        MajorVersionNumber  -   the '3' in '3.5.2a1'
+        MinorVersionNumber  -   the '5' in '3.5.2a1'
+        MicroVersionNumber  -   the '2' in '3.5.2a1'
+        ReleaseSerial       -   the '1' in '3.5.2a1'
+        ReleaseLevelName    -   the 'a1' in '3.5.2a1'
+        PythonVersionNumber -   '3.5.2' for '3.5.2a1'
+        PythonVersion       -   '3.5.2a1'
+        PythonVersionHex    -   0x030502a1 for '3.5.2a1'
+        ReleaseLevelNumber  -   10 for alpha, 11 for beta, 12 for RC (gamma), 
and 15 for final
+        Field3Value         -   2101 for '3.5.2a1' (== 1000*2 + 10*10 ('a') + 
1)
+    -->
+    
<_PatchLevelContent>$([System.IO.File]::ReadAllText(`$(PySourcePath)Include\patchlevel.h`))</_PatchLevelContent>
+    
<MajorVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent),
 `define\s+PY_MAJOR_VERSION\s+(\d+)`).Groups[1].Value)</MajorVersionNumber>
+    
<MinorVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent),
 `define\s+PY_MINOR_VERSION\s+(\d+)`).Groups[1].Value)</MinorVersionNumber>
+    
<MicroVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent),
 `define\s+PY_MICRO_VERSION\s+(\d+)`).Groups[1].Value)</MicroVersionNumber>
+    
<_ReleaseLevel>$([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent),
 
`define\s+PY_RELEASE_LEVEL\s+PY_RELEASE_LEVEL_(\w+)`).Groups[1].Value)</_ReleaseLevel>
+    
<ReleaseSerial>$([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent),
 `define\s+PY_RELEASE_SERIAL\s+(\d+)`).Groups[1].Value)</ReleaseSerial>
+    <ReleaseLevelNumber>15</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 
'ALPHA'">10</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 
'BETA'">11</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 
'GAMMA'">12</ReleaseLevelNumber>
+    <ReleaseLevelName Condition="$(_ReleaseLevel) == 
'ALPHA'">a$(ReleaseSerial)</ReleaseLevelName>
+    <ReleaseLevelName Condition="$(_ReleaseLevel) == 
'BETA'">b$(ReleaseSerial)</ReleaseLevelName>
+    <ReleaseLevelName Condition="$(_ReleaseLevel) == 
'GAMMA'">rc$(ReleaseSerial)</ReleaseLevelName>
+  </PropertyGroup>
+  
+  <PropertyGroup Condition="'$(OverrideVersion)' != ''">
+    <!--
+    Override the version number when building by specifying OverrideVersion.
+    For example:
+    
+        PCbuild\build.bat "/p:OverrideVersion=3.5.2a1"
+    
+    Use the -V option to check your version is valid:
+    
+        PCbuild\build.bat -V "/p:OverrideVersion=3.5.2a1"
+          PythonVersionNumber: 3.5.2
+          PythonVersion:       3.5.2a1
+          PythonVersionHex:    0x030502A1
+          Field3Value:         2101
+    
+    Note that this only affects the version numbers embedded in resources and
+    installers, but not sys.version.
+    -->
+    
<MajorVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion),
 `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[1].Value)</MajorVersionNumber>
+    
<MinorVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion),
 `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[2].Value)</MinorVersionNumber>
+    
<MicroVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion),
 `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[3].Value)</MicroVersionNumber>
+    
<ReleaseLevelName>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion),
 `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[4].Value)</ReleaseLevelName>
+    
<_ReleaseLevel>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion),
 `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[5].Value)</_ReleaseLevel>
+    
<ReleaseSerial>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion),
 `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[6].Value)</ReleaseSerial>
+    <ReleaseSerial Condition="'$(ReleaseSerial)' == ''">0</ReleaseSerial>
+    <ReleaseLevelNumber>15</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 
'a'">10</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 
'b'">11</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 
'rc'">12</ReleaseLevelNumber>
+  </PropertyGroup>
+  
+  <PropertyGroup>
+    
<PythonVersionNumber>$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)</PythonVersionNumber>
+    
<PythonVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)$(ReleaseLevelName)</PythonVersion>
+    <PythonVersionHex>$([msbuild]::BitwiseOr(
+        $([msbuild]::Multiply($(MajorVersionNumber), 16777216)),
+        $([msbuild]::BitwiseOr(
+            $([msbuild]::Multiply($(MinorVersionNumber), 65536)),
+            $([msbuild]::BitwiseOr(
+                $([msbuild]::Multiply($(MicroVersionNumber), 256)),
+                $([msbuild]::BitwiseOr(
+                    $([msbuild]::Multiply($(ReleaseLevelNumber), 16)),
+                    $(ReleaseSerial)
+                ))
+            ))
+        ))
+    ))</PythonVersionHex>
+    <Field3Value>$([msbuild]::Add(
+        $(ReleaseSerial),
+        $([msbuild]::Add(
+            $([msbuild]::Multiply($(ReleaseLevelNumber), 10)),
+            $([msbuild]::Multiply($(MicroVersionNumber), 1000))
+        ))
+    ))</Field3Value>
+    <Field3Value Condition="$(UseTestMarker) == 
'true'">$([msbuild]::Add($(Field3Value), 9000))</Field3Value>
+    
+    <!-- The name of the resulting pythonXY.dll (without the extension) -->
+    
<PyDllName>python$(MajorVersionNumber)$(MinorVersionNumber)$(PyDebugExt)</PyDllName>
+
+    <!-- The version and platform tag to include in .pyd filenames -->
+    <PydTag Condition="$(ArchName) == 
'win32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win32</PydTag>
+    <PydTag Condition="$(ArchName) == 
'amd64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_amd64</PydTag>
+    
+    <!-- The version number for sys.winver -->
+    
<SysWinVer>$(MajorVersionNumber).$(MinorVersionNumber)$(PyArchExt)$(PyTestExt)</SysWinVer>
+  </PropertyGroup>
+  
+  <!-- Displays the calculated version info -->
+  <Target Name="ShowVersionInfo">
+    <Message Importance="high" Text="PythonVersionNumber: 
$(PythonVersionNumber)" />
+    <Message Importance="high" Text="PythonVersion:       $(PythonVersion)" />
+    <Message Importance="high" Text="PythonVersionHex:    
0x$([System.UInt32]::Parse($(PythonVersionHex)).ToString(`X08`))" />
+    <Message Importance="high" Text="Field3Value:         $(Field3Value)" />
+    <Message Importance="high" Text="SysWinVer:           $(SysWinVer)" />
+    <Message Importance="high" Text="PyDllName:           $(PyDllName)" />
+  </Target>
+</Project>
diff --git a/PCbuild/tcltk.props b/PCbuild/tcltk.props
new file mode 100644
--- /dev/null
+++ b/PCbuild/tcltk.props
@@ -0,0 +1,45 @@
+&#65279;<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <Import Project="pyproject.props" />
+  <PropertyGroup>
+    <TclMajorVersion>8</TclMajorVersion>
+    <TclMinorVersion>6</TclMinorVersion>
+    <TclPatchLevel>8</TclPatchLevel>
+    <TclRevision>0</TclRevision>
+    <TkMajorVersion>$(TclMajorVersion)</TkMajorVersion>
+    <TkMinorVersion>$(TclMinorVersion)</TkMinorVersion>
+    <TkPatchLevel>$(TclPatchLevel)</TkPatchLevel>
+    <TkRevision>$(TclRevision)</TkRevision>
+    <TixMajorVersion>8</TixMajorVersion>
+    <TixMinorVersion>4</TixMinorVersion>
+    <TixPatchLevel>3</TixPatchLevel>
+    <TixRevision>6</TixRevision>
+    
<tclDir>$(ExternalsDir)tcl-core-$(TclMajorVersion).$(TclMinorVersion).$(TclPatchLevel).$(TclRevision)\</tclDir>
+    
<tkDir>$(ExternalsDir)tk-$(TkMajorVersion).$(TkMinorVersion).$(TkPatchLevel).$(TkRevision)\</tkDir>
+    
<tixDir>$(ExternalsDir)tix-$(TixMajorVersion).$(TixMinorVersion).$(TixPatchLevel).$(TixRevision)\</tixDir>
+    
<tcltkDir>$(ExternalsDir)tcltk-$(TclMajorVersion).$(TclMinorVersion).$(TclPatchLevel).$(TclRevision)\$(ArchName)\</tcltkDir>
+    <!--<TclDebugExt Condition="'$(Configuration)' == 
'Debug'">g</TclDebugExt>-->
+    
<tclDLLName>tcl$(TclMajorVersion)$(TclMinorVersion)t$(TclDebugExt).dll</tclDLLName>
+    
<tclLibName>tcl$(TclMajorVersion)$(TclMinorVersion)t$(TclDebugExt).lib</tclLibName>
+    
<tclShExeName>tclsh$(TclMajorVersion)$(TclMinorVersion)t$(TclDebugExt).exe</tclShExeName>
+    
<tkDLLName>tk$(TkMajorVersion)$(TkMinorVersion)t$(TclDebugExt).dll</tkDLLName>
+    
<tkLibName>tk$(TkMajorVersion)$(TkMinorVersion)t$(TclDebugExt).lib</tkLibName>
+    
<tixDLLName>tix$(TixMajorVersion)$(TixMinorVersion)$(TclDebugExt).dll</tixDLLName>
+    
<tixDLLPath>$(tcltkDir)lib\tix$(TixMajorVersion).$(TixMinorVersion).$(TixPatchLevel)\$(tixDLLName)</tixDLLPath>
+    
<tcltkLib>$(tcltkDir)lib\tcl$(TclMajorVersion)$(TclMinorVersion)t$(TclDebugExt).lib;$(tcltkDir)lib\tk$(TkMajorVersion)$(TkMinorVersion)t$(TclDebugExt).lib</tcltkLib>
+    <TclMachine>IX86</TclMachine>
+    <TclMachine Condition="'$(Platform)' == 'x64'">AMD64</TclMachine>
+    <TclVersions>TCL_MAJOR_VERSION=$(TclMajorVersion) 
TCL_MINOR_VERSION=$(TclMinorVersion) 
TCL_PATCH_LEVEL=$(TclPatchLevel)</TclVersions>
+    <TclShortVersions>TCL_MAJOR=$(TclMajorVersion) 
TCL_MINOR=$(TclMinorVersion) TCL_PATCH=$(TclPatchLevel)</TclShortVersions>
+    <TkVersions>TK_MAJOR_VERSION=$(TkMajorVersion) 
TK_MINOR_VERSION=$(TkMinorVersion) TK_PATCH_LEVEL=$(TkPatchLevel)</TkVersions>
+
+    <BuildDirTop>Release</BuildDirTop>
+    <BuildDirTop Condition="$(Configuration) == 'Debug'">Debug</BuildDirTop>
+    <BuildDirTop Condition="$(TclMachine) != 
'IX86'">$(BuildDirTop)_$(TclMachine)</BuildDirTop>
+    <BuildDirTop Condition="$(PlatformToolset) == 
'v141'">$(BuildDirTop)_VC13</BuildDirTop>
+    <BuildDirTop Condition="$(PlatformToolset) == 
'v140'">$(BuildDirTop)_VC13</BuildDirTop>
+    <BuildDirTop Condition="$(PlatformToolset) == 
'v120'">$(BuildDirTop)_VC12</BuildDirTop>
+    <BuildDirTop Condition="$(PlatformToolset) == 
'v110'">$(BuildDirTop)_VC11</BuildDirTop>
+    <BuildDirTop Condition="$(PlatformToolset) == 
'v100'">$(BuildDirTop)_VC10</BuildDirTop>
+  </PropertyGroup>
+</Project>
diff --git a/PCbuild/win32/en-us/exe.msi b/PCbuild/win32/en-us/exe.msi
new file mode 100644
index 
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a444b52839ec6e9ad8eadde9653e7dd370910671
GIT binary patch

[cut]

diff --git a/pypy/tool/release/windowsinstaller/README 
b/pypy/tool/release/windowsinstaller/README
new file mode 100644
--- /dev/null
+++ b/pypy/tool/release/windowsinstaller/README
@@ -0,0 +1,15 @@
+Prerequisites:
+    Visual Studio 2017 or at least the compilers and desktop cevelopment
+with c++
+        .Net 3.5.1
+    Wix 3.11.1 http://wixtoolset.org/releases/
+    Wix VSExtension for VS 2017
+https://marketplace.visualstudio.com/items?itemName=RobMensching.WixToolsetVisualStudio2017Extension
+    Windows 10 SDK (10.0.17134.0)
+    
+Steps:
+    1. Translate the interpretter from the \pypy\goal folder.
+    2. Remove all __pycache__ directories (maybe do this in the script?)
+    3. Run buildrelease.bat from the visual studio command line.
+
+Now you should have .\PCbuild\win32\en-us\pypy-3.5.3.6609.exe
diff --git a/pypy/tool/release/windowsinstaller/buildrelease.bat 
b/pypy/tool/release/windowsinstaller/buildrelease.bat
new file mode 100644
--- /dev/null
+++ b/pypy/tool/release/windowsinstaller/buildrelease.bat
@@ -0,0 +1,44 @@
+@setlocal
+@echo off
+
+
+set D=%~dp0
+set PCBUILD=%D%..\..\..\..\PCbuild\
+if "%Py_OutDir%"=="" set Py_OutDir=%PCBUILD%
+set EXTERNALS=%D%..\..\externals\windows-installer\
+
+set BUILDX86=
+set BUILDX64=
+set TARGET=Rebuild
+set TESTTARGETDIR=
+set PGO=-m test -q --pgo
+set BUILDNUGET=1
+set BUILDZIP=1
+
+
+:CheckOpts
+if "%1" EQU "-h" goto Help
+if "%1" EQU "-o" (set OUTDIR=%~2) && shift && shift && goto CheckOpts
+if "%1" EQU "--out" (set OUTDIR=%~2) && shift && shift && goto CheckOpts
+
+
+if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1
+
+if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set 
BUILDX64=1)
+
+call "%PCBUILD%find_msbuild.bat" %MSBUILD%
+if ERRORLEVEL 1 (echo Cannot locate MSBuild.exe on PATH or as MSBUILD variable 
& exit /b 2)
+
+
+%MSBUILD% "%D%bundle\releaselocal.wixproj" /t:Rebuild /p:RebuildAll=true
+if errorlevel 1 exit /B
+
+exit /B 0
+
+:Help
+echo buildrelease.bat [--out DIR]
+echo                  [-h]
+echo.
+echo    --out (-o)          Specify an additional output directory for 
installers
+echo    -h                  Display this help information
+echo.
diff --git a/pypy/tool/release/windowsinstaller/bundle/Default.thm 
b/pypy/tool/release/windowsinstaller/bundle/Default.thm
new file mode 100644
--- /dev/null
+++ b/pypy/tool/release/windowsinstaller/bundle/Default.thm
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010";>
+    <Window Width="670" Height="412" HexStyle="100a0000" 
FontId="0">#(loc.Caption)</Window>
+    <Font Id="0" Height="-14" Weight="500" Foreground="000000" 
Background="ffffff">Segoe UI</Font>
+    <Font Id="1" Height="-26" Weight="500" Foreground="000000" 
Background="ffffff">Segoe UI</Font>
+    <Font Id="2" Height="-24" Weight="500" Foreground="808080" 
Background="ffffff">Segoe UI</Font>
+    <Font Id="3" Height="-14" Weight="500" Foreground="000000" 
Background="ffffff">Segoe UI</Font>
+    <Font Id="4" Height="-14" Weight="500" Foreground="ff0000" 
Background="ffffff" Underline="yes">Segoe UI</Font>
+    <Font Id="5" Height="-14" Weight="500" Foreground="808080" 
Background="ffffff">Segoe UI</Font>
+
+    <Page Name="Help">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.HelpHeader)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+
+        <Hypertext X="185" Y="50" Width="-11" Height="-35" FontId="3" 
DisablePrefix="yes">#(loc.HelpText)</Hypertext>
+        <Button Name="SuccessCancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
+    </Page>
+    <Page Name="Install">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.InstallHeader)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+
+        <Text X="185" Y="50" Width="-11" Height="50" FontId="3" 
TabStop="yes">#(loc.InstallMessage)</Text>
+
+        <Button Name="InstallButton" X="185" Y="101" Width="-11" Height="109" 
TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallButton)</Button>
+
+        <Checkbox Name="InstallLauncherAllUsers" X="185" Y="-37" Width="-100" 
Height="24" TabStop="yes" 
FontId="3">#(loc.ShortInstallLauncherAllUsersLabel)</Checkbox>
+        <Checkbox Name="PrependPath" X="185" Y="-13" Width="-100" Height="24" 
TabStop="yes" FontId="3">#(loc.ShortPrependPathLabel)</Checkbox>
+
+        <Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
+    </Page>
+    <Page Name="Upgrade">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.InstallUpgradeHeader)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+
+        <Text X="185" Y="50" Width="-11" Height="50" FontId="3" 
TabStop="yes">#(loc.InstallUpgradeMessage)</Text>
+
+        <Button Name="InstallUpgradeButton" X="185" Y="101" Width="-11" 
Height="129" TabStop="yes" FontId="3" 
HexStyle="0xE">#(loc.InstallUpgradeButton)</Button>
+        <Button Name="InstallUpgradeCustomButton" X="185" Y="241" Width="-11" 
Height="59" TabStop="yes" FontId="3" 
HexStyle="0xE">#(loc.InstallUpgradeCustomButton)</Button>
+
+        <Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
+    </Page>
+    <Page Name="SimpleInstall">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.InstallHeader)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+
+        <Button Name="InstallSimpleButton" X="185" Y="101" Width="-11" 
Height="129" TabStop="yes" FontId="3" HideWhenDisabled="yes" 
HexStyle="0xF">#(loc.InstallSimpleButton)</Button>
+
+        <Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
+    </Page>
+    <Page Name="Custom1">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.Custom1Header)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+        
+        <Checkbox Name="Include_doc" X="185" Y="51" Width="-11" Height="24" 
TabStop="yes" FontId="3" 
HideWhenDisabled="yes">#(loc.Include_docLabel)</Checkbox>
+        <Text X="205" Y="76" Width="-11" Height="24" TabStop="no" 
FontId="5">#(loc.Include_docHelpLabel)</Text>
+        
+        <Checkbox Name="Include_pip" X="185" Y="101" Width="-11" Height="24" 
TabStop="yes" FontId="3" 
HideWhenDisabled="yes">#(loc.Include_pipLabel)</Checkbox>
+        <Text X="205" Y="126" Width="-11" Height="24" TabStop="no" 
FontId="5">#(loc.Include_pipHelpLabel)</Text>
+        
+        <Checkbox Name="Include_tcltk" X="185" Y="151" Width="-11" Height="24" 
TabStop="yes" FontId="3" 
HideWhenDisabled="yes">#(loc.Include_tcltkLabel)</Checkbox>
+        <Text X="205" Y="176" Width="-11" Height="24" TabStop="no" 
FontId="5">#(loc.Include_tcltkHelpLabel)</Text>
+        
+        <Checkbox Name="Include_test" X="185" Y="201" Width="-11" Height="24" 
TabStop="yes" FontId="3" 
HideWhenDisabled="yes">#(loc.Include_testLabel)</Checkbox>
+        <Text X="205" Y="226" Width="-11" Height="24" TabStop="no" 
FontId="5">#(loc.Include_testHelpLabel)</Text>
+
+        <Checkbox Name="Include_launcher" X="185" Y="251" Width="100" 
Height="24" TabStop="yes" FontId="3" 
HideWhenDisabled="no">#(loc.Include_launcherLabel)</Checkbox>
+        <Checkbox Name="CustomInstallLauncherAllUsers" X="285" Y="251" 
Width="-11" Height="24" TabStop="yes" 
FontId="3">#(loc.InstallLauncherAllUsersLabel)</Checkbox>
+        <Text Name="Include_launcherHelp" X="205" Y="276" Width="-11" 
Height="24" TabStop="no" FontId="5"></Text>
+
+        <Button Name="Custom1BackButton" X="185" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CustomBackButton)</Button>
+        <Button Name="CustomNextButton" X="-101" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CustomNextButton)</Button>
+        <Button Name="Custom1CancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
+    </Page>
+    <Page Name="Custom2">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.Custom2Header)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+        
+        <Checkbox Name="InstallAllUsers" X="185" Y="51" Width="-11" 
Height="24" TabStop="yes" FontId="3" 
HideWhenDisabled="no">#(loc.InstallAllUsersLabel)</Checkbox>
+        <Checkbox Name="AssociateFiles" X="185" Y="76" Width="-11" Height="24" 
TabStop="yes" FontId="3" 
HideWhenDisabled="no">#(loc.AssociateFilesLabel)</Checkbox>
+        <Checkbox Name="Shortcuts" X="185" Y="101" Width="-11" Height="24" 
TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.ShortcutsLabel)</Checkbox>
+        <Checkbox Name="PrependPath" X="185" Y="126" Width="-11" Height="24" 
TabStop="yes" FontId="3" 
HideWhenDisabled="no">#(loc.PrependPathLabel)</Checkbox>
+        <Checkbox Name="CompileAll" X="185" Y="151" Width="-11" Height="24" 
TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.PrecompileLabel)</Checkbox>
+        <Checkbox Name="Include_symbols" X="185" Y="176" Width="-11" 
Height="24" TabStop="yes" FontId="3" 
HideWhenDisabled="no">#(loc.Include_symbolsLabel)</Checkbox>
+        <Checkbox Name="Include_debug" X="185" Y="201" Width="-11" Height="24" 
TabStop="yes" FontId="3" 
HideWhenDisabled="no">#(loc.Include_debugLabel)</Checkbox>
+
+        <Text X="185" Y="256" Width="-11" Height="17" 
FontId="3">#(loc.CustomLocationLabel)</Text>
+        <Editbox Name="TargetDir" X="185" Y="277" Width="-101" Height="27" 
TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
+        <Button Name="CustomBrowseButton" X="-11" Y="276" Width="85" 
Height="27" TabStop="yes" FontId="3">#(loc.CustomBrowseButton)</Button>
+        <Text Name="CustomBrowseButtonLabel" X="185" Y="306" Width="-91" 
Height="35" FontId="5" 
HideWhenDisabled="yes">#(loc.CustomLocationHelpLabel)</Text>
+
+        <Button Name="Custom2BackButton" X="185" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CustomBackButton)</Button>
+        <Button Name="CustomInstallButton" X="-101" Y="-11" Width="95" 
Height="27" TabStop="yes" FontId="0">#(loc.CustomInstallButton)</Button>
+        <Button Name="Custom2CancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
+    </Page>
+    <Page Name="Progress">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.ProgressHeader)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+
+        <Text X="185" Y="111" Width="-11" Height="20" FontId="3" 
DisablePrefix="yes">#(loc.ProgressLabel)</Text>
+        <Text Name="OverallProgressPackageText" X="185" Y="146" Width="-11" 
Height="20" FontId="3" 
DisablePrefix="yes">#(loc.OverallProgressPackageText)</Text>
+        <Progressbar Name="OverallCalculatedProgressbar" X="185" Y="171" 
Width="-11" Height="24" />
+        <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="95" 
Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
+    </Page>
+    <Page Name="Modify">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.ModifyHeader)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+
+        <Button Name="ModifyButton" X="185" Y="101" Width="-11" Height="59" 
TabStop="yes" FontId="3" HexStyle="0xF">#(loc.ModifyModifyButton)</Button>
+        <Button Name="RepairButton" X="185" Y="171" Width="-11" Height="59" 
TabStop="yes" FontId="3" HexStyle="0xE">#(loc.ModifyRepairButton)</Button>
+        <Button Name="UninstallButton" X="185" Y="241" Width="-11" Height="59" 
TabStop="yes" FontId="3" HexStyle="0xE">#(loc.ModifyUninstallButton)</Button>
+
+        <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
+    </Page>
+    <Page Name="Success">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.SuccessHeader)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+
+        <Hypertext Name="SuccessText" X="205" Y="71" Width="-71" Height="150" 
FontId="3" DisablePrefix="yes"></Hypertext>
+
+        <Button Name="SuccessMaxPathButton" X="185" Y="-70" Width="-11" 
Height="81" TabStop="yes" FontId="3" HexStyle="0xE" 
HideWhenDisabled="yes">#(loc.SuccessMaxPathButton)</Button>
+
+        <Text Name="SuccessRestartText" X="205" Y="-40" Width="-11" 
Height="34" FontId="3" HideWhenDisabled="yes" 
DisablePrefix="yes">#(loc.SuccessRestartText)</Text>
+        <Button Name="SuccessRestartButton" X="-101" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0" 
HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
+        <Button Name="SuccessCancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
+    </Page>
+    <Page Name="Failure">
+        <Text X="185" Y="11" Width="-11" Height="36" FontId="1" 
DisablePrefix="yes">#(loc.FailureHeader)</Text>
+        <Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
+
+        <Hypertext Name="FailureLogFileLink" X="205" Y="71" Width="-11" 
Height="60" FontId="3" TabStop="yes" 
HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
+        <Hypertext Name="FailureMessageText" X="205" Y="151" Width="-11" 
Height="120" FontId="3" TabStop="yes" HideWhenDisabled="yes"></Hypertext>
+        <Text Name="FailureRestartText" X="205" Y="-40" Width="-11" 
Height="34" FontId="3" HideWhenDisabled="yes" 
DisablePrefix="yes">#(loc.FailureRestartText)</Text>
+        <Button Name="FailureRestartButton" X="-101" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0" 
HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
+        <Button Name="FailureCancelButton" X="-11" Y="-11" Width="85" 
Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
+    </Page>
+</Theme>
\ No newline at end of file
diff --git a/pypy/tool/release/windowsinstaller/bundle/Default.wxl 
b/pypy/tool/release/windowsinstaller/bundle/Default.wxl
new file mode 100644
--- /dev/null
+++ b/pypy/tool/release/windowsinstaller/bundle/Default.wxl
@@ -0,0 +1,145 @@
+&#65279;<?xml version="1.0" encoding="utf-8"?>
+<WixLocalization Culture="en-us" Language="1033" 
xmlns="http://schemas.microsoft.com/wix/2006/localization";>
+  <String Id="Caption">[WixBundleName] Setup</String>
+  <String Id="Title">[WixBundleName]</String>
+  <String Id="Installing">Installing</String>
+  <String Id="Installation">Setup</String>
+  <String Id="Modifying">Updating</String>
+  <String Id="Modification">Modify</String>
+  <String Id="Repairing">Repairing</String>
+  <String Id="Repair">Repair</String>
+  <String Id="Uninstalling">Removing</String>
+  <String Id="Uninstallation">Uninstall</String>
+  
+  <String Id="ElevateForCRTInstall">You will be prompted for Administrator 
privileges to install a C Runtime Library update (KB2999226).
+
+
+Continue?</String>
+  
+  <String Id="CancelButton">&amp;Cancel</String>
+  <String Id="CloseButton">&amp;Close</String>
+  <String Id="InstallHeader">Install [WixBundleName]</String>
+  <String Id="InstallMessage">Select Install Now to install PyPy with default 
settings.</String>
+  <String Id="InstallVersion">Version [WixBundleVersion]</String>
+  <String Id="InstallUpgradeHeader">Upgrade to [WixBundleName]</String>
+  <String Id="InstallUpgradeMessage">Select Upgrade Now to keep your current 
settings, or choose Customize to enable or disable features.</String>
+  <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
+  <String Id="ExecuteUpgradeRelatedBundleMessage">Previous version</String>
+  <String Id="HelpHeader">Setup Help</String>
+  <String Id="HelpText">Visit &lt;a 
href="http://doc.pypy.org/en/latest/"&gt;doc.pypy.org[ShortVersion]/en/latest/&lt;/a&gt;
 for the full list of options, including the ability to enable and disable 
specific features.
+
+"/passive" to display progress without requiring user interaction
+
+"/quiet" to install/uninstall without displaying any UI
+
+"/simple" to prevent user customization
+
+"/uninstall" to remove PyPy (without confirmation)
+
+"/layout [\[]directory[\]]" to pre-download all components
+
+"/log [\[]filename[\]]" to specify log files location</String>
+  <String Id="InstallLicenseLinkText">[WixBundleName] &lt;a 
href="#"&gt;license terms&lt;/a&gt;.</String>
+  <String Id="InstallAcceptCheckbox">I &amp;agree to the license terms and 
conditions</String>
+  <String Id="InstallButton">&amp;Install Now</String>
+  <String Id="InstallButtonNote">[TargetDir]
+
+Creates shortcuts and file associations</String>
+  <String Id="InstallCustomButton">C&amp;ustomize installation</String>
+  <String Id="InstallCustomButtonNote">Choose location and features</String>
+  <String Id="InstallSimpleButton">&amp;Install</String>
+  <String Id="InstallSimpleButtonNote">Use settings preselected by your 
administrator
+
+[SimpleInstallDescription]</String>
+  <String Id="InstallUpgradeButton">Up&amp;grade Now</String>
+  <String Id="InstallUpgradeButtonNote">[TargetDir]
+
+Replaces your existing installation without changing settings.
+Select Customize to review current options.</String>
+  <String Id="InstallUpgradeCustomButton">C&amp;ustomize installation</String>
+  <String Id="InstallUpgradeCustomButtonNote">Choose location and 
features</String>
+  <String Id="Custom1Header">Optional Features</String>
+  <String Id="Custom2Header">Advanced Options</String>
+  <String Id="CustomLocationLabel">Customize install location</String>
+  <String Id="CustomLocationHelpLabel">You will require write permissions for 
the selected location.</String>
+  <String Id="CustomInstallButton">&amp;Install</String>
+  <String Id="CustomNextButton">&amp;Next</String>
+  <String Id="CustomBackButton">&amp;Back</String>
+  <String Id="CustomBrowseButton">B&amp;rowse</String>
+  <String Id="Include_docLabel">&amp;Documentation</String>
+  <String Id="Include_docHelpLabel">Installs the PyPy documentation 
file.</String>
+  <String Id="Include_pipLabel">&amp;pip</String>
+  <String Id="Include_pipHelpLabel">Installs pip, which can download and 
install other PyPy packages.</String>
+  <String Id="Include_tcltkLabel">tcl/tk and &amp;IDLE</String>
+  <String Id="Include_tcltkHelpLabel">Installs tkinter and the IDLE 
development environment.</String>
+  <String Id="Include_testLabel">PyPy &amp;test suite</String>
+  <String Id="Include_testHelpLabel">Installs the standard library test 
suite.</String>
+  <String Id="Include_launcherLabel">py &amp;launcher</String>
+  <String Id="Include_launcherHelp">Installs the global 'py' launcher to make 
it easier to start Python.</String>
+  <String Id="Include_launcherRemove">Use Programs and Features to remove the 
'py' launcher.</String>
+  <String Id="Include_launcherUpgrade">Upgrades the global 'py' launcher from 
the previous version.</String>
+  
+  <String Id="AssociateFilesLabel">Associate &amp;files with PyPy (requires 
the py launcher)</String>
+  <String Id="ShortcutsLabel">Create shortcuts for installed 
applications</String>
+  <String Id="PrependPathLabel">Add PyPy to &amp;environment variables</String>
+  <String Id="ShortPrependPathLabel">Add &amp;PyPy [ShortVersion] to 
PATH</String>
+  <String Id="InstallAllUsersLabel">Install for &amp;all users</String>
+  <String Id="InstallLauncherAllUsersLabel">for &amp;all users (requires 
elevation)</String>
+  <String Id="ShortInstallLauncherAllUsersLabel">Install &amp;launcher for all 
users (recommended)</String>
+  <String Id="PrecompileLabel">&amp;Precompile standard library</String>
+  <String Id="Include_symbolsLabel">Download debugging &amp;symbols</String>
+  <String Id="Include_debugLabel">Download debu&amp;g binaries (requires VS 
2015 or later)</String>
+  
+  <String Id="ProgressHeader">[ActionLikeInstallation] Progress</String>
+  <String Id="ProgressLabel">[ActionLikeInstalling]:</String>
+  <String Id="OverallProgressPackageText">Initializing...</String>
+  <String Id="ModifyHeader">Modify Setup</String>
+  <String Id="ModifyModifyButton">&amp;Modify</String>
+  <String Id="ModifyButtonNote">Add or remove individual features.</String>
+  <String Id="ModifyRepairButton">&amp;Repair</String>
+  <String Id="RepairButtonNote">Ensure all current features are correctly 
installed.</String>
+  <String Id="ModifyUninstallButton">&amp;Uninstall</String>
+  <String Id="UninstallButtonNote">Remove the entire [WixBundleName] 
installation.</String>
+  <String Id="SuccessHeader">[ActionLikeInstallation] was successful</String>
+  <String Id="SuccessLaunchButton">&amp;Launch</String>
+  <String Id="SuccessRestartText">You may need to restart your computer to 
finish updating files.</String>
+  <String Id="SuccessRestartButton">&amp;Restart</String>
+  <String Id="SuccessInstallMessage">New to Python? Start with the &lt;a 
href="https://docs.python.org/[ShortVersion]/tutorial/index.html"&gt;online 
tutorial&lt;/a&gt; and &lt;a 
href="https://docs.python.org/[ShortVersion]/index.html"&gt;documentation&lt;/a&gt;.
+
+See &lt;a 
href="https://docs.python.org/[ShortVersion]/whatsnew/[ShortVersion].html"&gt;what's
 new&lt;/a&gt; in this release.</String>
+  <String Id="SuccessModifyMessage">Thank you for using 
[WixBundleName].</String>
+  <String Id="SuccessRepairMessage">Thank you for using [WixBundleName].
+
+Feel free to email &lt;a 
href="mailto:[email protected]"&gt;[email protected]&lt;/a&gt; if you 
continue to encounter issues.</String>
+  <String Id="SuccessRemoveMessage">Thank you for using [WixBundleName].
+
+Feel free to email &lt;a 
href="mailto:[email protected]"&gt;[email protected]&lt;/a&gt; if you 
encountered problems.</String>
+  <String Id="FailureHeader">Setup failed</String>
+  <String Id="FailureHyperlinkLogText">One or more issues caused the setup to 
fail. Please fix the issues and then retry setup. For more information see the 
&lt;a href="#"&gt;log file&lt;/a&gt;.</String>
+  <String Id="FailureRestartText">You must restart your computer to complete 
the rollback of the software.</String>
+  <String Id="FailureRestartButton">&amp;Restart</String>
+  <String Id="FailureExistingInstall">Unable to install [WixBundleName] due to 
an existing install. Use Programs and Features to modify, repair or remove 
[WixBundleName].</String>
+  
+  <String Id="FailureWin7MissingSP1">Windows 7 Service Pack 1 and all 
applicable updates are required to install [WixBundleName].
+
+Please &lt;a 
href="https://www.bing.com/search?q=how%20to%20install%20windows%207%20service%20pack%201"&gt;update
 your machine&lt;/a&gt; and then restart the installation.</String>
+  <String Id="FailureVistaMissingSP2">Windows Vista Service Pack 2 and all 
applicable updates are required to install [WixBundleName].
+
+Please &lt;a 
href="https://www.bing.com/search?q=how%20to%20install%20windows%20vista%20service%20pack%202"&gt;update
 your machine&lt;/a&gt; and then restart the installation.</String>
+  <String Id="FailureXPOrEarlier">Windows Vista or later is required to 
install and use [WixBundleName].
+
+Visit &lt;a href="https://www.python.org/"&gt;python.org&lt;/a&gt; to download 
Python 3.4.</String>
+
+  <String Id="FailureWS2K8R2MissingSP1">Windows Server 2008 R2 Service Pack 1 
and all applicable updates are required to install [WixBundleName].
+
+Please &lt;a 
href="https://www.bing.com/search?q=how%20to%20install%20windows%20server%202008%20r2%20service%20pack%201"&gt;update
 your machine&lt;/a&gt; and then restart the installation.</String>
+  <String Id="FailureWS2K8MissingSP2">Windows Server 2008 Service Pack 2 and 
all applicable updates are required to install [WixBundleName].
+
+Please &lt;a 
href="https://www.bing.com/search?q=how%20to%20install%20windows%20server%202008%20service%20pack%202"&gt;update
 your machine&lt;/a&gt; and then restart the installation.</String>
+  <String Id="FailureWS2K3OrEarlier">Windows Server 2008 SP2 or later is 
required to install and use [WixBundleName].
+
+Visit &lt;a href="https://www.python.org/"&gt;python.org&lt;/a&gt; to download 
Python 3.4.</String>
+
+  <String Id="SuccessMaxPathButton">Disable path length limit</String>
+  <String Id="SuccessMaxPathButtonNote">Changes your machine configuration to 
allow programs, including Python, to bypass the 260 character "MAX_PATH" 
limitation.</String>
+</WixLocalization>
diff --git a/pypy/tool/release/windowsinstaller/bundle/SideBar.png 
b/pypy/tool/release/windowsinstaller/bundle/SideBar.png
new file mode 100644
index 
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..037da0d8515b469ff9e6ef1ad0e9b393b6f1f154
GIT binary patch

[cut]

diff --git a/pypy/tool/release/windowsinstaller/bundle/SideBar.xcf 
b/pypy/tool/release/windowsinstaller/bundle/SideBar.xcf
new file mode 100644
index 
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..19f731cb5a7d8be36ef5f14d5dfd677058ffeb75
GIT binary patch

[cut]

diff --git a/pypy/tool/release/windowsinstaller/bundle/bootstrap/LICENSE.txt 
b/pypy/tool/release/windowsinstaller/bundle/bootstrap/LICENSE.txt
new file mode 100644
--- /dev/null
+++ b/pypy/tool/release/windowsinstaller/bundle/bootstrap/LICENSE.txt
@@ -0,0 +1,25 @@
+This license applies to the bootstrapper application that is embedded within 
the installer. It has no impact on the licensing for the rest of the installer 
or Python itself, as no code covered by this license exists in any other part 
of the product.
+
+---
+
+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.
diff --git 
a/pypy/tool/release/windowsinstaller/bundle/bootstrap/PythonBootstrapperApplication.cpp
 
b/pypy/tool/release/windowsinstaller/bundle/bootstrap/PythonBootstrapperApplication.cpp
new file mode 100644
--- /dev/null
+++ 
b/pypy/tool/release/windowsinstaller/bundle/bootstrap/PythonBootstrapperApplication.cpp
@@ -0,0 +1,3233 @@
+//-------------------------------------------------------------------------------------------------
+// <copyright file="WixStandardBootstrapperApplication.cpp" 
company="Outercurve Foundation">
+//   Copyright (c) 2004, Outercurve Foundation.
+//   This software is released under Microsoft Reciprocal License (MS-RL).
+//   The license and further copyright text can be found in the file
+//   LICENSE.TXT at the root directory of the distribution.
+// </copyright>
+//-------------------------------------------------------------------------------------------------
+
+
+#include "pch.h"
+
+static const LPCWSTR PYBA_WINDOW_CLASS = L"PythonBA";
+static const DWORD PYBA_ACQUIRE_PERCENTAGE = 30;
+static const LPCWSTR PYBA_VARIABLE_BUNDLE_FILE_VERSION = 
L"WixBundleFileVersion";
+
+enum PYBA_STATE {
+    PYBA_STATE_INITIALIZING,
+    PYBA_STATE_INITIALIZED,
+    PYBA_STATE_HELP,
+    PYBA_STATE_DETECTING,
+    PYBA_STATE_DETECTED,
+    PYBA_STATE_PLANNING,
+    PYBA_STATE_PLANNED,
+    PYBA_STATE_APPLYING,
+    PYBA_STATE_CACHING,
+    PYBA_STATE_CACHED,
+    PYBA_STATE_EXECUTING,
+    PYBA_STATE_EXECUTED,
+    PYBA_STATE_APPLIED,
+    PYBA_STATE_FAILED,
+};
+
+static const int WM_PYBA_SHOW_HELP = WM_APP + 100;
+static const int WM_PYBA_DETECT_PACKAGES = WM_APP + 101;
+static const int WM_PYBA_PLAN_PACKAGES = WM_APP + 102;
+static const int WM_PYBA_APPLY_PACKAGES = WM_APP + 103;
+static const int WM_PYBA_CHANGE_STATE = WM_APP + 104;
+static const int WM_PYBA_SHOW_FAILURE = WM_APP + 105;
+
+// This enum must be kept in the same order as the PAGE_NAMES array.
+enum PAGE {
+    PAGE_LOADING,
+    PAGE_HELP,
+    PAGE_INSTALL,
+    PAGE_UPGRADE,
+    PAGE_SIMPLE_INSTALL,
+    PAGE_CUSTOM1,
+    PAGE_CUSTOM2,
+    PAGE_MODIFY,
+    PAGE_PROGRESS,
+    PAGE_PROGRESS_PASSIVE,
+    PAGE_SUCCESS,
+    PAGE_FAILURE,
+    COUNT_PAGE,
+};
+
+// This array must be kept in the same order as the PAGE enum.
+static LPCWSTR PAGE_NAMES[] = {
+    L"Loading",
+    L"Help",
+    L"Install",
+    L"Upgrade",
+    L"SimpleInstall",
+    L"Custom1",
+    L"Custom2",
+    L"Modify",
+    L"Progress",
+    L"ProgressPassive",
+    L"Success",
+    L"Failure",
+};
+
+enum CONTROL_ID {
+    // Non-paged controls
+    ID_CLOSE_BUTTON = THEME_FIRST_ASSIGN_CONTROL_ID,
+    ID_MINIMIZE_BUTTON,
+
+    // Welcome page
+    ID_INSTALL_BUTTON,
+    ID_INSTALL_CUSTOM_BUTTON,
+    ID_INSTALL_SIMPLE_BUTTON,
+    ID_INSTALL_UPGRADE_BUTTON,
+    ID_INSTALL_UPGRADE_CUSTOM_BUTTON,
+    ID_INSTALL_CANCEL_BUTTON,
+    ID_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX,
+
+    // Customize Page
+    ID_TARGETDIR_EDITBOX,
+    ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX,
+    ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX,
+    ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX,
+    ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL,
+    ID_CUSTOM_COMPILE_ALL_CHECKBOX,
+    ID_CUSTOM_BROWSE_BUTTON,
+    ID_CUSTOM_BROWSE_BUTTON_LABEL,
+    ID_CUSTOM_INSTALL_BUTTON,
+    ID_CUSTOM_NEXT_BUTTON,
+    ID_CUSTOM1_BACK_BUTTON,
+    ID_CUSTOM2_BACK_BUTTON,
+    ID_CUSTOM1_CANCEL_BUTTON,
+    ID_CUSTOM2_CANCEL_BUTTON,
+
+    // Modify page
+    ID_MODIFY_BUTTON,
+    ID_REPAIR_BUTTON,
+    ID_UNINSTALL_BUTTON,
+    ID_MODIFY_CANCEL_BUTTON,
+
+    // Progress page
+    ID_CACHE_PROGRESS_PACKAGE_TEXT,
+    ID_CACHE_PROGRESS_BAR,
+    ID_CACHE_PROGRESS_TEXT,
+
+    ID_EXECUTE_PROGRESS_PACKAGE_TEXT,
+    ID_EXECUTE_PROGRESS_BAR,
+    ID_EXECUTE_PROGRESS_TEXT,
+    ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT,
+
+    ID_OVERALL_PROGRESS_PACKAGE_TEXT,
+    ID_OVERALL_PROGRESS_BAR,
+    ID_OVERALL_CALCULATED_PROGRESS_BAR,
+    ID_OVERALL_PROGRESS_TEXT,
+
+    ID_PROGRESS_CANCEL_BUTTON,
+
+    // Success page
+    ID_SUCCESS_TEXT,
+    ID_SUCCESS_RESTART_TEXT,
+    ID_SUCCESS_RESTART_BUTTON,
+    ID_SUCCESS_CANCEL_BUTTON,
+    ID_SUCCESS_MAX_PATH_BUTTON,
+
+    // Failure page
+    ID_FAILURE_LOGFILE_LINK,
+    ID_FAILURE_MESSAGE_TEXT,
+    ID_FAILURE_RESTART_TEXT,
+    ID_FAILURE_RESTART_BUTTON,
+    ID_FAILURE_CANCEL_BUTTON
+};
+
+static THEME_ASSIGN_CONTROL_ID CONTROL_ID_NAMES[] = {
+    { ID_CLOSE_BUTTON, L"CloseButton" },
+    { ID_MINIMIZE_BUTTON, L"MinimizeButton" },
+
+    { ID_INSTALL_BUTTON, L"InstallButton" },
+    { ID_INSTALL_CUSTOM_BUTTON, L"InstallCustomButton" },
+    { ID_INSTALL_SIMPLE_BUTTON, L"InstallSimpleButton" },
+    { ID_INSTALL_UPGRADE_BUTTON, L"InstallUpgradeButton" },
+    { ID_INSTALL_UPGRADE_CUSTOM_BUTTON, L"InstallUpgradeCustomButton" },
+    { ID_INSTALL_CANCEL_BUTTON, L"InstallCancelButton" },
+    { ID_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, L"InstallLauncherAllUsers" },
+
+    { ID_TARGETDIR_EDITBOX, L"TargetDir" },
+    { ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, L"AssociateFiles" },
+    { ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX, L"InstallAllUsers" },
+    { ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, 
L"CustomInstallLauncherAllUsers" },
+    { ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL, L"Include_launcherHelp" },
+    { ID_CUSTOM_COMPILE_ALL_CHECKBOX, L"CompileAll" },
+    { ID_CUSTOM_BROWSE_BUTTON, L"CustomBrowseButton" },
+    { ID_CUSTOM_BROWSE_BUTTON_LABEL, L"CustomBrowseButtonLabel" },
+    { ID_CUSTOM_INSTALL_BUTTON, L"CustomInstallButton" },
+    { ID_CUSTOM_NEXT_BUTTON, L"CustomNextButton" },
+    { ID_CUSTOM1_BACK_BUTTON, L"Custom1BackButton" },
+    { ID_CUSTOM2_BACK_BUTTON, L"Custom2BackButton" },
+    { ID_CUSTOM1_CANCEL_BUTTON, L"Custom1CancelButton" },
+    { ID_CUSTOM2_CANCEL_BUTTON, L"Custom2CancelButton" },
+
+    { ID_MODIFY_BUTTON, L"ModifyButton" },
+    { ID_REPAIR_BUTTON, L"RepairButton" },
+    { ID_UNINSTALL_BUTTON, L"UninstallButton" },
+    { ID_MODIFY_CANCEL_BUTTON, L"ModifyCancelButton" },
+
+    { ID_CACHE_PROGRESS_PACKAGE_TEXT, L"CacheProgressPackageText" },
+    { ID_CACHE_PROGRESS_BAR, L"CacheProgressbar" },
+    { ID_CACHE_PROGRESS_TEXT, L"CacheProgressText" },
+    { ID_EXECUTE_PROGRESS_PACKAGE_TEXT, L"ExecuteProgressPackageText" },
+    { ID_EXECUTE_PROGRESS_BAR, L"ExecuteProgressbar" },
+    { ID_EXECUTE_PROGRESS_TEXT, L"ExecuteProgressText" },
+    { ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L"ExecuteProgressActionDataText" },
+    { ID_OVERALL_PROGRESS_PACKAGE_TEXT, L"OverallProgressPackageText" },
+    { ID_OVERALL_PROGRESS_BAR, L"OverallProgressbar" },
+    { ID_OVERALL_CALCULATED_PROGRESS_BAR, L"OverallCalculatedProgressbar" },
+    { ID_OVERALL_PROGRESS_TEXT, L"OverallProgressText" },
+    { ID_PROGRESS_CANCEL_BUTTON, L"ProgressCancelButton" },
+
+    { ID_SUCCESS_TEXT, L"SuccessText" },
+    { ID_SUCCESS_RESTART_TEXT, L"SuccessRestartText" },
+    { ID_SUCCESS_RESTART_BUTTON, L"SuccessRestartButton" },
+    { ID_SUCCESS_CANCEL_BUTTON, L"SuccessCancelButton" },
+    { ID_SUCCESS_MAX_PATH_BUTTON, L"SuccessMaxPathButton" },
+
+    { ID_FAILURE_LOGFILE_LINK, L"FailureLogFileLink" },
+    { ID_FAILURE_MESSAGE_TEXT, L"FailureMessageText" },
+    { ID_FAILURE_RESTART_TEXT, L"FailureRestartText" },
+    { ID_FAILURE_RESTART_BUTTON, L"FailureRestartButton" },
+    { ID_FAILURE_CANCEL_BUTTON, L"FailureCancelButton" },
+};
+
+static struct { LPCWSTR regName; LPCWSTR variableName; } OPTIONAL_FEATURES[] = 
{
+    { L"core_d", L"Include_debug" },
+    { L"core_pdb", L"Include_symbols" },
+    { L"dev", L"Include_dev" },
+    { L"doc", L"Include_doc" },
+    { L"exe", L"Include_exe" },
+    { L"lib", L"Include_lib" },
+    { L"path", L"PrependPath" },
+    { L"pip", L"Include_pip" },
+    { L"tcltk", L"Include_tcltk" },
+    { L"test", L"Include_test" },
+    { L"tools", L"Include_tools" },
+    { L"Shortcuts", L"Shortcuts" },
+    // Include_launcher and AssociateFiles are handled separately and so do
+    // not need to be included in this list.
+    { nullptr, nullptr }
+};
+
+
+
+class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
+    void ShowPage(DWORD newPageId) {
+        // Process each control for special handling in the new page.
+        ProcessPageControls(ThemeGetPage(_theme, newPageId));
+
+        // Enable disable controls per-page.
+        if (_pageIds[PAGE_INSTALL] == newPageId ||
+            _pageIds[PAGE_SIMPLE_INSTALL] == newPageId ||
+            _pageIds[PAGE_UPGRADE] == newPageId) {
+            InstallPage_Show();
+        } else if (_pageIds[PAGE_CUSTOM1] == newPageId) {
+            Custom1Page_Show();
+        } else if (_pageIds[PAGE_CUSTOM2] == newPageId) {
+            Custom2Page_Show();
+        } else if (_pageIds[PAGE_MODIFY] == newPageId) {
+            ModifyPage_Show();
+        } else if (_pageIds[PAGE_SUCCESS] == newPageId) {
+            SuccessPage_Show();
+        } else if (_pageIds[PAGE_FAILURE] == newPageId) {
+            FailurePage_Show();
+        }
+
+        // Prevent repainting while switching page to avoid ugly flickering
+        _suppressPaint = TRUE;
+        ThemeShowPage(_theme, newPageId, SW_SHOW);
+        ThemeShowPage(_theme, _visiblePageId, SW_HIDE);
+        _suppressPaint = FALSE;
+        InvalidateRect(_theme->hwndParent, nullptr, TRUE);
+        _visiblePageId = newPageId;
+
+        // On the install page set the focus to the install button or
+        // the next enabled control if install is disabled
+        if (_pageIds[PAGE_INSTALL] == newPageId) {
+            ThemeSetFocus(_theme, ID_INSTALL_BUTTON);
+        } else if (_pageIds[PAGE_SIMPLE_INSTALL] == newPageId) {
+            ThemeSetFocus(_theme, ID_INSTALL_SIMPLE_BUTTON);
+        }
+    }
+
+    //
+    // Handles control clicks
+    //
+    void OnCommand(CONTROL_ID id) {
+        LPWSTR defaultDir = nullptr;
+        LPWSTR targetDir = nullptr;
+        LONGLONG elevated, crtInstalled, installAllUsers;
+        BOOL checked, launcherChecked;
+        WCHAR wzPath[MAX_PATH] = { };
+        BROWSEINFOW browseInfo = { };
+        PIDLIST_ABSOLUTE pidl = nullptr;
+        DWORD pageId;
+        HRESULT hr = S_OK;
+
+        switch(id) {
+        case ID_CLOSE_BUTTON:
+            OnClickCloseButton();
+            break;
+
+        // Install commands
+        case ID_INSTALL_SIMPLE_BUTTON: __fallthrough;
+        case ID_INSTALL_UPGRADE_BUTTON: __fallthrough;
+        case ID_INSTALL_BUTTON:
+            SavePageSettings();
+
+            hr = BalGetNumericVariable(L"InstallAllUsers", &installAllUsers);
+            ExitOnFailure(hr, L"Failed to get install scope");
+
+            hr = _engine->SetVariableNumeric(L"CompileAll", installAllUsers);
+            ExitOnFailure(hr, L"Failed to update CompileAll");
+
+            hr = EnsureTargetDir();
+            ExitOnFailure(hr, L"Failed to set TargetDir");
+
+            OnPlan(BOOTSTRAPPER_ACTION_INSTALL);
+            break;
+
+        case ID_CUSTOM1_BACK_BUTTON:
+            SavePageSettings();
+            if (_modifying) {
+                GoToPage(PAGE_MODIFY);
+            } else if (_upgrading) {
+                GoToPage(PAGE_UPGRADE);
+            } else {
+                GoToPage(PAGE_INSTALL);
+            }
+            break;
+
+        case ID_INSTALL_CUSTOM_BUTTON: __fallthrough;
+        case ID_INSTALL_UPGRADE_CUSTOM_BUTTON: __fallthrough;
+        case ID_CUSTOM2_BACK_BUTTON:
+            SavePageSettings();
+            GoToPage(PAGE_CUSTOM1);
+            break;
+
+        case ID_CUSTOM_NEXT_BUTTON:
+            SavePageSettings();
+            GoToPage(PAGE_CUSTOM2);
+            break;
+
+        case ID_CUSTOM_INSTALL_BUTTON:
+            SavePageSettings();
+
+            hr = EnsureTargetDir();
+            ExitOnFailure(hr, L"Failed to set TargetDir");
+
+            hr = BalGetStringVariable(L"TargetDir", &targetDir);
+            if (SUCCEEDED(hr)) {
+                // TODO: Check whether directory exists and contains another 
installation
+                ReleaseStr(targetDir);
+            }
+
+            OnPlan(_command.action);
+            break;
+
+        case ID_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX:
+            checked = ThemeIsControlChecked(_theme, 
ID_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX);
+            _engine->SetVariableNumeric(L"InstallLauncherAllUsers", checked);
+
+            ThemeControlElevates(_theme, ID_INSTALL_BUTTON, WillElevate());
+            break;
+
+        case ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX:
+            checked = ThemeIsControlChecked(_theme, 
ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX);
+            _engine->SetVariableNumeric(L"InstallLauncherAllUsers", checked);
+
+            ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, 
WillElevate());
+            break;
+
+        case ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX:
+            checked = ThemeIsControlChecked(_theme, 
ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX);
+            _engine->SetVariableNumeric(L"InstallAllUsers", checked);
+
+            ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, 
WillElevate());
+            ThemeControlEnable(_theme, ID_CUSTOM_BROWSE_BUTTON_LABEL, 
!checked);
+            if (checked) {
+                _engine->SetVariableNumeric(L"CompileAll", 1);
+                ThemeSendControlMessage(_theme, 
ID_CUSTOM_COMPILE_ALL_CHECKBOX, BM_SETCHECK, BST_CHECKED, 0);
+            }
+            ThemeGetTextControl(_theme, ID_TARGETDIR_EDITBOX, &targetDir);
+            if (targetDir) {
+                // Check the current value against the default to see
+                // if we should switch it automatically.
+                hr = BalGetStringVariable(
+                    checked ? L"DefaultJustForMeTargetDir" : 
L"DefaultAllUsersTargetDir",
+                    &defaultDir
+                );
+                
+                if (SUCCEEDED(hr) && defaultDir) {
+                    LPWSTR formatted = nullptr;
+                    if (defaultDir[0] && SUCCEEDED(BalFormatString(defaultDir, 
&formatted))) {
+                        if (wcscmp(formatted, targetDir) == 0) {
+                            ReleaseStr(defaultDir);
+                            defaultDir = nullptr;
+                            ReleaseStr(formatted);
+                            formatted = nullptr;
+                            
+                            hr = BalGetStringVariable(
+                                checked ? L"DefaultAllUsersTargetDir" : 
L"DefaultJustForMeTargetDir",
+                                &defaultDir
+                            );
+                            if (SUCCEEDED(hr) && defaultDir && defaultDir[0] 
&& SUCCEEDED(BalFormatString(defaultDir, &formatted))) {
+                                ThemeSetTextControl(_theme, 
ID_TARGETDIR_EDITBOX, formatted);
+                                ReleaseStr(formatted);
+                            }
+                        } else {
+                            ReleaseStr(formatted);
+                        }
+                    }
+                    
+                    ReleaseStr(defaultDir);
+                }
+            }
+            break;
+
+        case ID_CUSTOM_BROWSE_BUTTON:
+            browseInfo.hwndOwner = _hWnd;
+            browseInfo.pszDisplayName = wzPath;
+            browseInfo.lpszTitle = _theme->sczCaption;
+            browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
+            pidl = ::SHBrowseForFolderW(&browseInfo);
+            if (pidl && ::SHGetPathFromIDListW(pidl, wzPath)) {
+                ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, wzPath);
+            }
+
+            if (pidl) {
+                ::CoTaskMemFree(pidl);
+            }
+            break;
+
+        // Modify commands
+        case ID_MODIFY_BUTTON:
+            // Some variables cannot be modified
+            _engine->SetVariableString(L"InstallAllUsersState", L"disable");
+            _engine->SetVariableString(L"InstallLauncherAllUsersState", 
L"disable");
+            _engine->SetVariableString(L"TargetDirState", L"disable");
+            _engine->SetVariableString(L"CustomBrowseButtonState", L"disable");
+            _modifying = TRUE;
+            GoToPage(PAGE_CUSTOM1);
+            break;
+
+        case ID_REPAIR_BUTTON:
+            OnPlan(BOOTSTRAPPER_ACTION_REPAIR);
+            break;
+
+        case ID_UNINSTALL_BUTTON:
+            OnPlan(BOOTSTRAPPER_ACTION_UNINSTALL);
+            break;
+
+        case ID_SUCCESS_MAX_PATH_BUTTON:
+            EnableMaxPathSupport();
+            ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+            break;
+        }
+
+    LExit:
+        return;
+    }
+
+    void InstallPage_Show() {
+        // Ensure the All Users install button has a UAC shield
+        BOOL elevated = WillElevate();
+        ThemeControlElevates(_theme, ID_INSTALL_BUTTON, elevated);
+        ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, elevated);
+        ThemeControlElevates(_theme, ID_INSTALL_UPGRADE_BUTTON, elevated);
+    }
+
+    void Custom1Page_Show() {
+        LONGLONG installLauncherAllUsers;
+
+        if (FAILED(BalGetNumericVariable(L"InstallLauncherAllUsers", 
&installLauncherAllUsers))) {
+            installLauncherAllUsers = 0;
+        }
+
+        ThemeSendControlMessage(_theme, 
ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, BM_SETCHECK,
+            installLauncherAllUsers ? BST_CHECKED : BST_UNCHECKED, 0);
+
+        LOC_STRING *pLocString = nullptr;
+        LPCWSTR locKey = L"#(loc.Include_launcherHelp)";
+        LONGLONG detectedLauncher;
+
+        if (SUCCEEDED(BalGetNumericVariable(L"DetectedLauncher", 
&detectedLauncher)) && detectedLauncher) {
+            locKey = L"#(loc.Include_launcherRemove)";
+        } else if (SUCCEEDED(BalGetNumericVariable(L"DetectedOldLauncher", 
&detectedLauncher)) && detectedLauncher) {
+            locKey = L"#(loc.Include_launcherUpgrade)";
+        }
+
+        if (SUCCEEDED(LocGetString(_wixLoc, locKey, &pLocString)) && 
pLocString) {
+            ThemeSetTextControl(_theme, ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL, 
pLocString->wzText);
+        }
+    }
+
+    void Custom2Page_Show() {
+        HRESULT hr;
+        LONGLONG installAll, includeLauncher;
+        
+        if (FAILED(BalGetNumericVariable(L"InstallAllUsers", &installAll))) {
+            installAll = 0;
+        }
+
+        if (WillElevate()) {
+            ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, TRUE);
+            ThemeShowControl(_theme, ID_CUSTOM_BROWSE_BUTTON_LABEL, SW_HIDE);
+        } else {
+            ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, FALSE);
+            ThemeShowControl(_theme, ID_CUSTOM_BROWSE_BUTTON_LABEL, SW_SHOW);
+        }
+
+        if (SUCCEEDED(BalGetNumericVariable(L"Include_launcher", 
&includeLauncher)) && includeLauncher) {
+            ThemeControlEnable(_theme, ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, 
TRUE);
+        } else {
+            ThemeSendControlMessage(_theme, 
ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, BM_SETCHECK, BST_UNCHECKED, 0);
+            ThemeControlEnable(_theme, ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, 
FALSE);
+        }
+
+        LPWSTR targetDir = nullptr;
+        hr = BalGetStringVariable(L"TargetDir", &targetDir);
+        if (SUCCEEDED(hr) && targetDir && targetDir[0]) {
+            ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, targetDir);
+            StrFree(targetDir);
+        } else if (SUCCEEDED(hr)) {
+            StrFree(targetDir);
+            targetDir = nullptr;
+
+            LPWSTR defaultTargetDir = nullptr;
+            hr = BalGetStringVariable(L"DefaultCustomTargetDir", 
&defaultTargetDir);
+            if (SUCCEEDED(hr) && defaultTargetDir && !defaultTargetDir[0]) {
+                StrFree(defaultTargetDir);
+                defaultTargetDir = nullptr;
+                
+                hr = BalGetStringVariable(
+                    installAll ? L"DefaultAllUsersTargetDir" : 
L"DefaultJustForMeTargetDir",
+                    &defaultTargetDir
+                );
+            }
+            if (SUCCEEDED(hr) && defaultTargetDir) {
+                if (defaultTargetDir[0] && 
SUCCEEDED(BalFormatString(defaultTargetDir, &targetDir))) {
+                    ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, 
targetDir);
+                    StrFree(targetDir);
+                }
+                StrFree(defaultTargetDir);
+            }
+        }
+    }
+
+    void ModifyPage_Show() {
+        ThemeControlEnable(_theme, ID_REPAIR_BUTTON, !_suppressRepair);
+    }
+
+    void SuccessPage_Show() {
+        // on the "Success" page, check if the restart button should be 
enabled.
+        BOOL showRestartButton = FALSE;
+        LOC_STRING *successText = nullptr;
+        HRESULT hr = S_OK;
+        
+        if (_restartRequired) {
+            if (BOOTSTRAPPER_RESTART_PROMPT == _command.restart) {
+                showRestartButton = TRUE;
+            }
+        }
+
+        switch (_plannedAction) {
+        case BOOTSTRAPPER_ACTION_INSTALL:
+            hr = LocGetString(_wixLoc, L"#(loc.SuccessInstallMessage)", 
&successText);
+            break;
+        case BOOTSTRAPPER_ACTION_MODIFY:
+            hr = LocGetString(_wixLoc, L"#(loc.SuccessModifyMessage)", 
&successText);
+            break;
+        case BOOTSTRAPPER_ACTION_REPAIR:
+            hr = LocGetString(_wixLoc, L"#(loc.SuccessRepairMessage)", 
&successText);
+            break;
+        case BOOTSTRAPPER_ACTION_UNINSTALL:
+            hr = LocGetString(_wixLoc, L"#(loc.SuccessRemoveMessage)", 
&successText);
+            break;
+        }
+
+        if (successText) {
+            LPWSTR formattedString = nullptr;
+            BalFormatString(successText->wzText, &formattedString);
+            if (formattedString) {
+                ThemeSetTextControl(_theme, ID_SUCCESS_TEXT, formattedString);
+                StrFree(formattedString);
+            }
+        }
+
+        ThemeControlEnable(_theme, ID_SUCCESS_RESTART_TEXT, showRestartButton);
+        ThemeControlEnable(_theme, ID_SUCCESS_RESTART_BUTTON, 
showRestartButton);
+
+        if (_command.action != BOOTSTRAPPER_ACTION_INSTALL ||
+            !IsWindowsVersionOrGreater(10, 0, 0)) {
+            ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+        } else {
+            DWORD dataType = 0, buffer = 0, bufferLen = sizeof(buffer);
+            HKEY hKey;
+            LRESULT res = RegOpenKeyExW(
+                HKEY_LOCAL_MACHINE,
+                L"SYSTEM\\CurrentControlSet\\Control\\FileSystem",
+                0,
+                KEY_READ,
+                &hKey
+            );
+            if (res == ERROR_SUCCESS) {
+                res = RegQueryValueExW(hKey, L"LongPathsEnabled", nullptr, 
&dataType,
+                    (LPBYTE)&buffer, &bufferLen);
+                RegCloseKey(hKey);
+            }
+            else {
+                BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Failed to open 
SYSTEM\\CurrentControlSet\\Control\\FileSystem: error code %d", res);
+            }
+            if (res == ERROR_SUCCESS && dataType == REG_DWORD && buffer == 0) {
+                ThemeControlElevates(_theme, ID_SUCCESS_MAX_PATH_BUTTON, TRUE);
+            }
+            else {
+                if (res == ERROR_SUCCESS)
+                    BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Failed to read 
LongPathsEnabled value: error code %d", res);
+                else
+                    BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Hiding MAX_PATH 
button because it is already enabled");
+                ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+            }
+        }
+    }
+
+    void FailurePage_Show() {
+        // on the "Failure" page, show error message and check if the restart 
button should be enabled.
+
+        // if there is a log file variable then we'll assume the log file 
exists.
+        BOOL showLogLink = (_bundle.sczLogVariable && *_bundle.sczLogVariable);
+        BOOL showErrorMessage = FALSE;
+        BOOL showRestartButton = FALSE;
+
+        if (FAILED(_hrFinal)) {
+            LPWSTR unformattedText = nullptr;
+            LPWSTR text = nullptr;
+
+            // If we know the failure message, use that.
+            if (_failedMessage && *_failedMessage) {
+                StrAllocString(&unformattedText, _failedMessage, 0);
+            } else {
+                // try to get the error message from the error code.
+                StrAllocFromError(&unformattedText, _hrFinal, nullptr);
+                if (!unformattedText || !*unformattedText) {
+                    StrAllocFromError(&unformattedText, E_FAIL, nullptr);
+                }
+            }
+
+            if (E_WIXSTDBA_CONDITION_FAILED == _hrFinal) {
+                if (unformattedText) {
+                    StrAllocString(&text, unformattedText, 0);
+                }
+            } else {
+                StrAllocFormatted(&text, L"0x%08x - %ls", _hrFinal, 
unformattedText);
+            }
+
+            if (text) {
+                ThemeSetTextControl(_theme, ID_FAILURE_MESSAGE_TEXT, text);
+                showErrorMessage = TRUE;
+            }
+
+            ReleaseStr(text);
+            ReleaseStr(unformattedText);
+        }
+
+        if (_restartRequired && BOOTSTRAPPER_RESTART_PROMPT == 
_command.restart) {
+            showRestartButton = TRUE;
+        }
+
+        ThemeControlEnable(_theme, ID_FAILURE_LOGFILE_LINK, showLogLink);
+        ThemeControlEnable(_theme, ID_FAILURE_MESSAGE_TEXT, showErrorMessage);
+        ThemeControlEnable(_theme, ID_FAILURE_RESTART_TEXT, showRestartButton);
+        ThemeControlEnable(_theme, ID_FAILURE_RESTART_BUTTON, 
showRestartButton);
+    }
+
+    static void EnableMaxPathSupport() {
+        LPWSTR targetDir = nullptr, defaultDir = nullptr;
+        HRESULT hr = BalGetStringVariable(L"TargetDir", &targetDir);
+        if (FAILED(hr) || !targetDir || !targetDir[0]) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to get TargetDir");
+            return;
+        }
+
+        LPWSTR pythonw = nullptr;
+        StrAllocFormatted(&pythonw, L"%ls\\pythonw.exe", targetDir);
+        if (!pythonw || !pythonw[0]) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to construct 
pythonw.exe path");
+            return;
+        }
+
+        LPCWSTR arguments = L"-c \"import winreg; "
+            "winreg.SetValueEx("
+                "winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, "
+                    "r'SYSTEM\\CurrentControlSet\\Control\\FileSystem'), "
+                "'LongPathsEnabled', "
+                "None, "
+                "winreg.REG_DWORD, "
+                "1"
+            ")\"";
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Executing %ls %ls", pythonw, 
arguments);
+        HINSTANCE res = ShellExecuteW(0, L"runas", pythonw, arguments, NULL, 
SW_HIDE);
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "return code 0x%08x", res);
+    }
+
+public: // IBootstrapperApplication
+    virtual STDMETHODIMP OnStartup() {
+        HRESULT hr = S_OK;
+        DWORD dwUIThreadId = 0;
+
+        // create UI thread
+        _hUiThread = ::CreateThread(nullptr, 0, UiThreadProc, this, 0, 
&dwUIThreadId);
+        if (!_hUiThread) {
+            ExitWithLastError(hr, "Failed to create UI thread.");
+        }
+
+    LExit:
+        return hr;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnShutdown() {
+        int nResult = IDNOACTION;
+
+        // wait for UI thread to terminate
+        if (_hUiThread) {
+            ::WaitForSingleObject(_hUiThread, INFINITE);
+            ReleaseHandle(_hUiThread);
+        }
+
+        // If a restart was required.
+        if (_restartRequired && _allowRestart) {
+            nResult = IDRESTART;
+        }
+
+        return nResult;
+    }
+
+    virtual STDMETHODIMP_(int) OnDetectRelatedMsiPackage(
+        __in_z LPCWSTR wzPackageId,
+        __in_z LPCWSTR /*wzProductCode*/,
+        __in BOOL fPerMachine,
+        __in DWORD64 /*dw64Version*/,
+        __in BOOTSTRAPPER_RELATED_OPERATION operation
+    ) {
+        if (BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE == operation && 
+            (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, 
-1, L"launcher_AllUsers", -1) ||
+             CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, 
-1, L"launcher_JustForMe", -1))) {
+            auto hr = LoadAssociateFilesStateFromKey(_engine, fPerMachine ? 
HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
+            if (hr == S_OK) {
+                _engine->SetVariableNumeric(L"AssociateFiles", 1);
+            } else if (FAILED(hr)) {
+                BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load 
AssociateFiles state: error code 0x%08X", hr);
+            }
+
+            _engine->SetVariableNumeric(L"Include_launcher", 1);
+            _engine->SetVariableNumeric(L"DetectedOldLauncher", 1);
+            _engine->SetVariableNumeric(L"InstallLauncherAllUsers", 
fPerMachine ? 1 : 0);
+        }
+        return CheckCanceled() ? IDCANCEL : IDNOACTION;
+    }
+
+    virtual STDMETHODIMP_(int) OnDetectRelatedBundle(
+        __in LPCWSTR wzBundleId,
+        __in BOOTSTRAPPER_RELATION_TYPE relationType,
+        __in LPCWSTR /*wzBundleTag*/,
+        __in BOOL fPerMachine,
+        __in DWORD64 /*dw64Version*/,
+        __in BOOTSTRAPPER_RELATED_OPERATION operation
+    ) {
+        BalInfoAddRelatedBundleAsPackage(&_bundle.packages, wzBundleId, 
relationType, fPerMachine);
+
+        // Remember when our bundle would cause a downgrade.
+        if (BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE == operation) {
+            _downgradingOtherVersion = TRUE;
+        } else if (BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE == operation) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Detected previous version 
- planning upgrade");
+            _upgrading = TRUE;
+
+            LoadOptionalFeatureStates(_engine);
+        } else if (BOOTSTRAPPER_RELATED_OPERATION_NONE == operation) {
+            if (_command.action == BOOTSTRAPPER_ACTION_INSTALL) {
+                LOC_STRING *pLocString = nullptr;
+                if (SUCCEEDED(LocGetString(_wixLoc, 
L"#(loc.FailureExistingInstall)", &pLocString)) && pLocString) {
+                    BalFormatString(pLocString->wzText, &_failedMessage);
+                } else {
+                    BalFormatString(L"Cannot install [WixBundleName] because 
it is already installed.", &_failedMessage);
+                }
+                BalLog(
+                    BOOTSTRAPPER_LOG_LEVEL_ERROR,
+                    "Related bundle %ls is preventing install",
+                    wzBundleId
+                );
+                SetState(PYBA_STATE_FAILED, E_WIXSTDBA_CONDITION_FAILED);
+            }
+        }
+
+        return CheckCanceled() ? IDCANCEL : IDOK;
+    }
+
+
+    virtual STDMETHODIMP_(void) OnDetectPackageComplete(
+        __in LPCWSTR wzPackageId,
+        __in HRESULT hrStatus,
+        __in BOOTSTRAPPER_PACKAGE_STATE state
+    ) {
+        if (FAILED(hrStatus)) {
+            return;
+        }
+
+        BOOL detectedLauncher = FALSE;
+        HKEY hkey = HKEY_LOCAL_MACHINE;
+        if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, 
L"launcher_AllUsers", -1)) {
+            if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || 
BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE == state) {
+                detectedLauncher = TRUE;
+                _engine->SetVariableNumeric(L"InstallLauncherAllUsers", 1);
+            }
+        } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, 
wzPackageId, -1, L"launcher_JustForMe", -1)) {
+            if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || 
BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE == state) {
+                detectedLauncher = TRUE;
+                _engine->SetVariableNumeric(L"InstallLauncherAllUsers", 0);
+            }
+        }
+
+        if (detectedLauncher) {
+            /* When we detect the current version of the launcher. */
+            _engine->SetVariableNumeric(L"Include_launcher", 1);
+            _engine->SetVariableNumeric(L"DetectedLauncher", 1);
+            _engine->SetVariableString(L"Include_launcherState", L"disable");
+            _engine->SetVariableString(L"InstallLauncherAllUsersState", 
L"disable");
+
+            auto hr = LoadAssociateFilesStateFromKey(_engine, hkey);
+            if (hr == S_OK) {
+                _engine->SetVariableNumeric(L"AssociateFiles", 1);
+            } else if (FAILED(hr)) {
+                BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load 
AssociateFiles state: error code 0x%08X", hr);
+            }
+        }
+    }
+
+
+    virtual STDMETHODIMP_(void) OnDetectComplete(__in HRESULT hrStatus) {
+        if (SUCCEEDED(hrStatus) && _baFunction) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running detect complete 
BA function");
+            _baFunction->OnDetectComplete();
+        }
+
+        if (SUCCEEDED(hrStatus)) {
+            hrStatus = EvaluateConditions();
+        }
+
+        if (SUCCEEDED(hrStatus)) {
+            // Ensure the default path has been set
+            hrStatus = EnsureTargetDir();
+        }
+
+        SetState(PYBA_STATE_DETECTED, hrStatus);
+
+        // If we're not interacting with the user or we're doing a layout or 
we're just after a force restart
+        // then automatically start planning.
+        if (BOOTSTRAPPER_DISPLAY_FULL > _command.display ||
+            BOOTSTRAPPER_ACTION_LAYOUT == _command.action ||
+            BOOTSTRAPPER_ACTION_UNINSTALL == _command.action ||
+            BOOTSTRAPPER_RESUME_TYPE_REBOOT == _command.resumeType) {
+            if (SUCCEEDED(hrStatus)) {
+                ::PostMessageW(_hWnd, WM_PYBA_PLAN_PACKAGES, 0, 
_command.action);
+            }
+        }
+    }
+
+
+    virtual STDMETHODIMP_(int) OnPlanRelatedBundle(
+        __in_z LPCWSTR /*wzBundleId*/,
+        __inout_z BOOTSTRAPPER_REQUEST_STATE* pRequestedState
+    ) {
+        return CheckCanceled() ? IDCANCEL : IDOK;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnPlanPackageBegin(
+        __in_z LPCWSTR wzPackageId,
+        __inout BOOTSTRAPPER_REQUEST_STATE *pRequestState
+    ) {
+        HRESULT hr = S_OK;
+        BAL_INFO_PACKAGE* pPackage = nullptr;
+
+        if (_nextPackageAfterRestart) {
+            // After restart we need to finish the dependency registration for 
our package so allow the package
+            // to go present.
+            if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, 
-1, _nextPackageAfterRestart, -1)) {
+                // Do not allow a repair because that could put us in a 
perpetual restart loop.
+                if (BOOTSTRAPPER_REQUEST_STATE_REPAIR == *pRequestState) {
+                    *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
+                }
+
+                ReleaseNullStr(_nextPackageAfterRestart); // no more skipping 
now.
+            } else {
+                // not the matching package, so skip it.
+                BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Skipping package: 
%ls, after restart because it was applied before the restart.", wzPackageId);
+
+                *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
+            }
+        } else if ((_plannedAction == BOOTSTRAPPER_ACTION_INSTALL || 
_plannedAction == BOOTSTRAPPER_ACTION_MODIFY) &&
+                   SUCCEEDED(BalInfoFindPackageById(&_bundle.packages, 
wzPackageId, &pPackage))) {
+            BOOL f = FALSE;
+            if 
(SUCCEEDED(_engine->EvaluateCondition(pPackage->sczInstallCondition, &f)) && f) 
{
+                *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
+            }
+        }
+
+        return CheckCanceled() ? IDCANCEL : IDOK;
+    }
+
+    virtual STDMETHODIMP_(int) OnPlanMsiFeature(
+        __in_z LPCWSTR wzPackageId,
+        __in_z LPCWSTR wzFeatureId,
+        __inout BOOTSTRAPPER_FEATURE_STATE* pRequestedState
+    ) {
+        LONGLONG install;
+        
+        if (wcscmp(wzFeatureId, L"AssociateFiles") == 0 || wcscmp(wzFeatureId, 
L"Shortcuts") == 0) {
+            if (SUCCEEDED(_engine->GetVariableNumeric(wzFeatureId, &install)) 
&& install) {
+                *pRequestedState = BOOTSTRAPPER_FEATURE_STATE_LOCAL;
+            } else {
+                *pRequestedState = BOOTSTRAPPER_FEATURE_STATE_ABSENT;
+            }
+        } else {
+            *pRequestedState = BOOTSTRAPPER_FEATURE_STATE_LOCAL;
+        }
+        return CheckCanceled() ? IDCANCEL : IDNOACTION;
+    }
+
+    virtual STDMETHODIMP_(void) OnPlanComplete(__in HRESULT hrStatus) {
+        if (SUCCEEDED(hrStatus) && _baFunction) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running plan complete BA 
function");
+            _baFunction->OnPlanComplete();
+        }
+
+        SetState(PYBA_STATE_PLANNED, hrStatus);
+
+        if (SUCCEEDED(hrStatus)) {
+            ::PostMessageW(_hWnd, WM_PYBA_APPLY_PACKAGES, 0, 0);
+        }
+
+        _startedExecution = FALSE;
+        _calculatedCacheProgress = 0;
+        _calculatedExecuteProgress = 0;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnCachePackageBegin(
+        __in_z LPCWSTR wzPackageId,
+        __in DWORD cCachePayloads,
+        __in DWORD64 dw64PackageCacheSize
+    ) {
+        if (wzPackageId && *wzPackageId) {
+            BAL_INFO_PACKAGE* pPackage = nullptr;
+            HRESULT hr = BalInfoFindPackageById(&_bundle.packages, 
wzPackageId, &pPackage);
+            LPCWSTR wz = (SUCCEEDED(hr) && pPackage->sczDisplayName) ? 
pPackage->sczDisplayName : wzPackageId;
+
+            ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_PACKAGE_TEXT, wz);
+
+            // If something started executing, leave it in the overall 
progress text.
+            if (!_startedExecution) {
+                ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_PACKAGE_TEXT, 
wz);
+            }
+        }
+
+        return __super::OnCachePackageBegin(wzPackageId, cCachePayloads, 
dw64PackageCacheSize);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnCacheAcquireProgress(
+        __in_z LPCWSTR wzPackageOrContainerId,
+        __in_z_opt LPCWSTR wzPayloadId,
+        __in DWORD64 dw64Progress,
+        __in DWORD64 dw64Total,
+        __in DWORD dwOverallPercentage
+    ) {
+        WCHAR wzProgress[5] = { };
+
+#ifdef DEBUG
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: 
OnCacheAcquireProgress() - container/package: %ls, payload: %ls, progress: 
%I64u, total: %I64u, overall progress: %u%%", wzPackageOrContainerId, 
wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage);
+#endif
+
+        ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", 
dwOverallPercentage);
+        ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_TEXT, wzProgress);
+
+        ThemeSetProgressControl(_theme, ID_CACHE_PROGRESS_BAR, 
dwOverallPercentage);
+
+        _calculatedCacheProgress = dwOverallPercentage * 
PYBA_ACQUIRE_PERCENTAGE / 100;
+        ThemeSetProgressControl(_theme, ID_OVERALL_CALCULATED_PROGRESS_BAR, 
_calculatedCacheProgress + _calculatedExecuteProgress);
+
+        SetTaskbarButtonProgress(_calculatedCacheProgress + 
_calculatedExecuteProgress);
+
+        return __super::OnCacheAcquireProgress(wzPackageOrContainerId, 
wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnCacheAcquireComplete(
+        __in_z LPCWSTR wzPackageOrContainerId,
+        __in_z_opt LPCWSTR wzPayloadId,
+        __in HRESULT hrStatus,
+        __in int nRecommendation
+    ) {
+        SetProgressState(hrStatus);
+        return __super::OnCacheAcquireComplete(wzPackageOrContainerId, 
wzPayloadId, hrStatus, nRecommendation);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnCacheVerifyComplete(
+        __in_z LPCWSTR wzPackageId,
+        __in_z LPCWSTR wzPayloadId,
+        __in HRESULT hrStatus,
+        __in int nRecommendation
+    ) {
+        SetProgressState(hrStatus);
+        return __super::OnCacheVerifyComplete(wzPackageId, wzPayloadId, 
hrStatus, nRecommendation);
+    }
+
+
+    virtual STDMETHODIMP_(void) OnCacheComplete(__in HRESULT /*hrStatus*/) {
+        ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_PACKAGE_TEXT, L"");
+        SetState(PYBA_STATE_CACHED, S_OK); // we always return success here 
and let OnApplyComplete() deal with the error.
+    }
+
+
+    virtual STDMETHODIMP_(int) OnError(
+        __in BOOTSTRAPPER_ERROR_TYPE errorType,
+        __in LPCWSTR wzPackageId,
+        __in DWORD dwCode,
+        __in_z LPCWSTR wzError,
+        __in DWORD dwUIHint,
+        __in DWORD /*cData*/,
+        __in_ecount_z_opt(cData) LPCWSTR* /*rgwzData*/,
+        __in int nRecommendation
+    ) {
+        int nResult = nRecommendation;
+        LPWSTR sczError = nullptr;
+
+        if (BOOTSTRAPPER_DISPLAY_EMBEDDED == _command.display) {
+            HRESULT hr = _engine->SendEmbeddedError(dwCode, wzError, dwUIHint, 
&nResult);
+            if (FAILED(hr)) {
+                nResult = IDERROR;
+            }
+        } else if (BOOTSTRAPPER_DISPLAY_FULL == _command.display) {
+            // If this is an authentication failure, let the engine try to 
handle it for us.
+            if (BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_SERVER == errorType || 
BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_PROXY == errorType) {
+                nResult = IDTRYAGAIN;
+            } else // show a generic error message box.
+            {
+                BalRetryErrorOccurred(wzPackageId, dwCode);
+
+                if (!_showingInternalUIThisPackage) {
+                    // If no error message was provided, use the error code to 
try and get an error message.
+                    if (!wzError || !*wzError || 
BOOTSTRAPPER_ERROR_TYPE_WINDOWS_INSTALLER != errorType) {
+                        HRESULT hr = StrAllocFromError(&sczError, dwCode, 
nullptr);
+                        if (FAILED(hr) || !sczError || !*sczError) {
+                            StrAllocFormatted(&sczError, L"0x%x", dwCode);
+                        }
+                    }
+
+                    nResult = ::MessageBoxW(_hWnd, sczError ? sczError : 
wzError, _theme->sczCaption, dwUIHint);
+                }
+            }
+
+            SetProgressState(HRESULT_FROM_WIN32(dwCode));
+        } else {
+            // just take note of the error code and let things continue.
+            BalRetryErrorOccurred(wzPackageId, dwCode);
+        }
+
+        ReleaseStr(sczError);
+        return nResult;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnExecuteMsiMessage(
+        __in_z LPCWSTR wzPackageId,
+        __in INSTALLMESSAGE mt,
+        __in UINT uiFlags,
+        __in_z LPCWSTR wzMessage,
+        __in DWORD cData,
+        __in_ecount_z_opt(cData) LPCWSTR* rgwzData,
+        __in int nRecommendation
+    ) {
+#ifdef DEBUG
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnExecuteMsiMessage() - 
package: %ls, message: %ls", wzPackageId, wzMessage);
+#endif
+        if (BOOTSTRAPPER_DISPLAY_FULL == _command.display && 
(INSTALLMESSAGE_WARNING == mt || INSTALLMESSAGE_USER == mt)) {
+            int nResult = ::MessageBoxW(_hWnd, wzMessage, _theme->sczCaption, 
uiFlags);
+            return nResult;
+        }
+
+        if (INSTALLMESSAGE_ACTIONSTART == mt) {
+            ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, 
wzMessage);
+        }
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to