mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-09-22 13:01:05 +03:00
Fixed the Unicode-path crash and misleading AI Assistant teardown fault (SpartanJ/ecode#953).
- Windows executable paths now always use GetModuleFileNameW(), with dynamic long-path support. - Sys::getProcessPath() derives directly from the UTF-8 executable path. - Windows working-directory APIs now use wide-character functions under both MinGW and MSVC. - AI Assistant teardown checks that the editor splitter exists during partial initialization. - Added process-path and Unicode working-directory regression tests using EXPECT_STDSTREQ.
This commit is contained in:
@@ -655,12 +655,8 @@ std::string FileSystem::sizeToString( const Int64& Size ) {
|
||||
|
||||
bool FileSystem::changeWorkingDirectory( const std::string& path ) {
|
||||
int res;
|
||||
#ifdef EE_COMPILER_MSVC
|
||||
#ifdef UNICODE
|
||||
res = _wchdir( String::fromUtf8( path ).toWideString().c_str() );
|
||||
#else
|
||||
res = _chdir( String::fromUtf8( path ).toAnsiString().c_str() );
|
||||
#endif
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
res = SetCurrentDirectoryW( String::fromUtf8( path ).toWideString().c_str() ) ? 0 : -1;
|
||||
#else
|
||||
res = chdir( path.c_str() );
|
||||
#endif
|
||||
@@ -668,19 +664,19 @@ bool FileSystem::changeWorkingDirectory( const std::string& path ) {
|
||||
}
|
||||
|
||||
std::string FileSystem::getCurrentWorkingDirectory() {
|
||||
#ifdef EE_COMPILER_MSVC
|
||||
#if defined( UNICODE ) && !defined( EE_NO_WIDECHAR )
|
||||
wchar_t dir[_MAX_PATH];
|
||||
return ( 0 != GetCurrentDirectoryW( _MAX_PATH, dir ) ) ? String( dir ).toUtf8() : std::string();
|
||||
#else
|
||||
char dir[_MAX_PATH];
|
||||
return ( 0 != GetCurrentDirectory( _MAX_PATH, dir ) ) ? String( dir, std::locale() ).toUtf8()
|
||||
: std::string();
|
||||
#endif
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
DWORD size = GetCurrentDirectoryW( 0, nullptr );
|
||||
if ( size == 0 )
|
||||
return {};
|
||||
std::wstring dir( size, 0 );
|
||||
DWORD length = GetCurrentDirectoryW( size, &dir[0] );
|
||||
if ( length == 0 || length >= size )
|
||||
return {};
|
||||
dir.resize( length );
|
||||
return String( dir ).toUtf8();
|
||||
#else
|
||||
char dir[PATH_MAX + 1];
|
||||
getcwd( dir, PATH_MAX + 1 );
|
||||
return std::string( dir );
|
||||
return getcwd( dir, PATH_MAX + 1 ) != nullptr ? std::string( dir ) : std::string();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -627,44 +627,7 @@ static std::string sGetProcessPath() {
|
||||
return std::string( dirname( exe_file ) ) + "/";
|
||||
}
|
||||
#elif EE_PLATFORM == EE_PLATFORM_WIN
|
||||
#ifdef UNICODE
|
||||
// Get path to executable:
|
||||
char szDrive[_MAX_DRIVE];
|
||||
char szDir[_MAX_DIR];
|
||||
char szFilename[_MAX_DIR];
|
||||
char szExt[_MAX_DIR];
|
||||
std::wstring dllName( _MAX_DIR, 0 );
|
||||
|
||||
GetModuleFileName( 0, &dllName[0], _MAX_PATH );
|
||||
|
||||
std::string dllstrName( String( dllName ).toUtf8() );
|
||||
|
||||
#ifdef EE_COMPILER_MSVC
|
||||
_splitpath_s( dllstrName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR,
|
||||
szExt, _MAX_DIR );
|
||||
#else
|
||||
_splitpath( dllstrName.c_str(), szDrive, szDir, szFilename, szExt );
|
||||
#endif
|
||||
|
||||
return std::string( szDrive ) + std::string( szDir );
|
||||
#else
|
||||
// Get path to executable:
|
||||
TCHAR szDllName[_MAX_PATH];
|
||||
TCHAR szDrive[_MAX_DRIVE];
|
||||
TCHAR szDir[_MAX_DIR];
|
||||
TCHAR szFilename[_MAX_DIR];
|
||||
TCHAR szExt[_MAX_DIR];
|
||||
GetModuleFileName( 0, szDllName, _MAX_PATH );
|
||||
|
||||
#ifdef EE_COMPILER_MSVC
|
||||
_splitpath_s( szDllName, szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, szExt,
|
||||
_MAX_DIR );
|
||||
#else
|
||||
_splitpath( szDllName, szDrive, szDir, szFilename, szExt );
|
||||
#endif
|
||||
|
||||
return std::string( szDrive ) + std::string( szDir );
|
||||
#endif
|
||||
return FileSystem::fileRemoveFileName( Sys::getProcessFilePath() );
|
||||
#elif EE_PLATFORM == EE_PLATFORM_BSD
|
||||
int mib[4];
|
||||
mib[0] = CTL_KERN;
|
||||
@@ -1393,11 +1356,23 @@ std::string Sys::getProcessFilePath() {
|
||||
#endif
|
||||
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
std::wstring exename( _MAX_DIR, 0 );
|
||||
DWORD size = GetModuleFileNameW( 0, &exename[0], _MAX_PATH );
|
||||
if ( size > 0 && size < _MAX_PATH )
|
||||
exename.resize( size ); // Resize to actual size without extra null characters
|
||||
return String( exename ).toUtf8();
|
||||
// Windows paths are UTF-16. Using GetModuleFileNameA here makes executable paths containing
|
||||
// characters outside the active ANSI code page unusable (for example, CJK install paths).
|
||||
DWORD capacity = _MAX_PATH;
|
||||
while ( capacity <= 32768 ) {
|
||||
std::wstring exename( capacity, 0 );
|
||||
DWORD size = GetModuleFileNameW( nullptr, &exename[0], capacity );
|
||||
if ( size == 0 )
|
||||
return {};
|
||||
if ( size < capacity ) {
|
||||
exename.resize( size );
|
||||
return String( exename ).toUtf8();
|
||||
}
|
||||
if ( capacity == 32768 )
|
||||
break;
|
||||
capacity = eemin<DWORD>( capacity * 2, 32768 );
|
||||
}
|
||||
return {};
|
||||
#elif EE_PLATFORM == EE_PLATFORM_LINUX || EE_PLATFORM == EE_PLATFORM_ANDROID
|
||||
char path[] = "/proc/self/exe";
|
||||
ssize_t len = readlink( path, exename, PATH_MAX - 1 );
|
||||
|
||||
47
src/tests/unit_tests/systempath_tests.cpp
Normal file
47
src/tests/unit_tests/systempath_tests.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "utest.hpp"
|
||||
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/sys.hpp>
|
||||
|
||||
using namespace EE;
|
||||
using namespace EE::System;
|
||||
|
||||
namespace {
|
||||
|
||||
struct TemporaryWorkingDirectory {
|
||||
TemporaryWorkingDirectory() : originalPath( FileSystem::getCurrentWorkingDirectory() ) {
|
||||
path = Sys::getTempPath();
|
||||
FileSystem::dirAddSlashAtEnd( path );
|
||||
path += "eepp-path-路径-" + std::to_string( Sys::getProcessID() ) + "-" +
|
||||
std::to_string( Sys::getTicks() );
|
||||
created = FileSystem::makeDir( path );
|
||||
changed = created && FileSystem::changeWorkingDirectory( path );
|
||||
}
|
||||
|
||||
~TemporaryWorkingDirectory() {
|
||||
FileSystem::changeWorkingDirectory( originalPath );
|
||||
if ( created )
|
||||
FileSystem::dirRemoveAll( path );
|
||||
}
|
||||
|
||||
std::string originalPath;
|
||||
std::string path;
|
||||
bool created{ false };
|
||||
bool changed{ false };
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
UTEST( SystemPath, processPathMatchesExecutablePath ) {
|
||||
const std::string executablePath( Sys::getProcessFilePath() );
|
||||
ASSERT_FALSE( executablePath.empty() );
|
||||
EXPECT_TRUE( FileSystem::fileExists( executablePath ) );
|
||||
EXPECT_STDSTREQ( FileSystem::fileRemoveFileName( executablePath ), Sys::getProcessPath() );
|
||||
}
|
||||
|
||||
UTEST( SystemPath, workingDirectoryRoundTripsUnicode ) {
|
||||
TemporaryWorkingDirectory temp;
|
||||
ASSERT_TRUE( temp.created );
|
||||
ASSERT_TRUE( temp.changed );
|
||||
EXPECT_STDSTREQ( temp.path, FileSystem::getCurrentWorkingDirectory() );
|
||||
}
|
||||
@@ -276,7 +276,8 @@ AIAssistantPlugin::~AIAssistantPlugin() {
|
||||
mModelCatalog->cancel();
|
||||
mModelCatalog.reset();
|
||||
}
|
||||
if ( SceneManager::existsSingleton() && !SceneManager::instance()->isShuttingDown() ) {
|
||||
if ( SceneManager::existsSingleton() && !SceneManager::instance()->isShuttingDown() &&
|
||||
getPluginContext() && getPluginContext()->getSplitter() ) {
|
||||
getPluginContext()->getSplitter()->forEachWidgetClass(
|
||||
"llm_chatui", []( UIWidget* widget ) {
|
||||
LLMChatUI* chat = static_cast<LLMChatUI*>( widget );
|
||||
|
||||
Reference in New Issue
Block a user