Support user directory
Package managers can create a "userdir" file next to x64dbg.exe with a file path (UTF-8) in there. If no path is specified it will be %APPDATA%\<executable name>. This directory contains the "db" folder, INI settings, memory dumps
This commit is contained in:
parent
10d978deb4
commit
c59271893b
|
@ -7,10 +7,12 @@
|
|||
#include "_global.h"
|
||||
#include "bridgemain.h"
|
||||
#include <stdio.h>
|
||||
#include <ShlObj.h>
|
||||
#include "Utf8Ini.h"
|
||||
|
||||
static HINSTANCE hInst;
|
||||
static Utf8Ini settings;
|
||||
static wchar_t szUserDirectory[MAX_PATH] = L"";
|
||||
static wchar_t szIniFile[MAX_PATH] = L"";
|
||||
static CRITICAL_SECTION csIni;
|
||||
static CRITICAL_SECTION csTranslate;
|
||||
|
@ -42,6 +44,27 @@ static bool bDisableGUIUpdate;
|
|||
return szError; \
|
||||
}
|
||||
|
||||
static std::wstring Utf8ToUtf16(const char* str)
|
||||
{
|
||||
std::wstring convertedString;
|
||||
if(!str || !*str)
|
||||
return convertedString;
|
||||
int requiredSize = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
|
||||
if(requiredSize > 0)
|
||||
{
|
||||
convertedString.resize(requiredSize - 1);
|
||||
if(!MultiByteToWideChar(CP_UTF8, 0, str, -1, (wchar_t*)convertedString.c_str(), requiredSize))
|
||||
convertedString.clear();
|
||||
}
|
||||
return convertedString;
|
||||
}
|
||||
|
||||
static bool DirExists(const wchar_t* dir)
|
||||
{
|
||||
DWORD attrib = GetFileAttributesW(dir);
|
||||
return (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP const wchar_t* BridgeInit()
|
||||
{
|
||||
//Initialize critial section
|
||||
|
@ -49,15 +72,75 @@ BRIDGE_IMPEXP const wchar_t* BridgeInit()
|
|||
InitializeCriticalSection(&csTranslate);
|
||||
|
||||
//Settings load
|
||||
if(!GetModuleFileNameW(0, szIniFile, MAX_PATH))
|
||||
if(!GetModuleFileNameW(0, szUserDirectory, _countof(szUserDirectory)))
|
||||
return L"Error getting module path!";
|
||||
int len = (int)wcslen(szIniFile);
|
||||
while(szIniFile[len] != L'.' && szIniFile[len] != L'\\' && len)
|
||||
len--;
|
||||
if(szIniFile[len] == L'\\')
|
||||
wcscat_s(szIniFile, L".ini");
|
||||
|
||||
auto backslash = wcsrchr(szUserDirectory, L'\\');
|
||||
if(backslash == nullptr)
|
||||
return L"Error getting module directory!";
|
||||
|
||||
*backslash = L'\0';
|
||||
|
||||
// Extract the file name of the x64dbg executable (without extension)
|
||||
auto fileNameWithoutExtension = backslash + 1;
|
||||
auto period = wcschr(fileNameWithoutExtension, L'.');
|
||||
if(period != nullptr)
|
||||
{
|
||||
*period = L'\0';
|
||||
}
|
||||
|
||||
wchar_t szFolderRedirect[MAX_PATH];
|
||||
wcscpy_s(szFolderRedirect, szUserDirectory);
|
||||
wcscat_s(szFolderRedirect, L"\\userdir");
|
||||
|
||||
std::wstring userDirUtf16;
|
||||
{
|
||||
std::vector<char> userDirUtf8;
|
||||
auto hFile = CreateFileW(szFolderRedirect, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
auto size = GetFileSize(hFile, nullptr);
|
||||
userDirUtf8.resize(size + 1);
|
||||
DWORD read = 0;
|
||||
if(!ReadFile(hFile, userDirUtf8.data(), size, &read, nullptr))
|
||||
userDirUtf8.clear();
|
||||
CloseHandle(hFile);
|
||||
userDirUtf16 = Utf8ToUtf16(userDirUtf8.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
userDirUtf16 = szUserDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
if(userDirUtf16.empty())
|
||||
{
|
||||
wchar_t szAppData[MAX_PATH] = L"";
|
||||
if(!SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_APPDATA, nullptr, 0, szAppData)))
|
||||
return L"Error getting AppData path";
|
||||
userDirUtf16 = szAppData;
|
||||
if(userDirUtf16.back() != L'\\')
|
||||
userDirUtf16 += L'\\';
|
||||
userDirUtf16 += fileNameWithoutExtension;
|
||||
CreateDirectoryW(userDirUtf16.c_str(), nullptr);
|
||||
}
|
||||
else
|
||||
wcscpy_s(&szIniFile[len], _countof(szIniFile) - len, L".ini");
|
||||
{
|
||||
if(userDirUtf16.back() == L'\\')
|
||||
userDirUtf16.pop_back();
|
||||
}
|
||||
|
||||
if(!DirExists(userDirUtf16.c_str()))
|
||||
return L"Specified user directory doesn't exist";
|
||||
|
||||
wcscpy_s(szIniFile, userDirUtf16.c_str());
|
||||
wcscat_s(szIniFile, L"\\");
|
||||
wcscat_s(szIniFile, fileNameWithoutExtension);
|
||||
wcscat_s(szIniFile, L".ini");
|
||||
|
||||
MessageBoxW(0, szIniFile, L"szIniFile", MB_SYSTEMMODAL);
|
||||
|
||||
wcscpy_s(szUserDirectory, userDirUtf16.c_str());
|
||||
|
||||
HINSTANCE hInst;
|
||||
const wchar_t* szLib;
|
||||
|
@ -283,6 +366,11 @@ BRIDGE_IMPEXP unsigned int BridgeGetNtBuildNumber()
|
|||
return NtBuildNumber;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP const wchar_t* BridgeUserDirectory()
|
||||
{
|
||||
return szUserDirectory;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool DbgMemRead(duint va, void* dest, duint size)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
|
|
|
@ -136,6 +136,11 @@ BRIDGE_IMPEXP bool BridgeIsProcessElevated();
|
|||
/// <returns>NtBuildNumber</returns>
|
||||
BRIDGE_IMPEXP unsigned int BridgeGetNtBuildNumber();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the user directory (without trailing backslash).
|
||||
/// </summary>
|
||||
BRIDGE_IMPEXP const wchar_t* BridgeUserDirectory();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -195,7 +195,7 @@ bool cbInstrSavedata(int argc, char* argv[])
|
|||
|
||||
String name = stringformatinline(argv[1]);
|
||||
if(name == ":memdump:")
|
||||
name = StringUtils::sprintf("%s\\memdumps\\memdump_%X_%p_%x.bin", szProgramDir, fdProcessInfo->dwProcessId, addr, size);
|
||||
name = StringUtils::sprintf("%s\\memdumps\\memdump_%X_%p_%x.bin", szUserDir, fdProcessInfo->dwProcessId, addr, size);
|
||||
|
||||
if(!FileHelper::WriteAllData(name, data(), data.size()))
|
||||
{
|
||||
|
|
|
@ -71,6 +71,7 @@ static duint exceptionDispatchAddr = 0;
|
|||
static bool bPausedOnException = false;
|
||||
static HANDLE DebugDLLFileMapping = 0;
|
||||
char szProgramDir[MAX_PATH] = "";
|
||||
char szUserDir[MAX_PATH] = "";
|
||||
char szDebuggeePath[MAX_PATH] = "";
|
||||
char szDllLoaderPath[MAX_PATH] = "";
|
||||
char szSymbolCachePath[MAX_PATH] = "";
|
||||
|
@ -2679,7 +2680,7 @@ static void* InitDLLDebugW(const wchar_t* szFileName, const wchar_t* szCommandLi
|
|||
WString loaderPath = StringUtils::Utf8ToUtf16(szDllLoaderPath);
|
||||
if(!CopyFileW(loaderPath.c_str(), debuggeeLoaderPath.c_str(), FALSE))
|
||||
{
|
||||
debuggeeLoaderPath = StringUtils::Utf8ToUtf16(szProgramDir);
|
||||
debuggeeLoaderPath = StringUtils::Utf8ToUtf16(szUserDir);
|
||||
debuggeeLoaderPath += loaderFilename;
|
||||
if(!CopyFileW(loaderPath.c_str(), debuggeeLoaderPath.c_str(), FALSE))
|
||||
{
|
||||
|
|
|
@ -138,6 +138,7 @@ extern PROCESS_INFORMATION* fdProcessInfo;
|
|||
extern HANDLE hActiveThread;
|
||||
extern HANDLE hProcessToken;
|
||||
extern char szProgramDir[MAX_PATH];
|
||||
extern char szUserDir[MAX_PATH];
|
||||
extern char szDebuggeePath[MAX_PATH];
|
||||
extern char szDllLoaderPath[MAX_PATH];
|
||||
extern char szSymbolCachePath[MAX_PATH];
|
||||
|
|
|
@ -13,6 +13,8 @@ extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
|
|||
hInst = hinstDLL;
|
||||
|
||||
// Get program directory
|
||||
strcpy_s(szUserDir, StringUtils::Utf16ToUtf8(BridgeUserDirectory()).c_str());
|
||||
|
||||
{
|
||||
wchar_t wszDir[deflen] = L"";
|
||||
if(GetModuleFileNameW(hInst, wszDir, deflen))
|
||||
|
|
|
@ -621,7 +621,7 @@ static DWORD WINAPI loadDbThread(LPVOID hEvent)
|
|||
|
||||
// Load global notes
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Reading notes file..."));
|
||||
notesFile = String(szProgramDir) + "\\notes.txt";
|
||||
notesFile = String(szUserDir) + "\\notes.txt";
|
||||
String text;
|
||||
if(!FileExists(notesFile.c_str()) || FileHelper::ReadAllText(notesFile, text))
|
||||
GuiSetGlobalNotes(text.c_str());
|
||||
|
@ -687,9 +687,6 @@ PfnDliHook __pfnDliNotifyHook2 = delayHook;
|
|||
|
||||
extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
||||
{
|
||||
if(!*szProgramDir)
|
||||
return "GetModuleFileNameW failed!";
|
||||
|
||||
if(!EngineCheckStructAlignment(UE_STRUCT_TITAN_ENGINE_CONTEXT, sizeof(TITAN_ENGINE_CONTEXT_t)))
|
||||
return "Invalid TITAN_ENGINE_CONTEXT_t alignment!";
|
||||
|
||||
|
@ -699,7 +696,7 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
strcat_s(szDllLoaderPath, "\\loaddll.exe");
|
||||
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
strcpy_s(alloctrace, szProgramDir);
|
||||
strcpy_s(alloctrace, szUserDir);
|
||||
strcat_s(alloctrace, "\\alloctrace.txt");
|
||||
DeleteFileW(StringUtils::Utf8ToUtf16(alloctrace).c_str());
|
||||
setalloctrace(alloctrace);
|
||||
|
@ -720,7 +717,7 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
Zydis::GlobalInitialize();
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Getting directory information..."));
|
||||
|
||||
strcpy_s(scriptDllDir, szProgramDir);
|
||||
strcpy_s(scriptDllDir, szUserDir);
|
||||
strcat_s(scriptDllDir, "\\scripts\\");
|
||||
initDataInstMap();
|
||||
|
||||
|
@ -734,10 +731,10 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
}
|
||||
|
||||
// Create database directory in the local debugger folder
|
||||
DbSetPath(StringUtils::sprintf("%s\\db", szProgramDir).c_str(), nullptr);
|
||||
DbSetPath(StringUtils::sprintf("%s\\db", szUserDir).c_str(), nullptr);
|
||||
|
||||
char szLocalSymbolPath[MAX_PATH] = "";
|
||||
strcpy_s(szLocalSymbolPath, szProgramDir);
|
||||
strcpy_s(szLocalSymbolPath, szUserDir);
|
||||
strcat_s(szLocalSymbolPath, "\\symbols");
|
||||
|
||||
Memory<char*> cachePath(MAX_SETTING_SIZE + 1);
|
||||
|
@ -750,7 +747,7 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
{
|
||||
if(_strnicmp(cachePath(), ".\\", 2) == 0)
|
||||
{
|
||||
strncpy_s(szSymbolCachePath, szProgramDir, _TRUNCATE);
|
||||
strncpy_s(szSymbolCachePath, szUserDir, _TRUNCATE);
|
||||
strncat_s(szSymbolCachePath, cachePath() + 1, _TRUNCATE);
|
||||
}
|
||||
else
|
||||
|
@ -805,7 +802,7 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
strcpy_s(plugindir, szProgramDir);
|
||||
strcat_s(plugindir, "\\plugins");
|
||||
CreateDirectoryW(StringUtils::Utf8ToUtf16(plugindir).c_str(), nullptr);
|
||||
CreateDirectoryW(StringUtils::Utf8ToUtf16(StringUtils::sprintf("%s\\memdumps", szProgramDir)).c_str(), nullptr);
|
||||
CreateDirectoryW(StringUtils::Utf8ToUtf16(StringUtils::sprintf("%s\\memdumps", szUserDir)).c_str(), nullptr);
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Initialization successful!"));
|
||||
bIsStopped = false;
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Loading plugins..."));
|
||||
|
|
|
@ -384,7 +384,7 @@ void LogView::redirectLogSlot()
|
|||
}
|
||||
else
|
||||
{
|
||||
BrowseDialog browse(this, tr("Redirect log to file"), tr("Enter the file to which you want to redirect log messages."), tr("Log files (*.txt);;All files (*.*)"), QCoreApplication::applicationDirPath(), true);
|
||||
BrowseDialog browse(this, tr("Redirect log to file"), tr("Enter the file to which you want to redirect log messages."), tr("Log files (*.txt);;All files (*.*)"), QString::fromWCharArray(BridgeUserDirectory()), true);
|
||||
if(browse.exec() == QDialog::Accepted)
|
||||
{
|
||||
logRedirection = _wfopen(browse.path.toStdWString().c_str(), L"ab");
|
||||
|
|
|
@ -2409,7 +2409,7 @@ void MainWindow::customizeMenu()
|
|||
|
||||
void MainWindow::on_actionImportSettings_triggered()
|
||||
{
|
||||
auto filename = QFileDialog::getOpenFileName(this, tr("Open file"), QCoreApplication::applicationDirPath(), tr("Settings (*.ini);;All files (*.*)"));
|
||||
auto filename = QFileDialog::getOpenFileName(this, tr("Open file"), QString::fromWCharArray(BridgeUserDirectory()), tr("Settings (*.ini);;All files (*.*)"));
|
||||
if(!filename.length())
|
||||
return;
|
||||
importSettings(filename);
|
||||
|
|
|
@ -90,7 +90,7 @@ void SystemBreakpointScriptDialog::on_openGlobal_clicked()
|
|||
{
|
||||
// The new script is at app dir
|
||||
QString defaultFileName("autorun.txt");
|
||||
defaultFileName = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QDir::separator() + defaultFileName);
|
||||
defaultFileName = QDir::toNativeSeparators(QString::fromWCharArray(BridgeUserDirectory()) + QDir::separator() + defaultFileName);
|
||||
// Create it
|
||||
if(!QFile::exists(defaultFileName))
|
||||
{
|
||||
|
|
|
@ -352,7 +352,7 @@ QIcon DIconHelper(QString name)
|
|||
|
||||
QString getDbPath(const QString & filename, bool addDateTimeSuffix)
|
||||
{
|
||||
auto path = QString("%1/db").arg(QCoreApplication::applicationDirPath());
|
||||
auto path = QString("%1/db").arg(QString::fromWCharArray(BridgeUserDirectory()));
|
||||
if(!filename.isEmpty())
|
||||
{
|
||||
path += '/';
|
||||
|
|
Loading…
Reference in New Issue