From 07064c8714a4798341d5039408dd8bf785c43e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ed=C3=AAnis=20Freindorfer=20Azevedo?= Date: Thu, 7 May 2020 23:06:00 -0300 Subject: [PATCH] [Windows,MacOS] Auto-updater refactoring. (#639) Create and enable auto-updater for MacOS using `Sparkle=1.23`. We need to sign our app using an `Apple Developer Key` for it to work properly, since we are not going to sign updates with the Sparkle key. Add all auto-updater files to `gettext`'s pot. Use `str_split` to always get related stable version. We do not want to check for nightly builds. For Windows, we create the flag `-DHTTPS` to select between using an HTTPS or HTTP URL for the auto-updater checks. We use this to keep support for Windows XP (HTTP only) while all others should be HTTPS. Also, use `::FreeLibrary` to allow us to remove the temporary file that stores the `WinSparkle.dll`. Previously, we could not get it to work with `wine`. --- CMakeLists.txt | 8 +- cmake/UpdateAppcast.cmake | 2 +- src/wx/CMakeLists.txt | 117 ++++++++++++++---- src/wx/autoupdater/autoupdater.h | 8 ++ src/wx/autoupdater/macos/autoupdater.cpp | 22 ++++ src/wx/autoupdater/macos/sparkle-wrapper.h | 17 +++ src/wx/autoupdater/macos/sparkle-wrapper.mm | 40 ++++++ src/wx/autoupdater/wxmsw/autoupdater.cpp | 30 +++++ .../wxmsw}/winsparkle-path.h.in | 0 .../{ => autoupdater/wxmsw}/winsparkle-rc.h | 0 .../wxmsw}/winsparkle-wrapper.cpp | 26 ++-- .../wxmsw}/winsparkle-wrapper.h | 0 src/wx/cmdevents.cpp | 12 +- src/wx/guiinit.cpp | 2 +- src/wx/wxvbam.cpp | 29 ++--- src/wx/wxvbam.rc | 116 ++++++++--------- 16 files changed, 300 insertions(+), 129 deletions(-) create mode 100644 src/wx/autoupdater/autoupdater.h create mode 100644 src/wx/autoupdater/macos/autoupdater.cpp create mode 100644 src/wx/autoupdater/macos/sparkle-wrapper.h create mode 100644 src/wx/autoupdater/macos/sparkle-wrapper.mm create mode 100644 src/wx/autoupdater/wxmsw/autoupdater.cpp rename src/wx/{ => autoupdater/wxmsw}/winsparkle-path.h.in (100%) rename src/wx/{ => autoupdater/wxmsw}/winsparkle-rc.h (100%) rename src/wx/{ => autoupdater/wxmsw}/winsparkle-wrapper.cpp (84%) rename src/wx/{ => autoupdater/wxmsw}/winsparkle-wrapper.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c908e25..ce0bf5dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,11 +176,15 @@ option(ENABLE_FFMPEG "Enable ffmpeg A/V recording" ${FFMPEG_DEFAULT}) set(ONLINEUPDATES_DEFAULT OFF) -if(WIN32 AND (X64 OR X86)) - set(ONLINEUPDATES_DEFAULT ON) # use winsparkle +if((WIN32 AND (X64 OR X86)) OR APPLE) # winsparkle/sparkle + set(ONLINEUPDATES_DEFAULT ON) endif() option(ENABLE_ONLINEUPDATES "Enable online update checks" ${ONLINEUPDATES_DEFAULT}) +option(HTTPS "Use https URL for winsparkle" ON) +if(NOT HTTPS) + add_definitions(-DNO_HTTPS) +endif() set(LTO_DEFAULT ON) diff --git a/cmake/UpdateAppcast.cmake b/cmake/UpdateAppcast.cmake index 6d007cb2..98a2675b 100644 --- a/cmake/UpdateAppcast.cmake +++ b/cmake/UpdateAppcast.cmake @@ -50,7 +50,7 @@ Ignore the following cmake error. execute_process( COMMAND ${GIT_EXECUTABLE} clone git@github.com:visualboyadvance-m/visualboyadvance-m.github.io web-data - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) # Rewrite appcast.xml. diff --git a/src/wx/CMakeLists.txt b/src/wx/CMakeLists.txt index 4a0e4064..2df3950d 100644 --- a/src/wx/CMakeLists.txt +++ b/src/wx/CMakeLists.txt @@ -784,13 +784,32 @@ set( ) set(ALL_HDR_WX ${HDR_WX}) - -list(APPEND ALL_SRC_WX winsparkle-wrapper.cpp) -list(APPEND ALL_HDR_WX winsparkle-wrapper.h winsparkle-rc.h) +# make files included for gettext pot generation +list(APPEND ALL_SRC_WX autoupdater/wxmsw/autoupdater.cpp) +list(APPEND ALL_HDR_WX autoupdater/autoupdater.h) +list(APPEND ALL_SRC_WX autoupdater/wxmsw/winsparkle-wrapper.cpp) +list(APPEND ALL_HDR_WX autoupdater/wxmsw/winsparkle-wrapper.h) +list(APPEND ALL_HDR_WX autoupdater/wxmsw/winsparkle-rc.h) if(WIN32 AND (AMD64 OR X86_32) AND ENABLE_ONLINEUPDATES) - list(APPEND SRC_WX winsparkle-wrapper.cpp) - list(APPEND HDR_WX winsparkle-wrapper.h winsparkle-rc.h) + list(APPEND SRC_WX autoupdater/wxmsw/autoupdater.cpp) + list(APPEND HDR_WX autoupdater/autoupdater.h) + list(APPEND SRC_WX autoupdater/wxmsw/winsparkle-wrapper.cpp) + list(APPEND HDR_WX autoupdater/wxmsw/winsparkle-wrapper.h) + list(APPEND HDR_WX autoupdater/wxmsw/winsparkle-rc.h) +endif() + +# make files included for gettext pot generation +list(APPEND ALL_HDR_WX autoupdater/autoupdater.h) +list(APPEND ALL_SRC_WX autoupdater/macos/autoupdater.cpp) +list(APPEND ALL_SRC_WX autoupdater/macos/sparkle-wrapper.mm) +list(APPEND ALL_HDR_WX autoupdater/macos/sparkle-wrapper.h) + +if(APPLE AND ENABLE_ONLINEUPDATES) + list(APPEND HDR_WX autoupdater/autoupdater.h) + list(APPEND SRC_WX autoupdater/macos/autoupdater.cpp) + list(APPEND SRC_WX autoupdater/macos/sparkle-wrapper.mm) + list(APPEND HDR_WX autoupdater/macos/sparkle-wrapper.h) endif() set( @@ -881,7 +900,47 @@ if(WIN32 AND (AMD64 OR X86_32) AND ENABLE_ONLINEUPDATES) set(WINSPARKLE_DLL ${CMAKE_SOURCE_DIR}/dependencies/WinSparkle-0.6.0/Release/WinSparkle.dll) endif() - configure_file(winsparkle-path.h.in ${CMAKE_BINARY_DIR}/winsparkle-path.h) + configure_file(autoupdater/wxmsw/winsparkle-path.h.in ${CMAKE_BINARY_DIR}/winsparkle-path.h) +endif() + +if(APPLE AND ENABLE_ONLINEUPDATES) + + include(FetchContent) + FetchContent_Declare(Sparkle + URL "https://github.com/sparkle-project/Sparkle/releases/download/1.23.0/Sparkle-1.23.0.tar.bz2" + URL_HASH SHA512=fa7e9736d4319bf839cd5e11177d1ddac78c38048be7e59b5c94ea76c9ffc02919dd17890295d21b7f0e35afe0ec9aba9ba36912caed6e5017420345f9f66682 + ) + FetchContent_MakeAvailable(Sparkle) + + find_library(SPARKLE_FRAMEWORK + NAMES Sparkle + HINTS ${sparkle_SOURCE_DIR} + ) + find_path(SPARKLE_INCLUDE_DIR Sparkle.h HINTS ${SPARKLE_FRAMEWORK}/Headers) + target_include_directories( + visualboyadvance-m + PRIVATE ${SPARKLE_INCLUDE_DIR} + ) + + set(APPCAST_URL "https://data.vba-m.com/appcast.xml") + set(CCS1 mkdir -p ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Frameworks) + # The following commands *should* be run to make sure Sparkle is not going + # to bug randomly (version=1.23) + set(CCS2 cp -a ${SPARKLE_FRAMEWORK} ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Frameworks/Sparkle.framework) + set(CCS3 defaults write ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Info.plist CFBundleVersion -string "${VERSION}") + set(CCS4 defaults write ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Info.plist SUEnableAutomaticChecks -bool YES) + #set(CCS5 defaults write ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Info.plist SUPublicEDKey -string "${PUBLIC_KEY}") + set(CCS6 defaults write ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Info.plist SUFeedURL -string "${APPCAST_URL}") + add_custom_command(TARGET visualboyadvance-m POST_BUILD + COMMAND ${CCS1} + COMMAND ${CCS2} + COMMAND ${CCS3} + COMMAND ${CCS4} + #COMMAND ${CCS5} + COMMAND ${CCS6} + ) + + TARGET_LINK_LIBRARIES(visualboyadvance-m ${SPARKLE_FRAMEWORK}) endif() target_link_libraries( @@ -1139,7 +1198,7 @@ if(APPLE) endif() endif() -if(UPSTREAM_RELEASE AND APPLE) +if(APPLE AND (UPSTREAM_RELEASE OR ENABLE_ONLINEUPDATES)) if(NOT CMAKE_BUILD_TYPE MATCHES Debug) find_program(STRIP_PROGRAM strip) @@ -1163,32 +1222,48 @@ if(UPSTREAM_RELEASE AND APPLE) add_custom_command( TARGET visualboyadvance-m POST_BUILD - COMMAND codesign -s "Developer ID Application" --deep ./visualboyadvance-m.app + COMMAND codesign --sign "Developer ID Application" --force ./visualboyadvance-m.app WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) + + if(EXISTS ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Frameworks) + # Sign frameworks individually, like Xcode. + file(GLOB frameworks ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Frameworks/*) + foreach(framework ${frameworks}) + message(STATUS "Signing framework: " ${framework}) + add_custom_command( + TARGET visualboyadvance-m + POST_BUILD + COMMAND codesign --sign "Developer ID Application" --force ${framework} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + endforeach() + endif() else() message(WARNING "Set the environment variable LOGIN_KEYCHAIN_PASSWORD to your login keychain password to codesign.") endif() - set(appzip visualboyadvance-m-Mac-${BITS}bit${ZIP_SUFFIX}.zip) + if(UPSTREAM_RELEASE) + set(appzip visualboyadvance-m-Mac-${BITS}bit${ZIP_SUFFIX}.zip) - add_custom_command( - TARGET visualboyadvance-m - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E remove ${appzip} - COMMAND ${ZIP_PROGRAM} -9r ${appzip} ./visualboyadvance-m.app - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) - - if(GPG_KEYS) add_custom_command( TARGET visualboyadvance-m POST_BUILD - COMMAND ${CMAKE_COMMAND} -E remove ${appzip}.asc - COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/interactive-pause.cmake - COMMAND ${GPG_PROGRAM} --detach-sign -a ${appzip} + COMMAND ${CMAKE_COMMAND} -E remove ${appzip} + COMMAND ${ZIP_PROGRAM} -9r ${appzip} ./visualboyadvance-m.app WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) + + if(GPG_KEYS) + add_custom_command( + TARGET visualboyadvance-m + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E remove ${appzip}.asc + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/interactive-pause.cmake + COMMAND ${GPG_PROGRAM} --detach-sign -a ${appzip} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + endif() endif() endif() diff --git a/src/wx/autoupdater/autoupdater.h b/src/wx/autoupdater/autoupdater.h new file mode 100644 index 00000000..7c5aa9e4 --- /dev/null +++ b/src/wx/autoupdater/autoupdater.h @@ -0,0 +1,8 @@ +#ifndef AUTOUPDATER_H +#define AUTOUPDATER_H + +void initAutoupdater(); +void checkUpdatesUi(); +void shutdownAutoupdater(); + +#endif // AUTOUPDATER_H diff --git a/src/wx/autoupdater/macos/autoupdater.cpp b/src/wx/autoupdater/macos/autoupdater.cpp new file mode 100644 index 00000000..0f3a3667 --- /dev/null +++ b/src/wx/autoupdater/macos/autoupdater.cpp @@ -0,0 +1,22 @@ +#include "../autoupdater.h" +#include "../../../common/version_cpp.h" +#include "../../strutils.h" +#include "sparkle-wrapper.h" + +SparkleWrapper autoupdater; + +void initAutoupdater() +{ + autoupdater.addAppcastURL("https://data.vba-m.com/appcast.xml"); +} + + +void checkUpdatesUi() +{ + autoupdater.checkForUpdatesUi(); +} + + +void shutdownAutoupdater() +{ +} diff --git a/src/wx/autoupdater/macos/sparkle-wrapper.h b/src/wx/autoupdater/macos/sparkle-wrapper.h new file mode 100644 index 00000000..f83f39ed --- /dev/null +++ b/src/wx/autoupdater/macos/sparkle-wrapper.h @@ -0,0 +1,17 @@ +#ifndef SPARKLE_WRAPPER_H +#define SPARKLE_WRAPPER_H + +class SparkleWrapper +{ + public: + void checkForUpdatesUi(); + void addAppcastURL(const char *appcastUrl); + SparkleWrapper(); + ~SparkleWrapper(); + + private: + class Private; + Private* d; +}; + +#endif // SPARKLE_WRAPPER_H diff --git a/src/wx/autoupdater/macos/sparkle-wrapper.mm b/src/wx/autoupdater/macos/sparkle-wrapper.mm new file mode 100644 index 00000000..ee2f0045 --- /dev/null +++ b/src/wx/autoupdater/macos/sparkle-wrapper.mm @@ -0,0 +1,40 @@ +#include "sparkle-wrapper.h" + +#include +#include +#include + + +class SparkleWrapper::Private +{ + public: + SUUpdater* updater; +}; + + +void SparkleWrapper::addAppcastURL(const char *appcastUrl) +{ + NSURL* url = [NSURL URLWithString: [NSString stringWithUTF8String: appcastUrl]]; + [d->updater setFeedURL: url]; +} + + +SparkleWrapper::SparkleWrapper() +{ + d = new Private; + d->updater = [SUUpdater sharedUpdater]; + [d->updater retain]; +} + + +SparkleWrapper::~SparkleWrapper() +{ + [d->updater release]; + delete d; +} + + +void SparkleWrapper::checkForUpdatesUi() +{ + [d->updater checkForUpdates: nullptr]; +} diff --git a/src/wx/autoupdater/wxmsw/autoupdater.cpp b/src/wx/autoupdater/wxmsw/autoupdater.cpp new file mode 100644 index 00000000..1f4c7173 --- /dev/null +++ b/src/wx/autoupdater/wxmsw/autoupdater.cpp @@ -0,0 +1,30 @@ +#include "../autoupdater.h" +#include "../../../common/version_cpp.h" +#include "../../strutils.h" +#include "winsparkle-wrapper.h" + + +void initAutoupdater() +{ + // even if we are a nightly, only check latest stable version + wxString version = str_split(vbam_version, '-')[0]; +#ifndef NO_HTTPS + win_sparkle_set_appcast_url("https://data.vba-m.com/appcast.xml"); +#else + win_sparkle_set_appcast_url("http://data.vba-m.com/appcast.xml"); +#endif // NO_HTTPS + win_sparkle_set_app_details(L"visualboyadvance-m", L"VisualBoyAdvance-M", version.wc_str()); + win_sparkle_init(); +} + + +void checkUpdatesUi() +{ + win_sparkle_check_update_with_ui(); +} + + +void shutdownAutoupdater() +{ + win_sparkle_cleanup(); +} diff --git a/src/wx/winsparkle-path.h.in b/src/wx/autoupdater/wxmsw/winsparkle-path.h.in similarity index 100% rename from src/wx/winsparkle-path.h.in rename to src/wx/autoupdater/wxmsw/winsparkle-path.h.in diff --git a/src/wx/winsparkle-rc.h b/src/wx/autoupdater/wxmsw/winsparkle-rc.h similarity index 100% rename from src/wx/winsparkle-rc.h rename to src/wx/autoupdater/wxmsw/winsparkle-rc.h diff --git a/src/wx/winsparkle-wrapper.cpp b/src/wx/autoupdater/wxmsw/winsparkle-wrapper.cpp similarity index 84% rename from src/wx/winsparkle-wrapper.cpp rename to src/wx/autoupdater/wxmsw/winsparkle-wrapper.cpp index f3a0fd23..21655ab9 100644 --- a/src/wx/winsparkle-wrapper.cpp +++ b/src/wx/autoupdater/wxmsw/winsparkle-wrapper.cpp @@ -7,6 +7,7 @@ #include "winsparkle-wrapper.h" #include "wx/msw/private.h" + WinSparkleDllWrapper *WinSparkleDllWrapper::GetInstance() { static WinSparkleDllWrapper instance; @@ -14,6 +15,7 @@ WinSparkleDllWrapper *WinSparkleDllWrapper::GetInstance() return &instance; } + WinSparkleDllWrapper::WinSparkleDllWrapper() { wxFile temp_file; @@ -46,32 +48,24 @@ WinSparkleDllWrapper::WinSparkleDllWrapper() winsparkle_cleanup = reinterpret_cast(winsparkle_dll->GetSymbol("win_sparkle_cleanup")); } + WinSparkleDllWrapper::~WinSparkleDllWrapper() { + HMODULE hMod = winsparkle_dll->Detach(); + while(::FreeLibrary(hMod)) { + wxMilliSleep(50); + } delete winsparkle_dll; - - // Wait for the program to exit and release the DLL before deleting the temp file, otherwise access is denied. - char executable[] = "cmd.exe"; - char cmd_switch[] = "/c"; - - char shell_cmd[500]; - snprintf(shell_cmd, 500, "ping -n 3 127.0.0.1 > nul&set _file=%s&call del %%^_file%%", temp_file_name.mb_str().data()); - - char* cmd[]{ - executable, - cmd_switch, - shell_cmd, - NULL - }; - - wxExecute(cmd, wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE); + wxRemoveFile(temp_file_name); } + void win_sparkle_init() { WinSparkleDllWrapper::GetInstance()->winsparkle_init(); } + void win_sparkle_check_update_with_ui() { WinSparkleDllWrapper::GetInstance()->winsparkle_check_update_with_ui(); diff --git a/src/wx/winsparkle-wrapper.h b/src/wx/autoupdater/wxmsw/winsparkle-wrapper.h similarity index 100% rename from src/wx/winsparkle-wrapper.h rename to src/wx/autoupdater/wxmsw/winsparkle-wrapper.h diff --git a/src/wx/cmdevents.cpp b/src/wx/cmdevents.cpp index 9b05aff6..95a9a036 100644 --- a/src/wx/cmdevents.cpp +++ b/src/wx/cmdevents.cpp @@ -2714,18 +2714,14 @@ EVT_HANDLER(Customize, "Customize UI...") } #ifndef NO_ONLINEUPDATES -#ifdef __WXMSW__ -#include "winsparkle-wrapper.h" -#endif -#endif +#include "autoupdater/autoupdater.h" +#endif // NO_ONLINEUPDATES EVT_HANDLER(UpdateEmu, "Check for updates...") { #ifndef NO_ONLINEUPDATES -#ifdef __WXMSW__ - win_sparkle_check_update_with_ui(); -#endif -#endif + checkUpdatesUi(); +#endif // NO_ONLINEUPDATES } EVT_HANDLER(FactoryReset, "Factory Reset...") diff --git a/src/wx/guiinit.cpp b/src/wx/guiinit.cpp index faa85564..44d5cf52 100644 --- a/src/wx/guiinit.cpp +++ b/src/wx/guiinit.cpp @@ -2819,7 +2819,7 @@ bool MainFrame::BindControls() continue; } #endif -#if defined(NO_ONLINEUPDATES) || !defined(__WXMSW__) +#if defined(NO_ONLINEUPDATES) if (cmdtab[i].cmd_id == XRCID("UpdateEmu")) { if (mi) diff --git a/src/wx/wxvbam.cpp b/src/wx/wxvbam.cpp index d0ec7887..d3c6c206 100644 --- a/src/wx/wxvbam.cpp +++ b/src/wx/wxvbam.cpp @@ -41,6 +41,10 @@ int main(int argc, char** argv) } #endif +#ifndef NO_ONLINEUPDATES +#include "autoupdater/autoupdater.h" +#endif // NO_ONLINEUPDATES + // Initializer for struct cmditem cmditem new_cmditem(const wxString cmd, const wxString name, int cmd_id, int mask_flags, wxMenuItem* mi) @@ -194,24 +198,6 @@ wxString wxvbamApp::GetAbsolutePath(wxString path) return path; } -#ifndef NO_ONLINEUPDATES -#include "../common/version_cpp.h" - -#ifdef __WXMSW__ -#include "winsparkle-wrapper.h" -#endif // __WXMSW__ - -static void init_check_for_updates() -{ -#ifdef __WXMSW__ - wxString version(vbam_version); - win_sparkle_set_appcast_url("http://data.vba-m.com/appcast.xml"); - win_sparkle_set_app_details(L"visualboyadvance-m", L"VisualBoyAdvance-M", version.wc_str()); - win_sparkle_init(); -#endif // __WXMSW__ -} -#endif // NO_ONLINEUPDATES - #ifdef __WXMSW__ #include #include @@ -470,9 +456,8 @@ bool wxvbamApp::OnInit() frame->Show(true); #ifndef NO_ONLINEUPDATES - init_check_for_updates(); + initAutoupdater(); #endif - return true; } @@ -723,8 +708,8 @@ wxvbamApp::~wxvbamApp() { } delete overrides; -#if defined(__WXMSW__) && !defined(NO_ONLINEUPDATES) - win_sparkle_cleanup(); +#ifndef NO_ONLINEUPDATES + shutdownAutoupdater(); #endif } diff --git a/src/wx/wxvbam.rc b/src/wx/wxvbam.rc index 395901a7..b3dc78e9 100644 --- a/src/wx/wxvbam.rc +++ b/src/wx/wxvbam.rc @@ -1,58 +1,58 @@ -#pragma code_page(65001) - -AAAAA_MAINICON ICON "icons/visualboyadvance-m.ico" - -#include "wx/msw/wx.rc" - -#include "version.h" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#define VER_PRODUCTVERSION VER_FILEVERSION -#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR - -#ifndef NO_ONLINEUPDATES - -#include "winsparkle-rc.h" -#include "winsparkle-path.h" - -WINSPARKLE_DLL_RC RCDATA WINSPARKLE_DLL_PATH - -#endif /* NO_ONLINEUPDATES */ - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VER_FILEVERSION - PRODUCTVERSION VER_PRODUCTVERSION - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "VisualBoyAdvance-M comes with NO WARRANTY. Use it at your own risk." - VALUE "CompanyName", "http://vba-m.com/" - VALUE "FileDescription", "VisualBoyAdvance-M" - VALUE "FileVersion", VER_FILEVERSION_STR - VALUE "InternalName", "wxvbam" - VALUE "LegalCopyright", "Copyright © 2008-2019 VisualBoyAdvance-M development team" - VALUE "OriginalFilename", "VisualBoyAdvance-M.exe" - VALUE "ProductName", "VisualBoyAdvance-M" - VALUE "ProductVersion", VER_PRODUCTVERSION_STR - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END +#pragma code_page(65001) + +AAAAA_MAINICON ICON "icons/visualboyadvance-m.ico" + +#include "wx/msw/wx.rc" + +#include "version.h" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#define VER_PRODUCTVERSION VER_FILEVERSION +#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR + +#ifndef NO_ONLINEUPDATES + +#include "autoupdater/wxmsw/winsparkle-rc.h" +#include "winsparkle-path.h" + +WINSPARKLE_DLL_RC RCDATA WINSPARKLE_DLL_PATH + +#endif /* NO_ONLINEUPDATES */ + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VER_FILEVERSION + PRODUCTVERSION VER_PRODUCTVERSION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "VisualBoyAdvance-M comes with NO WARRANTY. Use it at your own risk." + VALUE "CompanyName", "http://vba-m.com/" + VALUE "FileDescription", "VisualBoyAdvance-M" + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", "wxvbam" + VALUE "LegalCopyright", "Copyright © 2008-2019 VisualBoyAdvance-M development team" + VALUE "OriginalFilename", "VisualBoyAdvance-M.exe" + VALUE "ProductName", "VisualBoyAdvance-M" + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END