diff --git a/.github/workflows/win32.yml b/.github/workflows/win32.yml index f5f1d11fc..b9cd7499e 100644 --- a/.github/workflows/win32.yml +++ b/.github/workflows/win32.yml @@ -27,14 +27,14 @@ jobs: # Check-out repository under $GITHUB_WORKSPACE # https://github.com/actions/checkout - name: Check-out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true # Discover location of MSBuild tool and to PATH environment variables # https://github.com/microsoft/setup-msbuild - name: Locate MSBuild - uses: microsoft/setup-msbuild@v1.3.1 + uses: microsoft/setup-msbuild@v2 # Use NuGet to download the latest libVLC. - name: Download libVLC @@ -98,7 +98,6 @@ jobs: -DSDL2_LIBRARY=%SDL2_LIBRARY% -DVLC_LIBRARIES=%VLC_LIBRARIES% -DVLC_VERSION=%VLC_VERSION% - -DCMAKE_EXE_LINKER_FLAGS=/SAFESEH:NO # Use CMake to build project - name: Build EmulationStation @@ -130,7 +129,7 @@ jobs: # Uploads artifacts from workflow # https://github.com/actions/upload-artifact - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: EmulationStation path: | diff --git a/README.md b/README.md index 0f16f47a2..e91e771fe 100644 --- a/README.md +++ b/README.md @@ -158,8 +158,7 @@ C:\src\EmulationStation>cmake . -B build -A Win32 ^ -DCURL_LIBRARY=%CURL_LIBRARY% ^ -DSDL2_LIBRARY=%SDL2_LIBRARY% ^ -DVLC_LIBRARIES=%VLC_LIBRARIES% ^ --DVLC_VERSION=%VLC_VERSION% ^ --DCMAKE_EXE_LINKER_FLAGS=/SAFESEH:NO +-DVLC_VERSION=%VLC_VERSION% ``` * Use CMake to build the Visual Studio project. diff --git a/es-app/CMakeLists.txt b/es-app/CMakeLists.txt index a828a462f..0c29f5c48 100644 --- a/es-app/CMakeLists.txt +++ b/es-app/CMakeLists.txt @@ -120,6 +120,7 @@ set(ES_SOURCES if(MSVC) LIST(APPEND ES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.rc + ${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.manifest ) endif() diff --git a/es-app/src/EmulationStation.manifest b/es-app/src/EmulationStation.manifest new file mode 100644 index 000000000..36a689197 --- /dev/null +++ b/es-app/src/EmulationStation.manifest @@ -0,0 +1,9 @@ + + + + + PerMonitorV2 + UTF-8 + + + diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index 1aa4f0f07..38314dbeb 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -283,7 +283,9 @@ void FileData::launchGame(Window* window) AudioManager::getInstance()->deinit(); VolumeControl::getInstance()->deinit(); InputManager::getInstance()->deinit(); +#ifndef _WIN32 window->deinit(); +#endif std::string command = mEnvData->mLaunchCommand; @@ -299,7 +301,7 @@ void FileData::launchGame(Window* window) Scripting::fireEvent("game-start", rom, basename, name); LOG(LogInfo) << " " << command; - int exitCode = runSystemCommand(command); + int exitCode = launchGameCommand(command); if(exitCode != 0) { @@ -308,7 +310,9 @@ void FileData::launchGame(Window* window) Scripting::fireEvent("game-end"); +#ifndef _WIN32 window->init(); +#endif InputManager::getInstance()->init(); VolumeControl::getInstance()->init(); window->normalizeNextUpdate(); diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index b3150db4a..ed0666438 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -522,6 +522,7 @@ void GuiMenu::openQuitMenu() ComponentListRow row; if (UIModeController::getInstance()->isUIModeFull()) { +#ifndef _WIN32 auto static restart_es_fx = []() { Scripting::fireEvent("quit"); if (quitES(QuitMode::RESTART)) { @@ -538,6 +539,7 @@ void GuiMenu::openQuitMenu() } row.addElement(std::make_shared(window, "RESTART EMULATIONSTATION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); s->addRow(row); +#endif if(Settings::getInstance()->getBool("ShowExit")) { diff --git a/es-core/src/Scripting.cpp b/es-core/src/Scripting.cpp index 19b7797a4..6cb67ff8d 100644 --- a/es-core/src/Scripting.cpp +++ b/es-core/src/Scripting.cpp @@ -30,12 +30,10 @@ namespace Scripting for(std::list::const_iterator dirIt = scriptDirList.cbegin(); dirIt != scriptDirList.cend(); ++dirIt) { std::list scripts = Utils::FileSystem::getDirContent(*dirIt); for (std::list::const_iterator it = scripts.cbegin(); it != scripts.cend(); ++it) { -#ifndef WIN32 // osx / linux if (!Utils::FileSystem::isExecutable(*it)) { LOG(LogWarning) << *it << " is not executable. Review file permissions."; continue; } -#endif std::string script = *it; if (arg1.length() > 0) { script += " \"" + arg1 + "\""; diff --git a/es-core/src/components/VideoVlcComponent.cpp b/es-core/src/components/VideoVlcComponent.cpp index 4ef7500d0..7ad0ca02b 100644 --- a/es-core/src/components/VideoVlcComponent.cpp +++ b/es-core/src/components/VideoVlcComponent.cpp @@ -7,7 +7,6 @@ #include "Settings.h" #ifdef WIN32 #include -#include typedef SSIZE_T ssize_t; #else #include diff --git a/es-core/src/platform.cpp b/es-core/src/platform.cpp index dc904c49e..92dffd695 100644 --- a/es-core/src/platform.cpp +++ b/es-core/src/platform.cpp @@ -2,7 +2,9 @@ #include #ifdef WIN32 -#include +#include +#include +#include "renderers/Renderer.h" #else #include #endif @@ -30,15 +32,56 @@ int runRestartCommand() int runSystemCommand(const std::string& cmd_utf8) { -#ifdef WIN32 - // on Windows we use _wsystem to support non-ASCII paths - // which requires converting from utf8 to a wstring - typedef std::codecvt_utf8 convert_type; - std::wstring_convert converter; - std::wstring wchar_str = converter.from_bytes(cmd_utf8); - return _wsystem(wchar_str.c_str()); -#else return system(cmd_utf8.c_str()); +} + +int launchGameCommand(const std::string& cmd_utf8) +{ +#ifdef _WIN32 + STARTUPINFO + si; + PROCESS_INFORMATION + pi; + SDL_Event + event; + DWORD + rcode = 0; + Uint32 + wf; + + wf = SDL_GetWindowFlags(Renderer::getSDLWindow()); + SDL_SetWindowFullscreen(Renderer::getSDLWindow(), 0); + SDL_SetWindowBordered(Renderer::getSDLWindow(), SDL_TRUE); + + Renderer::swapBuffers(); + + memset(&si, 0, sizeof si); + memset(&pi, 0, sizeof pi); + si.cb = sizeof si; + + if(!CreateProcess(NULL, (LPSTR)cmd_utf8.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + return 9009; + + while(WaitForSingleObject(pi.hProcess, 200) == WAIT_TIMEOUT) + while(SDL_PollEvent(&event)) + ; // NOP + + GetExitCodeProcess(pi.hProcess, &rcode); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + if(wf & SDL_WINDOW_FULLSCREEN) + SDL_SetWindowFullscreen(Renderer::getSDLWindow(), SDL_WINDOW_FULLSCREEN); + if(wf & SDL_WINDOW_BORDERLESS) + SDL_SetWindowBordered(Renderer::getSDLWindow(), SDL_FALSE); + + wf = SDL_GetWindowFlags(Renderer::getSDLWindow()); + if(wf & SDL_WINDOW_MINIMIZED) + SDL_RestoreWindow(Renderer::getSDLWindow()); + + return rcode; +#else + return runSystemCommand(cmd_utf8); #endif } @@ -57,9 +100,7 @@ int quitES(QuitMode mode) void touch(const std::string& filename) { #ifdef WIN32 - FILE* fp = fopen(filename.c_str(), "ab+"); - if (fp != NULL) - fclose(fp); + // Windows hasn't /tmp directory usualy so nothing to touch. #else int fd = open(filename.c_str(), O_CREAT|O_WRONLY, 0644); if (fd >= 0) diff --git a/es-core/src/platform.h b/es-core/src/platform.h index 1df4d56c6..b774a07be 100644 --- a/es-core/src/platform.h +++ b/es-core/src/platform.h @@ -17,7 +17,8 @@ enum QuitMode REBOOT = 3 }; -int runSystemCommand(const std::string& cmd_utf8); // run a utf-8 encoded in the shell (requires wstring conversion on Windows) +int runSystemCommand(const std::string& cmd_utf8); // run a utf-8 encoded in the shell +int launchGameCommand(const std::string& cmd_utf8); int quitES(QuitMode mode = QuitMode::QUIT); void processQuitMode(); diff --git a/es-core/src/utils/FileSystemUtil.cpp b/es-core/src/utils/FileSystemUtil.cpp index 94be3a58b..50ff815b5 100644 --- a/es-core/src/utils/FileSystemUtil.cpp +++ b/es-core/src/utils/FileSystemUtil.cpp @@ -9,6 +9,7 @@ #if defined(_WIN32) // because windows... +#include "utils/StringUtil.h" #include #include #define getcwd _getcwd @@ -34,21 +35,6 @@ namespace Utils static std::string exePath = ""; static std::map pathExistsIndex = std::map(); -////////////////////////////////////////////////////////////////////////// - -#if defined(_WIN32) - static std::string convertFromWideString(const std::wstring _wstring) - { - const int numBytes = WideCharToMultiByte(CP_UTF8, 0, _wstring.c_str(), (int)_wstring.length(), nullptr, 0, nullptr, nullptr); - std::string string(numBytes, 0); - - WideCharToMultiByte(CP_UTF8, 0, _wstring.c_str(), (int)_wstring.length(), (char*)string.c_str(), numBytes, nullptr, nullptr); - - return std::string(string); - - } // convertFromWideString -#endif // _WIN32 - ////////////////////////////////////////////////////////////////////////// stringList getDirContent(const std::string& _path, const bool _recursive) @@ -62,16 +48,16 @@ namespace Utils #if defined(_WIN32) const std::unique_lock lock(mutex); - WIN32_FIND_DATAW findData; + WIN32_FIND_DATA findData; const std::string wildcard = path + "/*"; - const HANDLE hFind = FindFirstFileW(std::wstring(wildcard.begin(), wildcard.end()).c_str(), &findData); + const HANDLE hFind = FindFirstFile(wildcard.c_str(), &findData); if(hFind != INVALID_HANDLE_VALUE) { // loop over all files in the directory do { - const std::string name = convertFromWideString(findData.cFileName); + const std::string name = findData.cFileName; // ignore "." and ".." if((name != ".") && (name != "..")) @@ -83,8 +69,10 @@ namespace Utils if(_recursive && isDirectory(fullName)) contentList.merge(getDirContent(fullName, true)); } + + FindNextFile(hFind, &findData); } - while(FindNextFileW(hFind, &findData)); + while(GetLastError() != ERROR_NO_MORE_FILES); FindClose(hFind); } @@ -216,13 +204,14 @@ namespace Utils void setExePath(const std::string& _path) { const size_t path_max = 32767; + std::string result(path_max, 0); #if defined(_WIN32) - std::wstring result(path_max, 0); - if(GetModuleFileNameW(nullptr, &result[0], path_max) != 0) - exePath = convertFromWideString(result); + if(GetModuleFileName(nullptr, &result[0], path_max) != 0){ + result.resize(result.find_first_of('\0')); + exePath = result; + } #else // _WIN32 - std::string result(path_max, 0); if(readlink("/proc/self/exe", &result[0], path_max) != -1) exePath = result; #endif // !_WIN32 @@ -570,9 +559,9 @@ namespace Utils if(hFile != INVALID_HANDLE_VALUE) { resolved.resize(GetFinalPathNameByHandle(hFile, nullptr, 0, FILE_NAME_NORMALIZED) + 1); - if(GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(), (DWORD)resolved.size(), FILE_NAME_NORMALIZED) > 0) + if(GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(), resolved.size(), FILE_NAME_NORMALIZED) > 0) { - resolved.resize(resolved.size() - 1); + resolved.resize(resolved.find_first_of('\0')); resolved = getGenericPath(resolved); } CloseHandle(hFile); @@ -606,7 +595,7 @@ namespace Utils return true; bool removed = (unlink(path.c_str()) == 0); - + // if removed, let's remove it from the index if (removed) pathExistsIndex[_path] = false; @@ -764,9 +753,19 @@ namespace Utils ////////////////////////////////////////////////////////////////////////// -#if !defined(_WIN32) bool isExecutable(const std::string& _path) { +#ifdef _WIN32 + std::string ext = getenv("PATHEXT"); + Utils::String::stringVector pathext = Utils::String::delimitedStringToVector(ext, ";"); + + ext = getExtension(_path); + for(auto it = pathext.cbegin(); it != pathext.cend(); it++) + if(stricmp(ext.c_str(), it->c_str()) == 0) + return true; + + return false; +#else const std::string path = getGenericPath(_path); // regular files and executables, but not setuid, setgid, shared text @@ -780,9 +779,8 @@ namespace Utils // check for mask attributes return (info.st_mode & mask) == mask && (info.st_mode & mask_exec) != 0; - +#endif } // isExecutable -#endif // !_WIN32 } // FileSystem:: diff --git a/es-core/src/utils/FileSystemUtil.h b/es-core/src/utils/FileSystemUtil.h index ac7a42384..cb950b1ab 100644 --- a/es-core/src/utils/FileSystemUtil.h +++ b/es-core/src/utils/FileSystemUtil.h @@ -39,9 +39,7 @@ namespace Utils bool isDirectory (const std::string& _path); bool isSymlink (const std::string& _path); bool isHidden (const std::string& _path); -#if !defined(_WIN32) bool isExecutable (const std::string& _path); -#endif // !_WIN32 } // FileSystem::