From 9a7241708c548ce4da2dacfa6cd55a40d600a370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 6 Mar 2026 13:18:31 +0100 Subject: [PATCH] Win32 file dialog: Prefill the filename when saving --- Windows/Debugger/CtrlDisAsmView.cpp | 2 +- Windows/Debugger/DumpMemoryWindow.cpp | 2 +- Windows/GEDebugger/GEDebugger.cpp | 2 +- Windows/MainWindowMenu.cpp | 16 ++++++++------ Windows/W32Util/ShellUtil.cpp | 32 +++++++++------------------ Windows/W32Util/ShellUtil.h | 2 +- Windows/main.cpp | 11 ++++----- 7 files changed, 30 insertions(+), 37 deletions(-) diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index f8ee0e29fe..8f328112c6 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -1315,7 +1315,7 @@ void CtrlDisAsmView::disassembleToFile() { } std::string filename; - if (W32Util::BrowseForFileName(false, nullptr, L"Save Disassembly As...", nullptr, L"All Files\0*.*\0\0", nullptr, filename)) { + if (W32Util::BrowseForFileName(false, nullptr, L"Save Disassembly As...", nullptr, nullptr, L"All Files\0*.*\0\0", nullptr, filename)) { std::wstring fileName = ConvertUTF8ToWString(filename); FILE *output = _wfopen(fileName.c_str(), L"wb"); if (output == nullptr) { diff --git a/Windows/Debugger/DumpMemoryWindow.cpp b/Windows/Debugger/DumpMemoryWindow.cpp index 4942a7cf03..fa82aa3cbf 100644 --- a/Windows/Debugger/DumpMemoryWindow.cpp +++ b/Windows/Debugger/DumpMemoryWindow.cpp @@ -20,7 +20,7 @@ void DumpMemoryWindow::HandleBrowseClick(HWND hwnd) { GetWindowTextW(filenameWnd, &buffer[0], (int)buffer.size()); std::string fn = ConvertWStringToUTF8(buffer); - bool result = W32Util::BrowseForFileName(false, hwnd, L"Select filename", NULL, NULL, NULL, fn); + bool result = W32Util::BrowseForFileName(false, hwnd, L"Select filename", nullptr, L"dump.bin", nullptr, nullptr, fn); if (result) { filenameChosen_ = true; buffer = ConvertUTF8ToWString(fn); diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index a9ac39a364..0310aa524d 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -439,7 +439,7 @@ void CGEDebugger::DescribeSecondPreview(const GPUgstate &state, char desc[256]) void CGEDebugger::PreviewExport(const GPUDebugBuffer *dbgBuffer) { constexpr const wchar_t *filter = L"PNG Image (*.png)\0*.png\0JPEG Image (*.jpg)\0*.jpg\0All files\0*.*\0\0"; std::string fn; - if (W32Util::BrowseForFileName(false, GetDlgHandle(), L"Save Preview Image...", nullptr, filter, L"png", fn)) { + if (W32Util::BrowseForFileName(false, GetDlgHandle(), L"Save Preview Image...", nullptr, L"preview.png", filter, L"png", fn)) { ScreenshotFormat fmt = fn.find(".jpg") != fn.npos ? ScreenshotFormat::JPG : ScreenshotFormat::PNG; Path filename(fn); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index b6e8314fc7..856e39d1ec 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -558,7 +558,7 @@ namespace MainWindow { case ID_FILE_LOADSTATEFILE: if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) { - if (W32Util::BrowseForFileName(true, hWnd, L"Load state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { + if (W32Util::BrowseForFileName(true, hWnd, L"Load state", nullptr, nullptr, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::Load(Path(fn), -1, SaveStateActionFinished); } @@ -566,7 +566,7 @@ namespace MainWindow { break; case ID_FILE_SAVESTATEFILE: if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { - if (W32Util::BrowseForFileName(false, hWnd, L"Save state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { + if (W32Util::BrowseForFileName(false, hWnd, L"Save state", nullptr, L"state.ppst", L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::Save(Path(fn), -1, SaveStateActionFinished); } @@ -773,27 +773,29 @@ namespace MainWindow { } case ID_DEBUG_LOADMAPFILE: - if (W32Util::BrowseForFileName(true, hWnd, L"Load .ppmap", 0, L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn)) { + if (W32Util::BrowseForFileName(true, hWnd, L"Load .ppmap", nullptr, nullptr, L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn)) { g_symbolMap->LoadSymbolMap(Path(fn)); NotifyDebuggerMapLoaded(); } break; case ID_DEBUG_SAVEMAPFILE: - if (W32Util::BrowseForFileName(false, hWnd, L"Save .ppmap", 0, L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn)) + if (W32Util::BrowseForFileName(false, hWnd, L"Save .ppmap", nullptr, L"map.ppmap", L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn)) { g_symbolMap->SaveSymbolMap(Path(fn)); + } break; case ID_DEBUG_LOADSYMFILE: - if (W32Util::BrowseForFileName(true, hWnd, L"Load .sym", 0, L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn)) { + if (W32Util::BrowseForFileName(true, hWnd, L"Load .sym", nullptr, nullptr, L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn)) { g_symbolMap->LoadNocashSym(Path(fn)); NotifyDebuggerMapLoaded(); } break; case ID_DEBUG_SAVESYMFILE: - if (W32Util::BrowseForFileName(false, hWnd, L"Save .sym", 0, L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn)) + if (W32Util::BrowseForFileName(false, hWnd, L"Save .sym", nullptr, L"symbols.sym", L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn)) { g_symbolMap->SaveNocashSym(Path(fn)); + } break; case ID_DEBUG_RESETSYMBOLTABLE: @@ -845,7 +847,7 @@ namespace MainWindow { MessageBox(hWnd, L"File does not exist.", L"Sorry", 0); } else if (info.type == FILETYPE_DIRECTORY) { MessageBox(hWnd, L"Cannot extract directories.", L"Sorry", 0); - } else if (W32Util::BrowseForFileName(false, hWnd, L"Save file as...", 0, L"All files\0*.*\0\0", L"", fn)) { + } else if (W32Util::BrowseForFileName(false, hWnd, L"Save file as...", nullptr, nullptr, L"All files\0*.*\0\0", L"", fn)) { const u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ, ""); // Note: len may be in blocks. size_t len = pspFileSystem.SeekFile(handle, 0, FILEMOVE_END); diff --git a/Windows/W32Util/ShellUtil.cpp b/Windows/W32Util/ShellUtil.cpp index dbeefc06bb..7da6300114 100644 --- a/Windows/W32Util/ShellUtil.cpp +++ b/Windows/W32Util/ShellUtil.cpp @@ -114,40 +114,30 @@ std::string BrowseForFolder2(HWND parent, std::string_view title, std::string_vi } bool BrowseForFileName(bool _bLoad, HWND _hParent, const wchar_t *_pTitle, - const wchar_t *_pInitialFolder, const wchar_t *_pFilter, const wchar_t *_pExtension, + const wchar_t *_pInitialFolder, const wchar_t *initialFilename, const wchar_t *_pFilter, const wchar_t *_pExtension, std::string &_strFileName) { // Let's hope this is large enough, don't want to trigger the dialog twice... - std::wstring filenameBuffer(32768 * 10, '\0'); + wchar_t fileBuffer[2048]{}; + wchar_t fileNameBuffer[2048]{}; + + if (initialFilename) { + wcscpy_s(fileBuffer, initialFilename); + } OPENFILENAME ofn{ sizeof(OPENFILENAME) }; - - auto resetFileBuffer = [&] { - ofn.nMaxFile = (DWORD)filenameBuffer.size(); - ofn.lpstrFile = &filenameBuffer[0]; - if (!_strFileName.empty()) - wcsncpy(ofn.lpstrFile, ConvertUTF8ToWString(_strFileName).c_str(), filenameBuffer.size() - 1); - }; - - resetFileBuffer(); ofn.lpstrInitialDir = _pInitialFolder; ofn.lpstrFilter = _pFilter; - ofn.lpstrFileTitle = nullptr; - ofn.nMaxFileTitle = 0; + ofn.lpstrFileTitle = fileNameBuffer; + ofn.nMaxFileTitle = ARRAY_SIZE(fileNameBuffer); ofn.lpstrDefExt = _pExtension; ofn.hwndOwner = _hParent; + ofn.lpstrFile = fileBuffer; + ofn.nMaxFile = ARRAY_SIZE(fileBuffer); ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER; if (!_bLoad) ofn.Flags |= OFN_HIDEREADONLY; int success = _bLoad ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn); - if (success == 0 && CommDlgExtendedError() == FNERR_BUFFERTOOSMALL) { - size_t sz = *(unsigned short *)&filenameBuffer[0]; - // Documentation is unclear if this is WCHARs to CHARs. - filenameBuffer.resize(filenameBuffer.size() + sz * 2); - resetFileBuffer(); - success = _bLoad ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn); - } - if (success) { _strFileName = ConvertWStringToUTF8(ofn.lpstrFile); return true; diff --git a/Windows/W32Util/ShellUtil.h b/Windows/W32Util/ShellUtil.h index 818838607a..06c78d1600 100644 --- a/Windows/W32Util/ShellUtil.h +++ b/Windows/W32Util/ShellUtil.h @@ -11,7 +11,7 @@ namespace W32Util { std::string BrowseForFolder2(HWND parent, std::string_view title, std::string_view initialPath); bool BrowseForFileName(bool _bLoad, HWND _hParent, const wchar_t*_pTitle, - const wchar_t *_pInitialFolder, const wchar_t *_pFilter, const wchar_t*_pExtension, + const wchar_t *_pInitialFolder, const wchar_t *initialFilename, const wchar_t *_pFilter, const wchar_t*_pExtension, std::string& _strFileName); std::vector BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const wchar_t*_pTitle, const wchar_t*_pInitialFolder, const wchar_t*_pFilter, const wchar_t*_pExtension); diff --git a/Windows/main.cpp b/Windows/main.cpp index 4f9e182265..01478b0665 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -686,7 +686,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string std::thread([=] { SetCurrentThreadName("BrowseForImage"); std::string out; - if (W32Util::BrowseForFileName(true, MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), nullptr, + if (W32Util::BrowseForFileName(true, MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), nullptr, nullptr, FinalizeFilter(L"All supported images (*.jpg *.jpeg *.png)|*.jpg;*.jpeg;*.png|All files (*.*)|*.*||").c_str(), L"jpg", out)) { g_requestManager.PostSystemSuccess(requestId, out.c_str()); } else { @@ -699,16 +699,17 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string { const BrowseFileType browseType = (BrowseFileType)param3; std::wstring filter = MakeWindowsFilter(browseType); - std::wstring initialFilename = ConvertUTF8ToWString(param2); // TODO: Plumb through + std::string initialFilename = param2; if (filter.empty()) { // Unsupported. return false; } const bool load = type == SystemRequestType::BROWSE_FOR_FILE; - std::thread([=] { + std::thread([load, param1, initialFilename, filter, requestId] { SetCurrentThreadName("BrowseForFile"); - std::string out; - if (W32Util::BrowseForFileName(load, MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), nullptr, filter.c_str(), L"", out)) { + std::string out = initialFilename; + std::wstring wInitial = ConvertUTF8ToWString(initialFilename); + if (W32Util::BrowseForFileName(load, MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), nullptr, wInitial.c_str(), filter.c_str(), L"", out)) { g_requestManager.PostSystemSuccess(requestId, out.c_str()); } else { g_requestManager.PostSystemFailure(requestId);