From 33ee219ce3a321c8f986e1bde4d3bb32c6e10096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Zalewski?= Date: Fri, 9 Feb 2007 17:13:25 +0100 Subject: [PATCH] shell32: Allow overwriting files in SHFileOperation(FO_COPY) (with confirmation dialogs). --- dlls/shell32/shell32_Bg.rc | 6 +- dlls/shell32/shell32_Cs.rc | 8 ++- dlls/shell32/shell32_De.rc | 6 +- dlls/shell32/shell32_En.rc | 8 ++- dlls/shell32/shell32_Eo.rc | 7 +- dlls/shell32/shell32_Es.rc | 6 +- dlls/shell32/shell32_Fi.rc | 6 +- dlls/shell32/shell32_Fr.rc | 6 +- dlls/shell32/shell32_It.rc | 6 +- dlls/shell32/shell32_Ko.rc | 6 +- dlls/shell32/shell32_No.rc | 6 +- dlls/shell32/shell32_Pl.rc | 6 +- dlls/shell32/shell32_Pt.rc | 6 +- dlls/shell32/shell32_Ru.rc | 6 +- dlls/shell32/shell32_Tr.rc | 6 +- dlls/shell32/shell32_Uk.rc | 6 +- dlls/shell32/shell32_main.h | 3 +- dlls/shell32/shfldr_unixfs.c | 2 +- dlls/shell32/shlfileop.c | 128 +++++++++++++++++++++++++-------- dlls/shell32/shresdef.h | 1 + dlls/shell32/tests/shlfileop.c | 55 ++++++++++++++ 21 files changed, 241 insertions(+), 49 deletions(-) diff --git a/dlls/shell32/shell32_Bg.rc b/dlls/shell32/shell32_Bg.rc index 100b9b681ea..4c4d16b4878 100644 --- a/dlls/shell32/shell32_Bg.rc +++ b/dlls/shell32/shell32_Bg.rc @@ -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 "Ðåñòàðòèðàíå" diff --git a/dlls/shell32/shell32_Cs.rc b/dlls/shell32/shell32_Cs.rc index 6451dbbf5c9..8790db41045 100644 --- a/dlls/shell32/shell32_Cs.rc +++ b/dlls/shell32/shell32_Cs.rc @@ -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 */ diff --git a/dlls/shell32/shell32_De.rc b/dlls/shell32/shell32_De.rc index bde62bf46c5..d6cb8152ca3 100644 --- a/dlls/shell32/shell32_De.rc +++ b/dlls/shell32/shell32_De.rc @@ -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" diff --git a/dlls/shell32/shell32_En.rc b/dlls/shell32/shell32_En.rc index 09530c6ead8..a67cc8a6f4a 100644 --- a/dlls/shell32/shell32_En.rc +++ b/dlls/shell32/shell32_En.rc @@ -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" diff --git a/dlls/shell32/shell32_Eo.rc b/dlls/shell32/shell32_Eo.rc index e8fa407bd38..980a414bf3d 100644 --- a/dlls/shell32/shell32_Eo.rc +++ b/dlls/shell32/shell32_Eo.rc @@ -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" } - diff --git a/dlls/shell32/shell32_Es.rc b/dlls/shell32/shell32_Es.rc index dd83a6e54fd..c3d2f4c776e 100644 --- a/dlls/shell32/shell32_Es.rc +++ b/dlls/shell32/shell32_Es.rc @@ -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 */ diff --git a/dlls/shell32/shell32_Fi.rc b/dlls/shell32/shell32_Fi.rc index e842bbd5d99..e43a94ed816 100644 --- a/dlls/shell32/shell32_Fi.rc +++ b/dlls/shell32/shell32_Fi.rc @@ -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" diff --git a/dlls/shell32/shell32_Fr.rc b/dlls/shell32/shell32_Fr.rc index 043c66cc042..246045c2165 100644 --- a/dlls/shell32/shell32_Fr.rc +++ b/dlls/shell32/shell32_Fr.rc @@ -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" diff --git a/dlls/shell32/shell32_It.rc b/dlls/shell32/shell32_It.rc index 809f44a5a1f..19f7339055c 100644 --- a/dlls/shell32/shell32_It.rc +++ b/dlls/shell32/shell32_It.rc @@ -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" diff --git a/dlls/shell32/shell32_Ko.rc b/dlls/shell32/shell32_Ko.rc index 413ad7bac1e..bb00f83c4bc 100644 --- a/dlls/shell32/shell32_Ko.rc +++ b/dlls/shell32/shell32_Ko.rc @@ -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 "´Ù½Ã ½ÃÀÛ" diff --git a/dlls/shell32/shell32_No.rc b/dlls/shell32/shell32_No.rc index a7ad4f4b247..c7ec26998a7 100644 --- a/dlls/shell32/shell32_No.rc +++ b/dlls/shell32/shell32_No.rc @@ -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" diff --git a/dlls/shell32/shell32_Pl.rc b/dlls/shell32/shell32_Pl.rc index 60b6a756767..d6139e778a6 100644 --- a/dlls/shell32/shell32_Pl.rc +++ b/dlls/shell32/shell32_Pl.rc @@ -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" diff --git a/dlls/shell32/shell32_Pt.rc b/dlls/shell32/shell32_Pt.rc index 18261624b9b..0a6a274494a 100644 --- a/dlls/shell32/shell32_Pt.rc +++ b/dlls/shell32/shell32_Pt.rc @@ -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" diff --git a/dlls/shell32/shell32_Ru.rc b/dlls/shell32/shell32_Ru.rc index 53baaa90e11..7ed84dc5bbb 100644 --- a/dlls/shell32/shell32_Ru.rc +++ b/dlls/shell32/shell32_Ru.rc @@ -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 "Ïåðåçàãðóçèòü" diff --git a/dlls/shell32/shell32_Tr.rc b/dlls/shell32/shell32_Tr.rc index b41be5301b5..197562ca882 100644 --- a/dlls/shell32/shell32_Tr.rc +++ b/dlls/shell32/shell32_Tr.rc @@ -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" diff --git a/dlls/shell32/shell32_Uk.rc b/dlls/shell32/shell32_Uk.rc index c535ba9c550..a4cf56499cb 100644 --- a/dlls/shell32/shell32_Uk.rc +++ b/dlls/shell32/shell32_Uk.rc @@ -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 */ diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index a17eec499da..29370657e47 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -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); diff --git a/dlls/shell32/shfldr_unixfs.c b/dlls/shell32/shfldr_unixfs.c index 4668afee0cf..a4f4ade3cc3 100644 --- a/dlls/shell32/shfldr_unixfs.c +++ b/dlls/shell32/shfldr_unixfs.c @@ -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); diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c index 0a64531b7d9..07f19e08ca7 100644 --- a/dlls/shell32/shlfileop.c +++ b/dlls/shell32/shlfileop.c @@ -27,6 +27,7 @@ #include #include #include +#include #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); diff --git a/dlls/shell32/shresdef.h b/dlls/shell32/shresdef.h index b9a7bad7c20..dfcd339a750 100644 --- a/dlls/shell32/shresdef.h +++ b/dlls/shell32/shresdef.h @@ -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 diff --git a/dlls/shell32/tests/shlfileop.c b/dlls/shell32/tests/shlfileop.c index 23aaeba79c4..c952baef341 100644 --- a/dlls/shell32/tests/shlfileop.c +++ b/dlls/shell32/tests/shlfileop.c @@ -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 */