8214566: --win-dir-chooser does not prompt if destination folder is not empty
Submitten-by: almatvee
Reviewed-by: herrick
--- a/make/lib/Lib-jdk.jpackage.gmk Mon Mar 11 13:21:49 2019 -0400
+++ b/make/lib/Lib-jdk.jpackage.gmk Mon Mar 11 13:24:47 2019 -0400
@@ -67,3 +67,21 @@
endif
+# Build Wix custom action helper
+# Output library in resources dir, and symbols in the object dir
+ifeq ($(OPENJDK_TARGET_OS), windows)
+
+ $(eval $(call SetupJdkLibrary, BUILD_LIB_WIXHELPER, \
+ NAME := wixhelper, \
+ OUTPUT_DIR := $(JDK_OUTPUTDIR)/modules/$(MODULE)/jdk/jpackage/internal/resources, \
+ SYMBOLS_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libwixhelper, \
+ OPTIMIZATION := LOW, \
+ CFLAGS := $(CXXFLAGS_JDKLIB), \
+ CFLAGS_windows := -EHsc -DUNICODE -D_UNICODE, \
+ LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK), \
+ LIBS := $(LIBCXX), \
+ LIBS_windows := msi.lib Shlwapi.lib User32.lib, \
+ ))
+
+ TARGETS += $(BUILD_LIB_WIXHELPER)
+endif
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java Mon Mar 11 13:21:49 2019 -0400
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java Mon Mar 11 13:24:47 2019 -0400
@@ -592,6 +592,15 @@
data.put("UI_BLOCK", getUIBlock(params));
+ // Add CA to check install dir
+ if (INSTALLDIR_CHOOSER.fetchFrom(params)) {
+ data.put("CA_BLOCK", CA_BLOCK);
+ data.put("INVALID_INSTALL_DIR_DLG_BLOCK", INVALID_INSTALL_DIR_DLG_BLOCK);
+ } else {
+ data.put("CA_BLOCK", "");
+ data.put("INVALID_INSTALL_DIR_DLG_BLOCK", "");
+ }
+
List<Map<String, ? super Object>> secondaryLaunchers =
SECONDARY_LAUNCHERS.fetchFrom(params);
@@ -635,6 +644,28 @@
private int compId;
private final static String LAUNCHER_ID = "LauncherId";
+ private static final String CA_BLOCK =
+ "<Binary Id=\"CustomActionDLL\" SourceFile=\"wixhelper.dll\" />\n" +
+ "<CustomAction Id=\"CHECK_INSTALLDIR\" BinaryKey=\"CustomActionDLL\" " +
+ "DllEntry=\"CheckInstallDir\" />";
+
+ private static final String INVALID_INSTALL_DIR_DLG_BLOCK =
+ "<Dialog Id=\"InvalidInstallDir\" Width=\"300\" Height=\"85\" " +
+ "Title=\"[ProductName] Setup\" NoMinimize=\"yes\">\n" +
+ "<Control Id=\"InvalidInstallDirYes\" Type=\"PushButton\" X=\"100\" Y=\"55\" " +
+ "Width=\"50\" Height=\"15\" Default=\"no\" Cancel=\"no\" Text=\"Yes\">\n" +
+ "<Publish Event=\"NewDialog\" Value=\"VerifyReadyDlg\">1</Publish>\n" +
+ "</Control>\n" +
+ "<Control Id=\"InvalidInstallDirNo\" Type=\"PushButton\" X=\"150\" Y=\"55\" " +
+ "Width=\"50\" Height=\"15\" Default=\"yes\" Cancel=\"yes\" Text=\"No\">\n" +
+ "<Publish Event=\"NewDialog\" Value=\"InstallDirDlg\">1</Publish>\n" +
+ "</Control>\n" +
+ "<Control Id=\"Text\" Type=\"Text\" X=\"25\" Y=\"15\" Width=\"250\" Height=\"30\" " +
+ "TabSkip=\"no\">\n" +
+ "<Text>" + I18N.getString("message.install.dir.exist") + "</Text>\n" +
+ "</Control>\n" +
+ "</Dialog>";
+
/**
* Overrides the dialog sequence in built-in dialog set "WixUI_InstallDir"
* to exclude license dialog
@@ -642,12 +673,21 @@
private static final String TWEAK_FOR_EXCLUDING_LICENSE =
" <Publish Dialog=\"WelcomeDlg\" Control=\"Next\""
+ " Event=\"NewDialog\" Value=\"InstallDirDlg\""
- + " Order=\"2\"> 1"
- + " </Publish>\n"
+ + " Order=\"2\">1</Publish>\n"
+ " <Publish Dialog=\"InstallDirDlg\" Control=\"Back\""
+ " Event=\"NewDialog\" Value=\"WelcomeDlg\""
- + " Order=\"2\"> 1"
- + " </Publish>\n";
+ + " Order=\"2\">1</Publish>\n";
+
+ private static final String CHECK_INSTALL_DLG_CTRL =
+ " <Publish Dialog=\"InstallDirDlg\" Control=\"Next\""
+ + " Event=\"DoAction\" Value=\"CHECK_INSTALLDIR\""
+ + " Order=\"3\">1</Publish>\n"
+ + " <Publish Dialog=\"InstallDirDlg\" Control=\"Next\""
+ + " Event=\"NewDialog\" Value=\"InvalidInstallDir\""
+ + " Order=\"5\">INSTALLDIR_VALID=\"0\"</Publish>\n"
+ + " <Publish Dialog=\"InstallDirDlg\" Control=\"Next\""
+ + " Event=\"NewDialog\" Value=\"VerifyReadyDlg\""
+ + " Order=\"5\">INSTALLDIR_VALID=\"1\"</Publish>\n";
// Required upgrade element for installers which support major upgrade (when user
// specifies --win-upgrade-uuid). We will allow downgrades.
@@ -671,23 +711,28 @@
* WixUI_InstallDir for installdir dialog only or for both
* installdir/license dialogs
*/
- private String getUIBlock(Map<String, ? super Object> params) {
- String uiBlock = " <UI/>\n"; // UI-less element
+ private String getUIBlock(Map<String, ? super Object> params) throws IOException {
+ String uiBlock = ""; // UI-less element
+
+ // Copy CA dll to include with installer
+ if (INSTALLDIR_CHOOSER.fetchFrom(params)) {
+ File helper = new File(CONFIG_ROOT.fetchFrom(params), "wixhelper.dll");
+ try (InputStream is_lib = getResourceAsStream("wixhelper.dll")) {
+ Files.copy(is_lib, helper.toPath());
+ }
+ }
if (INSTALLDIR_CHOOSER.fetchFrom(params)) {
boolean enableTweakForExcludingLicense =
(getLicenseFile(params) == null);
- uiBlock = " <UI>\n"
- + " <Property Id=\"WIXUI_INSTALLDIR\""
+ uiBlock = " <Property Id=\"WIXUI_INSTALLDIR\""
+ " Value=\"APPLICATIONFOLDER\" />\n"
+ " <UIRef Id=\"WixUI_InstallDir\" />\n"
+ (enableTweakForExcludingLicense ?
TWEAK_FOR_EXCLUDING_LICENSE : "")
- +" </UI>\n";
+ + CHECK_INSTALL_DLG_CTRL;
} else if (getLicenseFile(params) != null) {
- uiBlock = " <UI>\n"
- + " <UIRef Id=\"WixUI_Minimal\" />\n"
- + " </UI>\n";
+ uiBlock = " <UIRef Id=\"WixUI_Minimal\" />\n";
}
return uiBlock;
@@ -1076,6 +1121,13 @@
commandLine.add("-ext");
commandLine.add("WixUIExtension.dll");
}
+
+ // Only needed if we using CA dll, so Wix can find it
+ if (enableInstalldirUI) {
+ commandLine.add("-b");
+ commandLine.add(CONFIG_ROOT.fetchFrom(params).getAbsolutePath());
+ }
+
commandLine.add("-out");
commandLine.add(msiOut.getAbsolutePath());
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties Mon Mar 11 13:21:49 2019 -0400
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties Mon Mar 11 13:24:47 2019 -0400
@@ -129,4 +129,5 @@
message.generating-msi=Generating MSI\: {0}
message.light-file-string=WiX light tool set to {0}
message.candle-file-string=WiX candle tool set to {0}
+message.install.dir.exist=The folder [APPLICATIONFOLDER] already exist. Whould you like to install to that folder anyway?
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_ja.properties Mon Mar 11 13:21:49 2019 -0400
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_ja.properties Mon Mar 11 13:24:47 2019 -0400
@@ -129,4 +129,5 @@
message.generating-msi=Generating MSI\: {0}
message.light-file-string=WiX light tool set to {0}
message.candle-file-string=WiX candle tool set to {0}
+message.install.dir.exist=The folder [APPLICATIONFOLDER] already exist. Whould you like to install to that folder anyway?
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_zh_CN.properties Mon Mar 11 13:21:49 2019 -0400
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_zh_CN.properties Mon Mar 11 13:24:47 2019 -0400
@@ -129,4 +129,5 @@
message.generating-msi=Generating MSI\: {0}
message.light-file-string=WiX light tool set to {0}
message.candle-file-string=WiX candle tool set to {0}
+message.install.dir.exist=The folder [APPLICATIONFOLDER] already exist. Whould you like to install to that folder anyway?
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/template.wxs Mon Mar 11 13:21:49 2019 -0400
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/template.wxs Mon Mar 11 13:24:47 2019 -0400
@@ -1,48 +1,52 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
- xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
- <Product Id="PRODUCT_GUID" Name="APPLICATION_NAME"
- Language="1033" Version="APPLICATION_VERSION"
- Manufacturer="APPLICATION_VENDOR"
- UpgradeCode="PRODUCT_UPGRADE_GUID">
- <Package Description="APPLICATION_DESCRIPTION" Comments="None"
- InstallerVersion="200" Compressed="yes"
- InstallScope="INSTALL_SCOPE" Platform="PLATFORM"/>
- <Media Id="1" Cabinet="simple.cab" EmbedCab="yes" />
-UPGRADE_BLOCK
-
- <!-- We use RemoveFolderEx to ensure application folder is fully
- removed on uninstall. Including files created outside of MSI
- after application had been installed (e.g. on AU or user state).
-
- Hovewer, RemoveFolderEx is only available in WiX 3.6,
- we will comment it out if we running older WiX.
-
- RemoveFolderEx requires that we "remember" the path for uninstall.
- Read the path value and set the APPLICATIONFOLDER property with the value.
- -->
- <Property Id="APPLICATIONFOLDER">
- <RegistrySearch Key="SOFTWARE\APPLICATION_VENDOR\APPLICATION_NAME"
- Root="REGISTRY_ROOT" Type="raw"
- Id="APPLICATIONFOLDER_REGSEARCH" Name="Path" />
- </Property>
- <DirectoryRef Id="APPLICATIONFOLDER">
- <Component Id="CleanupMainApplicationFolder" Guid="*" Win64="WIN64">
- <RegistryValue Root="REGISTRY_ROOT"
- Key="SOFTWARE\APPLICATION_VENDOR\APPLICATION_NAME"
- Name="Path" Type="string" Value="[APPLICATIONFOLDER]"
- KeyPath="yes" />
- <!-- We need to use APPLICATIONFOLDER variable here or RemoveFolderEx
- will not remove on "install". But only if WiX 3.6 is used. -->
- WIX36_ONLY_START
- <util:RemoveFolderEx On="uninstall" Property="APPLICATIONFOLDER" />
- WIX36_ONLY_END
- </Component>
- </DirectoryRef>
- <?include bundle.wxi ?>
-UI_BLOCK
- <Icon Id="DesktopIcon.exe" SourceFile="APPLICATION_ICON" />
- <Icon Id="StartMenuIcon.exe" SourceFile="APPLICATION_ICON" />
-SECONDARY_LAUNCHER_ICONS
- </Product>
-</Wix>
+<?xml version="1.0" encoding="utf-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
+ xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
+ <Product Id="PRODUCT_GUID" Name="APPLICATION_NAME"
+ Language="1033" Version="APPLICATION_VERSION"
+ Manufacturer="APPLICATION_VENDOR"
+ UpgradeCode="PRODUCT_UPGRADE_GUID">
+ <Package Description="APPLICATION_DESCRIPTION" Comments="None"
+ InstallerVersion="200" Compressed="yes"
+ InstallScope="INSTALL_SCOPE" Platform="PLATFORM"/>
+ <Media Id="1" Cabinet="simple.cab" EmbedCab="yes" />
+ UPGRADE_BLOCK
+
+ <!-- We use RemoveFolderEx to ensure application folder is fully
+ removed on uninstall. Including files created outside of MSI
+ after application had been installed (e.g. on AU or user state).
+
+ Hovewer, RemoveFolderEx is only available in WiX 3.6,
+ we will comment it out if we running older WiX.
+
+ RemoveFolderEx requires that we "remember" the path for uninstall.
+ Read the path value and set the APPLICATIONFOLDER property with the value.
+ -->
+ <Property Id="APPLICATIONFOLDER">
+ <RegistrySearch Key="SOFTWARE\APPLICATION_VENDOR\APPLICATION_NAME"
+ Root="REGISTRY_ROOT" Type="raw"
+ Id="APPLICATIONFOLDER_REGSEARCH" Name="Path" />
+ </Property>
+ <DirectoryRef Id="APPLICATIONFOLDER">
+ <Component Id="CleanupMainApplicationFolder" Guid="*" Win64="WIN64">
+ <RegistryValue Root="REGISTRY_ROOT"
+ Key="SOFTWARE\APPLICATION_VENDOR\APPLICATION_NAME"
+ Name="Path" Type="string" Value="[APPLICATIONFOLDER]"
+ KeyPath="yes" />
+ <!-- We need to use APPLICATIONFOLDER variable here or RemoveFolderEx
+ will not remove on "install". But only if WiX 3.6 is used. -->
+ WIX36_ONLY_START
+ <util:RemoveFolderEx On="uninstall" Property="APPLICATIONFOLDER" />
+ WIX36_ONLY_END
+ </Component>
+ </DirectoryRef>
+ <?include bundle.wxi ?>
+ CA_BLOCK
+ <UI>
+ INVALID_INSTALL_DIR_DLG_BLOCK
+ UI_BLOCK
+ </UI>
+ <Icon Id="DesktopIcon.exe" SourceFile="APPLICATION_ICON" />
+ <Icon Id="StartMenuIcon.exe" SourceFile="APPLICATION_ICON" />
+ SECONDARY_LAUNCHER_ICONS
+ </Product>
+</Wix>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp Mon Mar 11 13:24:47 2019 -0400
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <Windows.h>
+#include <msiquery.h>
+#include <shlwapi.h>
+
+extern "C" {
+
+#ifdef JP_EXPORT_FUNCTION
+#error Unexpected JP_EXPORT_FUNCTION define
+#endif
+#define JP_EXPORT_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
+
+ BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason,
+ LPVOID lpvReserved) {
+ return TRUE;
+ }
+
+ BOOL DirectoryExist(TCHAR *szValue) {
+ DWORD attr = GetFileAttributes(szValue);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ return FALSE;
+ }
+
+ if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ UINT __stdcall CheckInstallDir(MSIHANDLE hInstall) {
+ #pragma JP_EXPORT_FUNCTION
+
+ TCHAR *szValue = NULL;
+ DWORD cchSize = 0;
+
+ UINT result = MsiGetProperty(hInstall, TEXT("APPLICATIONFOLDER"), TEXT(""), &cchSize);
+ if (result == ERROR_MORE_DATA) {
+ cchSize = cchSize + 1; // NULL termination
+ szValue = new TCHAR[cchSize];
+ if (szValue) {
+ result = MsiGetProperty(hInstall, TEXT("APPLICATIONFOLDER"), szValue, &cchSize);
+ } else {
+ return ERROR_INSTALL_FAILURE;
+ }
+ }
+
+ if (result != ERROR_SUCCESS) {
+ delete [] szValue;
+ return ERROR_INSTALL_FAILURE;
+ }
+
+ if (DirectoryExist(szValue)) {
+ if (PathIsDirectoryEmpty(szValue)) {
+ MsiSetProperty(hInstall, TEXT("INSTALLDIR_VALID"), TEXT("1"));
+ } else {
+ MsiSetProperty(hInstall, TEXT("INSTALLDIR_VALID"), TEXT("0"));
+ }
+ } else {
+ MsiSetProperty(hInstall, TEXT("INSTALLDIR_VALID"), TEXT("1"));
+ }
+
+ delete [] szValue;
+
+ return ERROR_SUCCESS;
+ }
+}