diff --git a/CMakeLists.txt b/CMakeLists.txt index 961217f..6be7f52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,8 @@ set(SOURCES include_directories(${SRCDIR} ${EXTERNAL} ${FLTKINCDIR} ${FLTKLIBDIR}) if(WIN32) - add_executable(${PROJECT_NAME} WIN32 ${SOURCES}) + enable_language(RC) + add_executable(${PROJECT_NAME} WIN32 ${SOURCES} assets/windows/app_icon.rc) else() add_executable(${PROJECT_NAME} ${SOURCES}) endif() diff --git a/assets/windows/app_icon.rc b/assets/windows/app_icon.rc new file mode 100644 index 0000000..76fa796 --- /dev/null +++ b/assets/windows/app_icon.rc @@ -0,0 +1 @@ +MAINICON ICON "app_icon.ico" diff --git a/src/csvapplication.cpp b/src/csvapplication.cpp index adb49bf..c1477f7 100644 --- a/src/csvapplication.cpp +++ b/src/csvapplication.cpp @@ -195,7 +195,7 @@ CsvApplication::CsvApplication() { std::string tmp_key = TCRUNCHER_PREF_RECENT_FILES_STUB + std::to_string(i); std::string tmp_val = getPreference(&preferences, tmp_key, ""); if( tmp_val != "" ) { - std::filesystem::path recent_file(tmp_val); + std::filesystem::path recent_file = std::filesystem::u8path(tmp_val); if( std::filesystem::exists(recent_file) ) { recentFiles.add(tmp_val); } @@ -584,7 +584,7 @@ bool CsvApplication::splitCsvFiles() { bool splitFileExists = false; for(int i=0; i files) { std::string item_tpl = "&File/" TCRUNCHER_MENUTEXT_OPEN_RECENT "/&"; int i = 0; for( auto filepath : files ) { - std::string filename_only = std::filesystem::path(filepath).filename().u8string(); + std::string filename_only = std::filesystem::u8path(filepath).filename().u8string(); std::string item = item_tpl + filename_only; // + " (" + std::to_string(i+1) + ")"; add(item.c_str(), FL_COMMAND + ('1' + i), MyMenuCallback, (void *) &(INTEGERS[i]), 0); ++i; diff --git a/src/csvtable.cpp b/src/csvtable.cpp index 5b830e8..95c134e 100644 --- a/src/csvtable.cpp +++ b/src/csvtable.cpp @@ -694,8 +694,9 @@ int CsvTable::saveCsv(std::string path, void (*cb)(const char*, void *), void *w char msg[MAX_MSG_LEN + 1]; std::string tempStr; int retCode = 0; - std::ofstream output(path, std::ios::binary); - + std::ofstream output; + Helper::openOutputStream(output, path, std::ios::binary); + // rather stupid TODO fix when `headerRow` gets fixed std::vector headerRowCopy; headerRowCopy.resize( headerRow->size() ); @@ -757,7 +758,8 @@ int CsvTable::saveCsv(std::string path, void (*cb)(const char*, void *), void *w int CsvTable::exportJSON(std::string path, void (*cb)(const char*, void *), void *win, bool convertNumbers) { table_index_t rowCount, colCount; int retCode = saveReturnCode::SAVE_OKAY; - std::ofstream output(path, std::ios::binary); + std::ofstream output; + Helper::openOutputStream(output, path, std::ios::binary); const int MAX_MSG_LEN = 500; char msg[MAX_MSG_LEN + 1]; std::map item; diff --git a/src/csvwindow.cpp b/src/csvwindow.cpp index 9781abe..96904fa 100644 --- a/src/csvwindow.cpp +++ b/src/csvwindow.cpp @@ -344,7 +344,7 @@ bool CsvWindow::loadFile(std::string filename, bool askUser, bool reopen) { return false; } - input.open(filename); + Helper::openInputStream(input, filename); if( !input ) { CsvApplication::myFlChoice("", "Could not open file!", {"Okay"}); return false; diff --git a/src/helper.cpp b/src/helper.cpp index dcb8cf6..16b1d21 100644 --- a/src/helper.cpp +++ b/src/helper.cpp @@ -495,9 +495,15 @@ std::string Helper::padInteger(int num, int length) { // https://stackoverflow.com/questions/5840148/how-can-i-get-a-files-size-in-c long Helper::getFileSize(std::string filename) { +#ifdef _WIN64 + struct _stat64 stat_buf; + int rc = _wstat64(utf8_to_ws(filename).c_str(), &stat_buf); + return rc == 0 ? (long)stat_buf.st_size : -1; +#else struct stat stat_buf; int rc = stat(filename.c_str(), &stat_buf); return rc == 0 ? stat_buf.st_size : -1; +#endif } @@ -792,6 +798,46 @@ unsigned int Helper::getFltkFontCode(std::string fontname) { } +void Helper::openInputStream(std::ifstream& stream, const std::string& utf8Path, std::ios_base::openmode mode) { +#ifdef _WIN64 + stream.open(utf8_to_ws(utf8Path), mode); +#else + stream.open(utf8Path, mode); +#endif +} + + +void Helper::openOutputStream(std::ofstream& stream, const std::string& utf8Path, std::ios_base::openmode mode) { +#ifdef _WIN64 + stream.open(utf8_to_ws(utf8Path), mode); +#else + stream.open(utf8Path, mode); +#endif +} + + +#ifdef _WIN64 +std::string Helper::ws_to_utf8(std::wstring const& s) { + if( s.empty() ) return std::string(); + int needed = WideCharToMultiByte(CP_UTF8, 0, s.data(), (int)s.size(), nullptr, 0, nullptr, nullptr); + if( needed <= 0 ) return std::string(); + std::string out((size_t)needed, '\0'); + WideCharToMultiByte(CP_UTF8, 0, s.data(), (int)s.size(), out.data(), needed, nullptr, nullptr); + return out; +} + + +std::wstring Helper::utf8_to_ws(std::string const& utf8) { + if( utf8.empty() ) return std::wstring(); + int needed = MultiByteToWideChar(CP_UTF8, 0, utf8.data(), (int)utf8.size(), nullptr, 0); + if( needed <= 0 ) return std::wstring(); + std::wstring out((size_t)needed, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, utf8.data(), (int)utf8.size(), out.data(), needed); + return out; +} +#endif + + diff --git a/src/helper.hh b/src/helper.hh index ba0f1fc..51a1341 100644 --- a/src/helper.hh +++ b/src/helper.hh @@ -96,6 +96,8 @@ public: static unsigned int getFltkFontCode(std::string fontname); static std::string ws_to_utf8(std::wstring const& s); static std::wstring utf8_to_ws(std::string const& utf8); + static void openInputStream(std::ifstream& stream, const std::string& utf8Path, std::ios_base::openmode mode = std::ios_base::in); + static void openOutputStream(std::ofstream& stream, const std::string& utf8Path, std::ios_base::openmode mode = std::ios_base::out); static void log(std::string msg); private: static std::map unicode2win1252; diff --git a/src/main.cpp b/src/main.cpp index c9ef7ec..1b05760 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,10 @@ #include #include +#ifdef _WIN64 +#include +#endif + /** Global function to access the application's preferences as stored in the preferences file. */ @@ -116,7 +120,20 @@ int main(int argc, char** argv) { app.setTheme(app.getTheme()); #endif - #ifndef _WIN64 + #ifdef _WIN64 + { + int wargc = 0; + LPWSTR* wargv = CommandLineToArgvW(GetCommandLineW(), &wargc); + if( wargv != nullptr ) { + for( int i = 1; i < wargc; ++i ) { + // open all files passed on the command line + std::string path = Helper::ws_to_utf8(std::wstring(wargv[i])); + CsvApplication::droppedFileCB(path.c_str()); + } + LocalFree(wargv); + } + } + #else for( int i = 1; i < argc; ++i ) { // open all files passed on the command line CsvApplication::droppedFileCB(argv[i]);