diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
|---|---|---|
| committer | <> | 2014-05-08 15:03:54 +0000 |
| commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
| tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Installer/win | |
| parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
| download | VirtualBox-master.tar.gz | |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Installer/win')
20 files changed, 1679 insertions, 504 deletions
diff --git a/src/VBox/Installer/win/Makefile.kmk b/src/VBox/Installer/win/Makefile.kmk index d2f67183..6621d1de 100644 --- a/src/VBox/Installer/win/Makefile.kmk +++ b/src/VBox/Installer/win/Makefile.kmk @@ -4,7 +4,7 @@ # # -# Copyright (C) 2006-2012 Oracle Corporation +# Copyright (C) 2006-2013 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -48,9 +48,20 @@ include $(PATH_SUB_CURRENT)/Resources/Makefile.kmk # # Globals and targets. # -VBOX_INSTALLER_LANGUAGES = en_US +VBOX_INSTALLER_LANGUAGES = de_DE en_US fr_FR it_IT zh_TW VBOX_INSTALLER_LANGUAGES += $(VBOX_INSTALLER_ADD_LANGUAGES) +# +# We don't have the license text in another language than English yet, +# so just define the branding targets to use the English one for now. +# +$(foreach lang,$(VBOX_INSTALLER_LANGUAGES), \ + $(eval VBOX_BRAND_$(lang)_LICENSE_RTF := $(VBOX_BRAND_LICENSE_RTF)) \ + $(eval VBOX_BRAND_$(lang)_LANGUAGE_CODEPAGE := 1252)) + +# Some languages need another codepage than 1252. Override them here. +VBOX_BRAND_zh_TW_LANGUAGE_CODEPAGE := 950 + VBOX_PATH_WIN_INST_SRC := $(PATH_SUB_CURRENT) VBOX_WIN_INST_OUT_DIR := $(PATH_TARGET)/Installer/win @@ -91,7 +102,7 @@ else endif BLDDIRS += \ $(VBOX_WIN_INST_OUT_DIR) \ - $(VBOX_WIN_INST_OUT_DIR)/Languages/ + $(VBOX_WIN_INST_OUT_DIR)/NLS/ OTHER_CLEAN += \ $(VBOX_WIN_INST_OUT_DIR)/VirtualBox.wixobj \ @@ -100,9 +111,9 @@ OTHER_CLEAN += \ $(VBOX_WIN_INST_OUT_DIR)/VBoxGuiNLS.wxi \ $(VBOX_WIN_INST_OUT_DIR)/VBoxKey.wxi \ $(foreach lang,$(VBOX_INSTALLER_LANGUAGES), \ - $(VBOX_WIN_INST_OUT_DIR)/Languages/Language_$(lang).wxl \ - $(VBOX_WIN_INST_OUT_DIR)/Languages/License_$(lang).wxl \ - $(VBOX_WIN_INST_OUT_DIR)/Languages/$(lang).mst \ + $(VBOX_WIN_INST_OUT_DIR)/NLS/Language_$(lang).wxl \ + $(VBOX_WIN_INST_OUT_DIR)/NLS/License_$(lang).wxl \ + $(VBOX_WIN_INST_OUT_DIR)/NLS/$(lang).mst \ $(VBOX_WIN_INST_OUT_DIR)/VirtualBox_$(lang).wixobj \ $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_LANG)_$(lang).msi) \ $(VBOX_WIN_INST_OUT_DIR)/Files_Doc.wxi \ @@ -163,7 +174,7 @@ VBOX_MSI_ICE_IGNORE := \ # takes place after all makefiles has been loaded and with the @ variable defined. # define def_vbox_lang_xml -$(VBOX_WIN_INST_OUT_DIR)/Languages/Language_$(lang).wxl: $(VBOX_PATH_WIN_INST_SRC)/Languages/$(lang).wxl | $$$$(dir $$$$@) +$(VBOX_WIN_INST_OUT_DIR)/NLS/Language_$(lang).wxl: $(VBOX_PATH_WIN_INST_SRC)/NLS/$(lang).wxl | $$$$(dir $$$$@) $$(call MSG_GENERATE,,$$@,$$<) $(QUIET)$(INSTALL) -m 0644 $$< $$@ endef @@ -186,12 +197,12 @@ $(foreach lang,$(VBOX_INSTALLER_LANGUAGES),$(eval $(def_vbox_lang_xml))) # between the tag and the RTF license text. # define def_vbox_license_xml -$(VBOX_WIN_INST_OUT_DIR)/Languages/License_$(lang).wxl: $(license_file) $(MAKEFILE_CURRENT) | $$$$(dir $$$$@) +$(VBOX_WIN_INST_OUT_DIR)/NLS/License_$(lang).wxl: $(license_file) $(MAKEFILE_CURRENT) | $$$$(dir $$$$@) $$(call MSG_GENERATE,,$$@,$$<) $(APPEND) -t $$@ '<?xml version="1.0" encoding="utf-8"?>' - $(APPEND) $$@ '<WixLocalization xmlns="http://schemas.microsoft.com/wix/2006/localization" Codepage="1252" Culture="$(lang)">' + $(APPEND) $$@ '<WixLocalization xmlns="http://schemas.microsoft.com/wix/2006/localization" Codepage="$(VBOX_BRAND_$(lang)_LANGUAGE_CODEPAGE)" Culture="$(lang)">' - $(REDIRECT) -a+to $$@ -- $(ECHO_EXT) -n '<String Id=\"LicenseText\">' + $(REDIRECT) -a+to $$@ -- $(ECHO_EXT) -n '<String Id="LicenseText">' $(REDIRECT) -a+to $$@ -- $(SED) -e "s|<|\<|g" -e "s|>|\>|g" $(license_file) $(APPEND) $$@ '</String>' @@ -218,22 +229,24 @@ $(VBOX_WIN_INST_OUT_DIR)/Files_Main.wxi: $(MAKEFILE_CURRENT) | $$(dir $$@) $(call MSG_GENERATE,,$@,$<) $(APPEND) -t $@ '<?xml version="1.0" ?>' $(APPEND) $@ '<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">' - ifdef VBOX_WITH_DOCS_CHM - $(APPEND) $@ ' <File Id="file_VirtualBox.chm" Name="VirtualBox.chm" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(PATH_STAGE_BIN)/VirtualBox.chm"></File>' - $(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \ - ' <File Id="file_VirtualBox_$(lang).chm" Name="VirtualBox_$(lang).chm" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(PATH_STAGE_BIN)/VirtualBox_$(lang).chm"></File>') - endif +ifdef VBOX_WITH_DOCS_PACKING + $(APPEND) $@ ' <File Id="file_VirtualBox.chm" Name="VirtualBox.chm" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(PATH_STAGE_BIN)/VirtualBox.chm"></File>' + $(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \ + ' <File Id="file_VirtualBox_$(lang).chm" Name="VirtualBox_$(lang).chm" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(PATH_STAGE_BIN)/VirtualBox_$(lang).chm"></File>') +endif $(APPEND) $@ '</Include>' -$(VBOX_WIN_INST_OUT_DIR)/Files_Doc.wxi: $(MAKEFILE_CURRENT) | $$(dir $$@) +$(VBOX_WIN_INST_OUT_DIR)/Files_Doc.wxi: $(MAKEFILE_CURRENT) | $$(dir $$@) $(call MSG_GENERATE,,$@,$<) $(APPEND) -t $@ '<?xml version="1.0" ?>' $(APPEND) $@ '<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">' +ifdef VBOX_WITH_DOCS_PACKING $(APPEND) $@ ' <File Id="file_UserManual.pdf" Name="UserManual.pdf" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(PATH_STAGE_BIN)/UserManual.pdf">' $(APPEND) $@ ' </File>' $(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \ ' <File Id="file_UserManual_$(lang).pdf" Name="UserManual_$(lang).pdf" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(PATH_STAGE_BIN)/UserManual_$(lang).pdf">' \ ' </File>') +endif $(APPEND) $@ '</Include>' $(VBOX_WIN_INST_OUT_DIR)/Files_License.wxi: $(MAKEFILE_CURRENT) | $$(dir $$@) @@ -254,13 +267,13 @@ $(VBOX_WIN_INST_OUT_DIR)/Shortcuts_StartMenu.wxi: $(MAKEFILE_CURRENT) | $$(dir $ # # Documentation (PDF/CHM) # - ifdef VBOX_WITH_DOCS_CHM +ifdef VBOX_WITH_DOCS_PACKING $(APPEND) $@ ' <Shortcut Id="sc_StartMenu_ManualCHM_en_US" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (CHM, English)" Description="!(loc.StartMenu_UserManual)"' \ ' Target="[INSTALLDIR]\VirtualBox.chm" WorkingDirectory="dir_Documents" Advertise="no"/>' $(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \ ' <Shortcut Id="sc_StartMenu_ManualCHM_$(lang)" Directory="dir_StartMenuVBox" Name="$!(loc.StartMenu_UserManual) (CHM, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \ ' Description="$!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\VirtualBox_$(lang).chm" WorkingDirectory="dir_Documents"/>') - endif +endif $(APPEND) $@ ' <Shortcut Id="sc_StartMenu_ManualPDF_en_US" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (PDF, English)" Description="!(loc.StartMenu_UserManual)"' \ ' Target="[INSTALLDIR]\doc\UserManual.pdf" WorkingDirectory="dir_Documents" Advertise="no"/>' $(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \ @@ -282,11 +295,14 @@ $(VBOX_WIN_INST_OUT_DIR)/Shortcuts_StartMenu.wxi: $(MAKEFILE_CURRENT) | $$(dir $ # Note: This will clean up any previous .msi to prevent dep build boxes from # filling up with old files. # +# Note: Disable parallel jobs here because of shared common.cab access issues. +# define def_vbox_link_msi +.NOTPARALLEL: $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_LANG)_$(lang).msi $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_LANG)_$(lang).msi: \ $(VBOX_WIN_INST_OUT_DIR)/VirtualBox_$(lang).wixobj \ - $(VBOX_WIN_INST_OUT_DIR)/Languages/Language_$(lang).wxl \ - $(VBOX_WIN_INST_OUT_DIR)/Languages/License_$(lang).wxl \ + $(VBOX_WIN_INST_OUT_DIR)/NLS/Language_$(lang).wxl \ + $(VBOX_WIN_INST_OUT_DIR)/NLS/License_$(lang).wxl \ $(PATH_STAGE_BIN)/VBoxInstallHelper.dll \ $(VBOX_SVN_REV_KMK) \ $(MAKEFILE_CURRENT) \ @@ -294,8 +310,8 @@ $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_LANG)_$(lang).msi: \ $$(call MSG_L1,Linking installer $$@) $(QUIET)$(RM) -f $$(wildcard $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_BASE)-r*_$(lang).msi) $(VBOX_PATH_WIX)/light.exe -nologo \ - -loc $(VBOX_WIN_INST_OUT_DIR)/Languages/Language_$(lang).wxl \ - -loc $(VBOX_WIN_INST_OUT_DIR)/Languages/License_$(lang).wxl \ + -loc $(VBOX_WIN_INST_OUT_DIR)/NLS/Language_$(lang).wxl \ + -loc $(VBOX_WIN_INST_OUT_DIR)/NLS/License_$(lang).wxl \ -ext $(VBOX_PATH_WIX)/WixUIExtension.dll \ -ext $(VBOX_PATH_WIX)/WixDifxAppExtension.dll \ $(VBOX_MSI_ICE_IGNORE) \ @@ -304,7 +320,7 @@ $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_LANG)_$(lang).msi: \ $(if-expr "$(KBUILD_TARGET_ARCH)" == "x86", \ $(VBOX_PATH_WIX)/difxapp_x86.wixlib, \ $(VBOX_PATH_WIX)/difxapp_x64.wixlib) - $(RM) -f $(VBOX_WIN_INST_OUT_DIR)/Languages/$(lang).mst + $(RM) -f $(VBOX_WIN_INST_OUT_DIR)/NLS/$(lang).mst $(call VBOX_SIGN_FILE_FN,$$@,$(VBOX_PRODUCT) $(VBOX_VERSION_STRING)r$(VBOX_SVN_REV) ($(KBUILD_TARGET_ARCH))) endef @@ -399,8 +415,10 @@ endif define def_vbox_compile_wixobj $(VBOX_WIN_INST_OUT_DIR)/VirtualBox_$(lang).wixobj: \ $(PATH_SUB_CURRENT)/VirtualBox.wxs \ + $(VBOX_WIN_INST_OUT_DIR)/Shortcuts_StartMenu.wxi \ $(PATH_SUB_CURRENT)/UserInterface.wxi \ $(VBOX_WIN_INST_OUT_DIR)/VirtualBox_TypeLib.wxi \ + $(if $(VBOX_WITH_32_ON_64_MAIN_API),$(VBOX_WIN_INST_OUT_DIR)/VirtualBox_TypeLib_x86.wxi,) \ $(VBOX_WIN_INST_OUT_DIR)/VBoxKey.wxi \ $(VBOX_WIN_INST_OUT_DIR)/VBoxGuiNLS.wxi \ $(VBOX_MSI_DEPENDENCIES) \ @@ -429,6 +447,7 @@ $(VBOX_WIN_INST_OUT_DIR)/VirtualBox_$(lang).wixobj: \ -E 'VBOX_VERSION_MINOR_INST=$(VBOX_VERSION_MINOR)' \ -E 'VBOX_SIGNING_MODE=$(strip $(if $(VBOX_SIGNING_MODE),$(VBOX_SIGNING_MODE),none))' \ -E 'VBOX_GUI_USE_QGL=$(if $(VBOX_GUI_USE_QGL),yes,no)' \ + -E 'VBOX_WITH_32_ON_64_MAIN_API=$(if $(VBOX_WITH_32_ON_64_MAIN_API),yes,no)' \ -E 'VBOX_WITH_ADDITIONS_PACKING=$(if $(VBOX_WITH_ADDITIONS_PACKING),yes,no)' \ -E 'VBOX_WITH_COMBINED_PACKAGE=$(if $(VBOX_WITH_COMBINED_PACKAGE),yes,no)' \ -E 'VBOX_WITH_CROGL=$(if $(VBOX_WITH_CROGL),yes,no)' \ @@ -483,6 +502,15 @@ $(VBOX_WIN_INST_OUT_DIR)/VirtualBox_TypeLib.wxi: \ | $$(dir $$@) $(VBOX_XSLTPROC) -o $@ $< $(VBOX_XIDL_FILE) +$(VBOX_WIN_INST_OUT_DIR)/VirtualBox_TypeLib_x86.wxi: \ + $(PATH_SUB_CURRENT)/VirtualBox_TypeLib.xsl \ + $(VBOX_XIDL_FILE) \ + | $$(dir $$@) + $(VBOX_XSLTPROC) --stringparam "a_sTarget" "VBoxClient-x86" -o $@.tmp $< $(VBOX_XIDL_FILE) + $(SED) -e 's/VBoxC/VBoxClient_x86/g' --output $@ $@.tmp + $(RM) -f $@.tmp + + # # Construct the list of GUI translations. # ('-t' -- truncate file; '-n' -- new line between arguments) @@ -516,8 +544,8 @@ $(VBOX_WIN_INST_OUT_DIR)/VBoxKey.wxi: $(PATH_SUB_CURRENT)/VBoxKey.wxi $(VBOX_VER # programs / scripts involved in this step. # define def_vbox_create_mst -.NOTPARALLEL: $(VBOX_WIN_INST_OUT_DIR)/Languages/$(lang).mst -$(VBOX_WIN_INST_OUT_DIR)/Languages/$(lang).mst: \ +.NOTPARALLEL: $(VBOX_WIN_INST_OUT_DIR)/NLS/$(lang).mst +$(VBOX_WIN_INST_OUT_DIR)/NLS/$(lang).mst: \ $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_LANG)_en_US.msi \ $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_LANG)_$(lang).msi \ | $$$$(dir $$$$@) @@ -550,7 +578,7 @@ $(PACKAGE_NAME_FINAL): \ $(VBOX_WIN_INST_OUT_DIR)/Files_License.wxi \ $(VBOX_WIN_INST_OUT_DIR)/Shortcuts_StartMenu.wxi \ $(foreach lang,$(VBOX_INSTALLER_LANGUAGES), $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_LANG)_$(lang).msi) \ - $(foreach lang,$(VBOX_INSTALLER_ADD_LANGUAGES), $(VBOX_WIN_INST_OUT_DIR)/Languages/$(lang).mst) \ + $(foreach lang,$(VBOX_INSTALLER_ADD_LANGUAGES), $(VBOX_WIN_INST_OUT_DIR)/NLS/$(lang).mst) \ $(VBOX_SVN_REV_KMK) \ | $$(dir $$@) $(QUIET)$(RM) -f $(wildcard $(PATH_STAGE_BIN)/$(PACKAGE_BASE)-r*.msi) @@ -568,11 +596,13 @@ if defined(VBOX_WITH_COMBINED_PACKAGE) && "$(KBUILD_TARGET_ARCH)" == "x86" # $(PATH_STAGE_BIN)/$(PACKAGE_NAME_MULTIARCH_FINAL): \ $(PATH_MULTIARCH_TEMP)/$(PACKAGE_NAME_MULTIARCH.x86) \ - $(PATH_MULTIARCH_TEMP)/$(PACKAGE_NAME_MULTIARCH.amd64) + $(PATH_MULTIARCH_TEMP)/$(PACKAGE_NAME_MULTIARCH.amd64) \ + $(PATH_STAGE_BIN)/VBoxStub.exe \ + $$(VBoxStubBld_1_TARGET) $(call MSG_L1,Building Windows combined package) $(call VBOX_SIGN_FILE_FN,$(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_MULTIARCH_COMMONCAB)) $(REDIRECT) -C $(@D) -- \ - VBoxStubBld -out $@ \ + $(VBoxStubBld_1_TARGET) -out $@ \ -target-x86 $(PATH_MULTIARCH_TEMP)/$(PACKAGE_NAME_MULTIARCH.x86) \ -target-amd64 $(PATH_MULTIARCH_TEMP)/$(PACKAGE_NAME_MULTIARCH.amd64) \ -target-all $(VBOX_WIN_INST_OUT_DIR)/$(PACKAGE_NAME_MULTIARCH_COMMONCAB) \ diff --git a/src/VBox/Installer/win/Languages/de_DE.wxl b/src/VBox/Installer/win/NLS/de_DE.wxl index a7d095f1..8f666ba7 100644 --- a/src/VBox/Installer/win/Languages/de_DE.wxl +++ b/src/VBox/Installer/win/NLS/de_DE.wxl @@ -119,6 +119,7 @@ <String Id="Customize2Dlg_Desc">Bitte unten die gewünschten Optionen auswählen:</String>
<String Id="Customize2Dlg_CreateShortcut">Verknüpfung auf dem Desktop anlegen</String>
<String Id="Customize2Dlg_CreateQuickLaunch">Verknüpfung in der Schnellstartleiste anlegen</String>
+ <String Id="Customize2Dlg_RegisterFileExtensions">Dateizuordnungen registrieren</String>
<!---->
diff --git a/src/VBox/Installer/win/Languages/en_US.wxl b/src/VBox/Installer/win/NLS/en_US.wxl index dd7f1283..8ffa8343 100644 --- a/src/VBox/Installer/win/Languages/en_US.wxl +++ b/src/VBox/Installer/win/NLS/en_US.wxl @@ -123,6 +123,7 @@ <String Id="Customize2Dlg_Desc">Please choose from the options below:</String>
<String Id="Customize2Dlg_CreateShortcut">Create a shortcut on the desktop</String>
<String Id="Customize2Dlg_CreateQuickLaunch">Create a shortcut in the Quick Launch Bar</String>
+ <String Id="Customize2Dlg_RegisterFileExtensions">Register file associations</String>
<!---->
diff --git a/src/VBox/Installer/win/Languages/fa_IR.wxl b/src/VBox/Installer/win/NLS/fa_IR.wxl index 446b89fe..37b7f672 100644 --- a/src/VBox/Installer/win/Languages/fa_IR.wxl +++ b/src/VBox/Installer/win/NLS/fa_IR.wxl @@ -90,6 +90,7 @@ <String Id="Customize2Dlg_Desc">لطفاً از گزینه های زیر انتخاب کنید:</String> <String Id="Customize2Dlg_CreateShortcut">ایجاد یک میانبر روی دسکتاپ</String> <String Id="Customize2Dlg_CreateQuickLaunch">ایجاد یک میانبر در اِجرای سریع</String> + <String Id="Customize2Dlg_RegisterFileExtensions">ثبت نام انجمن فایل</String> <!----> <String Id="WarnDisconNetIfacesDlg_Title">هشدار:</String> <String Id="WarnDisconNetIfacesDlg_Title2">رابط های شبکه</String> @@ -509,4 +510,4 @@ <String Id="UITextVolumeCostRequired">موردنیاز</String> <String Id="UITextVolumeCostSize">حجم دیسک</String> <String Id="UITextVolumeCostVolume">درایو</String> -</WixLocalization>
\ No newline at end of file +</WixLocalization>
\ No newline at end of file diff --git a/src/VBox/Installer/win/Languages/fr_FR.wxl b/src/VBox/Installer/win/NLS/fr_FR.wxl index bb726b50..fa3d77f3 100644 --- a/src/VBox/Installer/win/Languages/fr_FR.wxl +++ b/src/VBox/Installer/win/NLS/fr_FR.wxl @@ -58,7 +58,6 @@ <String Id="WrongOS">Cette application nécéssite Windows XP ou plus récent.</String>
<String Id="Only32Bit">Cette application ne marche que sur des systèmes Windows 32-bit. Veuillez installer la version 64-bit de [ProductName]!</String>
<String Id="Only64Bit">Cette application ne marche que sur des systèmes Windows 64-bit. Veuillez installer la version 32-bit de [ProductName]!</String>
- <String Id="InnotekFound">Vous avez une ancienne installation de Sun VirtualBox sur cette machine. Il vous faudra la désinstaller avant de pouvoir installer [ProductName].</String>
<String Id="InnotekFound">Vous avez une ancienne installation de innotek VirtualBox sur cette machine. Il vous faudra la désinstaller avant de pouvoir installer [ProductName].</String>
<!---->
@@ -118,6 +117,7 @@ <String Id="Customize2Dlg_Desc">Veuillez choisir une des options suivantes:</String>
<String Id="Customize2Dlg_CreateShortcut">Créer un raccourci sur le bureau</String>
<String Id="Customize2Dlg_CreateQuickLaunch">Créer un raccourci dans la barre de lancement rapide</String>
+ <String Id="Customize2Dlg_RegisterFileExtensions">Inscription des associations de fichiers</String>
<!---->
diff --git a/src/VBox/Installer/win/Languages/it_IT.wxl b/src/VBox/Installer/win/NLS/it_IT.wxl index 907e3369..98e6bc30 100644 --- a/src/VBox/Installer/win/Languages/it_IT.wxl +++ b/src/VBox/Installer/win/NLS/it_IT.wxl @@ -90,6 +90,7 @@ <String Id="Customize2Dlg_Desc">Scegli dalle opzioni seguenti:</String> <String Id="Customize2Dlg_CreateShortcut">Crea una scorciatoia sul desktop</String> <String Id="Customize2Dlg_CreateQuickLaunch">Crea una scorciatoia nella barra di avvio veloce</String> + <String Id="Customize2Dlg_RegisterFileExtensions">Registrati associazioni di file</String> <!----> <String Id="WarnDisconNetIfacesDlg_Title">Avviso:</String> <String Id="WarnDisconNetIfacesDlg_Title2">Interfacce di rete</String> @@ -509,4 +510,4 @@ <String Id="UITextVolumeCostRequired">Richiesto</String> <String Id="UITextVolumeCostSize">Dimensione disco</String> <String Id="UITextVolumeCostVolume">Volume</String> -</WixLocalization>
\ No newline at end of file +</WixLocalization>
\ No newline at end of file diff --git a/src/VBox/Installer/win/Languages/tr_TR.wxl b/src/VBox/Installer/win/NLS/tr_TR.wxl index e907e91a..e907e91a 100644 --- a/src/VBox/Installer/win/Languages/tr_TR.wxl +++ b/src/VBox/Installer/win/NLS/tr_TR.wxl diff --git a/src/VBox/Installer/win/NLS/zh_TW.wxl b/src/VBox/Installer/win/NLS/zh_TW.wxl new file mode 100644 index 00000000..383a8127 --- /dev/null +++ b/src/VBox/Installer/win/NLS/zh_TW.wxl @@ -0,0 +1,587 @@ +<?xml version="1.0" encoding="utf-8"?>
+<WixLocalization xmlns="http://schemas.microsoft.com/wix/2003/11/localization" Codepage="65001" Culture="zh_TW">
+
+ <!--
+ Language Definition Include for VirtualBox WiX script.
+
+ Copyright (C) 2011-2012 Oracle Corporation
+
+ This file is part of VirtualBox Open Source Edition (OSE), as
+ available from http://www.virtualbox.org. This file is free software;
+ you can redistribute it and/or modify it under the terms of the GNU
+ General Public License (GPL) as published by the Free Software
+ Foundation, in version 2 as it comes in the "COPYING" file of the
+ VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ -->
+
+ <String Id="LANG">1024</String>
+ <String Id="LangName">正體中文</String>
+
+ <String Id="ButtonText_No">否(&N)</String>
+ <String Id="ButtonText_Yes">是(&Y)</String>
+ <String Id="ButtonText_Cancel">取消(&C)</String>
+ <String Id="ButtonText_Next">下一步(&N) ></String>
+ <String Id="ButtonText_Back">< 上一步(&B)</String>
+ <String Id="ButtonText_Browse">瀏覽(&O)</String>
+ <String Id="ButtonText_OK">確定(&K)</String>
+ <String Id="ButtonText_Check">檢查(&C)</String>
+ <String Id="ButtonText_Install">安裝(&I)</String>
+ <String Id="ButtonText_Remove">移除(&R)</String>
+ <String Id="ButtonText_Finish">完成(&F)</String>
+ <String Id="ButtonText_Repair">修理(&R)</String>
+ <String Id="ButtonText_Return">返回(&R)</String>
+ <String Id="ButtonText_Retry">重試(&T)</String>
+ <String Id="ButtonText_Ignore">忽略(&G)</String>
+ <String Id="ButtonText_Exit">結束(&X)</String>
+
+ <String Id="InstallModeCustom">自訂</String>
+ <String Id="Setup">設定</String>
+
+ <!---->
+
+ <String Id="StartMenu_License">授權</String>
+ <String Id="StartMenu_UserManual">使用者手冊</String>
+
+ <!---->
+
+ <String Id="VB_App">[ProductName] 應用程式。</String>
+ <String Id="VB_USBDriver">[ProductName] USB 裝置驅動程式針對 USB 裝置支援。</String>
+ <String Id="VB_Network">[ProductName] 網路裝置驅動程式針對網路支援。</String>
+ <String Id="VB_NetFltDriver">[ProductName] 驅動程式針對橋接網路。</String>
+ <String Id="VB_NetAdpDriver">[ProductName] 虛擬網路介面卡針對「僅限主機」網路。</String>
+
+ <String Id="VB_Python">VirtualBox 的 Python 支援。</String>
+
+ <!---->
+
+ <String Id="NeedAdmin">您需要有系統管理員特殊權限以安裝 (或解除安裝)[ProductName]!此安裝程式現在將中止。</String>
+ <String Id="WrongOS">此應用程式只能執行在 Windows XP 或以上。</String>
+ <String Id="Only32Bit">此應用程式只能執行在 32 位元的 Windows 系統。 請安裝 [ProductName] 的 64 位元版本!</String>
+ <String Id="Only64Bit">此應用程式只能執行在 64 位元的 Windows 系統。 請安裝 [ProductName] 的 32 位元版本!</String>
+ <String Id="SunFound">在此電腦發現舊的 Sun VirtualBox 安裝。 請先解除安裝此套件然後安裝 [ProductName]!</String>
+ <String Id="InnotekFound">在此電腦發現舊的 innotek VirtualBox 安裝。 請先解除安裝此套件然後安裝 [ProductName]!</String>
+
+ <!---->
+
+ <String Id="CancelDlg_Question">您確定要取消 [ProductName] 安裝嗎?</String>
+
+ <!---->
+
+ <String Id="WelcomeDlg_Header">歡迎使用 [ProductName] 安裝精靈</String>
+ <String Id="WelcomeDlg_Body">安裝精靈將在您的電腦安裝 [ProductName]。 按一下「下一步」繼續或「取消」結束安裝精靈。</String>
+
+ <!---->
+
+ <String Id="LicenseAgreementDlg_Header">最終使用者授權協議</String>
+ <String Id="LicenseAgreementDlg_Body">請仔細閱讀以下授權協議。</String>
+ <String Id="LicenseAgreementDlg_Accept">我接受授權協議中條款(&A)</String>
+ <String Id="LicenseAgreementDlg_Decline">我不接受授權協議中條款(&D)</String>
+
+ <!---->
+
+ <String Id="CheckSerialDlg_Header">序號</String>
+ <String Id="CheckSerialDlg_Body">請在以下欄位輸入您的序號。 您可以在 VirtualBox CD 盒內的貼紙找到。</String>
+ <String Id="CheckSerialDlg_Footer">序號輸入完成時,按一下以下「檢查」按鈕。</String>
+
+ <!---->
+
+ <String Id="WrongSerialDlg_Header">輸入的序號無效!</String>
+ <String Id="WrongSerialDlg_Desc1">請返回再次輸入您的序號。</String>
+ <String Id="WrongSerialDlg_Desc2">請記得,序號必須和印在貼紙上的拼字完全一樣。</String>
+
+ <!---->
+
+ <String Id="WarnSaveStatesDlg_Header">警告:</String>
+ <String Id="WarnSaveStatesDlg_Header2">已經的儲存狀態不相容!</String>
+ <String Id="WarnSaveStatesDlg_Desc">升級 [ProductName] 時,所有來自已經存在機器的儲存狀態不再能動作!安裝後,您必須手動捨棄。</String>
+ <String Id="WarnSaveStatesDlg_Proceed">立即進行安裝嗎?</String>
+
+ <!---->
+
+ <String Id="WarnTAPDevicesDlg_Header">主機介面</String>
+ <String Id="WarnTAPDevicesDlg_Desc">如果您的機器在先前版本使用某些主機介面。 在此安裝後您必須重新建立它們。</String>
+
+ <!---->
+
+ <String Id="NetCfgLocked">繼續安裝前,必須關閉以下應用程式:"[2]"</String>
+
+ <!---->
+
+ <String Id="CustomizeDlg_Location">位置:</String>
+ <String Id="CustomizeDlg_DiskUsage">磁碟使用量(&U)</String>
+ <String Id="CustomizeDlg_SelFeatures">選取您要安裝功能的方式。</String>
+ <String Id="CustomizeDlg_IconTree">按一下以下樹狀中圖示以變更安裝功能的方式。</String>
+ <String Id="CustomizeDlg_CustomSetup">自訂安裝</String>
+ <String Id="CustomizeDlg_SelItemDesc">CustomizeDlgItemDescription-CustomizeDlgItemDescription</String>
+ <String Id="CustomizeDlg_SelItemSize">CustomizeDlgItemSize-CustomizeDlgItemSize</String>
+ <String Id="CustomizeDlg_SelItemPath">CustomizeDlgLocation-CustomizeDlgLocation</String>
+
+ <!---->
+
+ <String Id="Customize2Dlg_Header">自訂</String>
+ <String Id="Customize2Dlg_Desc">請選擇以下選項:</String>
+ <String Id="Customize2Dlg_CreateShortcut">在桌面建立捷徑</String>
+ <String Id="Customize2Dlg_CreateQuickLaunch">在快速啟動列建立捷徑</String>
+ <String Id="Customize2Dlg_RegisterFileExtensions">註冊文件關聯</String>
+
+ <!---->
+
+ <String Id="WarnDisconNetIfacesDlg_Title">警告:</String>
+ <String Id="WarnDisconNetIfacesDlg_Title2">網路介面</String>
+ <String Id="WarnDisconNetIfacesDlg_Desc">安裝 [ProductName] 網路功能將重設您的網路連線並暫時中斷網路連線。</String>
+ <String Id="WarnDisconNetIfacesDlg_Question">立即進行安裝嗎?</String>
+
+ <!---->
+
+ <String Id="DiskCostDlg_SpaceRequired">安裝選取功能所需的磁碟空間。</String>
+ <String Id="DiskCostDlg_NotEnoughSpace">反白的磁碟區(如果有)對於目前選取的功能沒有足夠的磁碟空間可以使用。 您可以從反白的磁碟區移除一些檔案,或選擇安裝較少功能在本機磁碟機,或選取不同目的地磁碟機。</String>
+ <String Id="DiskCostDlg_SpaceRequirements">磁碟空間需求</String>
+ <String Id="DiskCostDlg_VolumeList">{120}{70}{70}{70}{70}</String>
+
+ <!---->
+
+ <String Id="BrowseDlg_BrowseDestFolder">瀏覽目的地資料夾</String>
+ <String Id="BrowseDlg_ChangeCurFolder">變更目前目的地資料夾</String>
+ <String Id="BrowseDlg_UpOneLevelTooltip">上一層</String>
+ <String Id="BrowseDlg_CreateNewFolderTooltip">建立新的資料夾</String>
+ <String Id="BrowseDlg_LookIn">瀏覽(&L):</String>
+ <String Id="BrowseDlg_FolderName">資料夾名稱(&F):</String>
+
+ <!---->
+
+ <String Id="VerifyReadyDlg_ReadyToBegin">安裝精靈準備好進行 [InstallMode] 安裝。</String>
+ <String Id="VerifyReadyDlg_ClickInstall">按一下「安裝」開始安裝。 如果您要檢閱或變更任何安裝設定,按一下「上一步」。 按一下「取消」結束精靈。</String>
+ <String Id="VerifyReadyDlg_ReadyToInstall">準備好安裝</String>
+
+ <!---->
+
+ <String Id="ExitDlg_ClickFinish">按一下「完成」按鈕結束安裝精靈。</String>
+ <String Id="ExitDlg_InstComplete">[ProductName] 安裝完成。</String>
+ <String Id="ExitDlg_StartVBox">安裝後啟動 [ProductName]</String>
+
+ <!---->
+
+ <String Id="FatalErrorDlg_Header">[ProductName] 安裝精靈太早結束</String>
+ <String Id="FatalErrorDlg_Desc">[ProductName] 安裝因為錯誤太早結束。 您的系統未做修改。 若要稍後安裝此程式,請再次執行安裝。</String>
+ <String Id="FatalErrorDlg_Footer">按一下「完成」按鈕結束安裝精靈。</String>
+
+ <!---->
+
+ <String Id="FilesInUse_Text">以下應用程式使用此安裝需要更新的檔案。 關閉這些應用程式接著按一下「重試(&R)」以繼續安裝或「取消」結束精靈。</String>
+ <String Id="FilesInUse_Description">某些需要更新的檔案目前使用中。</String>
+ <String Id="FilesInUse_Title">檔案使用中</String>
+
+ <!---->
+
+ <String Id="UserExitDlg_Header">[ProductName] 安裝精靈中斷</String>
+ <String Id="UserExitDlg_Desc">[ProductName] 安裝中斷。 您的系統未做修改。 若要稍後安裝此程式,請再次執行安裝。</String>
+ <String Id="UserExitDlg_Footer">按一下「完成」按鈕結束安裝精靈。</String>
+
+ <!---->
+
+ <String Id="ProgressDlg_PleaseWait">在安裝精靈安裝 [ProductName] 時請稍候。 這需要幾分鐘時間。</String>
+
+ <!---->
+
+ <String Id="ResumeDlg_Header">正在繼續 [ProductName] 安裝精靈</String>
+ <String Id="ResumeDlg_Desc">安裝精靈將在您的電腦完成 [ProductName] 的安裝。 按一下「安裝」以繼續或「取消」結束安裝精靈。</String>
+
+ <!---->
+
+ <String Id="MaintenanceTypeDlg_Header">修改、修復或移除安裝</String>
+ <String Id="MaintenanceTypeDlg_SelOption">選取您希望執行的操作。</String>
+ <String Id="MaintenanceTypeDlg_Repair">修復(&P)</String>
+ <String Id="MaintenanceTypeDlg_RepairText">修復在最近安裝狀態的錯誤 - 修復缺少或損毀的檔案、捷徑和登錄檔項目。</String>
+ <String Id="MaintenanceTypeDlg_RepairTooltip">修復安裝</String>
+ <String Id="MaintenanceTypeDlg_RepairProgress1">正在修復</String>
+ <String Id="MaintenanceTypeDlg_RepairProgress2">repairs</String>
+ <String Id="MaintenanceTypeDlg_Remove">移除(&R)</String>
+ <String Id="MaintenanceTypeDlg_RemoveText">從電腦移除 [ProductName]。</String>
+ <String Id="MaintenanceTypeDlg_RemoveTooltip">移除安裝</String>
+ <String Id="MaintenanceTypeDlg_RemoveProgress1">正在移除</String>
+ <String Id="MaintenanceTypeDlg_RemoveProgress2">removes</String>
+
+ <!---->
+
+ <String Id="MaintenanceWelcomeDlg_Header">歡迎使用 [ProductName] 安裝精靈</String>
+ <String Id="MaintenanceWelcomeDlg_Desc">安裝精靈將允許您修復目前的安裝或從您的電腦移除 [ProductName]。 按一下「下一步」以繼續或「取消」結束安裝精靈。</String>
+
+ <!---->
+
+ <String Id="OutOfDiskDlg_InstallationExceeds">安裝所需的磁碟空間超過可用的磁碟空間。</String>
+ <String Id="OutOfDiskDlg_NotEnoughDiskSpace">反白的磁碟區對於目前選取的功能沒有足夠的磁碟空間可以使用。 您可以從反白的磁碟區移除一些檔案,或選擇安裝較少功能在本機磁碟機,或選取不同目的地磁碟機。</String>
+ <String Id="OutOfDiskDlg_OutOfDiskSpace">磁碟空間不足</String>
+
+ <!---->
+
+ <String Id="OutOfRbDiskDlg_InstallationExceeds">安裝所需的磁碟空間超過可用的磁碟空間。</String>
+ <String Id="OutOfRbDiskDlg_NotEnoughDiskSpace">反白的磁碟區對於目前選取的功能沒有足夠的磁碟空間可以使用。 您可以從反白的磁碟區移除一些檔案,或選擇安裝較少功能在本機磁碟機,或選取不同目的地磁碟機。</String>
+ <String Id="OutOfRbDiskDlg_OutOfDiskSpace">磁碟空間不足</String>
+ <String Id="OutOfRbDiskDlg_Desc">或者,您可以選擇停用安裝程式的回復功能。 這允許安裝程式在任何方式中斷安裝時還原您電腦的原始狀態。 按一下「是」如果您希望承擔停用回復功能的風險。</String>
+
+ <!---->
+
+ <String Id="VerifyRemoveDlg_Header">移除 [ProductName]</String>
+ <String Id="VerifyRemoveDlg_Desc">您已經選擇從您的電腦移除程式。</String>
+ <String Id="VerifyRemoveDlg_ClickRemove">按一下「移除」以從您的電腦移除 [ProductName]。 如果您要檢閱或變更任何安裝設定,按一下「上一步」。 按一下「取消」結束精靈。</String>
+
+ <!---->
+
+ <String Id="VerifyRepairDlg_Header">修復 [ProductName]</String>
+ <String Id="VerifyRepairDlg_ReadyToBegin">安裝精靈準備好開始修復 [ProductName]。</String>
+ <String Id="VerifyRepairDlg_ClickRepair">按一下「修復」以修復 [ProductName] 的安裝。 如果您要檢閱或變更任何安裝設定,按一下「上一步」。 按一下「取消」結束精靈。</String>
+
+ <!---->
+
+ <String Id="WaitForCostingDlg_PleaseWait">在安裝程式完成判斷您的磁碟空間需求時請稍候。</String>
+
+ <!---->
+
+ <String Id="MsiRMFilesInUse_Text">以下應用程式使用此安裝需要更新的檔案。 您可以讓安裝精靈關閉並嘗試重新啟動這些應用程式或稍後重新啟動電腦。</String>
+ <String Id="MsiRMFilesInUse_Description">某些需要更新的檔案目前使用中。</String>
+ <String Id="MsiRMFilesInUse_Title">檔案使用中</String>
+ <String Id="MsiRMFilesInUse_UseRM">關閉應用程式並嘗試重新啟動它們。 (&C)</String>
+ <String Id="MsiRMFilesInUse_DontUseRM">不要關閉應用程式,將需要重新開機。 (&D)</String>
+
+ <!-- The following strings are internally used by WiX and MSI -->
+ <String Id="Error0">{{嚴重錯誤:}}</String>
+ <String Id="Error1">{{錯誤 [1]。}}</String>
+ <String Id="Error2">警告 [1]。</String>
+ <String Id="Error3"/>
+ <String Id="Error4">資訊 [1]。</String>
+ <String Id="Error5">安裝程式安裝這個封裝時發生未預期的錯誤。 這可能表示這個封裝的問題。 錯誤碼 [1]。 {{引數:[2], [3], [4]}}</String>
+ <String Id="Error6"/>
+ <String Id="Error7">{{磁碟已滿:}}</String>
+ <String Id="Error8">動作 [Time]:[1]. [2]</String>
+ <String Id="Error9">[ProductName]</String>
+ <String Id="Error10">{[2]}{, [3]}{, [4]}</String>
+ <String Id="Error11">訊息類型:[1], 引數:[2]</String>
+ <String Id="Error12">=== 開啟記錄時間:[Date] [Time] ===</String>
+ <String Id="Error13">=== 停止記錄時間:[Date] [Time] ===</String>
+ <String Id="Error14">動作開始 [Time]:[1]。</String>
+ <String Id="Error15">動作結束 [Time]:[1]。 傳回值 [2]。</String>
+ <String Id="Error16">剩餘時間:{[1] 分 }{[2] 秒}</String>
+ <String Id="Error17">記憶體不足,重試之前先關閉其它應用程式。</String>
+ <String Id="Error18">安裝程式不再有回應。</String>
+ <String Id="Error19">安裝程式已經永久中止。</String>
+ <String Id="Error20">在 Windows 組態 [ProductName] 時請稍候</String>
+ <String Id="Error21">正在收集所需的資訊...</String>
+ <String Id="Error22">正在移除此應用程式的舊版本...</String>
+ <String Id="Error23">正在準備移除此應用程式的舊版本...</String>
+ <String Id="Error32">{[ProductName] } 安裝成功完成。</String>
+ <String Id="Error33">{[ProductName] } 安裝失敗。</String>
+ <String Id="Error1101">讀取檔案錯誤:[2]。{{ 系統錯誤 [3]。}} 檢查檔案是否存在,並且可以存取。</String>
+ <String Id="Error1301">無法建立目錄 '[2]'。 同名的目錄已經存在。 取消安裝並嘗試安裝到不同位置。</String>
+ <String Id="Error1302">請插入磁碟:[2]</String>
+ <String Id="Error1303">安裝程式的權限不足,無法存取這個目錄:[2],安裝無法繼續,以系統管理員的身份登入或是連絡您的系統管理員。</String>
+ <String Id="Error1304">寫入至檔案時發生錯誤:[2]。請檢查您可以存取那個目錄。</String>
+ <String Id="Error1305">讀取檔案時發生錯誤:[2]。{{ 系統錯誤 [3]。}} 請檢查檔案是否存在,並且可以存取。</String>
+ <String Id="Error1306">另一個應用程序獨占存取檔案 '[2]'。 請關閉所有其它應用程式,然後按一下「重試」。</String>
+ <String Id="Error1307">磁碟空間不足,無法安裝這個檔案:[2]。釋放一些磁碟空間然後按一下「重試」,或按一下「取消」結束。</String>
+ <String Id="Error1308">找不到來源檔案:[2]。 請驗證檔案存在並且您可以存取它。</String>
+ <String Id="Error1309">讀取檔案錯誤:[3]。{{ 系統錯誤 [2]。}} 請檢查檔案是否存在,並且可以存取。</String>
+ <String Id="Error1310">寫入至檔案時發生錯誤:[3]。{{ 系統錯誤 [2]。}} 請檢查您可以存取那個目錄。</String>
+ <String Id="Error1311">找不到來源檔案 {{(cabinet)}}:[2]。 請檢查檔案存在並且可以存取。</String>
+ <String Id="Error1312">無法建立目錄 '[2]'。 同名的檔案已經存在。 請重新命名或移除檔案並按一下「重試」,或按一下「取消」結束。</String>
+ <String Id="Error1313">磁碟區 [2] 目前不可使用。 請選取另一個。</String>
+ <String Id="Error1314">指定的路徑 '[2]' 不可使用。</String>
+ <String Id="Error1315">無法寫入指定的資料夾:[2]。</String>
+ <String Id="Error1316">嘗試從檔案讀取時發生網路錯誤:[2]</String>
+ <String Id="Error1317">嘗試建立目錄時發生錯誤:[2]</String>
+ <String Id="Error1318">嘗試建立目錄時發生網路錯誤:[2]</String>
+ <String Id="Error1319">嘗試開啟來源檔案時發生網路錯誤:[2]</String>
+ <String Id="Error1320">指定的路徑太長:[2]</String>
+ <String Id="Error1321">Installer 的權限不足以修改這個檔案:[2]。</String>
+ <String Id="Error1322">資料夾路徑的部份 '[2]' 無效。其為空或超過系統允許的長度。</String>
+ <String Id="Error1323">資料夾路徑 '[2]' 包含無效的字在資料夾路徑。</String>
+ <String Id="Error1324">資料夾路徑 '[2]' 包含無效字元。</String>
+ <String Id="Error1325">'[2]' 不是有效的短檔名。</String>
+ <String Id="Error1326">取得檔案安全性錯誤:[3] GetLastString:[2]</String>
+ <String Id="Error1327">無效的磁碟機:[2]</String>
+ <String Id="Error1328">套用修正檔到檔案 [2] 錯誤。 可能已由其他主機更新,且這個修正檔不再能修改。 更多資訊請聯絡您的修正檔供應商。 {{系統錯誤:[3]}}</String>
+ <String Id="Error1329">無法安裝所需的檔案,因為 cabinet 檔案 [2] 沒有數位簽章。 這表示 cabinet 檔案已經損毀。</String>
+ <String Id="Error1330">無法安裝所需的檔案,因為 cabinet 檔案 [2] 有無效的數位簽章。 這表示 cabinet 檔案已經損毀。 {{ WinVerifyTrust 返回錯誤 [3]。}}</String>
+ <String Id="Error1331">修正複製 [2] 檔案失敗:CRC 錯誤。</String>
+ <String Id="Error1332">修正移動 [2] 檔案失敗:CRC 錯誤。</String>
+ <String Id="Error1333">修正路徑 [2] 檔案失敗:CRC 錯誤。</String>
+ <String Id="Error1334">無法安裝 '[2]' 因為在 cainet 檔案 '[3]' 中找不到檔案。 這表示網路錯誤、從 CD-ROM 讀取錯誤、或此安裝包問題。</String>
+ <String Id="Error1335">此安裝所需的 cabinet 檔案 '[2]' 已經損毀且無法使用。 這表示網路錯誤、從 CD-ROM 讀取錯誤、或此安裝包問題。</String>
+ <String Id="Error1336">完成這個安裝所需的暫存檔案建立錯誤。 {{ 資料夾:[3]。 系統錯誤碼:[2]}}</String>
+ <String Id="Error1401">無法建立機碼:[2]。{{ 系統錯誤 [3]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1402">無法開啟機碼:[2]。{{ 系統錯誤 [3]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1403">無法從機碼 [3] 刪除值:[2]。{{ 系統錯誤 [4]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1404">無法刪除機碼:[2]。{{ 系統錯誤 [3]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1405">無法從機碼 [3] 讀取值 [2]。{{ 系統錯誤 [4]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1406">無法寫入值 [2] 至機碼 [3]。{{ 系統錯誤 [4]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1407">無法取得機碼 [2] 的值名稱。{{ 系統錯誤 [3]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1408">無法取得機碼 [2] 的子機碼名稱。{{ 系統錯誤 [3]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1409">無法讀取機碼 [2] 的安全資訊。{{ 系統錯誤 [3]。}} 檢查您是有足夠的權限存取該機碼,或是連絡您的支援人員。</String>
+ <String Id="Error1410">無法增加可用的登錄空間。 此應用程式須要 [2] KB 以上的空間。</String>
+ <String Id="Error1500">其它的安裝正在進行中,您必須完成該項安裝之後才能繼續。</String>
+ <String Id="Error1501">存取保全資料時發生錯誤,請確定 Windows Installer 是否正確組態,然後再試一次。</String>
+ <String Id="Error1502">使用者 '[2]' 先前已經啟動產品 '[3]' 的安裝。 該使用者在可以使用該產品前需要再次執行安裝。您目前的安裝現在將繼續。</String>
+ <String Id="Error1503">使用者 '[2]' 先前已經啟動產品 '[3]' 的安裝。 該使用者在可以使用該產品前需要再次執行安裝。</String>
+ <String Id="Error1601">磁碟空間不足 -- 磁碟區:'[2]',所需空間:[3] KB; 可用空間:[4] KB。 釋放一些磁碟空間並重試。</String>
+ <String Id="Error1602">您確定要取消嗎?</String>
+ <String Id="Error1603">檔案 [2][3] 正在由 { 以下處理程序:名稱:[4],Id:[5],視窗標題:'[6]'} 使用中。 關閉該應用程式並重試。</String>
+ <String Id="Error1604">已經安裝產品 '[2]',此產品防止安裝。 兩個產品不相容。</String>
+ <String Id="Error1605">磁碟區 '[2]' 沒有足夠的磁碟空間以啟用復原的安裝繼續。 需要 [3] KB,但只有 [4] KB 可以使用。 按一下「忽略」以不儲存復原資訊繼續安裝,按一下「重試」以再次檢查可用空間,或按一下「取消」以離開安裝。</String>
+ <String Id="Error1606">無法存取網路位置 [2]。</String>
+ <String Id="Error1607">繼續安裝前應該關閉以下應用程式:</String>
+ <String Id="Error1608">無法在本機中找到任何先前已安裝的合格版本。</String>
+ <String Id="Error1609">套用安全性設定時發生錯誤。 [2] 不是有效的使用者或群組。 這會是安裝包的問題或連線到網路上網域控制站的問題。 檢查您的網路連線並按一下「重試」,或「取消」以結束安裝。 {{找不到使用者的 SID,系統錯誤 [3]}}</String>
+ <String Id="Error1701">金鑰 [2] 是無效的,檢查您輸入的金鑰是否正確。</String>
+ <String Id="Error1702">要繼續設定 [2] 之前,Installer 必須重新啟動您的系統,按「是」將立即重新啟動;如果您想要稍後手動重新啟動請按「否」。</String>
+ <String Id="Error1703">您必須重新啟動您的系統,對 [2] 所做的組態變更才會生效,按「是」立即重新啟動;如果您想要稍後手動重新啟動請按「否」。</String>
+ <String Id="Error1704">安裝 [2] 目前已經暫停,您必須復原該安裝所做的變更才能繼續,您要復原這些變更嗎?</String>
+ <String Id="Error1705">另一個安裝這個產品的程式正在進行中,您必須復原該安裝所做的變更才能繼續,您要復原這些變更嗎?</String>
+ <String Id="Error1706">找不到產品 [2] 的安裝包。 嘗試使用安裝包 '[3]' 的有效副本嘗試再次安裝。</String>
+ <String Id="Error1707">安裝成功完成。</String>
+ <String Id="Error1708">安裝失敗。</String>
+ <String Id="Error1709">產品:[2] -- [3]</String>
+ <String Id="Error1710">您可以將電腦還原成先前的狀態或稍後繼續安裝,您希望還原嗎?</String>
+ <String Id="Error1711">寫入安裝資訊至磁碟時發生錯誤,確定磁碟的空間足夠,並按「重試」,或按「取消」來結束安裝。</String>
+ <String Id="Error1712">還原您的電腦成之前的狀態所需的一個或數個檔案找不到。 無法還原。</String>
+ <String Id="Error1713">[2] 無法安裝其所需的產品之一。 請聯絡您的技術支援小組。 {{系統字串:[3]。}}</String>
+ <String Id="Error1714">無法移除 [2] 的舊版本。 請聯絡您的技術支援小組。 {{系統字串 [3]。}}</String>
+ <String Id="Error1715">已經安裝 [2]</String>
+ <String Id="Error1716">已經組態 [2]</String>
+ <String Id="Error1717">已經移除 [2]</String>
+ <String Id="Error1718">數位簽章原則拒絕檔案 [2] 。</String>
+ <String Id="Error1719">無法存取 Windows Installer 服務。 如果您正執行在 Windows 安全模式,這將會發生。 請聯絡您的技術支援人員以取得協助。</String>
+ <String Id="Error1720">這個 Windows Installer 封裝有問題。 完成這個安裝需要的指令碼無法執行。 聯絡您的支援人員或封裝供應商。 {{自訂動作 [2] 指令碼錯誤 [3],[4]:[5] 行 [6],欄 [7],[8] }}</String>
+ <String Id="Error1721">這個 Windows Installer 封裝有問題。 完成這個安裝需要的程式無法執行。 聯絡您的支援人員或封裝供應商。 {{動作 [2],位置:[3],命令:[4] }}</String>
+ <String Id="Error1722">這個 Windows Installer 封裝有問題。 以 setup 部分執行的程式無法如預期完成。 聯絡您的支援人員或封裝供應商。 {{動作 [2],位置:[3],命令:[4] }}</String>
+ <String Id="Error1723">這個 Windows Installer 封裝有問題。 完成這個安裝需要的 DLL 無法執行。 聯絡您的支援人員或封裝供應商。 {{動作 [2],項目:[3],程式庫:[4] }}</String>
+ <String Id="Error1724">移除成功完成。</String>
+ <String Id="Error1725">移除失敗。</String>
+ <String Id="Error1726">宣告成功完成。</String>
+ <String Id="Error1727">宣告失敗。</String>
+ <String Id="Error1728">組態成功完成。</String>
+ <String Id="Error1729">組態失敗。</String>
+ <String Id="Error1730">您必須是管理者以移除這個應用程式。 要移除這個應用程式,您可以使用系統管理員登入或聯絡您的技術支援群組取得協助。</String>
+ <String Id="Error1801">路徑 [2] 無效。 請指定有效的路徑。</String>
+ <String Id="Error1802">記憶體不足,重試之前先關閉其它應用程式。</String>
+ <String Id="Error1803">磁碟機 [2] 中沒有磁片,請插入磁片然後重試,或按「取消」回到上次選取的磁碟區。</String>
+ <String Id="Error1804">磁碟機 [2] 中沒有磁片,請插入磁片然後按「重試」,或按「取消」回到瀏覽對話方塊,並選取不同的磁碟區。</String>
+ <String Id="Error1805">資料夾 [2] 不存在,請輸入一個現有的資料夾路徑。</String>
+ <String Id="Error1806">您的權限不足,無法讀取這個資料夾。</String>
+ <String Id="Error1807">無法決定合法的目的資料夾。</String>
+ <String Id="Error1901">嘗試讀取來源安裝資料庫時發生錯誤:[2]。</String>
+ <String Id="Error1902">正在排定重新開機作業:正在更改檔案名稱 [2] 成 [3],必須重新開機才能完成作業。</String>
+ <String Id="Error1903">正在排定重新開機作業:正在刪除檔案 [2],必須重新開機才能完成作業。</String>
+ <String Id="Error1904">註冊模組 [2] 失敗。HRESULT [3]。連絡您的支援人員。</String>
+ <String Id="Error1905">取消註冊模組 [2] 失敗。HRESULT [3]。連絡您的支援人員。</String>
+ <String Id="Error1906">無法預存封裝 [2]。錯誤:[3]。請連絡支援人員。</String>
+ <String Id="Error1907">無法註冊字型 [2]。 請確認是否有足夠的權限及系統支援。</String>
+ <String Id="Error1908">無法解除註冊字型 [2]。 請確認您有足夠的權限來移除字型。</String>
+ <String Id="Error1909">無法建立捷徑 [2]。 請確認目地資料夾是否存在及您的存取權。</String>
+ <String Id="Error1910">無法移除捷徑 [2]。 請確認目地資料夾是否存在及您的存取權。</String>
+ <String Id="Error1911">無法註冊檔案 [2] 的類型程式庫。 請連絡系統支援人員。</String>
+ <String Id="Error1912">無法解除註冊檔案 [2] 的 type library。 請連絡系統支援人員。</String>
+ <String Id="Error1913">無法更新 ini 檔 [2][3]。 請確認檔案是否存在及您的存取權。</String>
+ <String Id="Error1914">無法預定在重開機時將檔案 [2] 取代 [3]。 請確認您有 [3] 的存取權。</String>
+ <String Id="Error1915">移除 ODBC 驅動程式管理員錯誤,ODBC 錯誤 [2]:[3]。請連絡系統支援人員。</String>
+ <String Id="Error1916">安裝 ODBC 驅動程式管理員錯誤,ODBC 錯誤 [2]:[3]。請連絡系統支援人員。</String>
+ <String Id="Error1917">移除 ODBC 驅動程式管理員錯誤:[4],ODBC 錯誤 [2]:[3]。請確認您有足夠權限。</String>
+ <String Id="Error1918">安裝 ODBC 驅動程式管理員錯誤:[4],ODBC 錯誤 [2]:[3]。請確認檔案[4]存在並可存取。</String>
+ <String Id="Error1919">設定 ODBC 資料來源錯誤:[4],ODBC 錯誤 [2]:[3]。請確認檔案[4]存在並可存取。</String>
+ <String Id="Error1920">啟動服務 '[2]' ([3]) 失敗。 請確認您有足夠的特殊權限以啟動系統服務。</String>
+ <String Id="Error1921">停止服務 '[2]' ([3]) 失敗。 請確認您有足夠的特殊權限以啟動系統服務。</String>
+ <String Id="Error1922">刪除服務 '[2]' ([3]) 失敗。 請確認您有足夠的特殊權限以啟動系統服務。</String>
+ <String Id="Error1923">無法安裝服務 '[2]' ([3]) 。 請確認您有足夠的特殊權限以啟動系統服務。</String>
+ <String Id="Error1924">無法更新環境變數 '[2]'。 請確認您有足夠的特殊權限以修改環境變數。</String>
+ <String Id="Error1925">您沒有足夠的特殊權限使電腦的所有使用者都完成此安裝。請以系統管理員權限登入,接著再重試此安裝。</String>
+ <String Id="Error1926">無法設定檔案 '[3]' 的檔案安全性。 錯誤:[2]。 請確認您有足夠的特殊權限以修改此檔案的安全性權限。</String>
+ <String Id="Error1927">這台電腦並未安裝 Component Services (COM+ 1.0)。這項安裝需要有 Component Services 才能進行。Component Services 包含在 Windows XP 中。</String>
+ <String Id="Error1928">登錄 COM+ 應用程式時發生錯誤。請聯絡您的支援人員以取得其他資訊。</String>
+ <String Id="Error1929">解除 COM+ 應用程式登錄時發生錯誤。請聯絡您的支援人員以取得其他資訊。</String>
+ <String Id="Error1930">無法變更服務 '[2]' ([3]) 的描述。</String>
+ <String Id="Error1931">Windows Installer 服務無法更新系統檔案 [2] 因為檔案受 Windows 保護。 您可能需要更新您的作業系統使這個程式正確動作。 {{{封裝版本:[3],受 OS 保護的版本:[4]}}</String>
+ <String Id="Error1932">Windows Installer 服務無法更新受保護的 Windows 檔案 [2]。 {{封裝版本:[3],受 OS 保護的版本:[4],SFP 錯誤:[5]}}</String>
+ <String Id="Error1933">Windows Installer 服務無法更新一個或數個受保護的 Windows 檔案。 {{SFP 字串:[2]。 受保護的檔案清單:\r\n[3]}}</String>
+ <String Id="Error1934">電腦的原則停用使用者安裝。</String>
+ <String Id="Error1935">組件元件 [2] 的安裝期間發生錯誤。 HRESULT:[3]。 {{組件介面:[4],函數:[5],組件名稱:[6]}}</String>
+
+ <!-- Own / special errors -->
+ <String Id="Error25001">需要關閉應用程式 "[2]" 以繼續關閉。</String>
+
+ <String Id="ProgressTextInstallValidate">正在驗證安裝</String>
+ <String Id="ProgressTextInstallFiles">正在複製新檔案</String>
+ <String Id="ProgressTextInstallFilesTemplate">檔案:[1], 目錄:[9], 大小:[6]</String>
+ <String Id="ProgressTextInstallAdminPackage">正在複製網路安裝檔案</String>
+ <String Id="ProgressTextInstallAdminPackageTemplate">檔案:[1], 目錄:[9], 大小:[6]</String>
+ <String Id="ProgressTextFileCost">正在計算空間需求</String>
+ <String Id="ProgressTextCostInitialize">正在計算空間需求</String>
+ <String Id="ProgressTextCostFinalize">正在計算空間需求</String>
+ <String Id="ProgressTextCreateShortcuts">正在建立捷徑</String>
+ <String Id="ProgressTextCreateShortcutsTemplate">捷徑:[1]</String>
+ <String Id="ProgressTextPublishComponents">正在發佈合格的元件</String>
+ <String Id="ProgressTextPublishComponentsTemplate">元件 ID:[1], 公佈者:[2]</String>
+ <String Id="ProgressTextPublishFeatures">正在發佈產品功能</String>
+ <String Id="ProgressTextPublishFeaturesTemplate">功能:[1]</String>
+ <String Id="ProgressTextPublishProduct">正在發佈產品資訊</String>
+ <String Id="ProgressTextRegisterClassInfo">正在登錄類別伺服器</String>
+ <String Id="ProgressTextRegisterClassInfoTemplate">類別 Id:[1]</String>
+ <String Id="ProgressTextRegisterExtensionInfo">正在登錄擴充伺服器</String>
+ <String Id="ProgressTextRegisterExtensionInfoTemplate">副檔名 [1]</String>
+ <String Id="ProgressTextRegisterMIMEInfo">正在登錄 MIME 資訊</String>
+ <String Id="ProgressTextRegisterMIMEInfoTemplate">MIME 內容類型:[1],副檔名:[2]</String>
+ <String Id="ProgressTextRegisterProgIdInfo">正在登錄程式辨識字元</String>
+ <String Id="ProgressTextRegisterProgIdInfoTemplate">ProgId: [1]</String>
+ <String Id="ProgressTextAllocateRegistrySpace">正在配置登錄空間</String>
+ <String Id="ProgressTextAllocateRegistrySpaceTemplate">可用空間:[1]</String>
+ <String Id="ProgressTextAppSearch">正在搜尋已安裝的應用程式</String>
+ <String Id="ProgressTextAppSearchTemplate">內容:[1], 簽章:[2]</String>
+ <String Id="ProgressTextBindImage">正在繫結執行檔</String>
+ <String Id="ProgressTextBindImageTemplate">檔案:[1]</String>
+ <String Id="ProgressTextCCPSearch">正在搜尋查詢產品</String>
+ <String Id="ProgressTextCreateFolders">正在建立資料夾</String>
+ <String Id="ProgressTextCreateFoldersTemplate">資料夾:[1]</String>
+ <String Id="ProgressTextDeleteServices">正在刪除服務</String>
+ <String Id="ProgressTextDeleteServicesTemplate">服務:[1]</String>
+ <String Id="ProgressTextDuplicateFiles">正在建立重複檔案</String>
+ <String Id="ProgressTextDuplicateFilesTemplate">檔案:[1], 目錄:[9], 大小:[6]</String>
+ <String Id="ProgressTextFindRelatedProducts">正在搜尋相關的應用程式</String>
+ <String Id="ProgressTextFindRelatedProductsTemplate">找到應用程式:[1]</String>
+ <String Id="ProgressTextInstallODBC">正在安裝 ODBC 元件</String>
+ <String Id="ProgressTextInstallServices">正在安裝新服務</String>
+ <String Id="ProgressTextInstallServicesTemplate">服務:[2]</String>
+ <String Id="ProgressTextLaunchConditions">正在評估啟動條件</String>
+ <String Id="ProgressTextMigrateFeatureStates">正在從相關的應用程式遷移功能狀態</String>
+ <String Id="ProgressTextMigrateFeatureStatesTemplate">應用程式:[1]</String>
+ <String Id="ProgressTextMoveFiles">正在移動檔案</String>
+ <String Id="ProgressTextMoveFilesTemplate">檔案:[1], 目錄:[9], 大小:[6]</String>
+ <String Id="ProgressTextPatchFiles">正在修補檔案</String>
+ <String Id="ProgressTextPatchFilesTemplate">檔案:[1], 目錄:[2], 大小:[3]</String>
+ <String Id="ProgressTextProcessComponents">正在更新元件註冊</String>
+ <String Id="ProgressTextRegisterComPlus">正在註冊 COM+ 應用程式和元件</String>
+ <String Id="ProgressTextRegisterComPlusTemplate">AppId:[1]{{, AppType:[2],使用者:[3],RSN:[4]}}</String>
+ <String Id="ProgressTextRegisterFonts">正在註冊字型</String>
+ <String Id="ProgressTextRegisterFontsTemplate">字型:[1]</String>
+ <String Id="ProgressTextRegisterProduct">正在註冊產品</String>
+ <String Id="ProgressTextRegisterProductTemplate">[1]</String>
+ <String Id="ProgressTextRegisterTypeLibraries">正在登錄類別程式庫</String>
+ <String Id="ProgressTextRegisterTypeLibrariesTemplate">LibID: [1]</String>
+ <String Id="ProgressTextRegisterUser">正在登錄使用者</String>
+ <String Id="ProgressTextRegisterUserTemplate">[1]</String>
+ <String Id="ProgressTextRemoveDuplicateFiles">正在移除重複的檔案</String>
+ <String Id="ProgressTextRemoveDuplicateFilesTemplate">檔案:[1], 目錄:[9]</String>
+ <String Id="ProgressTextRemoveEnvironmentStrings">正在更新環境字串</String>
+ <String Id="ProgressTextRemoveEnvironmentStringsTemplate">名稱:[1], 數值:[2], 動作:[3]</String>
+ <String Id="ProgressTextRemoveExistingProducts">正在移除應用程式</String>
+ <String Id="ProgressTextRemoveExistingProductsTemplate">應用程式:[1], 命令列:[2]</String>
+ <String Id="ProgressTextRemoveFiles">正在移除檔案</String>
+ <String Id="ProgressTextRemoveFilesTemplate">檔案:[1], 目錄:[9]</String>
+ <String Id="ProgressTextRemoveFolders">正在移除資料夾</String>
+ <String Id="ProgressTextRemoveFoldersTemplate">資料夾:[1]</String>
+ <String Id="ProgressTextRemoveIniValues">正在移除 INI 檔案項目</String>
+ <String Id="ProgressTextRemoveIniValuesTemplate">檔案:[1], 區段:[2], 機碼:[3], 數值:[4]</String>
+ <String Id="ProgressTextRemoveODBC">正在移除 ODBC 元件</String>
+ <String Id="ProgressTextRemoveRegistryValues">正在移除系統登錄檔數值</String>
+ <String Id="ProgressTextRemoveRegistryValuesTemplate">機碼:[1], 名稱:[2]</String>
+ <String Id="ProgressTextRemoveShortcuts">正在移除捷徑</String>
+ <String Id="ProgressTextRemoveShortcutsTemplate">捷徑:[1]</String>
+ <String Id="ProgressTextRMCCPSearch">正在搜尋查詢產品</String>
+ <String Id="ProgressTextSelfRegModules">正在註冊模組</String>
+ <String Id="ProgressTextSelfRegModulesTemplate">檔案:[1], 資料夾:[2]</String>
+ <String Id="ProgressTextSelfUnregModules">正在解除模組登錄</String>
+ <String Id="ProgressTextSelfUnregModulesTemplate">檔案:[1], 資料夾:[2]</String>
+ <String Id="ProgressTextSetODBCFolders">正在初始化 ODBC 目錄</String>
+ <String Id="ProgressTextStartServices">正在啟動服務</String>
+ <String Id="ProgressTextStartServicesTemplate">服務:[1]</String>
+ <String Id="ProgressTextStopServices">正在停止服務</String>
+ <String Id="ProgressTextStopServicesTemplate">服務:[1]</String>
+ <String Id="ProgressTextUnpublishComponents">正在取消元件公佈</String>
+ <String Id="ProgressTextUnpublishComponentsTemplate">元件 ID:[1], 公佈者:[2]</String>
+ <String Id="ProgressTextUnpublishFeatures">正在取消功能公佈</String>
+ <String Id="ProgressTextUnpublishFeaturesTemplate">功能:[1]</String>
+ <String Id="ProgressTextUnregisterClassInfo">解除類別伺服器登錄</String>
+ <String Id="ProgressTextUnregisterClassInfoTemplate">類別 Id:[1]</String>
+ <String Id="ProgressTextUnregisterComPlus">正在解除 COM+ 應用程式和元件登錄</String>
+ <String Id="ProgressTextUnregisterComPlusTemplate">AppId: [1]{{, AppType: [2]}}</String>
+ <String Id="ProgressTextUnregisterExtensionInfo">正在解除擴充伺服器登錄</String>
+ <String Id="ProgressTextUnregisterExtensionInfoTemplate">副檔名 [1]</String>
+ <String Id="ProgressTextUnregisterFonts">正在解除字型登錄</String>
+ <String Id="ProgressTextUnregisterFontsTemplate">字型:[1]</String>
+ <String Id="ProgressTextUnregisterMIMEInfo">正在解除 MIME 資訊登錄</String>
+ <String Id="ProgressTextUnregisterMIMEInfoTemplate">MIME 內容類型:[1],副檔名:[2]</String>
+ <String Id="ProgressTextUnregisterProgIdInfo">正在解除程式識別碼登錄</String>
+ <String Id="ProgressTextUnregisterProgIdInfoTemplate">ProgId: [1]</String>
+ <String Id="ProgressTextUnregisterTypeLibraries">正在解除類別程式庫登錄</String>
+ <String Id="ProgressTextUnregisterTypeLibrariesTemplate">LibID: [1]</String>
+ <String Id="ProgressTextWriteEnvironmentStrings">正在更新環境字串</String>
+ <String Id="ProgressTextWriteEnvironmentStringsTemplate">名稱:[1], 數值:[2], 動作:[3]</String>
+ <String Id="ProgressTextWriteIniValues">正在寫入 INI 檔案數值</String>
+ <String Id="ProgressTextWriteIniValuesTemplate">檔案:[1], 區段:[2], 機碼:[3], 數值:[4]</String>
+ <String Id="ProgressTextWriteRegistryValues">正在寫入系統登錄檔數值</String>
+ <String Id="ProgressTextWriteRegistryValuesTemplate">機碼:[1],名稱:[2],值:[3]</String>
+ <String Id="ProgressTextAdvertise">正在宣告應用程式</String>
+ <String Id="ProgressTextGenerateScript">正在產生動作的 script 操作:</String>
+ <String Id="ProgressTextGenerateScriptTemplate">[1]</String>
+ <String Id="ProgressTextInstallSFPCatalogFile">正在安裝系統目錄</String>
+ <String Id="ProgressTextInstallSFPCatalogFileTemplate">檔案:[1],依存關係:[2]</String>
+ <String Id="ProgressTextMsiPublishAssemblies">正在發佈組件資訊</String>
+ <String Id="ProgressTextMsiPublishAssembliesTemplate">應用程式內容:[1],組件名稱:[2]</String>
+ <String Id="ProgressTextMsiUnpublishAssemblies">正在取消資訊公佈</String>
+ <String Id="ProgressTextMsiUnpublishAssembliesTemplate">應用程式內容:[1],組件名稱:[2]</String>
+ <String Id="ProgressTextRollback">回復動作:</String>
+ <String Id="ProgressTextRollbackTemplate">[1]</String>
+ <String Id="ProgressTextRollbackCleanup">正在移除備份檔案</String>
+ <String Id="ProgressTextRollbackCleanupTemplate">檔案:[1]</String>
+ <String Id="ProgressTextUnmoveFiles">正在移除移動的檔案</String>
+ <String Id="ProgressTextUnmoveFilesTemplate">檔案:[1], 目錄:[9]</String>
+ <String Id="ProgressTextUnpublishProduct">正在取消發佈產品資訊</String>
+
+ <String Id="UITextbytes">位元組</String>
+ <String Id="UITextGB">GB</String>
+ <String Id="UITextKB">KB</String>
+ <String Id="UITextMB">MB</String>
+ <String Id="UITextMenuAbsent">整個功能將不可用</String>
+ <String Id="UITextMenuAdvertise">需要時將安裝的功能</String>
+ <String Id="UITextMenuAllCD">整個功能將會安裝成從 CD 上執行</String>
+ <String Id="UITextMenuAllLocal">整個功能將會安裝到本機硬碟</String>
+ <String Id="UITextMenuAllNetwork">整個功能將會安裝成從網路上執行</String>
+ <String Id="UITextMenuCD">將會安裝成從 CD 上執行</String>
+ <String Id="UITextMenuLocal">將會安裝到本機硬碟</String>
+ <String Id="UITextMenuNetwork">將會安裝成從網路執行</String>
+ <String Id="UITextScriptInProgress">正在收集所需的資訊...</String>
+ <String Id="UITextSelAbsentAbsent">這個功能將保持未安裝的狀態</String>
+ <String Id="UITextSelAbsentAdvertise">這個功能會設定成視需要進行安裝</String>
+ <String Id="UITextSelAbsentCD">這個功能將會安裝成從 CD 執行</String>
+ <String Id="UITextSelAbsentLocal">這個功能將會安裝在本機硬碟中</String>
+ <String Id="UITextSelAbsentNetwork">這個功能將會安裝成從網路執行</String>
+ <String Id="UITextSelAdvertiseAbsent">這個功能將無法使用</String>
+ <String Id="UITextSelAdvertiseAdvertise">將會視需要進行安裝</String>
+ <String Id="UITextSelAdvertiseCD">這個功能可以從 CD 上執行</String>
+ <String Id="UITextSelAdvertiseLocal">這個功能將安裝在您的本機硬碟</String>
+ <String Id="UITextSelAdvertiseNetwork">這個功能可以從網路執行</String>
+ <String Id="UITextSelCDAbsent">這個功能將完整解除安裝,您將不能從 CD 執行</String>
+ <String Id="UITextSelCDAdvertise">這個功能會從 CD 執行變更成視需要進行安裝</String>
+ <String Id="UITextSelCDCD">這個功能仍將從 CD 執行</String>
+ <String Id="UITextSelCDLocal">這個功能將會從 CD 執行變更為安裝在本機硬碟中</String>
+ <String Id="UITextSelChildCostNeg">這個功能會在您的硬碟釋放 [1] 。</String>
+ <String Id="UITextSelChildCostPos">這個功能要求 [1] 在您的硬碟上。</String>
+ <String Id="UITextSelCostPending">正在編譯這個功能的花費...</String>
+ <String Id="UITextSelLocalAbsent">這個功能將會完整移除</String>
+ <String Id="UITextSelLocalAdvertise">這個功能會從您的本機硬碟上移除,但是會設定成視需要進行安裝</String>
+ <String Id="UITextSelLocalCD">這個功能將會從您的本機硬碟中移除,但是仍然可以從 CD 執行</String>
+ <String Id="UITextSelLocalLocal">這個功能將會保留在您的本機硬碟中</String>
+ <String Id="UITextSelLocalNetwork">這個功能將會從您的本機硬碟中移除,但是仍然可從網路上執行</String>
+ <String Id="UITextSelNetworkAbsent">這個功能將完整解除安裝,您將不能從網路執行</String>
+ <String Id="UITextSelNetworkAdvertise">這個功能將會從網路執行變更成視需要進行安裝</String>
+ <String Id="UITextSelNetworkLocal">這個功能將會從網路執行變更為安裝在本機硬碟中。</String>
+ <String Id="UITextSelNetworkNetwork">這個功能仍將保留成從網路執行</String>
+ <String Id="UITextSelParentCostNegNeg">這個功能在您的硬碟釋放 [1]。 它已選取 [2] 之 [3] 子功能。 子功能在您的硬碟釋放 [4] 。</String>
+ <String Id="UITextSelParentCostNegPos">這個功能在您的硬碟釋放 [1]。 它已選取 [2] 之 [3] 子功能。 子功能在您的硬碟需要 [4] 。</String>
+ <String Id="UITextSelParentCostPosNeg">這個功能在您的硬碟需要 [1]。 它已選取 [2] 之 [3] 子功能。 子功能在您的硬碟釋放 [4] 。</String>
+ <String Id="UITextSelParentCostPosPos">這個功能在您的硬碟需要 [1]。 它已選取 [2] 之 [3] 子功能。 子功能在您的硬碟需要 [4] 。</String>
+ <String Id="UITextTimeRemaining">剩餘時間:{[1] 分 }{[2] 秒}</String>
+ <String Id="UITextVolumeCostAvailable">可用</String>
+ <String Id="UITextVolumeCostDifference">差異</String>
+ <String Id="UITextVolumeCostRequired">需求</String>
+ <String Id="UITextVolumeCostSize">磁碟大小</String>
+ <String Id="UITextVolumeCostVolume">分割區</String>
+
+</WixLocalization>
diff --git a/src/VBox/Installer/win/Resources/resource.h b/src/VBox/Installer/win/Resources/resource.h index e2ea716e..ddc26153 100644 --- a/src/VBox/Installer/win/Resources/resource.h +++ b/src/VBox/Installer/win/Resources/resource.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Installer/win/Stub/Makefile.kmk b/src/VBox/Installer/win/Stub/Makefile.kmk index a2420c3f..5117edd3 100644 --- a/src/VBox/Installer/win/Stub/Makefile.kmk +++ b/src/VBox/Installer/win/Stub/Makefile.kmk @@ -21,43 +21,61 @@ include $(KBUILD_PATH)/subheader.kmk # This has to be 32-bit, so don't include it in the 64-bit build. if "$(KBUILD_TARGET_ARCH)" == "x86" -TEMPLATE_VBOXSTUB = Drop the signing, we will sign it later. -TEMPLATE_VBOXSTUB_EXTENDS = VBOXR3STATIC -TEMPLATE_VBOXSTUB_POST_CMDS = $(NO_SUCH_VARIABLE) - -PROGRAMS.x86 += VBoxStub -VBoxStub_TEMPLATE= VBOXSTUB -VBoxStub_DEFS = _WIN32_WINNT=0x0501 IN_RT_R3 -VBoxStub_SOURCES = \ - VBoxStub.cpp \ - VBoxStub.rc -VBoxStub_SDKS += \ - VBOX_NTDLL -VBoxStub_LIBS = \ - $(VBOX_LIB_RUNTIME_STATIC) \ - $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Msi.lib - -VBoxStub.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) -VBoxStub.cpp_DEPS = $(VBOX_SVN_REV_KMK) - -# The icon location is configurable. -VBoxStub.rc_INCS += $(VBoxStub_0_OUTDIR) -VBoxStub.rc_DEPS += \ - $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \ - $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc -VBoxStub.rc_CLEAN = \ - $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \ - $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc - -# Icon include file. -$$(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc: $(VBOX_WINDOWS_ICON_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@) + TEMPLATE_VBOXSTUB = Drop the signing, we will sign it later. + TEMPLATE_VBOXSTUB_EXTENDS = VBOXR3STATIC + TEMPLATE_VBOXSTUB_POST_CMDS = $(NO_SUCH_VARIABLE) + + PROGRAMS += VBoxStub + VBoxStub_TEMPLATE= VBOXSTUB + VBoxStub_DEFS = _WIN32_WINNT=0x0501 IN_RT_R3 + + VBoxStub_SOURCES = \ + VBoxStub.cpp \ + VBoxStub.rc + + VBoxStub_SDKS += \ + VBOX_NTDLL + VBoxStub_LIBS = \ + $(VBOX_LIB_RUNTIME_STATIC) \ + $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Msi.lib + + VBoxStub.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) + VBoxStub.cpp_DEPS = $(VBOX_SVN_REV_KMK) + + # If signing mode is enabled, then add the possibility to + # install public certificate automatically in /silent mode + ifdef VBOX_SIGNING_MODE + + VBoxStub_SOURCES += VBoxStubCertUtil.cpp + VBoxStub_LIBS += crypt32.lib + VBoxStub.cpp_DEPS += $(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h + VBoxStub.cpp_INCS += $(VBoxStub_0_OUTDIR) + VBoxStub.cpp_DEFS += VBOX_WITH_CODE_SIGNING + + $$(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h: $(VBOX_BIN2C) $(PATH_ROOT)/src/VBox/Additions/WINNT/tools/oracle-vbox.cer | $$(dir $$@) + $(VBOX_BIN2C) _VBoxStubPublicCert $(PATH_ROOT)/src/VBox/Additions/WINNT/tools/oracle-vbox.cer $@ + + endif + + # The icon location is configurable. + VBoxStub.rc_INCS += $(VBoxStub_0_OUTDIR) + VBoxStub.rc_DEPS += \ + $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \ + $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc + VBoxStub.rc_CLEAN = \ + $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \ + $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc + + # Icon include file. + $$(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc: $(VBOX_WINDOWS_ICON_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@) $(APPEND) -t $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ICON_FILE))"' -# Manifest. -VBOX_STUB_MANIFEST_FILE := $(PATH_SUB_CURRENT)/VBoxStub.manifest -$$(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc: $(VBOX_STUB_MANIFEST_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@) + # Manifest. + VBOX_STUB_MANIFEST_FILE := $(PATH_SUB_CURRENT)/VBoxStub.manifest + $$(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc: $(VBOX_STUB_MANIFEST_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@) $(APPEND) -t $@ 'APP_MANIFEST RT_MANIFEST "$(subst /,\\,$(VBOX_STUB_MANIFEST_FILE))"' + endif # x86 only include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/VBox/Installer/win/Stub/VBoxStub.cpp b/src/VBox/Installer/win/Stub/VBoxStub.cpp index 22b9bccb..188bf5e6 100644 --- a/src/VBox/Installer/win/Stub/VBoxStub.cpp +++ b/src/VBox/Installer/win/Stub/VBoxStub.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -18,11 +18,12 @@ /******************************************************************************* * Header Files * *******************************************************************************/ -#include <windows.h> +#include <Windows.h> #include <commctrl.h> #include <lmerr.h> #include <msiquery.h> #include <objbase.h> + #include <shlobj.h> #include <stdlib.h> #include <stdio.h> @@ -34,10 +35,14 @@ #include <iprt/assert.h> #include <iprt/dir.h> #include <iprt/file.h> +#include <iprt/getopt.h> #include <iprt/initterm.h> +#include <iprt/list.h> #include <iprt/mem.h> -#include <iprt/path.h> +#include <iprt/message.h> #include <iprt/param.h> +#include <iprt/path.h> +#include <iprt/stream.h> #include <iprt/string.h> #include <iprt/thread.h> @@ -45,109 +50,192 @@ #include "../StubBld/VBoxStubBld.h" #include "resource.h" -#ifndef _UNICODE -#define _UNICODE +#ifdef VBOX_WITH_CODE_SIGNING +# include "VBoxStubCertUtil.h" +# include "VBoxStubPublicCert.h" #endif +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#define MY_UNICODE_SUB(str) L ##str +#define MY_UNICODE(str) MY_UNICODE_SUB(str) + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ /** - * Shows a message box with a printf() style formatted string. - * - * @returns Message box result (IDOK, IDCANCEL, ...). - * - * @param uType Type of the message box (see MSDN). - * @param pszFmt Printf-style format string to show in the message box body. - * + * Cleanup record. */ -static int ShowInfo(const char *pszFmt, ...) +typedef struct STUBCLEANUPREC { - char *pszMsg; - va_list va; + /** List entry. */ + RTLISTNODE ListEntry; + /** True if file, false if directory. */ + bool fFile; + /** The path to the file or directory to clean up. */ + char szPath[1]; +} STUBCLEANUPREC; +/** Pointer to a cleanup record. */ +typedef STUBCLEANUPREC *PSTUBCLEANUPREC; - va_start(va, pszFmt); - RTStrAPrintfV(&pszMsg, pszFmt, va); - va_end(va); - int rc; - if (pszMsg) - rc = MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION); - else - rc = MessageBox(GetDesktopWindow(), pszFmt, VBOX_STUB_TITLE, MB_ICONINFORMATION); - RTStrFree(pszMsg); - return rc; -} +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Whether it's a silent or interactive GUI driven install. */ +static bool g_fSilent = false; +/** List of temporary files. */ +static RTLISTANCHOR g_TmpFiles; + /** * Shows an error message box with a printf() style formatted string. * - * @returns Message box result (IDOK, IDCANCEL, ...). - * + * @returns RTEXITCODE_FAILURE * @param pszFmt Printf-style format string to show in the message box body. * */ -static int ShowError(const char *pszFmt, ...) +static RTEXITCODE ShowError(const char *pszFmt, ...) { char *pszMsg; va_list va; - int rc; va_start(va, pszFmt); if (RTStrAPrintfV(&pszMsg, pszFmt, va)) { - rc = MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR); + if (g_fSilent) + RTMsgError("%s", pszMsg); + else + { + PRTUTF16 pwszMsg; + int rc = RTStrToUtf16(pszMsg, &pwszMsg); + if (RT_SUCCESS(rc)) + { + MessageBoxW(GetDesktopWindow(), pwszMsg, MY_UNICODE(VBOX_STUB_TITLE), MB_ICONERROR); + RTUtf16Free(pwszMsg); + } + else + MessageBoxA(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR); + } RTStrFree(pszMsg); } else /* Should never happen! */ AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt)); va_end(va); - return rc; + return RTEXITCODE_FAILURE; } /** - * Reads data from a built-in resource. - * - * @returns iprt status code. + * Shows a message box with a printf() style formatted string. * - * @param hInst Instance to read the data from. - * @param pszDataName Name of resource to read. - * @param ppvResource Pointer to buffer which holds the read resource data. - * @param pdwSize Pointer which holds the read data size. + * @param uType Type of the message box (see MSDN). + * @param pszFmt Printf-style format string to show in the message box body. * */ -static int ReadData(HINSTANCE hInst, - const char *pszDataName, - PVOID *ppvResource, - DWORD *pdwSize) +static void ShowInfo(const char *pszFmt, ...) { - do + char *pszMsg; + va_list va; + va_start(va, pszFmt); + int rc = RTStrAPrintfV(&pszMsg, pszFmt, va); + va_end(va); + if (rc >= 0) { - AssertMsgBreak(pszDataName, ("Resource name is empty!\n")); + if (g_fSilent) + RTPrintf("%s\n", pszMsg); + else + { + PRTUTF16 pwszMsg; + int rc = RTStrToUtf16(pszMsg, &pwszMsg); + if (RT_SUCCESS(rc)) + { + MessageBoxW(GetDesktopWindow(), pwszMsg, MY_UNICODE(VBOX_STUB_TITLE), MB_ICONINFORMATION); + RTUtf16Free(pwszMsg); + } + else + MessageBoxA(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION); + } + } + else /* Should never happen! */ + AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt)); + RTStrFree(pszMsg); +} - /* Find our resource. */ - HRSRC hRsrc = FindResourceEx(hInst, RT_RCDATA, pszDataName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); - AssertMsgBreak(hRsrc, ("Could not find resource!\n")); - /* Get resource size. */ - *pdwSize = SizeofResource(hInst, hRsrc); - AssertMsgBreak(*pdwSize > 0, ("Size of resource is invalid!\n")); +/** + * Finds the specified in the resource section of the executable. + * + * @returns IPRT status code. + * + * @param pszDataName Name of resource to read. + * @param ppvResource Where to return the pointer to the data. + * @param pdwSize Where to return the size of the data (if found). + * Optional. + */ +static int FindData(const char *pszDataName, PVOID *ppvResource, DWORD *pdwSize) +{ + AssertReturn(pszDataName, VERR_INVALID_PARAMETER); + HINSTANCE hInst = NULL; /* indicates the executable image */ + + /* Find our resource. */ + PRTUTF16 pwszDataName; + int rc = RTStrToUtf16(pszDataName, &pwszDataName); + AssertRCReturn(rc, rc); + HRSRC hRsrc = FindResourceExW(hInst, + (LPWSTR)RT_RCDATA, + pwszDataName, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); + RTUtf16Free(pwszDataName); + AssertReturn(hRsrc, VERR_IO_GEN_FAILURE); + + /* Get resource size. */ + DWORD cb = SizeofResource(hInst, hRsrc); + AssertReturn(cb > 0, VERR_NO_DATA); + if (pdwSize) + *pdwSize = cb; + + /* Get pointer to resource. */ + HGLOBAL hData = LoadResource(hInst, hRsrc); + AssertReturn(hData, VERR_IO_GEN_FAILURE); + + /* Lock resource. */ + *ppvResource = LockResource(hData); + AssertReturn(*ppvResource, VERR_IO_GEN_FAILURE); + return VINF_SUCCESS; +} - /* Get pointer to resource. */ - HGLOBAL hData = LoadResource(hInst, hRsrc); - AssertMsgBreak(hData, ("Could not load resource!\n")); - /* Lock resource. */ - *ppvResource = LockResource(hData); - AssertMsgBreak(*ppvResource, ("Could not lock resource!\n")); - return VINF_SUCCESS; +/** + * Finds the header for the given package. + * + * @returns Pointer to the package header on success. On failure NULL is + * returned after ShowError has been invoked. + * @param iPackage The package number. + */ +static PVBOXSTUBPKG FindPackageHeader(unsigned iPackage) +{ + char szHeaderName[32]; + RTStrPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", iPackage); - } while (0); + PVBOXSTUBPKG pPackage; + int rc = FindData(szHeaderName, (PVOID *)&pPackage, NULL); + if (RT_FAILURE(rc)) + { + ShowError("Internal error: Could not find package header #%u: %Rrc", iPackage, rc); + return NULL; + } - return VERR_IO_GEN_FAILURE; + /** @todo validate it. */ + return pPackage; } + /** * Constructs a full temporary file path from the given parameters. * @@ -192,7 +280,7 @@ static int ExtractFile(const char *pszResourceName, /* Read the data of the built-in resource. */ PVOID pvData = NULL; DWORD dwDataSize = 0; - rc = ReadData(NULL, pszResourceName, &pvData, &dwDataSize); + rc = FindData(pszResourceName, &pvData, &dwDataSize); AssertMsgRCBreak(rc, ("Could not read resource data!\n")); /* Create new (and replace an old) file. */ @@ -266,61 +354,427 @@ static BOOL IsWow64(void) /** * Decides whether we need a specified package to handle or not. * - * @returns TRUE if we need to handle the specified package, FALSE if not. + * @returns @c true if we need to handle the specified package, @c false if not. * * @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource. * */ -static BOOL PackageIsNeeded(PVBOXSTUBPKG pPackage) +static bool PackageIsNeeded(PVBOXSTUBPKG pPackage) { - BOOL bIsWow64 = IsWow64(); - if ((bIsWow64 && pPackage->byArch == VBOXSTUBPKGARCH_AMD64)) /* 64bit Windows. */ + if (pPackage->byArch == VBOXSTUBPKGARCH_ALL) + return true; + VBOXSTUBPKGARCH enmArch = IsWow64() ? VBOXSTUBPKGARCH_AMD64 : VBOXSTUBPKGARCH_X86; + return pPackage->byArch == enmArch; +} + + +/** + * Adds a cleanup record. + * + * @returns Fully complained boolean success indicator. + * @param pszPath The path to the file or directory to clean up. + * @param fFile @c true if file, @c false if directory. + */ +static bool AddCleanupRec(const char *pszPath, bool fFile) +{ + size_t cchPath = strlen(pszPath); Assert(cchPath > 0); + PSTUBCLEANUPREC pRec = (PSTUBCLEANUPREC)RTMemAlloc(RT_OFFSETOF(STUBCLEANUPREC, szPath[cchPath + 1])); + if (!pRec) { - return TRUE; + ShowError("Out of memory!"); + return false; } - else if ((!bIsWow64 && pPackage->byArch == VBOXSTUBPKGARCH_X86)) /* 32bit. */ + pRec->fFile = fFile; + memcpy(pRec->szPath, pszPath, cchPath + 1); + + RTListPrepend(&g_TmpFiles, &pRec->ListEntry); + return true; +} + + +/** + * Cleans up all the extracted files and optionally removes the package + * directory. + * + * @param cPackages The number of packages. + * @param pszPkgDir The package directory, NULL if it shouldn't be + * removed. + */ +static void CleanUp(unsigned cPackages, const char *pszPkgDir) +{ + for (int i = 0; i < 5; i++) { - return TRUE; + int rc; + bool fFinalTry = i == 4; + + PSTUBCLEANUPREC pCur, pNext; + RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry) + { + if (pCur->fFile) + rc = RTFileDelete(pCur->szPath); + else + { + rc = RTDirRemoveRecursive(pCur->szPath, RTDIRRMREC_F_CONTENT_AND_DIR); + if (rc == VERR_DIR_NOT_EMPTY && fFinalTry) + rc = VINF_SUCCESS; + } + if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND) + rc = VINF_SUCCESS; + if (RT_SUCCESS(rc)) + { + RTListNodeRemove(&pCur->ListEntry); + RTMemFree(pCur); + } + else if (fFinalTry) + { + if (pCur->fFile) + ShowError("Failed to delete temporary file '%s': %Rrc", pCur->szPath, rc); + else + ShowError("Failed to delete temporary directory '%s': %Rrc", pCur->szPath, rc); + } + } + + if (RTListIsEmpty(&g_TmpFiles) || fFinalTry) + { + if (!pszPkgDir) + return; + rc = RTDirRemove(pszPkgDir); + if (RT_SUCCESS(rc) || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND || fFinalTry) + return; + } + + /* Delay a little and try again. */ + RTThreadSleep(i == 0 ? 100 : 3000); + } +} + + +/** + * Processes an MSI package. + * + * @returns Fully complained exit code. + * @param pszMsi The path to the MSI to process. + * @param pszMsiArgs Any additional installer (MSI) argument + * @param fLogging Whether to enable installer logging. + */ +static RTEXITCODE ProcessMsiPackage(const char *pszMsi, const char *pszMsiArgs, bool fLogging) +{ + int rc; + + /* + * Set UI level. + */ + INSTALLUILEVEL enmDesiredUiLevel = g_fSilent ? INSTALLUILEVEL_NONE : INSTALLUILEVEL_FULL; + INSTALLUILEVEL enmRet = MsiSetInternalUI(enmDesiredUiLevel, NULL); + if (enmRet == INSTALLUILEVEL_NOCHANGE /* means error */) + return ShowError("Internal error: MsiSetInternalUI failed."); + + /* + * Enable logging? + */ + if (fLogging) + { + char szLogFile[RTPATH_MAX]; + rc = RTStrCopy(szLogFile, sizeof(szLogFile), pszMsi); + if (RT_SUCCESS(rc)) + { + RTPathStripFilename(szLogFile); + rc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxInstallLog.txt"); + } + if (RT_FAILURE(rc)) + return ShowError("Internal error: Filename path too long."); + + PRTUTF16 pwszLogFile; + rc = RTStrToUtf16(szLogFile, &pwszLogFile); + if (RT_FAILURE(rc)) + return ShowError("RTStrToUtf16 failed on '%s': %Rrc", szLogFile, rc); + + UINT uLogLevel = MsiEnableLogW(INSTALLLOGMODE_VERBOSE, + pwszLogFile, + INSTALLLOGATTRIBUTES_FLUSHEACHLINE); + RTUtf16Free(pwszLogFile); + if (uLogLevel != ERROR_SUCCESS) + return ShowError("MsiEnableLogW failed"); } - else if (pPackage->byArch == VBOXSTUBPKGARCH_ALL) + + /* + * Initialize the common controls (extended version). This is necessary to + * run the actual .MSI installers with the new fancy visual control + * styles (XP+). Also, an integrated manifest is required. + */ + INITCOMMONCONTROLSEX ccEx; + ccEx.dwSize = sizeof(INITCOMMONCONTROLSEX); + ccEx.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS | + ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | + ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES; + InitCommonControlsEx(&ccEx); /* Ignore failure. */ + + /* + * Convert both strings to UTF-16 and start the installation. + */ + PRTUTF16 pwszMsi; + rc = RTStrToUtf16(pszMsi, &pwszMsi); + if (RT_FAILURE(rc)) + return ShowError("RTStrToUtf16 failed on '%s': %Rrc", pszMsi, rc); + PRTUTF16 pwszMsiArgs; + rc = RTStrToUtf16(pszMsiArgs, &pwszMsiArgs); + if (RT_FAILURE(rc)) { - return TRUE; + RTUtf16Free(pwszMsi); + return ShowError("RTStrToUtf16 failed on '%s': %Rrc", pszMsi, rc); } - return FALSE; + + UINT uStatus = MsiInstallProductW(pwszMsi, pwszMsiArgs); + RTUtf16Free(pwszMsi); + RTUtf16Free(pwszMsiArgs); + + if (uStatus == ERROR_SUCCESS) + return RTEXITCODE_SUCCESS; + if (uStatus == ERROR_SUCCESS_REBOOT_REQUIRED) + return RTEXITCODE_SUCCESS; /* we currently don't indicate this */ + + /* + * Installation failed. Figure out what to say. + */ + switch (uStatus) + { + case ERROR_INSTALL_USEREXIT: + /* Don't say anything? */ + break; + + case ERROR_INSTALL_PACKAGE_VERSION: + ShowError("This installation package cannot be installed by the Windows Installer service.\n" + "You must install a Windows service pack that contains a newer version of the Windows Installer service."); + break; + + case ERROR_INSTALL_PLATFORM_UNSUPPORTED: + ShowError("This installation package is not supported on this platform."); + break; + + default: + { + /* + * Try get windows to format the message. + */ + DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_IGNORE_INSERTS + | FORMAT_MESSAGE_FROM_SYSTEM; + HMODULE hModule = NULL; + if (uStatus >= NERR_BASE && uStatus <= MAX_NERR) + { + hModule = LoadLibraryExW(L"netmsg.dll", + NULL, + LOAD_LIBRARY_AS_DATAFILE); + if (hModule != NULL) + dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE; + } + + PWSTR pwszMsg; + if (FormatMessageW(dwFormatFlags, + hModule, /* If NULL, load system stuff. */ + uStatus, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (PWSTR)&pwszMsg, + 0, + NULL) > 0) + { + ShowError("Installation failed! Error: %ls", pwszMsg); + LocalFree(pwszMsg); + } + else /* If text lookup failed, show at least the error number. */ + ShowError("Installation failed! Error: %u", uStatus); + + if (hModule) + FreeLibrary(hModule); + break; + } + } + + return RTEXITCODE_FAILURE; } /** - * Recursively copies a directory to another location. + * Processes a package. * - * @returns iprt status code. + * @returns Fully complained exit code. + * @param iPackage The package number. + * @param pszPkgDir The package directory (aka extraction dir). + * @param pszMsiArgs Any additional installer (MSI) argument + * @param fLogging Whether to enable installer logging. + */ +static RTEXITCODE ProcessPackage(unsigned iPackage, const char *pszPkgDir, const char *pszMsiArgs, bool fLogging) +{ + /* + * Get the package header and check if it's needed. + */ + PVBOXSTUBPKG pPackage = FindPackageHeader(iPackage); + if (pPackage == NULL) + return RTEXITCODE_FAILURE; + + if (!PackageIsNeeded(pPackage)) + return RTEXITCODE_SUCCESS; + + /* + * Deal with the file based on it's extension. + */ + char szPkgFile[RTPATH_MAX]; + int rc = RTPathJoin(szPkgFile, sizeof(szPkgFile), pszPkgDir, pPackage->szFileName); + if (RT_FAILURE(rc)) + return ShowError("Internal error: RTPathJoin failed: %Rrc", rc); + RTPathChangeToDosSlashes(szPkgFile, true /* Force conversion. */); /* paranoia */ + + RTEXITCODE rcExit; + const char *pszExt = RTPathExt(szPkgFile); + if (RTStrICmp(pszExt, ".msi") == 0) + rcExit = ProcessMsiPackage(szPkgFile, pszMsiArgs, fLogging); + else if (RTStrICmp(pszExt, ".cab") == 0) + rcExit = RTEXITCODE_SUCCESS; /* Ignore .cab files, they're generally referenced by other files. */ + else + rcExit = ShowError("Internal error: Do not know how to handle file '%s'.", pPackage->szFileName); + + return rcExit; +} + + +#ifdef VBOX_WITH_CODE_SIGNING +/** + * Install the public certificate into TrustedPublishers so the installer won't + * prompt the user during silent installs. + * + * @returns Fully complained exit code. + */ +static RTEXITCODE InstallCertificate(void) +{ + if (addCertToStore(CERT_SYSTEM_STORE_LOCAL_MACHINE, + "TrustedPublisher", + g_ab_VBoxStubPublicCert, + sizeof(g_ab_VBoxStubPublicCert))) + return RTEXITCODE_SUCCESS; + return ShowError("Failed to construct install certificate."); +} +#endif /* VBOX_WITH_CODE_SIGNING */ + + +/** + * Copies the "<exepath>.custom" directory to the extraction path if it exists. * - * @param pszDestDir Location to copy the source directory to. - * @param pszSourceDir The source directory to copy. + * This is used by the MSI packages from the resource section. * + * @returns Fully complained exit code. + * @param pszDstDir The destination directory. */ -int CopyDir(const char *pszDestDir, const char *pszSourceDir) +static RTEXITCODE CopyCustomDir(const char *pszDstDir) { - char szDest[RTPATH_MAX + 1]; - char szSource[RTPATH_MAX + 1]; + char szSrcDir[RTPATH_MAX]; + int rc = RTPathExecDir(szSrcDir, sizeof(szSrcDir)); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(szSrcDir, sizeof(szSrcDir), ".custom"); + if (RT_FAILURE(rc)) + return ShowError("Failed to construct '.custom' dir path: %Rrc", rc); + + if (RTDirExists(szSrcDir)) + { + /* + * Use SHFileOperation w/ FO_COPY to do the job. This API requires an + * extra zero at the end of both source and destination paths. + */ + size_t cwc; + RTUTF16 wszSrcDir[RTPATH_MAX + 1]; + PRTUTF16 pwszSrcDir = wszSrcDir; + rc = RTStrToUtf16Ex(szSrcDir, RTSTR_MAX, &pwszSrcDir, RTPATH_MAX, &cwc); + if (RT_FAILURE(rc)) + return ShowError("RTStrToUtf16Ex failed on '%s': %Rrc", szSrcDir, rc); + wszSrcDir[cwc] = '\0'; + + RTUTF16 wszDstDir[RTPATH_MAX + 1]; + PRTUTF16 pwszDstDir = wszSrcDir; + rc = RTStrToUtf16Ex(pszDstDir, RTSTR_MAX, &pwszDstDir, RTPATH_MAX, &cwc); + if (RT_FAILURE(rc)) + return ShowError("RTStrToUtf16Ex failed on '%s': %Rrc", pszDstDir, rc); + wszDstDir[cwc] = '\0'; + + SHFILEOPSTRUCTW FileOp; + RT_ZERO(FileOp); /* paranoia */ + FileOp.hwnd = NULL; + FileOp.wFunc = FO_COPY; + FileOp.pFrom = wszSrcDir; + FileOp.pTo = wszDstDir; + FileOp.fFlags = FOF_SILENT + | FOF_NOCONFIRMATION + | FOF_NOCONFIRMMKDIR + | FOF_NOERRORUI; + FileOp.fAnyOperationsAborted = FALSE; + FileOp.hNameMappings = NULL; + FileOp.lpszProgressTitle = NULL; + + rc = SHFileOperationW(&FileOp); + if (rc != 0) /* Not a Win32 status code! */ + return ShowError("Copying the '.custom' dir failed: %#x", rc); + + /* + * Add a cleanup record for recursively deleting the destination + * .custom directory. We should actually add this prior to calling + * SHFileOperationW since it may partially succeed... + */ + char *pszDstSubDir = RTPathJoinA(pszDstDir, ".custom"); + if (!pszDstSubDir) + return ShowError("Out of memory!"); + bool fRc = AddCleanupRec(pszDstSubDir, false /*fFile*/); + RTStrFree(pszDstSubDir); + if (!fRc) + return RTEXITCODE_FAILURE; + } + + return RTEXITCODE_SUCCESS; +} - AssertStmt(pszDestDir, "Destination directory invalid!"); - AssertStmt(pszSourceDir, "Source directory invalid!"); - SHFILEOPSTRUCT s = {0}; - if ( RTStrPrintf(szDest, _MAX_PATH, "%s%c", pszDestDir, '\0') > 0 - && RTStrPrintf(szSource, _MAX_PATH, "%s%c", pszSourceDir, '\0') > 0) +static RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly, bool *pfCreatedExtractDir) +{ + int rc; + + /* + * Make sure the directory exists. + */ + *pfCreatedExtractDir = false; + if (!RTDirExists(pszDstDir)) + { + rc = RTDirCreate(pszDstDir, 0700, 0); + if (RT_FAILURE(rc)) + return ShowError("Failed to create extraction path '%s': %Rrc", pszDstDir, rc); + *pfCreatedExtractDir = true; + } + + /* + * Extract files. + */ + for (unsigned k = 0; k < cPackages; k++) { - s.hwnd = NULL; - s.wFunc = FO_COPY; - s.pTo = szDest; - s.pFrom = szSource; - s.fFlags = FOF_SILENT | - FOF_NOCONFIRMATION | - FOF_NOCONFIRMMKDIR | - FOF_NOERRORUI; + PVBOXSTUBPKG pPackage = FindPackageHeader(k); + if (!pPackage) + return RTEXITCODE_FAILURE; /* Done complaining already. */ + + if (fExtractOnly || PackageIsNeeded(pPackage)) + { + char szDstFile[RTPATH_MAX]; + rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, pPackage->szFileName); + if (RT_FAILURE(rc)) + return ShowError("Internal error: RTPathJoin failed: %Rrc", rc); + + rc = Extract(pPackage, szDstFile); + if (RT_FAILURE(rc)) + return ShowError("Error extracting package #%u: %Rrc", k, rc); + + if (!fExtractOnly && !AddCleanupRec(szDstFile, true /*fFile*/)) + { + RTFileDelete(szDstFile); + return RTEXITCODE_FAILURE; + } + } } - return RTErrConvertFromWin32(SHFileOperation(&s)); + + return RTEXITCODE_SUCCESS; } @@ -334,361 +788,223 @@ int WINAPI WinMain(HINSTANCE hInstance, /* Check if we're already running and jump out if so. */ /* Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */ - HANDLE hMutexAppRunning = CreateMutex (NULL, FALSE, "VBoxStubInstaller"); - if ( (hMutexAppRunning != NULL) - && (GetLastError() == ERROR_ALREADY_EXISTS)) + HANDLE hMutexAppRunning = CreateMutex(NULL, FALSE, "VBoxStubInstaller"); + if ( hMutexAppRunning != NULL + && GetLastError() == ERROR_ALREADY_EXISTS) { /* Close the mutex for this application instance. */ CloseHandle(hMutexAppRunning); hMutexAppRunning = NULL; - return 1; + return RTEXITCODE_FAILURE; } /* Init IPRT. */ int vrc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(vrc)) - return vrc; + return RTMsgInitFailure(vrc); - BOOL fExtractOnly = FALSE; - BOOL fSilent = FALSE; - BOOL fEnableLogging = FALSE; - BOOL fExit = FALSE; + /* + * Parse arguments. + */ - /* Temp variables for arguments. */ + /* Parameter variables. */ + bool fExtractOnly = false; + bool fEnableLogging = false; +#ifdef VBOX_WITH_CODE_SIGNING + bool fEnableSilentCert = true; +#endif char szExtractPath[RTPATH_MAX] = {0}; - char szMSIArgs[RTPATH_MAX] = {0}; + char szMSIArgs[4096] = {0}; - /* Process arguments. */ - for (int i = 0; i < argc; i++) + /* Parameter definitions. */ + static const RTGETOPTDEF s_aOptions[] = { - if ( (0 == RTStrICmp(argv[i], "-x")) - || (0 == RTStrICmp(argv[i], "-extract")) - || (0 == RTStrICmp(argv[i], "/extract"))) - { - fExtractOnly = TRUE; - } - - else if ( (0 == RTStrICmp(argv[i], "-s")) - || (0 == RTStrICmp(argv[i], "-silent")) - || (0 == RTStrICmp(argv[i], "/silent"))) - { - fSilent = TRUE; - } - - else if ( (0 == RTStrICmp(argv[i], "-l")) - || (0 == RTStrICmp(argv[i], "-logging")) - || (0 == RTStrICmp(argv[i], "/logging"))) - { - fEnableLogging = TRUE; - } - - else if (( (0 == RTStrICmp(argv[i], "-p")) - || (0 == RTStrICmp(argv[i], "-path")) - || (0 == RTStrICmp(argv[i], "/path"))) - ) - { - if (argc > i) - { - vrc = ::StringCbCat(szExtractPath, sizeof(szExtractPath), argv[i+1]); - i++; /* Avoid the specified path from being parsed. */ - } - else - { - ShowError("No path for extraction specified!"); - fExit = TRUE; - } - } - - else if (( (0 == RTStrICmp(argv[i], "-msiparams")) - || (0 == RTStrICmp(argv[i], "/msiparams"))) - && (argc > i)) + { "--extract", 'x', RTGETOPT_REQ_NOTHING }, + { "-extract", 'x', RTGETOPT_REQ_NOTHING }, + { "/extract", 'x', RTGETOPT_REQ_NOTHING }, + { "--silent", 's', RTGETOPT_REQ_NOTHING }, + { "-silent", 's', RTGETOPT_REQ_NOTHING }, + { "/silent", 's', RTGETOPT_REQ_NOTHING }, +#ifdef VBOX_WITH_CODE_SIGNING + { "--no-silent-cert", 'c', RTGETOPT_REQ_NOTHING }, + { "-no-silent-cert", 'c', RTGETOPT_REQ_NOTHING }, + { "/no-silent-cert", 'c', RTGETOPT_REQ_NOTHING }, +#endif + { "--logging", 'l', RTGETOPT_REQ_NOTHING }, + { "-logging", 'l', RTGETOPT_REQ_NOTHING }, + { "/logging", 'l', RTGETOPT_REQ_NOTHING }, + { "--path", 'p', RTGETOPT_REQ_STRING }, + { "-path", 'p', RTGETOPT_REQ_STRING }, + { "/path", 'p', RTGETOPT_REQ_STRING }, + { "--msiparams", 'm', RTGETOPT_REQ_STRING }, + { "-msiparams", 'm', RTGETOPT_REQ_STRING }, + { "--version", 'V', RTGETOPT_REQ_NOTHING }, + { "-version", 'V', RTGETOPT_REQ_NOTHING }, + { "/version", 'V', RTGETOPT_REQ_NOTHING }, + { "-v", 'V', RTGETOPT_REQ_NOTHING }, + { "--help", 'h', RTGETOPT_REQ_NOTHING }, + { "-help", 'h', RTGETOPT_REQ_NOTHING }, + { "/help", 'h', RTGETOPT_REQ_NOTHING }, + { "/?", 'h', RTGETOPT_REQ_NOTHING }, + }; + + /* Parse the parameters. */ + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); + while ((ch = RTGetOpt(&GetState, &ValueUnion))) + { + switch (ch) { - for (int a = i + 1; a < argc; a++) - { - if (a > i+1) /* Insert a space. */ - vrc = ::StringCbCat(szMSIArgs, sizeof(szMSIArgs), " "); + case 'x': + fExtractOnly = true; + break; + + case 's': + g_fSilent = true; + break; + +#ifdef VBOX_WITH_CODE_SIGNING + case 'c': + fEnableSilentCert = false; + break; +#endif - vrc = ::StringCbCat(szMSIArgs, sizeof(szMSIArgs), argv[a]); - } - } + case 'l': + fEnableLogging = true; + break; - else if ( (0 == RTStrICmp(argv[i], "-v")) - || (0 == RTStrICmp(argv[i], "-version")) - || (0 == RTStrICmp(argv[i], "/version"))) - { - ShowInfo("Version: %d.%d.%d.%d", - VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV); - fExit = TRUE; - } + case 'p': + vrc = RTStrCopy(szExtractPath, sizeof(szExtractPath), ValueUnion.psz); + if (RT_FAILURE(vrc)) + return ShowError("Extraction path is too long."); + break; - else if ( (0 == RTStrICmp(argv[i], "-help")) - || (0 == RTStrICmp(argv[i], "/help")) - || (0 == RTStrICmp(argv[i], "/?"))) - { - ShowInfo("-- %s v%d.%d.%d.%d --\n" + case 'm': + if (szMSIArgs[0]) + vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), " "); + if (RT_SUCCESS(vrc)) + vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz); + if (RT_FAILURE(vrc)) + return ShowError("MSI parameters are too long."); + break; + + case 'V': + ShowInfo("Version: %d.%d.%d.%d", + VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV); + return VINF_SUCCESS; + + case 'h': + ShowInfo("-- %s v%d.%d.%d.%d --\n" + "\n" "Command Line Parameters:\n\n" - "-extract | -x - Extract file contents to temporary directory\n" - "-silent | -s - Enables silent mode installation\n" - "-path | -p - Sets the path of the extraction directory\n" - "-help | /? - Print this help and exit\n" - "-msiparams <parameters> - Specifies extra parameters for the MSI installers\n" - "-logging | -l - Enables installer logging\n" - "-version | -v - Print version number and exit\n\n" + "--extract - Extract file contents to temporary directory\n" + "--silent - Enables silent mode installation\n" + "--no-silent-cert - Do not install VirtualBox Certificate automatically when --silent option is specified\n" + "--path - Sets the path of the extraction directory\n" + "--msiparams <parameters> - Specifies extra parameters for the MSI installers\n" + "--logging - Enables installer logging\n" + "--help - Print this help and exit\n" + "--version - Print version number and exit\n\n" "Examples:\n" - "%s -msiparams INSTALLDIR=C:\\VBox\n" - "%s -extract -path C:\\VBox\n", + "%s --msiparams INSTALLDIR=C:\\VBox\n" + "%s --extract -path C:\\VBox", VBOX_STUB_TITLE, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV, argv[0], argv[0]); - fExit = TRUE; - } - else - { - if (i > 0) - { - ShowError("Unknown option \"%s\"!\n" - "Please refer to the command line help by specifying \"/?\"\n" - "to get more information.", argv[i]); - fExit = TRUE; - } - } - } + return VINF_SUCCESS; - if (fExit) - return 0; + default: + if (g_fSilent) + return RTGetOptPrintError(ch, &ValueUnion); + if (ch == VINF_GETOPT_NOT_OPTION || ch == VERR_GETOPT_UNKNOWN_OPTION) + ShowError("Unknown option \"%s\"!\n" + "Please refer to the command line help by specifying \"/?\"\n" + "to get more information.", ValueUnion.psz); + else + ShowError("Parameter parsing error: %Rrc\n" + "Please refer to the command line help by specifying \"/?\"\n" + "to get more information.", ch); + return RTEXITCODE_SYNTAX; - HRESULT hr = S_OK; + } + } - do /* break loop */ + /* + * Determine the extration path if not given by the user, and gather some + * other bits we'll be needing later. + */ + if (szExtractPath[0] == '\0') { - /* Get/create our temp path (only if not already set). */ - if (szExtractPath[0] == '\0') - { - vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath)); - AssertMsgRCBreak(vrc, ("Could not retrieve temp directory!\n")); - + vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath)); + if (RT_SUCCESS(vrc)) vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox"); - AssertMsgRCBreak(vrc, ("Could not construct temp directory!\n")); - - /* Convert slahes; this is necessary for MSI routines later! */ - RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); - } - if (!RTDirExists(szExtractPath)) - { - vrc = RTDirCreate(szExtractPath, 0700, 0); - AssertMsgRCBreak(vrc, ("Could not create temp directory!\n")); - } + if (RT_FAILURE(vrc)) + return ShowError("Failed to determin extraction path (%Rrc)", vrc); - /* Get our executable path */ - char szPathExe[_MAX_PATH]; - vrc = RTPathExecDir(szPathExe, sizeof(szPathExe)); - /** @todo error checking */ - - /* Read our manifest. */ - PVBOXSTUBPKGHEADER pHeader = NULL; - DWORD cbHeader = 0; - vrc = ReadData(NULL, "MANIFEST", (LPVOID*)&pHeader, &cbHeader); - AssertMsgRCBreak(vrc, ("Manifest not found!\n")); - - /* Extract files. */ - for (BYTE k = 0; k < pHeader->byCntPkgs; k++) - { - PVBOXSTUBPKG pPackage = NULL; - DWORD cbPackage = 0; - char szHeaderName[RTPATH_MAX + 1] = {0}; - - hr = ::StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k); - vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage); - AssertMsgRCBreak(vrc, ("Header not found!\n")); /** @todo include header name, how? */ - - if (PackageIsNeeded(pPackage) || fExtractOnly) - { - char *pszTempFile = NULL; - vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile); - AssertMsgRCBreak(vrc, ("Could not create name for temporary extracted file!\n")); - vrc = Extract(pPackage, pszTempFile); - AssertMsgRCBreak(vrc, ("Could not extract file!\n")); - RTStrFree(pszTempFile); - } - } + } + else + { + /** @todo should check if there is a .custom subdirectory there or not. */ + } + RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); /* MSI requirement. */ - if (FALSE == fExtractOnly && !RT_FAILURE(vrc)) + /* Read our manifest. */ + PVBOXSTUBPKGHEADER pHeader; + vrc = FindData("MANIFEST", (PVOID *)&pHeader, NULL); + if (RT_FAILURE(vrc)) + return ShowError("Internal package error: Manifest not found (%Rrc)", vrc); + /** @todo If we could, we should validate the header. Only the magic isn't + * commonly defined, nor the version number... */ + + RTListInit(&g_TmpFiles); + + /* + * Up to this point, we haven't done anything that requires any cleanup. + * From here on, we do everything in function so we can counter clean up. + */ + bool fCreatedExtractDir; + RTEXITCODE rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly, &fCreatedExtractDir); + if (rcExit == RTEXITCODE_SUCCESS) + { + if (fExtractOnly) + ShowInfo("Files were extracted to: %s", szExtractPath); + else { - /* - * Copy ".custom" directory into temp directory so that the extracted .MSI - * file(s) can use it. - */ - char *pszPathCustomDir = RTPathJoinA(szPathExe, ".custom"); - pszPathCustomDir = RTPathChangeToDosSlashes(pszPathCustomDir, true /* Force conversion. */); - if (pszPathCustomDir && RTDirExists(pszPathCustomDir)) + rcExit = CopyCustomDir(szExtractPath); +#ifdef VBOX_WITH_CODE_SIGNING + if (rcExit == RTEXITCODE_SUCCESS && fEnableSilentCert && g_fSilent) + rcExit = InstallCertificate(); +#endif + unsigned iPackage = 0; + while (iPackage < pHeader->byCntPkgs && rcExit == RTEXITCODE_SUCCESS) { - vrc = CopyDir(szExtractPath, pszPathCustomDir); - if (RT_FAILURE(vrc)) /* Don't fail if it's missing! */ - vrc = VINF_SUCCESS; - - RTStrFree(pszPathCustomDir); + rcExit = ProcessPackage(iPackage, szExtractPath, szMSIArgs, fEnableLogging); + iPackage++; } - /* Do actions on files. */ - for (BYTE k = 0; k < pHeader->byCntPkgs; k++) - { - PVBOXSTUBPKG pPackage = NULL; - DWORD cbPackage = 0; - char szHeaderName[RTPATH_MAX] = {0}; - - hr = StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k); - vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage); - AssertMsgRCBreak(vrc, ("Package not found!\n")); - - if (PackageIsNeeded(pPackage)) - { - char *pszTempFile = NULL; - - vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile); - AssertMsgRCBreak(vrc, ("Could not create name for temporary action file!\n")); - - /* Handle MSI files. */ - if (RTStrICmp(RTPathExt(pszTempFile), ".msi") == 0) - { - /* Set UI level. */ - INSTALLUILEVEL UILevel = MsiSetInternalUI( fSilent - ? INSTALLUILEVEL_NONE - : INSTALLUILEVEL_FULL, - NULL); - AssertMsgBreak(UILevel != INSTALLUILEVEL_NOCHANGE, ("Could not set installer UI level!\n")); - - /* Enable logging? */ - if (fEnableLogging) - { - char *pszLog = RTPathJoinA(szExtractPath, "VBoxInstallLog.txt"); - /* Convert slahes; this is necessary for MSI routines! */ - pszLog = RTPathChangeToDosSlashes(pszLog, true /* Force conversion. */); - AssertMsgBreak(pszLog, ("Could not construct path for log file!\n")); - UINT uLogLevel = MsiEnableLog(INSTALLLOGMODE_VERBOSE, - pszLog, INSTALLLOGATTRIBUTES_FLUSHEACHLINE); - RTStrFree(pszLog); - AssertMsgBreak(uLogLevel == ERROR_SUCCESS, ("Could not set installer logging level!\n")); - } - - /* Initialize the common controls (extended version). This is necessary to - * run the actual .MSI installers with the new fancy visual control - * styles (XP+). Also, an integrated manifest is required. */ - INITCOMMONCONTROLSEX ccEx; - ccEx.dwSize = sizeof(INITCOMMONCONTROLSEX); - ccEx.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS | - ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | - ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES; - InitCommonControlsEx(&ccEx); /* Ignore failure. */ - - UINT uStatus = ::MsiInstallProductA(pszTempFile, szMSIArgs); - if ( (uStatus != ERROR_SUCCESS) - && (uStatus != ERROR_SUCCESS_REBOOT_REQUIRED) - && (uStatus != ERROR_INSTALL_USEREXIT)) - { - if (!fSilent) - { - switch (uStatus) - { - case ERROR_INSTALL_PACKAGE_VERSION: - - ShowError("This installation package cannot be installed by the Windows Installer service.\n" - "You must install a Windows service pack that contains a newer version of the Windows Installer service."); - break; - - case ERROR_INSTALL_PLATFORM_UNSUPPORTED: - - ShowError("This installation package is not supported on this platform."); - break; - - default: - { - DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_IGNORE_INSERTS - | FORMAT_MESSAGE_FROM_SYSTEM; - HMODULE hModule = NULL; - if (uStatus >= NERR_BASE && uStatus <= MAX_NERR) - { - hModule = LoadLibraryEx(TEXT("netmsg.dll"), - NULL, - LOAD_LIBRARY_AS_DATAFILE); - if (hModule != NULL) - dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE; - } - - DWORD dwBufferLength; - LPSTR szMessageBuffer; - if (dwBufferLength = FormatMessageA(dwFormatFlags, - hModule, /* If NULL, load system stuff. */ - uStatus, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&szMessageBuffer, - 0, - NULL)) - { - ShowError("Installation failed! Error: %s", szMessageBuffer); - LocalFree(szMessageBuffer); - } - else /* If text lookup failed, show at least the error number. */ - ShowError("Installation failed! Error: %u", uStatus); - if (hModule) - FreeLibrary(hModule); - break; - } - } - } - - vrc = VERR_NO_CHANGE; /* No change done to the system. */ - } - } - RTStrFree(pszTempFile); - } /* Package needed? */ - } /* For all packages */ - } - - /* Clean up (only on success - prevent deleting the log). */ - if ( !fExtractOnly - && RT_SUCCESS(vrc)) - { - for (int i=0; i<5; i++) - { - vrc = RTDirRemoveRecursive(szExtractPath, 0 /*fFlags*/); - if (RT_SUCCESS(vrc)) - break; - RTThreadSleep(3000 /* Wait 3 seconds.*/); - } + /* Don't fail if cleanup fail. At least for now. */ + CleanUp(pHeader->byCntPkgs, !fEnableLogging && fCreatedExtractDir ? szExtractPath : NULL); } + } - } while (0); - - if (RT_SUCCESS(vrc)) + /* Free any left behind cleanup records (not strictly needed). */ + PSTUBCLEANUPREC pCur, pNext; + RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry) { - if ( fExtractOnly - && !fSilent) - { - ShowInfo("Files were extracted to: %s", szExtractPath); - } - - /** @todo Add more post installation stuff here if required. */ + RTListNodeRemove(&pCur->ListEntry); + RTMemFree(pCur); } - /* Release instance mutex. */ + /* + * Release instance mutex. + */ if (hMutexAppRunning != NULL) { CloseHandle(hMutexAppRunning); hMutexAppRunning = NULL; } - /* Set final exit (return) code (error level). */ - if (RT_FAILURE(vrc)) - { - switch(vrc) - { - case VERR_NO_CHANGE: - default: - vrc = 1; - } - } - else /* Always set to (VINF_SUCCESS), even if we got something else (like a VWRN etc). */ - vrc = VINF_SUCCESS; - return vrc; + return rcExit; } diff --git a/src/VBox/Installer/win/Stub/VBoxStub.h b/src/VBox/Installer/win/Stub/VBoxStub.h index 455023a6..e50bca06 100644 --- a/src/VBox/Installer/win/Stub/VBoxStub.h +++ b/src/VBox/Installer/win/Stub/VBoxStub.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Installer/win/Stub/VBoxStubCertUtil.cpp b/src/VBox/Installer/win/Stub/VBoxStubCertUtil.cpp new file mode 100644 index 00000000..cfa3b5e5 --- /dev/null +++ b/src/VBox/Installer/win/Stub/VBoxStubCertUtil.cpp @@ -0,0 +1,140 @@ +/* $Id: VBoxStubCertUtil.cpp $ */ +/** @file + * VBoxStub - VirtualBox's Windows installer stub (certificate manipulations). + * + * NOTE: The content of this file is partly + * grabbed from src/VBox/Additions/WINNT/tools/VBoxCertUtil.cpp + */ + +/* + * Copyright (C) 2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <Windows.h> +#include <Wincrypt.h> + +#include <iprt/string.h> +#include <iprt/message.h> +#include <iprt/err.h> + + +/** + * Reads a certificate from a (const char []) buffer, returning a context + * or a the handle to a temporary memory store. + * + * @returns true on success, false on failure (error message written). + * @param kpCertBuf The pointer to the buffer containing the + * certificates. + * @param cbCertBuf Size of @param kpCertBuf in bytes. + * @param ppOutCtx Where to return the handle to the temporary + * memory store. + */ +static bool readCertBuf(const unsigned char kpCertBuf[], DWORD cbCertBuf, PCCERT_CONTEXT *ppOutCtx) +{ + *ppOutCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + (PBYTE)kpCertBuf, cbCertBuf); + if (*ppOutCtx) + return true; + + return false; +} + +/** + * Opens a certificate store. + * + * @returns true on success, false on failure (error message written). + * @param dwDst The destination, like + * CERT_SYSTEM_STORE_LOCAL_MACHINE or + * CERT_SYSTEM_STORE_CURRENT_USER. + * @param pszStoreNm The store name. + */ +static HCERTSTORE openCertStore(DWORD dwDst, const char *pszStoreNm) +{ + HCERTSTORE hStore = NULL; + PRTUTF16 pwszStoreNm; + int rc = RTStrToUtf16(pszStoreNm, &pwszStoreNm); + if (RT_SUCCESS(rc)) + { + /* + * Make sure CERT_STORE_OPEN_EXISTING_FLAG is not set. This causes Windows XP + * to return ACCESS_DENIED when installing TrustedPublisher certificates via + * CertAddCertificateContextToStore() if the TrustedPublisher store never has + * been used (through certmgr.exe and friends) yet. + * + * According to MSDN, if neither CERT_STORE_OPEN_EXISTING_FLAG nor + * CERT_STORE_CREATE_NEW_FLAG is set, the store will be either opened or + * created accordingly. + */ + dwDst &= ~CERT_STORE_OPEN_EXISTING_FLAG; + + hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + NULL /* hCryptProv = default */, + dwDst, + pwszStoreNm); + + RTUtf16Free(pwszStoreNm); + } + return hStore; +} + +/** + * Adds a certificate to a store. + * + * @returns true on success, false on failure (error message written). + * @param dwDst The destination, like + * CERT_SYSTEM_STORE_LOCAL_MACHINE or + * CERT_SYSTEM_STORE_CURRENT_USER. + * @param pszStoreNm The store name. + * @param kpCertBuf Buffer that contains a certificate + * @param cbCertBuf Size of @param kpCertBuf in bytes + */ +bool addCertToStore(DWORD dwDst, const char *pszStoreNm, const unsigned char kpCertBuf[], DWORD cbCertBuf) +{ + /* + * Get certificate from buffer. + */ + PCCERT_CONTEXT pSrcCtx = NULL; + bool fRc = false; + + if (!readCertBuf(kpCertBuf, cbCertBuf, &pSrcCtx)) + { + RTMsgError("Unable to get certificate context: %d", GetLastError()); + return fRc; + } + + /* + * Open the certificates store. + */ + HCERTSTORE hDstStore = openCertStore(dwDst, pszStoreNm); + if (hDstStore) + { + /* + * Finally, add certificate to store + */ + if (CertAddCertificateContextToStore(hDstStore, pSrcCtx, CERT_STORE_ADD_REPLACE_EXISTING, NULL)) + fRc = true; + else + RTMsgError("Unable to install certificate: %d", GetLastError()); + + CertCloseStore(hDstStore, CERT_CLOSE_STORE_CHECK_FLAG); + } + else + RTMsgError("Unable to open certificates store: %d", GetLastError()); + + /* Release resources */ + CertFreeCertificateContext(pSrcCtx); + + return fRc; +} diff --git a/src/VBox/Installer/win/Stub/VBoxStubCertUtil.h b/src/VBox/Installer/win/Stub/VBoxStubCertUtil.h new file mode 100644 index 00000000..59bf0847 --- /dev/null +++ b/src/VBox/Installer/win/Stub/VBoxStubCertUtil.h @@ -0,0 +1,20 @@ +/* $Id: VBoxStubCertUtil.h $ */ +/** @file + * VBoxStub - VirtualBox's Windows installer stub (certificate manipulations). + */ + +/* + * Copyright (C) 2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#pragma once + +extern bool addCertToStore(DWORD dwDst, const char *pszStoreNm, const unsigned char kpCertBuf[], DWORD cbCertBuf); diff --git a/src/VBox/Installer/win/Stub/resource.h b/src/VBox/Installer/win/Stub/resource.h index fbffe226..fbc557a6 100644 --- a/src/VBox/Installer/win/Stub/resource.h +++ b/src/VBox/Installer/win/Stub/resource.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -14,8 +14,12 @@ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ + + #define IDI_VIRTUALBOX 101 -#define RT_MANIFEST 24 +#ifndef RT_MANIFEST +# define RT_MANIFEST 24 +#endif #define APP_MANIFEST 1 diff --git a/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp b/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp index 862b088d..b0ad0cb9 100644 --- a/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp +++ b/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Installer/win/StubBld/VBoxStubBld.h b/src/VBox/Installer/win/StubBld/VBoxStubBld.h index 67005674..49919f9b 100644 --- a/src/VBox/Installer/win/StubBld/VBoxStubBld.h +++ b/src/VBox/Installer/win/StubBld/VBoxStubBld.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -15,37 +15,52 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ -#pragma once +#ifndef ___VBoxStubBld_h___ +#define ___VBoxStubBld_h___ #define VBOXSTUB_MAX_PACKAGES 128 -typedef struct +typedef struct VBOXSTUBPKGHEADER { - char szMagic[9]; - DWORD dwVersion; - BYTE byCntPkgs; + /** Some magic string not defined by this header? Turns out it's a write only + * field... */ + char szMagic[9]; + /* Inbetween szMagic and dwVersion there are 3 bytes of implicit padding. */ + /** Some version number not defined by this header? Also write only field. + * Should be a uint32_t, not DWORD. */ + DWORD dwVersion; + /** Number of packages following the header. byte is prefixed 'b', not 'by'! + * Use uint8_t instead of BYTE. */ + BYTE byCntPkgs; + /* There are 3 bytes of implicit padding here. */ +} VBOXSTUBPKGHEADER; +typedef VBOXSTUBPKGHEADER *PVBOXSTUBPKGHEADER; -} VBOXSTUBPKGHEADER, *PVBOXSTUBPKGHEADER; - -enum VBOXSTUBPKGARCH +typedef enum VBOXSTUBPKGARCH { VBOXSTUBPKGARCH_ALL = 0, - VBOXSTUBPKGARCH_X86 = 1, - VBOXSTUBPKGARCH_AMD64 = 2 -}; + VBOXSTUBPKGARCH_X86, + VBOXSTUBPKGARCH_AMD64 +} VBOXSTUBPKGARCH; -typedef struct +typedef struct VBOXSTUBPKG { BYTE byArch; + /** Probably the name of the PE resource or something, read the source to + * find out for sure. Don't use _MAX_PATH, define your own max lengths! */ char szResourceName[_MAX_PATH]; char szFileName[_MAX_PATH]; -} VBOXSTUBPKG, *PVBOXSTUBPKG; +} VBOXSTUBPKG; +typedef VBOXSTUBPKG *PVBOXSTUBPKG; /* Only for construction. */ +/* Since it's only used by VBoxStubBld.cpp, why not just keep it there? */ -typedef struct +typedef struct VBOXSTUBBUILDPKG { char szSourcePath[_MAX_PATH]; BYTE byArch; -} VBOXSTUBBUILDPKG, *PVBOXSTUBBUILDPKG; +} VBOXSTUBBUILDPKG; +typedef VBOXSTUBBUILDPKG *PVBOXSTUBBUILDPKG; +#endif diff --git a/src/VBox/Installer/win/UserInterface.wxi b/src/VBox/Installer/win/UserInterface.wxi index 20a6e27b..9886befe 100644 --- a/src/VBox/Installer/win/UserInterface.wxi +++ b/src/VBox/Installer/win/UserInterface.wxi @@ -60,7 +60,7 @@ <Publish Event="NewDialog" Value="VBoxLicenseAgreementDlg">1</Publish> <?else ?> <!-- Decide which dialog to show next: The serial number dialog (if this is a branded build) - or directly proceed to the customization dialog (Vbox not installed yet) --> + or directly proceed to the customization dialog (VBox not installed yet) --> <?if $(env.VBOX_WITH_SERIALNUMBER_INSTALL) = "yes" ?> <Publish Event="NewDialog" Value="VBoxCheckSerialDlg">1</Publish> <?else ?> @@ -126,7 +126,7 @@ <Condition Action="disable"><![CDATA[IAgree <> "Yes"]]></Condition> <Condition Action="enable"><![CDATA[IAgree = "Yes"]]></Condition> <!-- Decide which dialog to show next: The serial number dialog (if this is a branded build) - or directly proceed to the customization dialog (Vbox not installed yet) --> + or directly proceed to the customization dialog (VBox not installed yet) --> <?if $(env.VBOX_WITH_SERIALNUMBER_INSTALL) = "yes" ?> <Publish Event="NewDialog" Value="VBoxCheckSerialDlg">1</Publish> <?else ?> @@ -334,6 +334,10 @@ Property="INSTALLQUICKLAUNCHSHORTCUT" CheckBoxValue="1"> <Text>!(loc.Customize2Dlg_CreateQuickLaunch)</Text> </Control> + <Control Id="RegisterFileExtensionsCheckBox" Type="CheckBox" X="25" Y="135" Width="200" Height="17" + Property="REGISTERFILEEXTENSIONS" CheckBoxValue="1"> + <Text>!(loc.Customize2Dlg_RegisterFileExtensions)</Text> + </Control> <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.ButtonText_Next)"> diff --git a/src/VBox/Installer/win/VirtualBox.wxs b/src/VBox/Installer/win/VirtualBox.wxs index 9823155a..176c1e17 100644 --- a/src/VBox/Installer/win/VirtualBox.wxs +++ b/src/VBox/Installer/win/VirtualBox.wxs @@ -2,7 +2,7 @@ <!-- VirtualBox Windows Installation Script (WiX) - Copyright (C) 2006-2012 Oracle Corporation + Copyright (C) 2006-2013 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -116,6 +116,7 @@ <Property Id="ARPURLUPDATEINFO">http://www.virtualbox.org</Property> <Property Id="INSTALLDESKTOPSHORTCUT" Value="1"></Property> <Property Id="INSTALLQUICKLAUNCHSHORTCUT" Value="1"></Property> + <Property Id="REGISTERFILEEXTENSIONS" Value="1"></Property> <Property Id="STARTVBOX" Value="1"></Property> <!-- Install the product for all users on the system --> @@ -334,6 +335,16 @@ </Component> </Directory> +<?if $(env.VBOX_WITH_32_ON_64_MAIN_API) = "yes" ?> + <!-- The 32-bit client COM component (see also cp_MainCom below). --> + <Component Id="cp_MainCOM_x86" Guid="B600824E-4A25-2EB3-4B44-3D8CB7F9B92D" Win64="no"> + <File Id="VBoxClient_x86" Name="VBoxClient-x86.dll" + Source="$(env.PATH_OUT)\bin\VBoxClient-x86.dll" KeyPath="yes"> + </File> + <?include $(env.PATH_TARGET)\VirtualBox_TypeLib_x86.wxi ?> + </Component> +<?endif?> + <!-- COM components have a separate entry mainly because of the KeyPath attribute (that hints the TypeLib element where to take the TLB resource from) may appear only once per Component. --> <Component Id="cp_MainCOM" Guid="CD4A3C6C-C2D5-428D-90A1-B6DA3D0777D6" Win64="$(var.Property_Win64)"> @@ -358,7 +369,7 @@ <!-- - <Component Id="Cp_StartMenuShortcut" Guid="1C137D24-E599-47BD-98D0-2F62F202A8EA" Win64="$(var.Property_Win64)"> + <Component Id="cp_StartMenuShortcut" Guid="1C137D24-E599-47BD-98D0-2F62F202A8EA" Win64="$(var.Property_Win64)"> <RegistryValue Root="HKCU" Key="$(var.Property_RegKeyInstall)" Type="string" Value="installed" KeyPath="yes" /> <Shortcut Id="ShortcutStartMenuVBox" Directory="ProgramMenuDir" @@ -368,14 +379,8 @@ <!----> - <!-- All Binaries, DLLs (except COM) and drivers are in one component because they belong together. Additional - binaries e.g. test tools, utilities etc. should be in another component so they"re clearly separated. --> - <Component Id="cp_MainBinaries" Guid="5C8FE57A-F744-4DE0-AA3F-A563F486AD98" Win64="$(var.Property_Win64)"> - - <!-- Set required environment variables. --> - <Environment Id="env_VBoxInstallDir" Action="set" Name="VBOX_INSTALL_PATH" - System="yes" Part="last" Permanent="no" Value="[INSTALLDIR]" /> - + <Component Id="cp_RegisterExtensions" Guid="FEB8943E-5D60-4E2D-846F-458207019D40" Win64="$(var.Property_Win64)"> + <Condition>REGISTERFILEEXTENSIONS</Condition> <!-- Register file extensions. Note: Extension Id's *must not* be changed! These specify the actual file extension to handle. Also, here would be the place to add more fancy DDE stuff later. Important: The IDs in "IconIndex" *must* be matching "Resources\resource.h". --> @@ -411,6 +416,15 @@ <ProgId Id="progId_VirtualBox.Shell.hdd" Description="Virtual Hard Disk" Icon="file_VBoxRes.dll" IconIndex="-306"> <Extension Id="hdd" ContentType="application/x-virtualbox-hdd" /> </ProgId> + </Component> <!-- RegisterExtensions --> + + <!-- All Binaries, DLLs (except COM) and drivers are in one component because they belong together. Additional + binaries e.g. test tools, utilities etc. should be in another component so they"re clearly separated. --> + <Component Id="cp_MainBinaries" Guid="5C8FE57A-F744-4DE0-AA3F-A563F486AD98" Win64="$(var.Property_Win64)"> + + <!-- Set required environment variables. --> + <Environment Id="env_VBoxInstallDir" Action="set" Name="VBOX_INSTALL_PATH" + System="yes" Part="last" Permanent="no" Value="[INSTALLDIR]" /> <!-- Files --> <?if $(env.VBOX_WITH_DOCS_PACKING) = "yes" ?> @@ -434,6 +448,8 @@ <!-- Misc tools --> <File Id="file_VBoxNetDHCP.exe" Name="VBoxNetDHCP.exe" Source="$(env.PATH_OUT)\bin\VBoxNetDHCP.exe"/> + <File Id="file_VBoxNetNAT.exe" Name="VBoxNetNAT.exe" + Source="$(env.PATH_OUT)\bin\VBoxNetNAT.exe"/> <?if $(env.VBOX_WITH_EXTPACK) = "yes" ?> <File Id="file_VBoxExtPackHelperApp.exe" Name="VBoxExtPackHelperApp.exe" Source="$(env.PATH_OUT)\bin\VBoxExtPackHelperApp.exe"/> @@ -624,6 +640,12 @@ </Component> <?endif?> + <!-- C API (glue) binding --> + <Component Id="cp_VBoxCAPI" Guid="097F7F53-7111-467F-8E0C-257D9926FDA0"> + <File Id="file_VBoxCAPI.dll" Name="VBoxCAPI.dll" + Source="$(env.PATH_OUT)\bin\VBoxCAPI.dll" /> + </Component> + <?if $(env.VBOX_WITH_PYTHON) = "yes" ?> <Component Id="cp_VBoxPythonBinding" Guid="293D7E11-78DA-4C31-AEED-AE2FE42F6881"> <Condition>PYTHON_INSTALLED</Condition> @@ -688,11 +710,15 @@ <ComponentRef Id="cp_StartMenuVBox" /> <ComponentRef Id="cp_DesktopShortcut" /> <ComponentRef Id="cp_QuickLaunchVBox" /> + <ComponentRef Id="cp_RegisterExtensions" /> <?if $(env.VBOX_WITH_DOCS_PACKING) = "yes" ?> <ComponentRef Id="cp_Docs" /> <?endif?> <ComponentRef Id="cp_NLS" /> +<?if $(env.VBOX_WITH_32_ON_64_MAIN_API) = "yes" ?> + <ComponentRef Id="cp_MainCOM_x86" /> +<?endif?> <ComponentRef Id="cp_MainCOM" /> <ComponentRef Id="cp_MainBinaries" /> <?if $(env.VBOX_WITH_QTGUI) = "yes" ?> @@ -710,6 +736,7 @@ <?if $(env.VBOX_WITH_WEBSERVICES) = "yes" ?> <ComponentRef Id="cp_VBoxWebService" /> <?endif?> + <ComponentRef Id="cp_VBoxCAPI" /> <ComponentRef Id="cp_VBoxDrv" /> <Feature Id="VBoxUSB" Title="VirtualBox USB Support" Level="1" @@ -802,7 +829,7 @@ <?if $(env.VBOX_WITH_NETFLT) = "yes" ?> <!-- Create host-only interfaces on first-time install. --> <Custom Action="ca_CreateHostOnlyInterfaceArgs" Before="ca_CreateHostOnlyInterface" ><![CDATA[&VBoxNetworkAdp=3]]></Custom> - <Custom Action="ca_CreateHostOnlyInterface" Before="InstallFinalize" ><![CDATA[&VBoxNetworkAdp=3]]></Custom> + <Custom Action="ca_CreateHostOnlyInterface" Before="InstallFinalize" ><![CDATA[&VBoxNetworkAdp=3]]></Custom> <!-- Don't remove the host-only interfaces on update, only on uninstall. --> <Custom Action="ca_RemoveHostOnlyInterfaces" After="ca_UninstallNetFlt" ><![CDATA[(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")]]></Custom> <!-- First stop the existing host-only interfaces on update ... --> diff --git a/src/VBox/Installer/win/VirtualBox_TypeLib.xsl b/src/VBox/Installer/win/VirtualBox_TypeLib.xsl index c0ccf6de..15fd770e 100644 --- a/src/VBox/Installer/win/VirtualBox_TypeLib.xsl +++ b/src/VBox/Installer/win/VirtualBox_TypeLib.xsl @@ -5,7 +5,7 @@ * type library definitions for VirtualBox COM components * from the generic interface definition expressed in XML. - Copyright (C) 2007-2010 Oracle Corporation + Copyright (C) 2007-2012 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -26,6 +26,8 @@ <xsl:strip-space elements="*"/> +<xsl:param name="a_sTarget">all</xsl:param> + <!-- // templates @@ -45,6 +47,7 @@ * * Source : src/VBox/Main/idl/VirtualBox.xidl * Generator : src/VBox/Installer/VirtualBox_TypeLib.xsl + * Arguments : a_sTarget=<xsl:value-of select="$a_sTarget"/> */ </xsl:comment> <xsl:apply-templates/> @@ -66,7 +69,14 @@ <AppId> <xsl:attribute name="Id"><xsl:value-of select="@appUuid"/></xsl:attribute> <xsl:attribute name="Description"><xsl:value-of select="@name"/> Application</xsl:attribute> - <xsl:apply-templates select="module/class"/> + <xsl:choose> + <xsl:when test="$a_sTarget = 'VBoxClient-x86'"> + <xsl:apply-templates select="module[@name='VBoxC']/class"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="module/class"/> + </xsl:otherwise> + </xsl:choose> </AppId> </TypeLib> </Include> |
