Merge pull request #12550 from unknownbrackets/win-long-path

Attempt support for Windows long paths
This commit is contained in:
Henrik Rydgård 2020-01-11 23:32:38 +01:00 committed by GitHub
commit 52156ec4e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 269 additions and 159 deletions

View File

@ -792,12 +792,23 @@ const std::string &GetExeDirectory()
if (ExePath.empty()) {
#ifdef _WIN32
TCHAR program_path[4096] = {0};
GetModuleFileName(NULL, program_path, ARRAY_SIZE(program_path) - 1);
program_path[ARRAY_SIZE(program_path) - 1] = '\0';
TCHAR *last_slash = _tcsrchr(program_path, '\\');
if (last_slash != NULL)
*(last_slash + 1) = '\0';
#ifdef UNICODE
std::wstring program_path;
#else
std::string program_path;
#endif
size_t sz;
do {
program_path.resize(program_path.size() + MAX_PATH);
// On failure, this will return the same value as passed in, but success will always be one lower.
sz = GetModuleFileName(nullptr, &program_path[0], (DWORD)program_path.size());
} while (sz >= program_path.size());
TCHAR *last_slash = _tcsrchr(&program_path[0], '\\');
if (last_slash != nullptr)
program_path.resize(last_slash - &program_path[0] + 1);
else
program_path.resize(sz);
#ifdef UNICODE
ExePath = ConvertWStringToUTF8(program_path);
#else

View File

@ -313,10 +313,18 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) {
static std::string NormalizePath(const std::string &path) {
#ifdef _WIN32
wchar_t buf[512] = {0};
std::wstring wpath = ConvertUTF8ToWString(path);
if (GetFullPathName(wpath.c_str(), (int)ARRAY_SIZE(buf) - 1, buf, NULL) == 0)
return "";
std::wstring buf;
buf.resize(512);
size_t sz = GetFullPathName(wpath.c_str(), (DWORD)buf.size(), &buf[0], nullptr);
if (sz != 0 && sz < buf.size()) {
buf.resize(sz);
} else if (sz > buf.size()) {
buf.resize(sz);
sz = GetFullPathName(wpath.c_str(), (DWORD)buf.size(), &buf[0], nullptr);
// This should truncate off the null terminator.
buf.resize(sz);
}
return ConvertWStringToUTF8(buf);
#else
char buf[PATH_MAX + 1];

View File

@ -23,6 +23,9 @@
#include <ShlObj.h>
#include <string>
#include <codecvt>
#if !PPSSPP_PLATFORM(UWP)
#include "Windows/W32Util/ShellUtil.h"
#endif
#endif
#include <thread>
@ -560,14 +563,14 @@ void InitSysDirectories() {
// We set g_Config.memStickDirectory outside.
#else
wchar_t myDocumentsPath[MAX_PATH];
const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/";
// Caller sets this to the Documents folder.
const std::string rootMyDocsPath = g_Config.internalDataDirectory;
const std::string myDocsPath = rootMyDocsPath + "/PPSSPP/";
const std::string installedFile = path + "installed.txt";
const bool installed = File::Exists(installedFile);
// If installed.txt exists(and we can determine the Documents directory)
if (installed && (result == S_OK)) {
if (installed && rootMyDocsPath.size() > 0) {
#if defined(_WIN32) && defined(__MINGW32__)
std::ifstream inputFile(installedFile);
#else

View File

@ -743,13 +743,12 @@ void GameSettingsScreen::CreateViews() {
SavePathInOtherChoice = systemSettings->Add(new CheckBox(&otherinstalled_, sy->T("Save path in installed.txt", "Save path in installed.txt")));
SavePathInOtherChoice->SetEnabled(false);
SavePathInOtherChoice->OnClick.Handle(this, &GameSettingsScreen::OnSavePathOther);
wchar_t myDocumentsPath[MAX_PATH];
const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
const bool myDocsExists = W32Util::UserDocumentsPath().size() != 0;
const std::string PPSSPPpath = File::GetExeDirectory();
const std::string installedFile = PPSSPPpath + "installed.txt";
installed_ = File::Exists(installedFile);
otherinstalled_ = false;
if (!installed_ && result == S_OK) {
if (!installed_ && myDocsExists) {
if (File::CreateEmptyFile(PPSSPPpath + "installedTEMP.txt")) {
// Disable the setting whether cannot create & delete file
if (!(File::Delete(PPSSPPpath + "installedTEMP.txt")))
@ -759,7 +758,7 @@ void GameSettingsScreen::CreateViews() {
} else
SavePathInMyDocumentChoice->SetEnabled(false);
} else {
if (installed_ && (result == S_OK)) {
if (installed_ && myDocsExists) {
#ifdef _MSC_VER
std::ifstream inputFile(ConvertUTF8ToWString(installedFile));
#else
@ -779,8 +778,9 @@ void GameSettingsScreen::CreateViews() {
}
}
inputFile.close();
} else if (result != S_OK)
} else if (!myDocsExists) {
SavePathInMyDocumentChoice->SetEnabled(false);
}
}
#endif
@ -925,26 +925,20 @@ UI::EventReturn GameSettingsScreen::OnSavePathMydoc(UI::EventParams &e) {
File::Delete(PPSSPPpath + "installed.txt");
File::CreateEmptyFile(PPSSPPpath + "installed.txt");
otherinstalled_ = false;
wchar_t myDocumentsPath[MAX_PATH];
const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/";
const std::string myDocsPath = W32Util::UserDocumentsPath() + "/PPSSPP/";
g_Config.memStickDirectory = myDocsPath;
}
else if (installed_) {
} else if (installed_) {
File::Delete(PPSSPPpath + "installed.txt");
installed_ = false;
g_Config.memStickDirectory = PPSSPPpath + "memstick/";
}
else {
} else {
std::ofstream myfile;
myfile.open(PPSSPPpath + "installed.txt");
if (myfile.is_open()){
myfile.close();
}
wchar_t myDocumentsPath[MAX_PATH];
const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/";
const std::string myDocsPath = W32Util::UserDocumentsPath() + "/PPSSPP/";
g_Config.memStickDirectory = myDocsPath;
installed_ = true;
}

View File

@ -96,8 +96,14 @@ static bool IsTempPath(const std::string &str) {
// Normalize slashes.
item = ReplaceAll(str, "/", "\\");
wchar_t tempPath[MAX_PATH];
GetTempPath(MAX_PATH, tempPath);
std::wstring tempPath(MAX_PATH, '\0');
size_t sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]);
if (sz >= tempPath.size()) {
tempPath.resize(sz);
sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]);
}
// Need to resize off the null terminator either way.
tempPath.resize(sz);
if (testPath(ConvertWStringToUTF8(tempPath)))
return true;
#endif

View File

@ -4,6 +4,7 @@
#include "Core/MemMap.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Windows/W32Util/Misc.h"
#include "Windows/W32Util/ShellUtil.h"
#include "Windows/MainWindow.h"
#include "Windows/InputBox.h"
@ -1323,47 +1324,31 @@ std::string CtrlDisAsmView::disassembleRange(u32 start, u32 size)
return result;
}
void CtrlDisAsmView::disassembleToFile()
{
wchar_t fileName[MAX_PATH];
u32 size;
void CtrlDisAsmView::disassembleToFile() {
// get size
if (executeExpressionWindow(wnd,debugger,size) == false) return;
if (size == 0 || size > 10*1024*1024)
{
u32 size;
if (executeExpressionWindow(wnd,debugger,size) == false)
return;
if (size == 0 || size > 10*1024*1024) {
MessageBox(wnd,L"Invalid size!",L"Error",MB_OK);
return;
}
// get file name
OPENFILENAME ofn;
ZeroMemory( &ofn , sizeof( ofn));
ofn.lStructSize = sizeof ( ofn );
ofn.hwndOwner = NULL ;
ofn.lpstrFile = fileName ;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof( fileName );
ofn.lpstrFilter = L"All Files\0*.*\0\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL ;
ofn.nMaxFileTitle = 0 ;
ofn.lpstrInitialDir = NULL ;
ofn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_OVERWRITEPROMPT;
std::string filename;
if (W32Util::BrowseForFileName(false, nullptr, L"Save Disassembly As...", 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) {
MessageBox(wnd, L"Could not open file!", L"Error", MB_OK);
return;
}
if (GetSaveFileName(&ofn) == false) return;
std::string disassembly = disassembleRange(curAddress, size);
fprintf(output, "%s", disassembly.c_str());
FILE* output = _wfopen(fileName, L"wb");
if (output == NULL) {
MessageBox(wnd,L"Could not open file!",L"Error",MB_OK);
return;
fclose(output);
MessageBox(wnd, L"Finished!", L"Done", MB_OK);
}
std::string disassembly = disassembleRange(curAddress,size);
fprintf(output,"%s",disassembly.c_str());
fclose(output);
MessageBox(wnd,L"Finished!",L"Done",MB_OK);
}
void CtrlDisAsmView::getOpcodeText(u32 address, char* dest, int bufsize)

View File

@ -1,11 +1,28 @@
#include "DumpMemoryWindow.h"
#include "../resource.h"
#include <stdio.h>
#include "Core/MemMap.h"
#include "Windows/W32Util/ShellUtil.h"
#include <algorithm>
#include <cstdio>
#include "util/text/utf8.h"
#include "Core/Core.h"
#include "Core/MemMap.h"
#include "Windows/Debugger/DumpMemoryWindow.h"
#include "Windows/resource.h"
#include "Windows/W32Util/ShellUtil.h"
DumpMemoryWindow* DumpMemoryWindow::bp;
void DumpMemoryWindow::HandleBrowseClick(HWND hwnd) {
std::wstring buffer;
HWND filenameWnd = GetDlgItem(hwnd, IDC_DUMP_FILENAME);
buffer.resize(GetWindowTextLengthW(filenameWnd) + 1);
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);
if (result) {
filenameChosen_ = true;
buffer = ConvertUTF8ToWString(fn);
SetWindowTextW(filenameWnd, buffer.c_str());
}
}
INT_PTR CALLBACK DumpMemoryWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
@ -53,16 +70,7 @@ INT_PTR CALLBACK DumpMemoryWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam,
switch (HIWORD(wParam))
{
case BN_CLICKED:
char str[MAX_PATH];
GetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),str,MAX_PATH);
std::string fn = str;
bool result = W32Util::BrowseForFileName(false, hwnd, L"Select filename", NULL,NULL,NULL,fn);
if (result)
{
bp->filenameChosen = true;
SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),fn.c_str());
}
bp->HandleBrowseClick(hwnd);
break;
}
break;
@ -73,10 +81,10 @@ INT_PTR CALLBACK DumpMemoryWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam,
if (!PSP_IsInited())
break;
FILE* output = fopen(bp->fileName,"wb");
FILE *output = _wfopen(bp->fileName_.c_str(), L"wb");
if (output == NULL) {
char errorMessage[2048];
snprintf(errorMessage, sizeof(errorMessage), "Could not open file \"%s\".",bp->fileName);
snprintf(errorMessage, sizeof(errorMessage), "Could not open file \"%S\".", bp->fileName_.c_str());
MessageBoxA(hwnd,errorMessage,"Error",MB_OK);
break;
}
@ -140,8 +148,10 @@ bool DumpMemoryWindow::fetchDialogData(HWND hwnd)
}
// get filename
GetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),fileName,MAX_PATH);
if (strlen(fileName) == 0) return false;
fileName_.resize(GetWindowTextLengthW(GetDlgItem(hwnd, IDC_DUMP_FILENAME)) + 1);
GetWindowTextW(GetDlgItem(hwnd, IDC_DUMP_FILENAME), &fileName_[0], (int)fileName_.size());
if (fileName_.size() == 0)
return false;
// now check if data makes sense...
bool invalidSize = false;
@ -190,7 +200,7 @@ void DumpMemoryWindow::changeMode(HWND hwnd, Mode newMode)
EnableWindow(GetDlgItem(hwnd,IDC_DUMP_STARTADDRESS),TRUE);
EnableWindow(GetDlgItem(hwnd,IDC_DUMP_SIZE),TRUE);
if (filenameChosen == false)
if (filenameChosen_ == false)
SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),"Custom.dump");
} else {
u32 start, size;
@ -223,7 +233,7 @@ void DumpMemoryWindow::changeMode(HWND hwnd, Mode newMode)
SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_SIZE),buffer);
EnableWindow(GetDlgItem(hwnd,IDC_DUMP_SIZE),FALSE);
if (filenameChosen == false)
if (filenameChosen_ == false)
SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),defaultFileName);
}
}

View File

@ -9,21 +9,23 @@ class DumpMemoryWindow
HWND parentHwnd;
DebugInterface* cpu;
bool filenameChosen;
bool filenameChosen_;
Mode selectedMode;
u32 start;
u32 size;
char fileName[MAX_PATH];
std::wstring fileName_;
static DumpMemoryWindow* bp;
void changeMode(HWND hwnd, Mode newMode);
bool fetchDialogData(HWND hwnd);
void HandleBrowseClick(HWND hwnd);
public:
DumpMemoryWindow(HWND parent, DebugInterface* cpu): cpu(cpu)
{
parentHwnd = parent;
filenameChosen = false;
filenameChosen_ = false;
selectedMode = MODE_RAM;
};

View File

@ -32,7 +32,8 @@
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- Should really use True/PM (per-monitor) here but as we are XP-compatible, we don't have access to the headers. -->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True</dpiAware>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
</assembly>

View File

@ -131,15 +131,36 @@ namespace W32Util
return cmdline;
}
void GetSelfExecuteParams(std::wstring &workingDirectory, std::wstring &moduleFilename) {
workingDirectory.resize(MAX_PATH);
size_t sz = GetCurrentDirectoryW((DWORD)workingDirectory.size(), &workingDirectory[0]);
if (sz != 0 && sz < workingDirectory.size()) {
// This means success, so now we can remove the null terminator.
workingDirectory.resize(sz);
} else if (sz > workingDirectory.size()) {
// If insufficient, sz will include the null terminator, so we remove after.
workingDirectory.resize(sz);
sz = GetCurrentDirectoryW((DWORD)sz, &workingDirectory[0]);
workingDirectory.resize(sz);
}
moduleFilename.clear();
do {
moduleFilename.resize(moduleFilename.size() + MAX_PATH);
// On failure, this will return the same value as passed in, but success will always be one lower.
sz = GetModuleFileName(GetModuleHandle(nullptr), &moduleFilename[0], (DWORD)moduleFilename.size());
} while (sz >= moduleFilename.size());
moduleFilename.resize(sz);
}
void ExitAndRestart() {
// This preserves arguments (for example, config file) and working directory.
std::wstring workingDirectory;
std::wstring moduleFilename;
GetSelfExecuteParams(workingDirectory, moduleFilename);
wchar_t moduleFilename[MAX_PATH];
wchar_t workingDirectory[MAX_PATH];
GetCurrentDirectoryW(MAX_PATH, workingDirectory);
const wchar_t *cmdline = RemoveExecutableFromCommandLine(GetCommandLineW());
GetModuleFileName(GetModuleHandle(NULL), moduleFilename, MAX_PATH);
ShellExecute(NULL, NULL, moduleFilename, cmdline, workingDirectory, SW_SHOW);
ShellExecute(nullptr, nullptr, moduleFilename.c_str(), cmdline, workingDirectory.c_str(), SW_SHOW);
ExitProcess(0);
}

View File

@ -12,6 +12,7 @@ namespace W32Util
BOOL CopyTextToClipboard(HWND hwnd, const std::wstring &wtext);
void MakeTopMost(HWND hwnd, bool topMost);
void ExitAndRestart();
void GetSelfExecuteParams(std::wstring &workingDirectory, std::wstring &moduleFilename);
}
struct GenericListViewColumn

View File

@ -9,10 +9,10 @@
#include "util/text/utf8.h"
#include "ShellUtil.h"
#include "CommDlg.h"
#include <shlobj.h>
#include <commdlg.h>
#include <cderr.h>
namespace W32Util
{
@ -31,93 +31,147 @@ namespace W32Util
//info.pszDisplayName
auto idList = SHBrowseForFolder(&info);
HMODULE shell32 = GetModuleHandle(L"shell32.dll");
typedef BOOL (WINAPI *SHGetPathFromIDListEx_f)(PCIDLIST_ABSOLUTE pidl, PWSTR pszPath, DWORD cchPath, GPFIDL_FLAGS uOpts);
SHGetPathFromIDListEx_f SHGetPathFromIDListEx_ = (SHGetPathFromIDListEx_f)GetProcAddress(shell32, "SHGetPathFromIDListEx");
std::string result;
if (SHGetPathFromIDListEx_) {
std::wstring temp;
do {
// Assume it's failing if it goes on too long.
if (temp.size() > 32768 * 10) {
temp.clear();
break;
}
temp.resize(temp.size() + MAX_PATH);
} while (SHGetPathFromIDListEx_(idList, &temp[0], (DWORD)temp.size(), GPFIDL_DEFAULT) == 0);
result = ConvertWStringToUTF8(temp);
} else {
wchar_t temp[MAX_PATH]{};
SHGetPathFromIDList(idList, temp);
result = ConvertWStringToUTF8(temp);
}
wchar_t temp[MAX_PATH];
SHGetPathFromIDList(idList, temp);
CoTaskMemFree(idList);
if (wcslen(temp))
return ConvertWStringToUTF8(temp);
else
return "";
return result;
}
//---------------------------------------------------------------------------------------------------
// function WinBrowseForFileName
//---------------------------------------------------------------------------------------------------
bool BrowseForFileName (bool _bLoad, HWND _hParent, const wchar_t *_pTitle,
const wchar_t *_pInitialFolder,const wchar_t *_pFilter,const wchar_t *_pExtension,
std::string& _strFileName)
{
wchar_t szFile [MAX_PATH+1] = {0};
wchar_t szFileTitle [MAX_PATH+1] = {0};
bool BrowseForFileName(bool _bLoad, HWND _hParent, const wchar_t *_pTitle,
const wchar_t *_pInitialFolder, 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');
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.nMaxFile = ARRAY_SIZE(szFile);
ofn.lpstrFile = szFile;
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = ARRAY_SIZE(szFileTitle);
ofn.lpstrFileTitle = nullptr;
ofn.nMaxFileTitle = 0;
ofn.lpstrDefExt = _pExtension;
ofn.hwndOwner = _hParent;
ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_HIDEREADONLY;
ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER;
if (!_bLoad)
ofn.Flags |= OFN_HIDEREADONLY;
if (!_strFileName.empty())
wcsncpy(ofn.lpstrFile, ConvertUTF8ToWString(_strFileName).c_str(), MAX_PATH);
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 (((_bLoad) ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)))
{
if (success) {
_strFileName = ConvertWStringToUTF8(ofn.lpstrFile);
return true;
}
else
return false;
return false;
}
std::vector<std::string> BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const wchar_t *_pTitle,
const wchar_t *_pInitialFolder,const wchar_t *_pFilter,const wchar_t *_pExtension)
{
wchar_t szFile [MAX_PATH+1+2048*2] = {0};
wchar_t szFileTitle [MAX_PATH+1] = {0};
const wchar_t *_pInitialFolder, const wchar_t *_pFilter, const wchar_t *_pExtension) {
// Let's hope this is large enough, don't want to trigger the dialog twice...
std::wstring filenameBuffer(32768 * 10, '\0');
OPENFILENAME ofn{ sizeof(OPENFILENAME) };
auto resetFileBuffer = [&] {
ofn.nMaxFile = (DWORD)filenameBuffer.size();
ofn.lpstrFile = &filenameBuffer[0];
};
resetFileBuffer();
ofn.lpstrInitialDir = _pInitialFolder;
ofn.lpstrFilter = _pFilter;
ofn.nMaxFile = ARRAY_SIZE(szFile);
ofn.lpstrFile = szFile;
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = ARRAY_SIZE(szFileTitle);
ofn.lpstrFileTitle = nullptr;
ofn.nMaxFileTitle = 0;
ofn.lpstrDefExt = _pExtension;
ofn.hwndOwner = _hParent;
ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT;
ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_ALLOWMULTISELECT;
if (!_bLoad)
ofn.Flags |= OFN_HIDEREADONLY;
std::vector<std::string> files;
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 (((_bLoad) ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)))
{
if (success) {
std::string directory = ConvertWStringToUTF8(ofn.lpstrFile);
wchar_t *temp = ofn.lpstrFile;
wchar_t *oldtemp = temp;
temp += wcslen(temp)+1;
if (*temp==0)
{
temp += wcslen(temp) + 1;
if (*temp == 0) {
//we only got one file
files.push_back(ConvertWStringToUTF8(oldtemp));
}
else
{
while (*temp)
{
files.push_back(directory+"\\"+ConvertWStringToUTF8(temp));
temp += wcslen(temp)+1;
files.push_back(directory);
} else {
while (*temp) {
files.push_back(directory + "\\" + ConvertWStringToUTF8(temp));
temp += wcslen(temp) + 1;
}
}
return files;
}
else
return std::vector<std::string>(); // empty vector;
return files;
}
std::string UserDocumentsPath() {
std::string result;
HMODULE shell32 = GetModuleHandle(L"shell32.dll");
typedef HRESULT(WINAPI *SHGetKnownFolderPath_f)(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
SHGetKnownFolderPath_f SHGetKnownFolderPath_ = (SHGetKnownFolderPath_f)GetProcAddress(shell32, "SHGetKnownFolderPath");
if (SHGetKnownFolderPath_) {
PWSTR path = nullptr;
if (SHGetKnownFolderPath_(FOLDERID_Documents, 0, nullptr, &path) == S_OK) {
result = ConvertWStringToUTF8(path);
}
if (path)
CoTaskMemFree(path);
} else {
wchar_t path[MAX_PATH];
if (SHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, path) == S_OK) {
result = ConvertWStringToUTF8(path);
}
}
return result;
}
AsyncBrowseDialog::AsyncBrowseDialog(HWND parent, UINT completeMsg, std::wstring title)

View File

@ -14,6 +14,8 @@ namespace W32Util
std::vector<std::string> BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const wchar_t*_pTitle,
const wchar_t*_pInitialFolder,const wchar_t*_pFilter,const wchar_t*_pExtension);
std::string UserDocumentsPath();
struct AsyncBrowseDialog {
public:
enum Type {
@ -49,4 +51,4 @@ namespace W32Util
bool result_;
std::string filename_;
};
}
}

View File

@ -353,6 +353,7 @@ bool WindowsHost::CreateDesktopShortcut(std::string argumentPath, std::string ga
// Get the desktop folder
// TODO: Not long path safe.
wchar_t *pathbuf = new wchar_t[MAX_PATH + gameTitle.size() + 100];
SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, pathbuf);
@ -370,10 +371,16 @@ bool WindowsHost::CreateDesktopShortcut(std::string argumentPath, std::string ga
wcscat(pathbuf, L"\\");
wcscat(pathbuf, ConvertUTF8ToWString(gameTitle).c_str());
wchar_t module[MAX_PATH];
GetModuleFileName(NULL, module, MAX_PATH);
std::wstring moduleFilename;
size_t sz;
do {
moduleFilename.resize(moduleFilename.size() + MAX_PATH);
// On failure, this will return the same value as passed in, but success will always be one lower.
sz = GetModuleFileName(nullptr, &moduleFilename[0], (DWORD)moduleFilename.size());
} while (sz >= moduleFilename.size());
moduleFilename.resize(sz);
CreateLink(module, ConvertUTF8ToWString(argumentPath).c_str(), pathbuf, ConvertUTF8ToWString(gameTitle).c_str());
CreateLink(moduleFilename.c_str(), ConvertUTF8ToWString(argumentPath).c_str(), pathbuf, ConvertUTF8ToWString(gameTitle).c_str());
delete [] pathbuf;
return false;

View File

@ -374,17 +374,17 @@ static std::string GetDefaultLangRegion() {
static const int EXIT_CODE_VULKAN_WORKS = 42;
static bool DetectVulkanInExternalProcess() {
wchar_t moduleFilename[MAX_PATH];
wchar_t workingDirectory[MAX_PATH];
GetCurrentDirectoryW(MAX_PATH, workingDirectory);
std::wstring workingDirectory;
std::wstring moduleFilename;
W32Util::GetSelfExecuteParams(workingDirectory, moduleFilename);
const wchar_t *cmdline = L"--vulkan-available-check";
GetModuleFileName(GetModuleHandle(NULL), moduleFilename, MAX_PATH);
SHELLEXECUTEINFO info{ sizeof(SHELLEXECUTEINFO) };
info.fMask = SEE_MASK_NOCLOSEPROCESS;
info.lpFile = moduleFilename;
info.lpFile = moduleFilename.c_str();
info.lpParameters = cmdline;
info.lpDirectory = workingDirectory;
info.lpDirectory = workingDirectory.c_str();
info.nShow = SW_HIDE;
if (ShellExecuteEx(&info) != TRUE) {
return false;
@ -493,6 +493,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
// On Win32 it makes more sense to initialize the system directories here
// because the next place it was called was in the EmuThread, and it's too late by then.
g_Config.internalDataDirectory = W32Util::UserDocumentsPath();
InitSysDirectories();
// Load config up here, because those changes below would be overwritten

View File

@ -52,15 +52,18 @@ bool checkDllExistsW(const WCHAR* fname, bool bIncludeExeDir) {
return ::GetFileAttributesW(fname) != DWORD(-1);
}
bool checkExistsDllW(const WCHAR* sDllFilename) {
std::wstring sfullpath;
WCHAR bufsysdir[MAX_PATH];
if (!::GetSystemDirectoryW(bufsysdir, MAX_PATH)) {
bool checkExistsDllW(const WCHAR *sDllFilename) {
std::wstring sfullpath(MAX_PATH, '\0');
size_t sz = ::GetSystemDirectoryW(&sfullpath[0], (UINT)sfullpath.size());
if (sz >= sfullpath.size()) {
sfullpath.resize(sz);
sz = ::GetSystemDirectoryW(&sfullpath[0], (UINT)sfullpath.size());
}
sfullpath.resize(sz);
if (sz == 0) {
throw (std::runtime_error("system error"));
}
sfullpath = bufsysdir;
sfullpath += L'\\';
sfullpath += sDllFilename;

View File

@ -379,6 +379,7 @@ int main(int argc, const char* argv[])
g_Config.iAudioLatency = 1;
#ifdef _WIN32
g_Config.internalDataDirectory = "";
InitSysDirectories();
#endif