Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.claude/
__pycache__/
install/
# OS files
Expand Down
2 changes: 2 additions & 0 deletions cmake/targets/salamand_sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ set(SALAMANDER_SOURCES
"${SAL_SRC}/common/trace.cpp"
"${SAL_SRC}/common/widepath.cpp"
"${SAL_SRC}/common/fsutil.cpp"
"${SAL_SRC}/common/CreateDirectoryFlow.cpp"
"${SAL_SRC}/common/WorkdirsHistorySerializer.cpp"
"${SAL_SRC}/common/Win32PathService.cpp"
"${SAL_SRC}/common/Win32FileSystem.cpp"
"${SAL_SRC}/common/Win32Clipboard.cpp"
Expand Down
142 changes: 138 additions & 4 deletions src/DialogWorkerObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

class CDialogWorkerObserver : public IWorkerObserver
{
// Non-owning bridge state. The progress dialog and worker-owned flags outlive
// the observer while a file operation is active.
HWND m_hProgressDlg;
HANDLE m_workerNotSuspended;
BOOL* m_cancelWorker;
Expand Down Expand Up @@ -97,16 +99,42 @@ class CDialogWorkerObserver : public IWorkerObserver
return ret;
}

int AskFileErrorW(const char* title, const char* fileName, const wchar_t* fileNameW,
const char* errorText) override
{
int ret = IDCANCEL;
void* data[5];
data[0] = &ret;
data[1] = const_cast<char*>(title);
data[2] = const_cast<char*>(fileName);
data[3] = const_cast<wchar_t*>(fileNameW);
data[4] = const_cast<char*>(errorText);
SendMessage(m_hProgressDlg, WM_USER_DIALOG, 100, (LPARAM)data);
return ret;
}

int AskFileErrorById(int titleId, const char* fileName, DWORD win32Error) override
{
return AskFileError(LoadStr(titleId), fileName, GetErrorText(win32Error));
}

int AskFileErrorByIdW(int titleId, const char* fileName, const wchar_t* fileNameW,
DWORD win32Error) override
{
return AskFileErrorW(LoadStr(titleId), fileName, fileNameW, GetErrorText(win32Error));
}

int AskFileErrorByIds(int titleId, const char* fileName, int errorTextId) override
{
return AskFileError(LoadStr(titleId), fileName, LoadStr(errorTextId));
}

int AskFileErrorByIdsW(int titleId, const char* fileName, const wchar_t* fileNameW,
int errorTextId) override
{
return AskFileErrorW(LoadStr(titleId), fileName, fileNameW, LoadStr(errorTextId));
}

int AskOverwrite(const char* sourceName, const char* sourceInfo,
const char* targetName, const char* targetInfo) override
{
Expand All @@ -121,6 +149,24 @@ class CDialogWorkerObserver : public IWorkerObserver
return ret;
}

int AskOverwriteW(const char* sourceName, const wchar_t* sourceNameW,
const char* sourceInfo, const char* targetName,
const wchar_t* targetNameW, const char* targetInfo,
bool dirOverwrite = false) override
{
int ret = IDCANCEL;
void* data[7];
data[0] = &ret;
data[1] = const_cast<char*>(sourceName);
data[2] = const_cast<wchar_t*>(sourceNameW);
data[3] = const_cast<char*>(sourceInfo);
data[4] = const_cast<char*>(targetName);
data[5] = const_cast<wchar_t*>(targetNameW);
data[6] = const_cast<char*>(targetInfo);
SendMessage(m_hProgressDlg, WM_USER_DIALOG, dirOverwrite ? 107 : 101, (LPARAM)data);
return ret;
}

int AskHiddenOrSystem(const char* title, const char* fileName,
const char* actionText) override
{
Expand All @@ -142,20 +188,62 @@ class CDialogWorkerObserver : public IWorkerObserver
int AskCannotMove(const char* errorText, const char* fileName,
const char* destPath, bool isDirectory) override
{
// The dialog handler at dialogs.cpp:874-879 (case 3) and :890-894
// (case 4) constructs CCannotMoveDlg(HWindow, IDD_..., data[1],
// data[2], data[3]) where the CCannotMoveDlg ctor takes
// (HWND, dlgId, fileName, targetPath, errorText). The wide variant
// AskCannotMoveW + cases 103/104 pack the same order (fileName at
// dataW[1], destPath at dataW[3], errorText at dataW[5]); ANSI must
// match. The prior packing here had errorText at [1] and fileName
// at [2], so the dialog showed the error text in the file-name slot
// and the destination path in the error slot.
int ret = IDCANCEL;
char* data[4];
data[0] = (char*)&ret;
data[1] = const_cast<char*>(errorText);
data[2] = const_cast<char*>(fileName);
data[3] = const_cast<char*>(destPath);
data[1] = const_cast<char*>(fileName);
data[2] = const_cast<char*>(destPath);
data[3] = const_cast<char*>(errorText);
SendMessage(m_hProgressDlg, WM_USER_DIALOG, isDirectory ? 4 : 3, (LPARAM)data);
return ret;
}

int AskCannotMoveW(const char* errorText, const char* fileName,
const wchar_t* fileNameW, const char* destPath,
const wchar_t* destPathW, bool isDirectory) override
{
int ret = IDCANCEL;
void* data[6];
data[0] = &ret;
data[1] = const_cast<char*>(fileName);
data[2] = const_cast<wchar_t*>(fileNameW);
data[3] = const_cast<char*>(destPath);
data[4] = const_cast<wchar_t*>(destPathW);
data[5] = const_cast<char*>(errorText);
SendMessage(m_hProgressDlg, WM_USER_DIALOG, isDirectory ? 104 : 103, (LPARAM)data);
return ret;
}

int AskCannotMoveErr(const char* sourceName, const char* targetName,
DWORD win32Error, bool isDirectory) override
{
return AskCannotMove(sourceName, targetName, GetErrorText(win32Error), isDirectory);
// AskCannotMove signature is (errorText, fileName, destPath,
// isDirectory). The wide sibling AskCannotMoveErrW already calls
// AskCannotMoveW(GetErrorText(...), sourceName, ...) in this order.
// Before this commit the wrapper passed (sourceName, targetName,
// errorText) and AskCannotMove packed those into the wrong slots
// (errorText/fileName/destPath); the two bugs composed to deliver
// the right data to the dialog. After the packing was corrected in
// this same patch, this wrapper must also pass args in the
// signature's order.
return AskCannotMove(GetErrorText(win32Error), sourceName, targetName, isDirectory);
}

int AskCannotMoveErrW(const char* sourceName, const wchar_t* sourceNameW,
const char* targetName, const wchar_t* targetNameW,
DWORD win32Error, bool isDirectory) override
{
return AskCannotMoveW(GetErrorText(win32Error), sourceName, sourceNameW,
targetName, targetNameW, isDirectory);
}

void NotifyError(const char* title, const char* fileName, const char* errorText) override
Expand All @@ -167,11 +255,28 @@ class CDialogWorkerObserver : public IWorkerObserver
SendMessage(m_hProgressDlg, WM_USER_DIALOG, 5, (LPARAM)data);
}

void NotifyErrorW(const char* title, const char* fileName, const wchar_t* fileNameW,
const char* errorText) override
{
void* data[4];
data[0] = const_cast<char*>(title);
data[1] = const_cast<char*>(fileName);
data[2] = const_cast<wchar_t*>(fileNameW);
data[3] = const_cast<char*>(errorText);
SendMessage(m_hProgressDlg, WM_USER_DIALOG, 105, (LPARAM)data);
}

void NotifyErrorById(int titleId, const char* fileName, int detailId) override
{
NotifyError(LoadStr(titleId), fileName, LoadStr(detailId));
}

void NotifyErrorByIdW(int titleId, const char* fileName, const wchar_t* fileNameW,
int detailId) override
{
NotifyErrorW(LoadStr(titleId), fileName, fileNameW, LoadStr(detailId));
}

int AskADSReadError(const char* fileName, const char* adsName) override
{
int ret = IDCANCEL;
Expand Down Expand Up @@ -240,6 +345,22 @@ class CDialogWorkerObserver : public IWorkerObserver
return ret;
}

int AskCopyPermErrorW(const char* sourceFile, const wchar_t* sourceFileW,
const char* targetFile, const wchar_t* targetFileW,
const char* errorText) override
{
int ret = IDCANCEL;
void* data[6];
data[0] = &ret;
data[1] = const_cast<char*>(sourceFile);
data[2] = const_cast<wchar_t*>(sourceFileW);
data[3] = const_cast<char*>(targetFile);
data[4] = const_cast<wchar_t*>(targetFileW);
data[5] = const_cast<char*>(errorText);
SendMessage(m_hProgressDlg, WM_USER_DIALOG, 110, (LPARAM)data);
return ret;
}

int AskCopyDirTimeError(const char* dirName, DWORD errorCode) override
{
int ret = IDCANCEL;
Expand All @@ -251,6 +372,19 @@ class CDialogWorkerObserver : public IWorkerObserver
return ret;
}

int AskCopyDirTimeErrorW(const char* dirName, const wchar_t* dirNameW,
DWORD errorCode) override
{
int ret = IDCANCEL;
void* data[4];
data[0] = &ret;
data[1] = const_cast<char*>(dirName);
data[2] = const_cast<wchar_t*>(dirNameW);
data[3] = (void*)(DWORD_PTR)errorCode;
SendMessage(m_hProgressDlg, WM_USER_DIALOG, 111, (LPARAM)data);
return ret;
}

int AskEncryptionLoss(bool isEncrypted, const char* fileName, bool isDir) override
{
int ret = IDCANCEL;
Expand Down
2 changes: 2 additions & 0 deletions src/cfgdlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,14 @@ struct CConfiguration
// the history arrays are destroyed in the ClearHistory() method
char* SelectHistory[SELECT_HISTORY_SIZE];
char* CopyHistory[COPY_HISTORY_SIZE];
wchar_t* CopyHistoryW[COPY_HISTORY_SIZE];
char* EditHistory[EDIT_HISTORY_SIZE];
char* ChangeDirHistory[CHANGEDIR_HISTORY_SIZE];
char* FileListHistory[FILELIST_HISTORY_SIZE];
char* CreateDirHistory[CREATEDIR_HISTORY_SIZE];
char* QuickRenameHistory[QUICKRENAME_HISTORY_SIZE];
char* EditNewHistory[EDITNEW_HISTORY_SIZE];
wchar_t* CreateDirHistoryW[CREATEDIR_HISTORY_SIZE];
wchar_t* QuickRenameHistoryW[QUICKRENAME_HISTORY_SIZE];
wchar_t* EditNewHistoryW[EDITNEW_HISTORY_SIZE];
char* ConvertHistory[CONVERT_HISTORY_SIZE];
Expand Down
49 changes: 35 additions & 14 deletions src/common/BuildScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ static char* AllocFullPath(const char* dir, const char* name)
return buf;
}

static std::wstring SnapshotPathW(const std::string& ansiPath, const std::wstring& widePath)
{
if (!widePath.empty())
return widePath;
if (ansiPath.empty())
return std::wstring();

int len = MultiByteToWideChar(CP_ACP, 0, ansiPath.c_str(), -1, NULL, 0);
if (len <= 0)
return std::wstring();

std::wstring out((size_t)len, L'\0');
if (MultiByteToWideChar(CP_ACP, 0, ansiPath.c_str(), -1, out.data(), len) == 0)
return std::wstring();
out.resize((size_t)len - 1);
return out;
}

BOOL BuildScriptFromSnapshot(
const CSelectionSnapshot& snapshot,
const CBuildConfig& config,
Expand All @@ -38,6 +56,9 @@ BOOL BuildScriptFromSnapshot(
if (script == NULL)
return FALSE;

const std::wstring sourcePathW = SnapshotPathW(snapshot.SourcePath, snapshot.SourcePathW);
const std::wstring targetPathW = SnapshotPathW(snapshot.TargetPath, snapshot.TargetPathW);

// Configure COperations fields from snapshot options
script->IsCopyOrMoveOperation = (snapshot.Action == EActionType::Copy || snapshot.Action == EActionType::Move);
script->IsCopyOperation = (snapshot.Action == EActionType::Copy);
Expand Down Expand Up @@ -90,9 +111,9 @@ BOOL BuildScriptFromSnapshot(
op.TargetName = NULL;
// Set wide path if available (with \\?\ prefix for long paths)
if (!item.NameW.empty())
op.SetSourceNameW(snapshot.SourcePath.c_str(), item.NameW);
op.SetSourceNameW(sourcePathW, item.NameW);
else if (!snapshot.SourcePath.empty())
op.SetSourceNameW(snapshot.SourcePath.c_str(), std::wstring(item.Name.begin(), item.Name.end()));
op.SetSourceNameW(sourcePathW, std::wstring(item.Name.begin(), item.Name.end()));

script->DirsCount++;
script->Add(op);
Expand All @@ -110,9 +131,9 @@ BOOL BuildScriptFromSnapshot(
return FALSE;
op.TargetName = NULL;
if (!item.NameW.empty())
op.SetSourceNameW(snapshot.SourcePath.c_str(), item.NameW);
op.SetSourceNameW(sourcePathW, item.NameW);
else if (!snapshot.SourcePath.empty())
op.SetSourceNameW(snapshot.SourcePath.c_str(), std::wstring(item.Name.begin(), item.Name.end()));
op.SetSourceNameW(sourcePathW, std::wstring(item.Name.begin(), item.Name.end()));

script->FilesCount++;
script->Add(op);
Expand Down Expand Up @@ -145,14 +166,14 @@ BOOL BuildScriptFromSnapshot(
// Set wide paths (with \\?\ prefix for long paths)
if (!item.NameW.empty())
{
dirOp.SetSourceNameW(snapshot.SourcePath.c_str(), item.NameW);
dirOp.SetTargetNameW(snapshot.TargetPath.c_str(), item.NameW);
dirOp.SetSourceNameW(sourcePathW, item.NameW);
dirOp.SetTargetNameW(targetPathW, item.NameW);
}
else if (!snapshot.SourcePath.empty())
{
std::wstring nameW(item.Name.begin(), item.Name.end());
dirOp.SetSourceNameW(snapshot.SourcePath.c_str(), nameW);
dirOp.SetTargetNameW(snapshot.TargetPath.c_str(), nameW);
dirOp.SetSourceNameW(sourcePathW, nameW);
dirOp.SetTargetNameW(targetPathW, nameW);
}

script->DirsCount++;
Expand Down Expand Up @@ -181,9 +202,9 @@ BOOL BuildScriptFromSnapshot(
return FALSE;
delOp.TargetName = NULL;
if (!item.NameW.empty())
delOp.SetSourceNameW(snapshot.SourcePath.c_str(), item.NameW);
delOp.SetSourceNameW(sourcePathW, item.NameW);
else if (!snapshot.SourcePath.empty())
delOp.SetSourceNameW(snapshot.SourcePath.c_str(), std::wstring(item.Name.begin(), item.Name.end()));
delOp.SetSourceNameW(sourcePathW, std::wstring(item.Name.begin(), item.Name.end()));

script->Add(delOp);
if (!script->IsGood())
Expand Down Expand Up @@ -214,14 +235,14 @@ BOOL BuildScriptFromSnapshot(
// Set wide paths (with \\?\ prefix for long paths)
if (!item.NameW.empty())
{
op.SetSourceNameW(snapshot.SourcePath.c_str(), item.NameW);
op.SetTargetNameW(snapshot.TargetPath.c_str(), item.NameW);
op.SetSourceNameW(sourcePathW, item.NameW);
op.SetTargetNameW(targetPathW, item.NameW);
}
else if (!snapshot.SourcePath.empty())
{
std::wstring nameW(item.Name.begin(), item.Name.end());
op.SetSourceNameW(snapshot.SourcePath.c_str(), nameW);
op.SetTargetNameW(snapshot.TargetPath.c_str(), nameW);
op.SetSourceNameW(sourcePathW, nameW);
op.SetTargetNameW(targetPathW, nameW);
}

script->FilesCount++;
Expand Down
Loading
Loading