shell32: Allow overwriting files in SHFileOperation(FO_COPY) (with confirmation dialogs).

This commit is contained in:
Mikołaj Zalewski 2007-02-09 17:13:25 +01:00 committed by Alexandre Julliard
parent c55277c7e1
commit 33ee219ce3
21 changed files with 241 additions and 49 deletions

View file

@ -165,8 +165,12 @@ STRINGTABLE DISCARDABLE
IDS_DELETEITEM_TEXT "Наистина ли искате да изтриете '%1'?"
IDS_DELETEMULTIPLE_TEXT "Наистина ли искате да изтриете тези %1 елемента?"
IDS_DELETESELECTED_TEXT "Наистина ли искате да изтриете избраните елементи?"
IDS_OVERWRITEFILE_TEXT "Наистина ли искате да презапишете %1?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Потвърдете презаписа на файла"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Рестартиране"

View file

@ -163,10 +163,14 @@ STRINGTABLE DISCARDABLE
IDS_CREATEFOLDER_CAPTION "Chyba pøi pokusu vytvoøit nový adresáø"
IDS_DELETEITEM_CAPTION "Potvrdit odstranìní souboru"
IDS_DELETEFOLDER_CAPTION "Potvrdit odstranìní adresáøe"
IDS_OVERWRITEFILE_CAPTION "Potvrdit přepsání souboru"
IDS_DELETEITEM_TEXT "Opravdu chcete odstranit '%1'?"
IDS_DELETEMULTIPLE_TEXT "Opravdu chcete odstranit tìchto %1 položek?"
IDS_OVERWRITEFILE_TEXT "Přejete si přepsat soubor '%1'?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Potvrdit pøepsání souboru"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
}
/* columns in the shellview */

View file

@ -173,8 +173,12 @@ STRINGTABLE DISCARDABLE
IDS_TRASHFOLDER_TEXT "Sind Sie sich sicher, dass Sie '%1' und seinen Inhalt in den Müll verschieben möchten?"
IDS_TRASHMULTIPLE_TEXT "Sind Sie sich sicher, dass Sie diese %1 Dateien in den Müll verschieben möchten?"
IDS_CANTTRASH_TEXT "Das Objekt '%1' kann nicht in den Müll verschoben werden. Möchten Sie es stattdessen löschen?"
IDS_OVERWRITEFILE_TEXT "Möchten Sie, dass die Datei '%1' überschrieben wird ?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Bestätigung: Datei überschreiben"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Neustarten"

View file

@ -185,8 +185,12 @@ STRINGTABLE DISCARDABLE
IDS_TRASHFOLDER_TEXT "Are you sure that you want to send '%1' and all it's content to the Trash?"
IDS_TRASHMULTIPLE_TEXT "Are you sure that you want to send these %1 items to the Trash?"
IDS_CANTTRASH_TEXT "The item '%1' can't be sent to Trash. Do you want to delete it instead?"
IDS_OVERWRITEFILE_TEXT "OverWrite File %1?"
IDS_OVERWRITEFILE_CAPTION "Confirm File OverWrite"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Confirm file overwrite"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Restart"

View file

@ -163,8 +163,12 @@ STRINGTABLE DISCARDABLE
IDS_DELETEFOLDER_CAPTION "Konfirmu forigon de dosierujo"
IDS_DELETEITEM_TEXT "Æu vi estas certa pri forigo de '%1'?"
IDS_DELETEMULTIPLE_TEXT "Æu vi estas certa pri forigo de æi tiuj %1 komponantoj?"
IDS_OVERWRITEFILE_TEXT "Æu vi supreskribas la dosieron %1?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Konfirmu supreskribiton de dosieron"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
}
/* columns in the shellview */
@ -222,4 +226,3 @@ STRINGTABLE DISCARDABLE
IDS_COMMON_VIDEO "Documents\\Video"
IDS_CDBURN_AREA "Local Settings\\Application Data\\Microsoft\\CD Burning"
}

View file

@ -162,8 +162,12 @@ STRINGTABLE DISCARDABLE
IDS_DELETEFOLDER_CAPTION "Confirmar eliminación de carpeta"
IDS_DELETEITEM_TEXT "¿Seguro que desea eliminar '%1'?"
IDS_DELETEMULTIPLE_TEXT "¿Seguro que desea eliminar estos %1 elementos?"
IDS_OVERWRITEFILE_TEXT "¿Sobreescribir el archivo '%1'?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Confirmar sobreescritura de archivo"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
}
/* columns in the shellview */

View file

@ -164,8 +164,12 @@ STRINGTABLE DISCARDABLE
IDS_DELETEFOLDER_CAPTION "Vahvista kansion tuhoaminen"
IDS_DELETEITEM_TEXT "Haluatko varmasti tuhota '%1':n?"
IDS_DELETEMULTIPLE_TEXT "Haluatko varmasti tuhota nämä %1?"
IDS_OVERWRITEFILE_TEXT "Ylikirjoita tiedosto %1?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Vahvista tiedoston ylikirjoitus"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Käynnistä uudelleen"

View file

@ -176,8 +176,12 @@ STRINGTABLE DISCARDABLE
IDS_TRASHFOLDER_TEXT "Êtes-vous sûr de vouloir mettre « %1 » et tout ce qu'il contient dans la corbeille ?"
IDS_TRASHMULTIPLE_TEXT "Êtes-vous sûr de vouloir mettre ces %1 éléments dans la corbeille ?"
IDS_CANTTRASH_TEXT "L'élément « %1 » ne peut pas être mis dans la corbeille. Souhaitez-vous le supprimer à la place ?"
IDS_OVERWRITEFILE_TEXT "Écraser le fichier %1 ?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Confirmer l'écrasement du fichier"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Redémarrer"

View file

@ -164,8 +164,12 @@ STRINGTABLE DISCARDABLE
IDS_DELETEFOLDER_CAPTION "Confermare la cancellazione della cartella"
IDS_DELETEITEM_TEXT "Sei sicuro di voler cancellare '%1'?"
IDS_DELETEMULTIPLE_TEXT "Sei sicuro di voler cancellare questi %1 elementi?"
IDS_OVERWRITEFILE_TEXT "Sovrascrivere il File %1?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Confermare la sovrascrizione del File"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Riavvia"

View file

@ -173,8 +173,12 @@ IDS_TRASHITEM_TEXT "
IDS_TRASHFOLDER_TEXT "당신은 '%1' 과 그 안의 내용을 휴지통으로 보내기를 바랍니까?"
IDS_TRASHMULTIPLE_TEXT "당신은 '%1' 들을(를) 휴지통으로 보내기를 바랍니까?"
IDS_CANTTRASH_TEXT "The item '%1' can't be sent to Trash. Do you want to delete it instead?"
IDS_OVERWRITEFILE_TEXT "파일 %1을 덮어쓰겠습니까?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "파일 덮어쓰기 확인"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "다시 시작"

View file

@ -172,8 +172,12 @@ STRINGTABLE DISCARDABLE
IDS_TRASHFOLDER_TEXT "Virkelig legge «%1» og alt innholdet i papirkurven?"
IDS_TRASHMULTIPLE_TEXT "Virkelig legge disse %1 valgte elementene i papirkurven?"
IDS_CANTTRASH_TEXT "Elementet «%1» kan ikke legges i papirkurven. Vil du slette det i stedet?"
IDS_OVERWRITEFILE_TEXT "Overskrive filen «%1»?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Bekreft overskriving av fil"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Starte på nytt"

View file

@ -173,8 +173,12 @@ STRINGTABLE DISCARDABLE
IDS_TRASHFOLDER_TEXT "Czy jesteś pewien, że chcesz umieścić folder '%1' i całą jego zawartość w koszu"
IDS_TRASHMULTIPLE_TEXT "Elementów: %1 - czy na pewno chcesz je umieścić w Koszu?"
IDS_CANTTRASH_TEXT "Nie mogę przenieść elementu '%1' do Kosza. Czy chcesz go zamiast tego usunąć?"
IDS_OVERWRITEFILE_TEXT "Zast¹piæ plik %1?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Potwierdź zastąpienie pliku"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Uruchom ponownie"

View file

@ -256,8 +256,12 @@ STRINGTABLE DISCARDABLE
IDS_DELETEFOLDER_CAPTION "Confirmar exclusão de pasta"
IDS_DELETEITEM_TEXT "Você tem certeza que deseja excluir '%1'?"
IDS_DELETEMULTIPLE_TEXT "Você tem certeza que deseja excluir estes %1 itens?"
IDS_OVERWRITEFILE_TEXT "Sobreescrever arquivo %1?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Confirmar sobreescrever arquivo"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Reiniciar"

View file

@ -165,8 +165,12 @@ STRINGTABLE DISCARDABLE
IDS_DELETEFOLDER_CAPTION "Подтверждение удаления папки"
IDS_DELETEITEM_TEXT "Удалить '%1'?"
IDS_DELETEMULTIPLE_TEXT "Удалить эти обьекты (%1?"
IDS_OVERWRITEFILE_TEXT "Заменить файл(ы) %1?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Подтверждение замены файла"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Перезагрузить"

View file

@ -172,8 +172,12 @@ STRINGTABLE DISCARDABLE
IDS_TRASHFOLDER_TEXT "'%1' adlı öğeyi ve tüm içeriğini çöpe göndermek istediğinizden emin misiniz?"
IDS_TRASHMULTIPLE_TEXT "Bu %1 öğeyi çöpe göndermek istediğinizden emin misiniz?"
IDS_CANTTRASH_TEXT "'%1' adlı öğe çöpe gönderilemiyor. Tamamen silmek ister misiniz?"
IDS_OVERWRITEFILE_TEXT "%1 dosyasının üzerine yazmak istiyor musunuz?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "Dosya Üzerine Yazmayı Onayla"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
/* message box strings */
IDS_RESTART_TITLE "Yeniden Başlat"

View file

@ -161,8 +161,12 @@ STRINGTABLE DISCARDABLE
IDS_DELETEFOLDER_CAPTION "ϳäòâåðäæåííÿ âèëó÷åííÿ òåêè"
IDS_DELETEITEM_TEXT "Âè âïåâíåí³, ùî õî÷åòå âèëó÷èòè '%1'?"
IDS_DELETEMULTIPLE_TEXT "Âè âïåâíåí³, ùî õî÷åòå âèëó÷èòè ö³ %1 åëåìåíòè(³â)?"
IDS_OVERWRITEFILE_TEXT "Ïåðåïèñàòè Ôàéë %1?"
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\n\nDo you want to replace it?"
IDS_OVERWRITEFILE_CAPTION "ϳäòâåðäæåííÿ Ïåðåçàïèñó Ôàéëó"
IDS_OVERWRITEFOLDER_TEXT "This folder already contains a folder named '%1'.\n\n"\
"If the files in the destination folder have the same names as files in the\n"\
"selected folder they will be replaced. Do you still want to move or copy\n"\
"the folder?"
}
/* columns in the shellview */

View file

@ -153,9 +153,10 @@ void FreeChangeNotifications(void);
#define ASK_TRASH_FOLDER 8
#define ASK_TRASH_MULTIPLE_ITEM 9
#define ASK_CANT_TRASH_ITEM 10
#define ASK_OVERWRITE_FOLDER 11
BOOL SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pwszDir, BOOL bShowUI);
BOOL SHELL_ConfirmDialogW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir);
BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir);
/* 16-bit functions */
void WINAPI DragAcceptFiles16(HWND16 hWnd, BOOL16 b);

View file

@ -1829,7 +1829,7 @@ static HRESULT UNIXFS_delete_with_syscalls(UnixFolder *This, UINT cidl, LPCITEMI
static const WCHAR empty[] = {0};
int i;
if (!SHELL_ConfirmDialogW(GetActiveWindow(), ASK_DELETE_SELECTED, empty))
if (!SHELL_ConfirmYesNoW(GetActiveWindow(), ASK_DELETE_SELECTED, empty))
return S_OK;
lstrcpyA(szAbsolute, This->m_pszPath);

View file

@ -27,6 +27,7 @@
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "windef.h"
#include "winbase.h"
@ -65,6 +66,14 @@ static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest);
static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists);
static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly);
typedef struct
{
SHFILEOPSTRUCTW *req;
DWORD dwYesToAllMask;
BOOL bManyItems;
BOOL bCancelled;
} FILE_OPERATION;
/* Confirm dialogs with an optional "Yes To All" as used in file operations confirmations
*/
static const WCHAR CONFIRM_MSG_PROP[] = {'W','I','N','E','_','C','O','N','F','I','R','M',0};
@ -250,22 +259,32 @@ static BOOL SHELL_ConfirmIDs(int nKindOfDialog, SHELL_ConfirmIDstruc *ids)
ids->icon_resource_id = IDI_WARNING;
ids->caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
ids->text_resource_id = IDS_OVERWRITEFILE_TEXT;
return TRUE;
return TRUE;
case ASK_OVERWRITE_FOLDER:
ids->hIconInstance = NULL;
ids->icon_resource_id = IDI_WARNING;
ids->caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
ids->text_resource_id = IDS_OVERWRITEFOLDER_TEXT;
return TRUE;
default:
FIXME(" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
}
return FALSE;
}
BOOL SHELL_ConfirmDialogW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir)
static BOOL SHELL_ConfirmDialogW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir, FILE_OPERATION *op)
{
WCHAR szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
SHELL_ConfirmIDstruc ids;
DWORD_PTR args[1];
HICON hIcon;
int ret;
if (!SHELL_ConfirmIDs(nKindOfDialog, &ids))
return FALSE;
assert(nKindOfDialog >= 0 && nKindOfDialog < 32);
if (op && (op->dwYesToAllMask & (1 << nKindOfDialog)))
return IDYES;
assert(SHELL_ConfirmIDs(nKindOfDialog, &ids));
LoadStringW(shell32_hInstance, ids.caption_resource_id, szCaption, sizeof(szCaption)/sizeof(WCHAR));
LoadStringW(shell32_hInstance, ids.text_resource_id, szText, sizeof(szText)/sizeof(WCHAR));
@ -275,7 +294,23 @@ BOOL SHELL_ConfirmDialogW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir)
szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)args);
hIcon = LoadIconW(ids.hIconInstance, (LPWSTR)MAKEINTRESOURCE(ids.icon_resource_id));
return (IDYES == SHELL_ConfirmMsgBox(hWnd, szBuffer, szCaption, hIcon, FALSE));
ret = SHELL_ConfirmMsgBox(hWnd, szBuffer, szCaption, hIcon, op && op->bManyItems);
if (op) {
if (ret == IDD_YESTOALL) {
op->dwYesToAllMask |= (1 << nKindOfDialog);
ret = IDYES;
}
if (ret == IDCANCEL)
op->bCancelled = TRUE;
if (ret != IDYES)
op->req->fAnyOperationsAborted = TRUE;
}
return ret == IDYES;
}
BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir)
{
return SHELL_ConfirmDialogW(hWnd, nKindOfDialog, szDir, NULL);
}
static DWORD SHELL32_AnsiToUnicodeBuf(LPCSTR aPath, LPWSTR *wPath, DWORD minChars)
@ -324,7 +359,7 @@ BOOL SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI)
if (hFind == INVALID_HANDLE_VALUE)
return FALSE;
if (!bShowUI || (ret = SHELL_ConfirmDialogW(hwnd, ASK_DELETE_FOLDER, pszDir)))
if (!bShowUI || (ret = SHELL_ConfirmDialogW(hwnd, ASK_DELETE_FOLDER, pszDir, NULL)))
{
do
{
@ -1047,7 +1082,7 @@ static void destroy_file_list(FILE_LIST *flList)
HeapFree(GetProcessHeap(), 0, flList->feFiles);
}
static void copy_dir_to_dir(LPSHFILEOPSTRUCTW lpFileOp, FILE_ENTRY *feFrom, LPWSTR szDestPath)
static void copy_dir_to_dir(FILE_OPERATION *op, FILE_ENTRY *feFrom, LPWSTR szDestPath)
{
WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
SHFILEOPSTRUCTW fileOp;
@ -1062,22 +1097,48 @@ static void copy_dir_to_dir(LPSHFILEOPSTRUCTW lpFileOp, FILE_ENTRY *feFrom, LPWS
else
lstrcpyW(szTo, szDestPath);
if (!(op->req->fFlags & FOF_NOCONFIRMATION) && PathFileExistsW(szTo)) {
if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FOLDER, feFrom->szFilename, op))
{
/* Vista returns an ERROR_CANCELLED even if user pressed "No" */
if (!op->bManyItems)
op->bCancelled = TRUE;
return;
}
}
szTo[lstrlenW(szTo) + 1] = '\0';
SHNotifyCreateDirectoryW(szTo, NULL);
PathCombineW(szFrom, feFrom->szFullPath, wildCardFiles);
szFrom[lstrlenW(szFrom) + 1] = '\0';
memcpy(&fileOp, lpFileOp, sizeof(fileOp));
memcpy(&fileOp, op->req, sizeof(fileOp));
fileOp.pFrom = szFrom;
fileOp.pTo = szTo;
fileOp.fFlags &= ~FOF_MULTIDESTFILES; /* we know we're copying to one dir */
/* Don't ask the user about overwriting files when he accepted to overwrite the
folder. FIXME: this is not exactly what Windows does - e.g. there would be
an additional confirmation for a nested folder */
fileOp.fFlags |= FOF_NOCONFIRMATION;
SHFileOperationW(&fileOp);
}
static BOOL copy_file_to_file(FILE_OPERATION *op, WCHAR *szFrom, WCHAR *szTo)
{
if (!(op->req->fFlags & FOF_NOCONFIRMATION) && PathFileExistsW(szTo))
{
if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FILE, PathFindFileNameW(szTo), op))
return 0;
}
return SHNotifyCopyFileW(szFrom, szTo, FALSE) == 0;
}
/* copy a file or directory to another directory */
static void copy_to_dir(LPSHFILEOPSTRUCTW lpFileOp, FILE_ENTRY *feFrom, FILE_ENTRY *feTo)
static void copy_to_dir(FILE_OPERATION *op, FILE_ENTRY *feFrom, FILE_ENTRY *feTo)
{
if (!PathFileExistsW(feTo->szFullPath))
SHNotifyCreateDirectoryW(feTo->szFullPath, NULL);
@ -1087,10 +1148,10 @@ static void copy_to_dir(LPSHFILEOPSTRUCTW lpFileOp, FILE_ENTRY *feFrom, FILE_ENT
WCHAR szDestPath[MAX_PATH];
PathCombineW(szDestPath, feTo->szFullPath, feFrom->szFilename);
SHNotifyCopyFileW(feFrom->szFullPath, szDestPath, FALSE);
copy_file_to_file(op, feFrom->szFullPath, szDestPath);
}
else if (!(lpFileOp->fFlags & FOF_FILESONLY && feFrom->bFromWildcard))
copy_dir_to_dir(lpFileOp, feFrom, feTo->szFullPath);
else if (!(op->req->fFlags & FOF_FILESONLY && feFrom->bFromWildcard))
copy_dir_to_dir(op, feFrom, feTo->szFullPath);
}
static void create_dest_dirs(LPWSTR szDestDir)
@ -1113,7 +1174,7 @@ static void create_dest_dirs(LPWSTR szDestDir)
}
/* the FO_COPY operation */
static HRESULT copy_files(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LIST *flTo)
static HRESULT copy_files(FILE_OPERATION *op, FILE_LIST *flFrom, FILE_LIST *flTo)
{
DWORD i;
FILE_ENTRY *entryToCopy;
@ -1123,13 +1184,13 @@ static HRESULT copy_files(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LI
if (flFrom->bAnyDontExist)
return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
if (lpFileOp->fFlags & FOF_MULTIDESTFILES && flFrom->bAnyFromWildcard)
if (op->req->fFlags & FOF_MULTIDESTFILES && flFrom->bAnyFromWildcard)
return ERROR_CANCELLED;
if (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) && flTo->dwNumFiles != 1)
if (!(op->req->fFlags & FOF_MULTIDESTFILES) && flTo->dwNumFiles != 1)
return ERROR_CANCELLED;
if (lpFileOp->fFlags & FOF_MULTIDESTFILES && flFrom->dwNumFiles != 1 &&
if (op->req->fFlags & FOF_MULTIDESTFILES && flFrom->dwNumFiles != 1 &&
flFrom->dwNumFiles != flTo->dwNumFiles)
{
return ERROR_CANCELLED;
@ -1145,11 +1206,11 @@ static HRESULT copy_files(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LI
if (flFrom->dwNumFiles > 1 && flTo->dwNumFiles == 1 && fileDest->bFromRelative &&
!PathFileExistsW(fileDest->szFullPath))
{
lpFileOp->fAnyOperationsAborted = TRUE;
op->req->fAnyOperationsAborted = TRUE;
return ERROR_CANCELLED;
}
if (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) && flFrom->dwNumFiles != 1 &&
if (!(op->req->fFlags & FOF_MULTIDESTFILES) && flFrom->dwNumFiles != 1 &&
PathFileExistsW(fileDest->szFullPath) &&
IsAttribFile(fileDest->attributes))
{
@ -1160,7 +1221,7 @@ static HRESULT copy_files(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LI
{
entryToCopy = &flFrom->feFiles[i];
if (lpFileOp->fFlags & FOF_MULTIDESTFILES)
if (op->req->fFlags & FOF_MULTIDESTFILES)
fileDest = &flTo->feFiles[i];
if (IsAttribDir(entryToCopy->attributes) &&
@ -1185,22 +1246,28 @@ static HRESULT copy_files(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LI
if ((flFrom->dwNumFiles > 1 && flTo->dwNumFiles == 1) ||
(flFrom->dwNumFiles == 1 && IsAttribDir(fileDest->attributes)))
{
copy_to_dir(lpFileOp, entryToCopy, fileDest);
copy_to_dir(op, entryToCopy, fileDest);
}
else if (IsAttribDir(entryToCopy->attributes))
{
copy_dir_to_dir(lpFileOp, entryToCopy, fileDest->szFullPath);
copy_dir_to_dir(op, entryToCopy, fileDest->szFullPath);
}
else
{
if (SHNotifyCopyFileW(entryToCopy->szFullPath, fileDest->szFullPath, TRUE))
if (!copy_file_to_file(op, entryToCopy->szFullPath, fileDest->szFullPath))
{
lpFileOp->fAnyOperationsAborted = TRUE;
op->req->fAnyOperationsAborted = TRUE;
return ERROR_CANCELLED;
}
}
/* Vista return code. XP would return e.g. ERROR_FILE_NOT_FOUND, ERROR_ALREADY_EXISTS */
if (op->bCancelled)
return ERROR_CANCELLED;
}
/* Vista return code. On XP if the used pressed "No" for the last item,
* ERROR_ARENA_TRASHED would be returned */
return ERROR_SUCCESS;
}
@ -1212,16 +1279,16 @@ static BOOL confirm_delete_list(HWND hWnd, DWORD fFlags, BOOL fTrash, FILE_LIST
const WCHAR format[] = {'%','d',0};
wnsprintfW(tmp, sizeof(tmp)/sizeof(tmp[0]), format, flFrom->dwNumFiles);
return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_MULTIPLE_ITEM:ASK_DELETE_MULTIPLE_ITEM), tmp);
return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_MULTIPLE_ITEM:ASK_DELETE_MULTIPLE_ITEM), tmp, NULL);
}
else
{
FILE_ENTRY *fileEntry = &flFrom->feFiles[0];
if (IsAttribFile(fileEntry->attributes))
return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FILE:ASK_DELETE_FILE), fileEntry->szFullPath);
return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FILE:ASK_DELETE_FILE), fileEntry->szFullPath, NULL);
else if (!(fFlags & FOF_FILESONLY && fileEntry->bFromWildcard))
return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FOLDER:ASK_DELETE_FOLDER), fileEntry->szFullPath);
return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FOLDER:ASK_DELETE_FOLDER), fileEntry->szFullPath, NULL);
}
return TRUE;
}
@ -1265,7 +1332,7 @@ static HRESULT delete_files(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom)
/* Note: Windows silently deletes the file in such a situation, we show a dialog */
if (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (lpFileOp->fFlags & FOF_WANTNUKEWARNING))
bDelete = SHELL_ConfirmDialogW(lpFileOp->hwnd, ASK_CANT_TRASH_ITEM, fileEntry->szFullPath);
bDelete = SHELL_ConfirmDialogW(lpFileOp->hwnd, ASK_CANT_TRASH_ITEM, fileEntry->szFullPath, NULL);
else
bDelete = TRUE;
@ -1423,6 +1490,7 @@ static void check_flags(FILEOP_FLAGS fFlags)
*/
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
{
FILE_OPERATION op;
FILE_LIST flFrom, flTo;
int ret = 0;
@ -1440,10 +1508,14 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
if (lpFileOp->wFunc != FO_DELETE)
parse_file_list(&flTo, lpFileOp->pTo);
ZeroMemory(&op, sizeof(op));
op.req = lpFileOp;
op.bManyItems = (flFrom.dwNumFiles > 1);
switch (lpFileOp->wFunc)
{
case FO_COPY:
ret = copy_files(lpFileOp, &flFrom, &flTo);
ret = copy_files(&op, &flFrom, &flTo);
break;
case FO_DELETE:
ret = delete_files(lpFileOp, &flFrom);

View file

@ -92,6 +92,7 @@
#define IDS_TRASHITEM_TEXT 138
#define IDS_TRASHMULTIPLE_TEXT 139
#define IDS_CANTTRASH_TEXT 140
#define IDS_OVERWRITEFOLDER_TEXT 141
/* Note: this string is referenced from the registry*/
#define IDS_RECYCLEBIN_FOLDER_NAME 8964

View file

@ -63,6 +63,21 @@ static BOOL file_exists(const CHAR *name)
return GetFileAttributesA(name) != INVALID_FILE_ATTRIBUTES;
}
static BOOL file_has_content(const CHAR *name, const CHAR *content)
{
CHAR buf[MAX_PATH];
HANDLE file;
DWORD read;
file = CreateFileA(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (file == INVALID_HANDLE_VALUE)
return FALSE;
ReadFile(file, buf, MAX_PATH - 1, &read, NULL);
buf[read] = 0;
CloseHandle(file);
return strcmp(buf, content)==0;
}
/* initializes the tests */
static void init_shfo_tests(void)
{
@ -92,6 +107,7 @@ static void clean_after_shfo_tests(void)
DeleteFileA("test2.txt");
DeleteFileA("test3.txt");
DeleteFileA("test_5.txt");
DeleteFileA("one.txt");
DeleteFileA("test4.txt\\test1.txt");
DeleteFileA("test4.txt\\test2.txt");
DeleteFileA("test4.txt\\test3.txt");
@ -761,6 +777,45 @@ static void test_copy(void)
ok(retval == 1026, "Expected 1026, got %d\n", retval);
ok(!file_exists("nonexistent\\e.txt"), "Expected nonexistent\\e.txt to not exist\n");
ok(!file_exists("nonexistent"), "Expected nonexistent to not exist\n");
/* Overwrite tests */
clean_after_shfo_tests();
init_shfo_tests();
shfo.fFlags = FOF_NOCONFIRMATION;
shfo.pFrom = "test1.txt\0";
shfo.pTo = "test2.txt\0";
shfo.fAnyOperationsAborted = FALSE;
/* without FOF_NOCOFIRMATION the confirmation is Yes/No */
retval = SHFileOperation(&shfo);
ok(retval == 0, "Expected 0, got %d\n", retval);
ok(file_has_content("test2.txt", "test1.txt\n"), "The file was not copied\n");
shfo.pFrom = "test3.txt\0test1.txt\0";
shfo.pTo = "test2.txt\0one.txt\0";
shfo.fFlags = FOF_NOCONFIRMATION | FOF_MULTIDESTFILES;
/* without FOF_NOCOFIRMATION the confirmation is Yes/Yes to All/No/Cancel */
retval = SHFileOperation(&shfo);
ok(retval == 0, "Expected 0, got %d\n", retval);
ok(file_has_content("test2.txt", "test3.txt\n"), "The file was not copied\n");
shfo.pFrom = "one.txt\0";
shfo.pTo = "testdir2\0";
shfo.fFlags = FOF_NOCONFIRMATION;
/* without FOF_NOCOFIRMATION the confirmation is Yes/No */
retval = SHFileOperation(&shfo);
ok(retval == 0, "Expected 0, got %d\n", retval);
ok(file_has_content("testdir2\\one.txt", "test1.txt\n"), "The file was not copied\n");
createTestFile("test4.txt\\test1.txt");
shfo.pFrom = "test4.txt\0";
shfo.pTo = "testdir2\0";
shfo.fFlags = FOF_NOCONFIRMATION;
ok(!SHFileOperation(&shfo), "First SHFileOperation failed\n");
createTestFile("test4.txt\\.\\test1.txt"); /* modify the content of the file */
/* without FOF_NOCOFIRMATION the confirmation is "This folder already contains a folder named ..." */
retval = SHFileOperation(&shfo);
ok(retval == 0, "Expected 0, got %d\n", retval);
ok(file_has_content("testdir2\\test4.txt\\test1.txt", "test4.txt\\.\\test1.txt\n"), "The file was not copied\n");
}
/* tests the FO_MOVE action */