summaryrefslogtreecommitdiffstats
path: root/platform/windows/export/export_plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows/export/export_plugin.cpp')
-rw-r--r--platform/windows/export/export_plugin.cpp226
1 files changed, 176 insertions, 50 deletions
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index febef5ad12..f04177d79a 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -31,34 +31,138 @@
#include "export_plugin.h"
#include "core/config/project_settings.h"
+#include "core/io/image_loader.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
-Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
- if (p_preset->get("codesign/enable")) {
- return _code_sign(p_preset, p_path);
+Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) {
+ static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ };
+
+ struct IconData {
+ Vector<uint8_t> data;
+ uint8_t pal_colors = 0;
+ uint16_t planes = 0;
+ uint16_t bpp = 32;
+ };
+
+ HashMap<uint8_t, IconData> images;
+ Error err;
+
+ if (p_src_path.get_extension() == "ico") {
+ Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err);
+ if (err != OK) {
+ return err;
+ }
+
+ // Read ICONDIR.
+ f->get_16(); // Reserved.
+ uint16_t icon_type = f->get_16(); // Image type: 1 - ICO.
+ uint16_t icon_count = f->get_16(); // Number of images.
+ ERR_FAIL_COND_V(icon_type != 1, ERR_CANT_OPEN);
+
+ for (uint16_t i = 0; i < icon_count; i++) {
+ // Read ICONDIRENTRY.
+ uint16_t w = f->get_8(); // Width in pixels.
+ uint16_t h = f->get_8(); // Height in pixels.
+ uint8_t pal_colors = f->get_8(); // Number of colors in the palette (0 - no palette).
+ f->get_8(); // Reserved.
+ uint16_t planes = f->get_16(); // Number of color planes.
+ uint16_t bpp = f->get_16(); // Bits per pixel.
+ uint32_t img_size = f->get_32(); // Image data size in bytes.
+ uint32_t img_offset = f->get_32(); // Image data offset.
+ if (w != h) {
+ continue;
+ }
+
+ // Read image data.
+ uint64_t prev_offset = f->get_position();
+ images[w].pal_colors = pal_colors;
+ images[w].planes = planes;
+ images[w].bpp = bpp;
+ images[w].data.resize(img_size);
+ f->seek(img_offset);
+ f->get_buffer(images[w].data.ptrw(), img_size);
+ f->seek(prev_offset);
+ }
} else {
- return OK;
+ Ref<Image> src_image;
+ src_image.instantiate();
+ err = ImageLoader::load_image(p_src_path, src_image);
+ ERR_FAIL_COND_V(err != OK || src_image->is_empty(), ERR_CANT_OPEN);
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ int size = (icon_size[i] == 0) ? 256 : icon_size[i];
+
+ Ref<Image> res_image = src_image->duplicate();
+ ERR_FAIL_COND_V(res_image.is_null() || res_image->is_empty(), ERR_CANT_OPEN);
+ res_image->resize(size, size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
+ images[icon_size[i]].data = res_image->save_png_to_buffer();
+ }
}
-}
-Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
- if (f.is_null()) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path));
- return ERR_CANT_CREATE;
+ uint16_t valid_icon_count = 0;
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ valid_icon_count++;
+ } else {
+ int size = (icon_size[i] == 0) ? 256 : icon_size[i];
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Icon size \"%d\" is missing."), size));
+ }
+ }
+ ERR_FAIL_COND_V(valid_icon_count == 0, ERR_CANT_OPEN);
+
+ Ref<FileAccess> fw = FileAccess::open(p_dst_path, FileAccess::WRITE, &err);
+ if (err != OK) {
+ return err;
}
- f->store_line("@echo off");
- f->store_line("title \"" + p_app_name + "\"");
- f->store_line("\"%~dp0" + p_pkg_name + "\" \"%*\"");
- f->store_line("pause > nul");
+ // Write ICONDIR.
+ fw->store_16(0); // Reserved.
+ fw->store_16(1); // Image type: 1 - ICO.
+ fw->store_16(valid_icon_count); // Number of images.
+
+ // Write ICONDIRENTRY.
+ uint32_t img_offset = 6 + 16 * valid_icon_count;
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ const IconData &di = images[icon_size[i]];
+ fw->store_8(icon_size[i]); // Width in pixels.
+ fw->store_8(icon_size[i]); // Height in pixels.
+ fw->store_8(di.pal_colors); // Number of colors in the palette (0 - no palette).
+ fw->store_8(0); // Reserved.
+ fw->store_16(di.planes); // Number of color planes.
+ fw->store_16(di.bpp); // Bits per pixel.
+ fw->store_32(di.data.size()); // Image data size in bytes.
+ fw->store_32(img_offset); // Image data offset.
+
+ img_offset += di.data.size();
+ }
+ }
+ // Write image data.
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ const IconData &di = images[icon_size[i]];
+ fw->store_buffer(di.data.ptr(), di.data.size());
+ }
+ }
return OK;
}
+Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
+ if (p_preset->get("codesign/enable")) {
+ return _code_sign(p_preset, p_path);
+ } else {
+ return OK;
+ }
+}
+
Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
if (p_preset->get("application/modify_resources")) {
- _rcedit_add_data(p_preset, p_path);
+ _rcedit_add_data(p_preset, p_path, true);
+ String wrapper_path = p_path.get_basename() + ".console.exe";
+ if (FileAccess::exists(wrapper_path)) {
+ _rcedit_add_data(p_preset, wrapper_path, false);
+ }
}
return OK;
}
@@ -71,6 +175,10 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
if (p_preset->get("codesign/enable") && err == OK) {
_code_sign(p_preset, pck_path);
+ String wrapper_path = p_path.get_basename() + ".console.exe";
+ if (FileAccess::exists(wrapper_path)) {
+ _code_sign(p_preset, wrapper_path);
+ }
}
if (p_preset->get("binary_format/embed_pck") && err == OK) {
@@ -81,25 +189,6 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
}
- String app_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- app_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
- } else {
- app_name = "Unnamed";
- }
- app_name = OS::get_singleton()->get_safe_dir_name(app_name);
-
- // Save console script.
- if (err == OK) {
- int con_scr = p_preset->get("debug/export_console_script");
- if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
- String scr_path = p_path.get_basename() + ".cmd";
- if (_export_debug_script(p_preset, app_name, p_path.get_file(), scr_path) != OK) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), TTR("Could not create console script."));
- }
- }
- }
-
return err;
}
@@ -113,7 +202,7 @@ List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<Editor
return list;
}
-bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const {
+bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
// This option is not supported by "osslsigncode", used on non-Windows host.
if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") {
return false;
@@ -123,12 +212,12 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_o
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32"), "x86_64"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1));
@@ -136,7 +225,9 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico.*.png,*.webp,*.svg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
@@ -146,8 +237,8 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
}
-Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
- String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
+Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) {
+ String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (rcedit_path != String() && !FileAccess::exists(rcedit_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find rcedit executable at \"%s\"."), rcedit_path));
@@ -160,7 +251,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
#ifndef WINDOWS_ENABLED
// On non-Windows we need WINE to run rcedit
- String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
+ String wine_path = EDITOR_GET("export/windows/wine");
if (!wine_path.is_empty() && !FileAccess::exists(wine_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find wine executable at \"%s\"."), wine_path));
@@ -173,6 +264,21 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
#endif
String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
+ if (p_console_icon) {
+ String console_icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/console_wrapper_icon"));
+ if (!console_icon_path.is_empty() && FileAccess::exists(console_icon_path)) {
+ icon_path = console_icon_path;
+ }
+ }
+
+ String tmp_icon_path = EditorPaths::get_singleton()->get_cache_dir().path_join("_rcedit.ico");
+ if (!icon_path.is_empty()) {
+ if (_process_icon(p_preset, icon_path, tmp_icon_path) != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Invalid icon file \"%s\"."), icon_path));
+ icon_path = String();
+ }
+ }
+
String file_verion = p_preset->get("application/file_version");
String product_version = p_preset->get("application/product_version");
String company_name = p_preset->get("application/company_name");
@@ -186,7 +292,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
args.push_back(p_path);
if (!icon_path.is_empty()) {
args.push_back("--set-icon");
- args.push_back(icon_path);
+ args.push_back(tmp_icon_path);
}
if (!file_verion.is_empty()) {
args.push_back("--set-file-version");
@@ -230,8 +336,13 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String str;
Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true);
+
+ if (FileAccess::exists(tmp_icon_path)) {
+ DirAccess::remove_file_or_error(tmp_icon_path);
+ }
+
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > Rcedit), or disable \"Application > Modify Resources\" in the export preset."));
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset."));
return err;
}
print_line("rcedit (" + p_path + "): " + str);
@@ -248,7 +359,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
List<String> args;
#ifdef WINDOWS_ENABLED
- String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
+ String signtool_path = EDITOR_GET("export/windows/signtool");
if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find signtool executable at \"%s\"."), signtool_path));
return ERR_FILE_NOT_FOUND;
@@ -257,7 +368,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
signtool_path = "signtool"; // try to run signtool from PATH
}
#else
- String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
+ String signtool_path = EDITOR_GET("export/windows/osslsigncode");
if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find osslsigncode executable at \"%s\"."), signtool_path));
return ERR_FILE_NOT_FOUND;
@@ -379,7 +490,11 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
String str;
Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > Signtool), or disable \"Codesign\" in the export preset."));
+#ifndef WINDOWS_ENABLED
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > signtool), or disable \"Codesign\" in the export preset."));
+#else
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start osslsigncode executable. Configure signtool path in the Editor Settings (Export > Windows > osslsigncode), or disable \"Codesign\" in the export preset."));
+#endif
return err;
}
@@ -412,15 +527,26 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
return OK;
}
-bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err = "";
- bool valid = EditorExportPlatformPC::can_export(p_preset, err, r_missing_templates);
+ bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates);
- String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
+ String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) {
- err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > Rcedit) to change the icon or app information data.") + "\n";
+ err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > rcedit) to change the icon or app information data.") + "\n";
+ }
+
+ if (!err.is_empty()) {
+ r_error = err;
}
+ return valid;
+}
+
+bool EditorExportPlatformWindows::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+ String err = "";
+ bool valid = true;
+
String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
if (!icon_path.is_empty() && !FileAccess::exists(icon_path)) {
err += TTR("Invalid icon path:") + " " + icon_path + "\n";