From e01d563654abf7279479c6383f29f671f67e8c06 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 27 Feb 2015 02:12:30 +0100 Subject: [PATCH] Added patch for support of shell32 file operation progress dialog. --- README.md | 3 +- debian/changelog | 1 + patches/patchinstall.sh | 34 + ...32-Correct-indentation-in-shfileop.c.patch | 1004 +++++++++++++++++ ...E_INFORMATION-into-SHNotify-function.patch | 527 +++++++++ ...ement-file-operation-progress-dialog.patch | 453 ++++++++ patches/shell32-Progress_Dialog/definition | 2 + ...eturn-value-for-SHFileOperationW-dep.patch | 12 +- patches/shell32-SHFileOperation/definition | 1 + 9 files changed, 2030 insertions(+), 7 deletions(-) create mode 100644 patches/shell32-Progress_Dialog/0001-shell32-Correct-indentation-in-shfileop.c.patch create mode 100644 patches/shell32-Progress_Dialog/0002-shell32-Pass-FILE_INFORMATION-into-SHNotify-function.patch create mode 100644 patches/shell32-Progress_Dialog/0003-shell32-Implement-file-operation-progress-dialog.patch create mode 100644 patches/shell32-Progress_Dialog/definition diff --git a/README.md b/README.md index d32c93a5..5d7140e2 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Wine. All those differences are also documented on the Included bug fixes and improvements =================================== -**Bugfixes and features included in the next upcoming release [7]:** +**Bugfixes and features included in the next upcoming release [8]:** * Add stub for gdiplus.GdipCreateEffect ([Wine Bug #32163](https://bugs.winehq.org/show_bug.cgi?id=32163)) * Add support for CopyFileEx progress callback ([Wine Bug #22692](https://bugs.winehq.org/show_bug.cgi?id=22692)) @@ -47,6 +47,7 @@ Included bug fixes and improvements * Fix race-condition when threads are killed during shutdown * Implement SetFileInformationByHandle * Process Hacker 2.x needs ntoskrnl.ProbeForRead ([Wine Bug #38103](https://bugs.winehq.org/show_bug.cgi?id=38103)) +* Support for shell32 file operation progress dialog **Bugs fixed in Wine Staging 1.7.37 [182]:** diff --git a/debian/changelog b/debian/changelog index 786d6a3c..ef287aef 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,7 @@ wine-staging (1.7.38) UNRELEASED; urgency=low * Added first set of patches for job objects (by Andrew Cook). * Added patch for stub of gdiplus.GdipCreateEffect. * Added patches for ntoskrnl.ProbeFor{Read,Write}. + * Added patch for support of shell32 file operation progress dialog. * Removed patch to properly call DriverUnload when unloading device drivers (accepted upstream). * Removed patch to allow Accept-Encoding for HTTP/1.0 in wininet (accepted upstream). * Removed patch to declare pDirectInputCreateEx in a MSVC compatible way (accepted upstream). diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 9442ab71..fc5112eb 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -167,6 +167,7 @@ patch_enable_all () enable_shell32_Default_Folder_ACLs="$1" enable_shell32_Default_Path="$1" enable_shell32_Icons="$1" + enable_shell32_Progress_Dialog="$1" enable_shell32_Quoted_ShellExecute="$1" enable_shell32_RunDLL_CallEntry16="$1" enable_shell32_SHCreateSessionKey="$1" @@ -534,6 +535,9 @@ patch_enable () shell32-Icons) enable_shell32_Icons="$2" ;; + shell32-Progress_Dialog) + enable_shell32_Progress_Dialog="$2" + ;; shell32-Quoted_ShellExecute) enable_shell32_Quoted_ShellExecute="$2" ;; @@ -889,6 +893,20 @@ patch_apply () } +if test "$enable_shell32_SHFileOperation" -eq 1; then + if test "$enable_shell32_Progress_Dialog" -gt 1; then + abort "Patchset shell32-Progress_Dialog disabled, but shell32-SHFileOperation depends on that." + fi + enable_shell32_Progress_Dialog=1 +fi + +if test "$enable_shell32_Progress_Dialog" -eq 1; then + if test "$enable_kernel32_CopyFileEx" -gt 1; then + abort "Patchset kernel32-CopyFileEx disabled, but shell32-Progress_Dialog depends on that." + fi + enable_kernel32_CopyFileEx=1 +fi + if test "$enable_server_ACL_Compat" -eq 1; then if test "$enable_server_Inherited_ACLs" -gt 1; then abort "Patchset server-Inherited_ACLs disabled, but server-ACL_Compat depends on that." @@ -3410,6 +3428,22 @@ if test "$enable_shell32_Icons" -eq 1; then ) >> "$patchlist" fi +# Patchset shell32-Progress_Dialog +# | +# | Modified files: +# | * dlls/shell32/shell32.rc, dlls/shell32/shlfileop.c, dlls/shell32/shresdef.h +# | +if test "$enable_shell32_Progress_Dialog" -eq 1; then + patch_apply shell32-Progress_Dialog/0001-shell32-Correct-indentation-in-shfileop.c.patch + patch_apply shell32-Progress_Dialog/0002-shell32-Pass-FILE_INFORMATION-into-SHNotify-function.patch + patch_apply shell32-Progress_Dialog/0003-shell32-Implement-file-operation-progress-dialog.patch + ( + echo '+ { "Michael Müller", "shell32: Correct indentation in shfileop.c.", 1 },'; + echo '+ { "Michael Müller", "shell32: Pass FILE_INFORMATION into SHNotify* functions.", 1 },'; + echo '+ { "Michael Müller", "shell32: Implement file operation progress dialog.", 1 },'; + ) >> "$patchlist" +fi + # Patchset shell32-Quoted_ShellExecute # | # | This patchset fixes the following Wine bugs: diff --git a/patches/shell32-Progress_Dialog/0001-shell32-Correct-indentation-in-shfileop.c.patch b/patches/shell32-Progress_Dialog/0001-shell32-Correct-indentation-in-shfileop.c.patch new file mode 100644 index 00000000..c9866618 --- /dev/null +++ b/patches/shell32-Progress_Dialog/0001-shell32-Correct-indentation-in-shfileop.c.patch @@ -0,0 +1,1004 @@ +From 46894941581a7d408983d55039308e03f2842b7a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Tue, 24 Feb 2015 04:25:29 +0100 +Subject: shell32: Correct indentation in shfileop.c. + +--- + dlls/shell32/shlfileop.c | 730 +++++++++++++++++++++++------------------------ + 1 file changed, 365 insertions(+), 365 deletions(-) + +diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c +index 62d7880..ee40e39 100644 +--- a/dlls/shell32/shlfileop.c ++++ b/dlls/shell32/shlfileop.c +@@ -164,7 +164,7 @@ static INT_PTR ConfirmMsgBox_Init(HWND hDlg, LPARAM lParam) + width = r.right - r.left; + height = r.bottom - r.top - yOffset; + MoveWindow(hDlg, (GetSystemMetrics(SM_CXSCREEN) - width)/2, +- (GetSystemMetrics(SM_CYSCREEN) - height)/2, width, height, FALSE); ++ (GetSystemMetrics(SM_CYSCREEN) - height)/2, width, height, FALSE); + + confirm_msg_move_button(hDlg, IDCANCEL, &xPos, yOffset, info->bYesToAll); + confirm_msg_move_button(hDlg, IDNO, &xPos, yOffset, TRUE); +@@ -206,107 +206,107 @@ static int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, H + /* confirmation dialogs content */ + typedef struct + { +- HINSTANCE hIconInstance; +- UINT icon_resource_id; +- UINT caption_resource_id, text_resource_id; ++ HINSTANCE hIconInstance; ++ UINT icon_resource_id; ++ UINT caption_resource_id, text_resource_id; + } SHELL_ConfirmIDstruc; + + static BOOL SHELL_ConfirmIDs(int nKindOfDialog, SHELL_ConfirmIDstruc *ids) + { +- ids->hIconInstance = shell32_hInstance; +- switch (nKindOfDialog) { +- case ASK_DELETE_FILE: ++ ids->hIconInstance = shell32_hInstance; ++ switch (nKindOfDialog) { ++ case ASK_DELETE_FILE: + ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE; +- ids->caption_resource_id = IDS_DELETEITEM_CAPTION; +- ids->text_resource_id = IDS_DELETEITEM_TEXT; +- return TRUE; +- case ASK_DELETE_FOLDER: ++ ids->caption_resource_id = IDS_DELETEITEM_CAPTION; ++ ids->text_resource_id = IDS_DELETEITEM_TEXT; ++ return TRUE; ++ case ASK_DELETE_FOLDER: + ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE; +- ids->caption_resource_id = IDS_DELETEFOLDER_CAPTION; +- ids->text_resource_id = IDS_DELETEITEM_TEXT; +- return TRUE; +- case ASK_DELETE_MULTIPLE_ITEM: ++ ids->caption_resource_id = IDS_DELETEFOLDER_CAPTION; ++ ids->text_resource_id = IDS_DELETEITEM_TEXT; ++ return TRUE; ++ case ASK_DELETE_MULTIPLE_ITEM: + ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE; +- ids->caption_resource_id = IDS_DELETEITEM_CAPTION; +- ids->text_resource_id = IDS_DELETEMULTIPLE_TEXT; +- return TRUE; +- case ASK_TRASH_FILE: ++ ids->caption_resource_id = IDS_DELETEITEM_CAPTION; ++ ids->text_resource_id = IDS_DELETEMULTIPLE_TEXT; ++ return TRUE; ++ case ASK_TRASH_FILE: + ids->icon_resource_id = IDI_SHELL_TRASH_FILE; + ids->caption_resource_id = IDS_DELETEITEM_CAPTION; + ids->text_resource_id = IDS_TRASHITEM_TEXT; + return TRUE; +- case ASK_TRASH_FOLDER: ++ case ASK_TRASH_FOLDER: + ids->icon_resource_id = IDI_SHELL_TRASH_FILE; + ids->caption_resource_id = IDS_DELETEFOLDER_CAPTION; + ids->text_resource_id = IDS_TRASHFOLDER_TEXT; + return TRUE; +- case ASK_TRASH_MULTIPLE_ITEM: ++ case ASK_TRASH_MULTIPLE_ITEM: + ids->icon_resource_id = IDI_SHELL_TRASH_FILE; + ids->caption_resource_id = IDS_DELETEITEM_CAPTION; + ids->text_resource_id = IDS_TRASHMULTIPLE_TEXT; + return TRUE; +- case ASK_CANT_TRASH_ITEM: ++ case ASK_CANT_TRASH_ITEM: + ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE; + ids->caption_resource_id = IDS_DELETEITEM_CAPTION; + ids->text_resource_id = IDS_CANTTRASH_TEXT; + return TRUE; +- case ASK_DELETE_SELECTED: ++ case ASK_DELETE_SELECTED: + ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE; + ids->caption_resource_id = IDS_DELETEITEM_CAPTION; + ids->text_resource_id = IDS_DELETESELECTED_TEXT; + return TRUE; +- case ASK_OVERWRITE_FILE: ++ case ASK_OVERWRITE_FILE: + ids->hIconInstance = NULL; + ids->icon_resource_id = IDI_WARNING; +- ids->caption_resource_id = IDS_OVERWRITEFILE_CAPTION; +- ids->text_resource_id = IDS_OVERWRITEFILE_TEXT; ++ ids->caption_resource_id = IDS_OVERWRITEFILE_CAPTION; ++ ids->text_resource_id = IDS_OVERWRITEFILE_TEXT; + return TRUE; +- case ASK_OVERWRITE_FOLDER: ++ 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; ++ default: ++ FIXME(" Unhandled nKindOfDialog %d stub\n", nKindOfDialog); ++ } ++ return FALSE; + } + + 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; +- +- assert(nKindOfDialog >= 0 && nKindOfDialog < 32); +- if (op && (op->dwYesToAllMask & (1 << nKindOfDialog))) +- return TRUE; ++ 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 TRUE; + +- LoadStringW(shell32_hInstance, ids.caption_resource_id, szCaption, sizeof(szCaption)/sizeof(WCHAR)); +- LoadStringW(shell32_hInstance, ids.text_resource_id, szText, sizeof(szText)/sizeof(WCHAR)); ++ if (!SHELL_ConfirmIDs(nKindOfDialog, &ids)) return FALSE; + +- args[0] = (DWORD_PTR)szDir; +- FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, +- szText, 0, 0, szBuffer, sizeof(szBuffer), (__ms_va_list*)args); +- hIcon = LoadIconW(ids.hIconInstance, (LPWSTR)MAKEINTRESOURCE(ids.icon_resource_id)); ++ LoadStringW(shell32_hInstance, ids.caption_resource_id, szCaption, sizeof(szCaption)/sizeof(WCHAR)); ++ LoadStringW(shell32_hInstance, ids.text_resource_id, szText, sizeof(szText)/sizeof(WCHAR)); + +- 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; ++ args[0] = (DWORD_PTR)szDir; ++ FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, ++ szText, 0, 0, szBuffer, sizeof(szBuffer), (__ms_va_list*)args); ++ hIcon = LoadIconW(ids.hIconInstance, (LPWSTR)MAKEINTRESOURCE(ids.icon_resource_id)); ++ ++ ret = SHELL_ConfirmMsgBox(hWnd, szBuffer, szCaption, hIcon, op && op->bManyItems); ++ if (op) { ++ if (ret == IDD_YESTOALL) { ++ op->dwYesToAllMask |= (1 << nKindOfDialog); ++ ret = IDYES; + } +- return 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) +@@ -316,23 +316,23 @@ BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir) + + static DWORD SHELL32_AnsiToUnicodeBuf(LPCSTR aPath, LPWSTR *wPath, DWORD minChars) + { +- DWORD len = MultiByteToWideChar(CP_ACP, 0, aPath, -1, NULL, 0); +- +- if (len < minChars) +- len = minChars; +- +- *wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); +- if (*wPath) +- { +- MultiByteToWideChar(CP_ACP, 0, aPath, -1, *wPath, len); +- return NO_ERROR; +- } +- return E_OUTOFMEMORY; ++ DWORD len = MultiByteToWideChar(CP_ACP, 0, aPath, -1, NULL, 0); ++ ++ if (len < minChars) ++ len = minChars; ++ ++ *wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); ++ if (*wPath) ++ { ++ MultiByteToWideChar(CP_ACP, 0, aPath, -1, *wPath, len); ++ return NO_ERROR; ++ } ++ return E_OUTOFMEMORY; + } + + static void SHELL32_FreeUnicodeBuf(LPWSTR wPath) + { +- HeapFree(GetProcessHeap(), 0, wPath); ++ HeapFree(GetProcessHeap(), 0, wPath); + } + + HRESULT WINAPI SHIsFileAvailableOffline(LPCWSTR path, LPDWORD status) +@@ -375,8 +375,8 @@ static DWORD SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI) + ret = SHNotifyRemoveDirectoryW(pszDir); + + return ret == ERROR_PATH_NOT_FOUND ? +- 0x7C: /* DE_INVALIDFILES (legacy Windows error) */ +- ret; ++ 0x7C: /* DE_INVALIDFILES (legacy Windows error) */ ++ ret; + } + + /************************************************************************** +@@ -396,41 +396,41 @@ static DWORD SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI) + */ + static DWORD SHNotifyCreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec) + { +- LPWSTR wPath; +- DWORD retCode; +- +- TRACE("(%s, %p)\n", debugstr_a(path), sec); +- +- retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); +- if (!retCode) +- { +- retCode = SHNotifyCreateDirectoryW(wPath, sec); +- SHELL32_FreeUnicodeBuf(wPath); +- } +- return retCode; ++ LPWSTR wPath; ++ DWORD retCode; ++ ++ TRACE("(%s, %p)\n", debugstr_a(path), sec); ++ ++ retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); ++ if (!retCode) ++ { ++ retCode = SHNotifyCreateDirectoryW(wPath, sec); ++ SHELL32_FreeUnicodeBuf(wPath); ++ } ++ return retCode; + } + + /**********************************************************************/ + + static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec) + { +- TRACE("(%s, %p)\n", debugstr_w(path), sec); +- +- if (CreateDirectoryW(path, sec)) +- { +- SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, path, NULL); +- return ERROR_SUCCESS; +- } +- return GetLastError(); ++ TRACE("(%s, %p)\n", debugstr_w(path), sec); ++ ++ if (CreateDirectoryW(path, sec)) ++ { ++ SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, path, NULL); ++ return ERROR_SUCCESS; ++ } ++ return GetLastError(); + } + + /**********************************************************************/ + + BOOL WINAPI Win32CreateDirectoryAW(LPCVOID path, LPSECURITY_ATTRIBUTES sec) + { +- if (SHELL_OsIsUnicode()) +- return (SHNotifyCreateDirectoryW(path, sec) == ERROR_SUCCESS); +- return (SHNotifyCreateDirectoryA(path, sec) == ERROR_SUCCESS); ++ if (SHELL_OsIsUnicode()) ++ return (SHNotifyCreateDirectoryW(path, sec) == ERROR_SUCCESS); ++ return (SHNotifyCreateDirectoryA(path, sec) == ERROR_SUCCESS); + } + + /************************************************************************ +@@ -450,51 +450,51 @@ BOOL WINAPI Win32CreateDirectoryAW(LPCVOID path, LPSECURITY_ATTRIBUTES sec) + */ + static DWORD SHNotifyRemoveDirectoryA(LPCSTR path) + { +- LPWSTR wPath; +- DWORD retCode; +- +- TRACE("(%s)\n", debugstr_a(path)); +- +- retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); +- if (!retCode) +- { +- retCode = SHNotifyRemoveDirectoryW(wPath); +- SHELL32_FreeUnicodeBuf(wPath); +- } +- return retCode; ++ LPWSTR wPath; ++ DWORD retCode; ++ ++ TRACE("(%s)\n", debugstr_a(path)); ++ ++ retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); ++ if (!retCode) ++ { ++ retCode = SHNotifyRemoveDirectoryW(wPath); ++ SHELL32_FreeUnicodeBuf(wPath); ++ } ++ return retCode; + } + + /***********************************************************************/ + + static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path) + { +- BOOL ret; +- TRACE("(%s)\n", debugstr_w(path)); +- +- ret = RemoveDirectoryW(path); +- if (!ret) +- { +- /* Directory may be write protected */ +- DWORD dwAttr = GetFileAttributesW(path); +- if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY)) +- if (SetFileAttributesW(path, dwAttr & ~FILE_ATTRIBUTE_READONLY)) +- ret = RemoveDirectoryW(path); +- } +- if (ret) +- { +- SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW, path, NULL); +- return ERROR_SUCCESS; +- } +- return GetLastError(); ++ BOOL ret; ++ TRACE("(%s)\n", debugstr_w(path)); ++ ++ ret = RemoveDirectoryW(path); ++ if (!ret) ++ { ++ /* Directory may be write protected */ ++ DWORD dwAttr = GetFileAttributesW(path); ++ if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY)) ++ if (SetFileAttributesW(path, dwAttr & ~FILE_ATTRIBUTE_READONLY)) ++ ret = RemoveDirectoryW(path); ++ } ++ if (ret) ++ { ++ SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW, path, NULL); ++ return ERROR_SUCCESS; ++ } ++ return GetLastError(); + } + + /***********************************************************************/ + + BOOL WINAPI Win32RemoveDirectoryAW(LPCVOID path) + { +- if (SHELL_OsIsUnicode()) +- return (SHNotifyRemoveDirectoryW(path) == ERROR_SUCCESS); +- return (SHNotifyRemoveDirectoryA(path) == ERROR_SUCCESS); ++ if (SHELL_OsIsUnicode()) ++ return (SHNotifyRemoveDirectoryW(path) == ERROR_SUCCESS); ++ return (SHNotifyRemoveDirectoryA(path) == ERROR_SUCCESS); + } + + /************************************************************************ +@@ -514,52 +514,52 @@ BOOL WINAPI Win32RemoveDirectoryAW(LPCVOID path) + */ + static DWORD SHNotifyDeleteFileA(LPCSTR path) + { +- LPWSTR wPath; +- DWORD retCode; +- +- TRACE("(%s)\n", debugstr_a(path)); +- +- retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); +- if (!retCode) +- { +- retCode = SHNotifyDeleteFileW(wPath); +- SHELL32_FreeUnicodeBuf(wPath); +- } +- return retCode; ++ LPWSTR wPath; ++ DWORD retCode; ++ ++ TRACE("(%s)\n", debugstr_a(path)); ++ ++ retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); ++ if (!retCode) ++ { ++ retCode = SHNotifyDeleteFileW(wPath); ++ SHELL32_FreeUnicodeBuf(wPath); ++ } ++ return retCode; + } + + /***********************************************************************/ + + static DWORD SHNotifyDeleteFileW(LPCWSTR path) + { +- BOOL ret; +- +- TRACE("(%s)\n", debugstr_w(path)); +- +- ret = DeleteFileW(path); +- if (!ret) +- { +- /* File may be write protected or a system file */ +- DWORD dwAttr = GetFileAttributesW(path); +- if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)) +- if (SetFileAttributesW(path, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))) +- ret = DeleteFileW(path); +- } +- if (ret) +- { +- SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, path, NULL); +- return ERROR_SUCCESS; +- } +- return GetLastError(); ++ BOOL ret; ++ ++ TRACE("(%s)\n", debugstr_w(path)); ++ ++ ret = DeleteFileW(path); ++ if (!ret) ++ { ++ /* File may be write protected or a system file */ ++ DWORD dwAttr = GetFileAttributesW(path); ++ if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)) ++ if (SetFileAttributesW(path, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))) ++ ret = DeleteFileW(path); ++ } ++ if (ret) ++ { ++ SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, path, NULL); ++ return ERROR_SUCCESS; ++ } ++ return GetLastError(); + } + + /***********************************************************************/ + + DWORD WINAPI Win32DeleteFileAW(LPCVOID path) + { +- if (SHELL_OsIsUnicode()) +- return (SHNotifyDeleteFileW(path) == ERROR_SUCCESS); +- return (SHNotifyDeleteFileA(path) == ERROR_SUCCESS); ++ if (SHELL_OsIsUnicode()) ++ return (SHNotifyDeleteFileW(path) == ERROR_SUCCESS); ++ return (SHNotifyDeleteFileA(path) == ERROR_SUCCESS); + } + + /************************************************************************ +@@ -576,36 +576,36 @@ DWORD WINAPI Win32DeleteFileAW(LPCVOID path) + */ + static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest) + { +- BOOL ret; +- +- TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest)); +- +- ret = MoveFileExW(src, dest, MOVEFILE_REPLACE_EXISTING); +- +- /* MOVEFILE_REPLACE_EXISTING fails with dirs, so try MoveFile */ +- if (!ret) +- ret = MoveFileW(src, dest); +- +- if (!ret) +- { +- DWORD dwAttr; +- +- dwAttr = SHFindAttrW(dest, FALSE); +- if (INVALID_FILE_ATTRIBUTES == dwAttr) +- { +- /* Source file may be write protected or a system file */ +- dwAttr = GetFileAttributesW(src); +- if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)) +- if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))) +- ret = MoveFileW(src, dest); +- } +- } +- if (ret) +- { +- SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATHW, src, dest); +- return ERROR_SUCCESS; +- } +- return GetLastError(); ++ BOOL ret; ++ ++ TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest)); ++ ++ ret = MoveFileExW(src, dest, MOVEFILE_REPLACE_EXISTING); ++ ++ /* MOVEFILE_REPLACE_EXISTING fails with dirs, so try MoveFile */ ++ if (!ret) ++ ret = MoveFileW(src, dest); ++ ++ if (!ret) ++ { ++ DWORD dwAttr; ++ ++ dwAttr = SHFindAttrW(dest, FALSE); ++ if (INVALID_FILE_ATTRIBUTES == dwAttr) ++ { ++ /* Source file may be write protected or a system file */ ++ dwAttr = GetFileAttributesW(src); ++ if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)) ++ if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))) ++ ret = MoveFileW(src, dest); ++ } ++ } ++ if (ret) ++ { ++ SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATHW, src, dest); ++ return ERROR_SUCCESS; ++ } ++ return GetLastError(); + } + + /************************************************************************ +@@ -624,24 +624,24 @@ static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest) + */ + static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists) + { +- BOOL ret; +- DWORD attribs; ++ BOOL ret; ++ DWORD attribs; + +- TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : ""); ++ TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : ""); + +- /* Destination file may already exist with read only attribute */ +- attribs = GetFileAttributesW(dest); +- if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY)) +- SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY); ++ /* Destination file may already exist with read only attribute */ ++ attribs = GetFileAttributesW(dest); ++ if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY)) ++ SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY); + +- ret = CopyFileW(src, dest, bFailIfExists); +- if (ret) +- { +- SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, dest, NULL); +- return ERROR_SUCCESS; +- } ++ ret = CopyFileW(src, dest, bFailIfExists); ++ if (ret) ++ { ++ SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, dest, NULL); ++ return ERROR_SUCCESS; ++ } + +- return GetLastError(); ++ return GetLastError(); + } + + /************************************************************************* +@@ -671,9 +671,9 @@ static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists) + */ + DWORD WINAPI SHCreateDirectory(HWND hWnd, LPCVOID path) + { +- if (SHELL_OsIsUnicode()) +- return SHCreateDirectoryExW(hWnd, path, NULL); +- return SHCreateDirectoryExA(hWnd, path, NULL); ++ if (SHELL_OsIsUnicode()) ++ return SHCreateDirectoryExW(hWnd, path, NULL); ++ return SHCreateDirectoryExA(hWnd, path, NULL); + } + + /************************************************************************* +@@ -710,18 +710,18 @@ DWORD WINAPI SHCreateDirectory(HWND hWnd, LPCVOID path) + */ + int WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES sec) + { +- LPWSTR wPath; +- DWORD retCode; +- +- TRACE("(%s, %p)\n", debugstr_a(path), sec); +- +- retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); +- if (!retCode) +- { +- retCode = SHCreateDirectoryExW(hWnd, wPath, sec); +- SHELL32_FreeUnicodeBuf(wPath); +- } +- return retCode; ++ LPWSTR wPath; ++ DWORD retCode; ++ ++ TRACE("(%s, %p)\n", debugstr_a(path), sec); ++ ++ retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); ++ if (!retCode) ++ { ++ retCode = SHCreateDirectoryExW(hWnd, wPath, sec); ++ SHELL32_FreeUnicodeBuf(wPath); ++ } ++ return retCode; + } + + /************************************************************************* +@@ -731,49 +731,49 @@ int WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES se + */ + int WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec) + { +- int ret = ERROR_BAD_PATHNAME; +- TRACE("(%p, %s, %p)\n", hWnd, debugstr_w(path), sec); +- +- if (PathIsRelativeW(path)) +- { +- SetLastError(ret); +- } +- else +- { +- ret = SHNotifyCreateDirectoryW(path, sec); +- /* Refuse to work on certain error codes before trying to create directories recursively */ +- if (ret != ERROR_SUCCESS && +- ret != ERROR_FILE_EXISTS && +- ret != ERROR_ALREADY_EXISTS && +- ret != ERROR_FILENAME_EXCED_RANGE) +- { +- WCHAR *pEnd, *pSlash, szTemp[MAX_PATH + 1]; /* extra for PathAddBackslash() */ +- +- lstrcpynW(szTemp, path, MAX_PATH); +- pEnd = PathAddBackslashW(szTemp); +- pSlash = szTemp + 3; +- +- while (*pSlash) +- { +- while (*pSlash && *pSlash != '\\') pSlash++; +- if (*pSlash) +- { +- *pSlash = 0; /* terminate path at separator */ +- +- ret = SHNotifyCreateDirectoryW(szTemp, pSlash + 1 == pEnd ? sec : NULL); +- } +- *pSlash++ = '\\'; /* put the separator back */ +- } +- } +- +- if (ret && hWnd && (ERROR_CANCELLED != ret)) +- { +- /* We failed and should show a dialog box */ +- FIXME("Show system error message, creating path %s, failed with error %d\n", debugstr_w(path), ret); +- ret = ERROR_CANCELLED; /* Error has been already presented to user (not really yet!) */ +- } +- } +- return ret; ++ int ret = ERROR_BAD_PATHNAME; ++ TRACE("(%p, %s, %p)\n", hWnd, debugstr_w(path), sec); ++ ++ if (PathIsRelativeW(path)) ++ { ++ SetLastError(ret); ++ } ++ else ++ { ++ ret = SHNotifyCreateDirectoryW(path, sec); ++ /* Refuse to work on certain error codes before trying to create directories recursively */ ++ if (ret != ERROR_SUCCESS && ++ ret != ERROR_FILE_EXISTS && ++ ret != ERROR_ALREADY_EXISTS && ++ ret != ERROR_FILENAME_EXCED_RANGE) ++ { ++ WCHAR *pEnd, *pSlash, szTemp[MAX_PATH + 1]; /* extra for PathAddBackslash() */ ++ ++ lstrcpynW(szTemp, path, MAX_PATH); ++ pEnd = PathAddBackslashW(szTemp); ++ pSlash = szTemp + 3; ++ ++ while (*pSlash) ++ { ++ while (*pSlash && *pSlash != '\\') pSlash++; ++ if (*pSlash) ++ { ++ *pSlash = 0; /* terminate path at separator */ ++ ++ ret = SHNotifyCreateDirectoryW(szTemp, pSlash + 1 == pEnd ? sec : NULL); ++ } ++ *pSlash++ = '\\'; /* put the separator back */ ++ } ++ } ++ ++ if (ret && hWnd && (ERROR_CANCELLED != ret)) ++ { ++ /* We failed and should show a dialog box */ ++ FIXME("Show system error message, creating path %s, failed with error %d\n", debugstr_w(path), ret); ++ ret = ERROR_CANCELLED; /* Error has been already presented to user (not really yet!) */ ++ } ++ } ++ return ret; + } + + /************************************************************************* +@@ -793,25 +793,25 @@ int WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES s + */ + static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly) + { +- WIN32_FIND_DATAW wfd; +- BOOL b_FileMask = fileOnly && (NULL != StrPBrkW(pName, wWildcardChars)); +- DWORD dwAttr = INVALID_FILE_ATTRIBUTES; +- HANDLE hFind = FindFirstFileW(pName, &wfd); +- +- TRACE("%s %d\n", debugstr_w(pName), fileOnly); +- if (INVALID_HANDLE_VALUE != hFind) +- { +- do +- { +- if (b_FileMask && IsAttribDir(wfd.dwFileAttributes)) +- continue; +- dwAttr = wfd.dwFileAttributes; +- break; +- } +- while (FindNextFileW(hFind, &wfd)); +- FindClose(hFind); +- } +- return dwAttr; ++ WIN32_FIND_DATAW wfd; ++ BOOL b_FileMask = fileOnly && (NULL != StrPBrkW(pName, wWildcardChars)); ++ DWORD dwAttr = INVALID_FILE_ATTRIBUTES; ++ HANDLE hFind = FindFirstFileW(pName, &wfd); ++ ++ TRACE("%s %d\n", debugstr_w(pName), fileOnly); ++ if (INVALID_HANDLE_VALUE != hFind) ++ { ++ do ++ { ++ if (b_FileMask && IsAttribDir(wfd.dwFileAttributes)) ++ continue; ++ dwAttr = wfd.dwFileAttributes; ++ break; ++ } ++ while (FindNextFileW(hFind, &wfd)); ++ FindClose(hFind); ++ } ++ return dwAttr; + } + + /************************************************************************* +@@ -825,27 +825,27 @@ static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly) + */ + static DWORD SHNameTranslate(LPWSTR* wString, LPCWSTR* pWToFrom, BOOL more) + { +- DWORD size = 0, aSize = 0; +- LPCSTR aString = (LPCSTR)*pWToFrom; +- +- if (aString) +- { +- do +- { +- size = lstrlenA(aString) + 1; +- aSize += size; +- aString += size; +- } while ((size != 1) && more); +- /* The two sizes might be different in the case of multibyte chars */ +- size = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, 0); +- if (*wString) /* only in the second loop */ +- { +- MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, size); +- *pWToFrom = *wString; +- *wString += size; +- } +- } +- return size; ++ DWORD size = 0, aSize = 0; ++ LPCSTR aString = (LPCSTR)*pWToFrom; ++ ++ if (aString) ++ { ++ do ++ { ++ size = lstrlenA(aString) + 1; ++ aSize += size; ++ aString += size; ++ } while ((size != 1) && more); ++ /* The two sizes might be different in the case of multibyte chars */ ++ size = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, 0); ++ if (*wString) /* only in the second loop */ ++ { ++ MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, size); ++ *pWToFrom = *wString; ++ *wString += size; ++ } ++ } ++ return size; + } + /************************************************************************* + * SHFileOperationA [SHELL32.@] +@@ -865,43 +865,43 @@ static DWORD SHNameTranslate(LPWSTR* wString, LPCWSTR* pWToFrom, BOOL more) + */ + int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp) + { +- SHFILEOPSTRUCTW nFileOp = *((LPSHFILEOPSTRUCTW)lpFileOp); +- int retCode = 0; +- DWORD size; +- LPWSTR ForFree = NULL, /* we change wString in SHNameTranslate and can't use it for freeing */ +- wString = NULL; /* we change this in SHNameTranslate */ +- +- TRACE("\n"); +- if (FO_DELETE == (nFileOp.wFunc & FO_MASK)) +- nFileOp.pTo = NULL; /* we need a NULL or a valid pointer for translation */ +- if (!(nFileOp.fFlags & FOF_SIMPLEPROGRESS)) +- nFileOp.lpszProgressTitle = NULL; /* we need a NULL or a valid pointer for translation */ +- while (1) /* every loop calculate size, second translate also, if we have storage for this */ +- { +- size = SHNameTranslate(&wString, &nFileOp.lpszProgressTitle, FALSE); /* no loop */ +- size += SHNameTranslate(&wString, &nFileOp.pFrom, TRUE); /* internal loop */ +- size += SHNameTranslate(&wString, &nFileOp.pTo, TRUE); /* internal loop */ +- +- if (ForFree) +- { +- retCode = SHFileOperationW(&nFileOp); +- HeapFree(GetProcessHeap(), 0, ForFree); /* we cannot use wString, it was changed */ +- break; +- } +- else +- { +- wString = ForFree = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); +- if (ForFree) continue; +- retCode = ERROR_OUTOFMEMORY; +- nFileOp.fAnyOperationsAborted = TRUE; +- SetLastError(retCode); +- return retCode; +- } +- } +- +- lpFileOp->hNameMappings = nFileOp.hNameMappings; +- lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted; +- return retCode; ++ SHFILEOPSTRUCTW nFileOp = *((LPSHFILEOPSTRUCTW)lpFileOp); ++ int retCode = 0; ++ DWORD size; ++ LPWSTR ForFree = NULL, /* we change wString in SHNameTranslate and can't use it for freeing */ ++ wString = NULL; /* we change this in SHNameTranslate */ ++ ++ TRACE("\n"); ++ if (FO_DELETE == (nFileOp.wFunc & FO_MASK)) ++ nFileOp.pTo = NULL; /* we need a NULL or a valid pointer for translation */ ++ if (!(nFileOp.fFlags & FOF_SIMPLEPROGRESS)) ++ nFileOp.lpszProgressTitle = NULL; /* we need a NULL or a valid pointer for translation */ ++ while (1) /* every loop calculate size, second translate also, if we have storage for this */ ++ { ++ size = SHNameTranslate(&wString, &nFileOp.lpszProgressTitle, FALSE); /* no loop */ ++ size += SHNameTranslate(&wString, &nFileOp.pFrom, TRUE); /* internal loop */ ++ size += SHNameTranslate(&wString, &nFileOp.pTo, TRUE); /* internal loop */ ++ ++ if (ForFree) ++ { ++ retCode = SHFileOperationW(&nFileOp); ++ HeapFree(GetProcessHeap(), 0, ForFree); /* we cannot use wString, it was changed */ ++ break; ++ } ++ else ++ { ++ wString = ForFree = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); ++ if (ForFree) continue; ++ retCode = ERROR_OUTOFMEMORY; ++ nFileOp.fAnyOperationsAborted = TRUE; ++ SetLastError(retCode); ++ return retCode; ++ } ++ } ++ ++ lpFileOp->hNameMappings = nFileOp.hNameMappings; ++ lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted; ++ return retCode; + } + + #define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026 +@@ -931,7 +931,7 @@ typedef struct + static inline void grow_list(FILE_LIST *list) + { + FILE_ENTRY *new = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list->feFiles, +- list->num_alloc * 2 * sizeof(*new) ); ++ list->num_alloc * 2 * sizeof(*new) ); + list->feFiles = new; + list->num_alloc *= 2; + } +@@ -1023,7 +1023,7 @@ static HRESULT parse_file_list(FILE_LIST *flList, LPCWSTR szFiles) + /* empty list */ + if (!szFiles[0]) + return ERROR_ACCESS_DENIED; +- ++ + flList->feFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + flList->num_alloc * sizeof(FILE_ENTRY)); + +@@ -1127,7 +1127,7 @@ static void copy_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWST + /* 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; ++ fileOp.fFlags |= FOF_NOCONFIRMATION; + + SHFileOperationW(&fileOp); + } +@@ -1339,7 +1339,7 @@ static DWORD delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom) + + /* Windows also checks only the first item */ + bTrash = (lpFileOp->fFlags & FOF_ALLOWUNDO) +- && TRASH_CanTrashFile(flFrom->feFiles[0].szFullPath); ++ && TRASH_CanTrashFile(flFrom->feFiles[0].szFullPath); + + if (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (!bTrash && lpFileOp->fFlags & FOF_WANTNUKEWARNING)) + if (!confirm_delete_list(lpFileOp->hwnd, lpFileOp->fFlags, bTrash, flFrom)) +@@ -1374,11 +1374,11 @@ static DWORD delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom) + break; + } + } +- ++ + /* delete the file or directory */ + if (IsAttribFile(fileEntry->attributes)) + ret = DeleteFileW(fileEntry->szFullPath) ? +- ERROR_SUCCESS : GetLastError(); ++ ERROR_SUCCESS : GetLastError(); + else + ret = SHELL_DeleteDirectoryW(lpFileOp->hwnd, fileEntry->szFullPath, FALSE); + +@@ -1528,8 +1528,8 @@ static DWORD rename_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, c + static void check_flags(FILEOP_FLAGS fFlags) + { + WORD wUnsupportedFlags = FOF_NO_CONNECTED_ELEMENTS | +- FOF_NOCOPYSECURITYATTRIBS | FOF_NORECURSEREPARSE | +- FOF_RENAMEONCOLLISION | FOF_WANTMAPPINGHANDLE; ++ FOF_NOCOPYSECURITYATTRIBS | FOF_NORECURSEREPARSE | ++ FOF_RENAMEONCOLLISION | FOF_WANTMAPPINGHANDLE; + + if (fFlags & wUnsupportedFlags) + FIXME("Unsupported flags: %04x\n", fFlags); +@@ -1611,19 +1611,19 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) + */ + void WINAPI SHFreeNameMappings(HANDLE hNameMapping) + { +- if (hNameMapping) +- { +- int i = SHDSA_GetItemCount((HDSA)hNameMapping) - 1; ++ if (hNameMapping) ++ { ++ int i = SHDSA_GetItemCount((HDSA)hNameMapping) - 1; + +- for (; i>= 0; i--) +- { ++ for (; i>= 0; i--) ++ { + LPSHNAMEMAPPINGW lp = DSA_GetItemPtr(hNameMapping, i); + +- SHFree(lp->pszOldPath); +- SHFree(lp->pszNewPath); +- } +- DSA_Destroy(hNameMapping); +- } ++ SHFree(lp->pszOldPath); ++ SHFree(lp->pszNewPath); ++ } ++ DSA_Destroy(hNameMapping); ++ } + } + + /************************************************************************* +@@ -1729,14 +1729,14 @@ DWORD WINAPI SheChangeDirW(LPWSTR path) + } + + /************************************************************************* +- * IsNetDrive [SHELL32.66] ++ * IsNetDrive [SHELL32.66] + */ + int WINAPI IsNetDrive(int drive) + { +- char root[4]; +- strcpy(root, "A:\\"); +- root[0] += (char)drive; +- return (GetDriveTypeA(root) == DRIVE_REMOTE); ++ char root[4]; ++ strcpy(root, "A:\\"); ++ root[0] += (char)drive; ++ return (GetDriveTypeA(root) == DRIVE_REMOTE); + } + + +-- +2.3.0 + diff --git a/patches/shell32-Progress_Dialog/0002-shell32-Pass-FILE_INFORMATION-into-SHNotify-function.patch b/patches/shell32-Progress_Dialog/0002-shell32-Pass-FILE_INFORMATION-into-SHNotify-function.patch new file mode 100644 index 00000000..3a178aff --- /dev/null +++ b/patches/shell32-Progress_Dialog/0002-shell32-Pass-FILE_INFORMATION-into-SHNotify-function.patch @@ -0,0 +1,527 @@ +From 8442c70f08cd95cf592ec4232489ea93c5d0a038 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Thu, 26 Feb 2015 23:21:26 +0100 +Subject: shell32: Pass FILE_INFORMATION into SHNotify* functions. + +Preparation of the progressbar work. Based on a patch by Huw Campbell. +--- + dlls/shell32/shlfileop.c | 222 +++++++++++++++++++++++------------------------ + 1 file changed, 111 insertions(+), 111 deletions(-) + +diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c +index ee40e39..ed8ff38 100644 +--- a/dlls/shell32/shlfileop.c ++++ b/dlls/shell32/shlfileop.c +@@ -59,16 +59,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); + static const WCHAR wWildcardFile[] = {'*',0}; + static const WCHAR wWildcardChars[] = {'*','?',0}; + +-static DWORD SHNotifyCreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec); +-static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec); +-static DWORD SHNotifyRemoveDirectoryA(LPCSTR path); +-static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path); +-static DWORD SHNotifyDeleteFileA(LPCSTR path); +-static DWORD SHNotifyDeleteFileW(LPCWSTR path); +-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; +@@ -77,6 +67,42 @@ typedef struct + BOOL bCancelled; + } FILE_OPERATION; + ++typedef struct ++{ ++ DWORD attributes; ++ LPWSTR szDirectory; ++ LPWSTR szFilename; ++ LPWSTR szFullPath; ++ BOOL bFromWildcard; ++ BOOL bFromRelative; ++ BOOL bExists; ++} FILE_ENTRY; ++ ++typedef struct ++{ ++ FILE_ENTRY *feFiles; ++ DWORD num_alloc; ++ DWORD dwNumFiles; ++ BOOL bAnyFromWildcard; ++ BOOL bAnyDirectories; ++ BOOL bAnyDontExist; ++} FILE_LIST; ++ ++#define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026 ++ ++static DWORD SHNotifyCreateDirectoryA(LPCSTR path, LPSECURITY_ATTRIBUTES sec); ++static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec); ++static DWORD SHNotifyRemoveDirectoryA(LPCSTR path); ++static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path); ++static DWORD SHNotifyDeleteFileA(FILE_OPERATION *op, LPCSTR path); ++static DWORD SHNotifyDeleteFileW(FILE_OPERATION *op, LPCWSTR path); ++static DWORD SHNotifyMoveFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest); ++static DWORD SHNotifyCopyFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists); ++static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly); ++ ++static DWORD copy_files(FILE_OPERATION *op, BOOL multidest, const FILE_LIST *flFrom, FILE_LIST *flTo); ++static DWORD move_files(FILE_OPERATION *op, BOOL multidest, const FILE_LIST *flFrom, const FILE_LIST *flTo); ++ + /* 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}; +@@ -347,7 +373,7 @@ HRESULT WINAPI SHIsFileAvailableOffline(LPCWSTR path, LPDWORD status) + * Asks for confirmation when bShowUI is true and deletes the directory and + * all its subdirectories and files if necessary. + */ +-static DWORD SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI) ++static DWORD SHELL_DeleteDirectoryW(FILE_OPERATION *op, LPCWSTR pszDir, BOOL bShowUI) + { + DWORD ret = 0; + HANDLE hFind; +@@ -357,16 +383,18 @@ static DWORD SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI) + PathCombineW(szTemp, pszDir, wWildcardFile); + hFind = FindFirstFileW(szTemp, &wfd); + +- if (hFind != INVALID_HANDLE_VALUE) { +- if (!bShowUI || SHELL_ConfirmDialogW(hwnd, ASK_DELETE_FOLDER, pszDir, NULL)) { ++ if (hFind != INVALID_HANDLE_VALUE) ++ { ++ if (!bShowUI || SHELL_ConfirmDialogW(op->req->hwnd, ASK_DELETE_FOLDER, pszDir, NULL)) ++ { + do { + if (IsDotDir(wfd.cFileName)) + continue; + PathCombineW(szTemp, pszDir, wfd.cFileName); + if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes) +- ret = SHELL_DeleteDirectoryW(hwnd, szTemp, FALSE); ++ ret = SHELL_DeleteDirectoryW(op, szTemp, FALSE); + else +- ret = SHNotifyDeleteFileW(szTemp); ++ ret = SHNotifyDeleteFileW(op, szTemp); + } while (!ret && FindNextFileW(hFind, &wfd)); + } + FindClose(hFind); +@@ -497,22 +525,9 @@ BOOL WINAPI Win32RemoveDirectoryAW(LPCVOID path) + return (SHNotifyRemoveDirectoryA(path) == ERROR_SUCCESS); + } + +-/************************************************************************ +- * Win32DeleteFile [SHELL32.164] +- * +- * Deletes a file. Also triggers a change notify if one exists. +- * +- * PARAMS +- * path [I] path to file to delete +- * +- * RETURNS +- * TRUE if successful, FALSE otherwise +- * +- * NOTES +- * Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be ANSI. +- * This is Unicode on NT/2000 +- */ +-static DWORD SHNotifyDeleteFileA(LPCSTR path) ++/***********************************************************************/ ++ ++static DWORD SHNotifyDeleteFileA(FILE_OPERATION *op, LPCSTR path) + { + LPWSTR wPath; + DWORD retCode; +@@ -522,7 +537,7 @@ static DWORD SHNotifyDeleteFileA(LPCSTR path) + retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0); + if (!retCode) + { +- retCode = SHNotifyDeleteFileW(wPath); ++ retCode = SHNotifyDeleteFileW(op, wPath); + SHELL32_FreeUnicodeBuf(wPath); + } + return retCode; +@@ -530,12 +545,14 @@ static DWORD SHNotifyDeleteFileA(LPCSTR path) + + /***********************************************************************/ + +-static DWORD SHNotifyDeleteFileW(LPCWSTR path) ++static DWORD SHNotifyDeleteFileW(FILE_OPERATION *op, LPCWSTR path) + { + BOOL ret; + + TRACE("(%s)\n", debugstr_w(path)); + ++ /* FIXME: Implement progress dialog - op can also be zero! */ ++ + ret = DeleteFileW(path); + if (!ret) + { +@@ -558,8 +575,8 @@ static DWORD SHNotifyDeleteFileW(LPCWSTR path) + DWORD WINAPI Win32DeleteFileAW(LPCVOID path) + { + if (SHELL_OsIsUnicode()) +- return (SHNotifyDeleteFileW(path) == ERROR_SUCCESS); +- return (SHNotifyDeleteFileA(path) == ERROR_SUCCESS); ++ return (SHNotifyDeleteFileW(NULL, path) == ERROR_SUCCESS); ++ return (SHNotifyDeleteFileA(NULL, path) == ERROR_SUCCESS); + } + + /************************************************************************ +@@ -568,18 +585,21 @@ DWORD WINAPI Win32DeleteFileAW(LPCVOID path) + * Moves a file. Also triggers a change notify if one exists. + * + * PARAMS ++ * op [I] file operation context + * src [I] path to source file to move + * dest [I] path to target file to move to + * + * RETURNS + * ERORR_SUCCESS if successful + */ +-static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest) ++static DWORD SHNotifyMoveFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest) + { + BOOL ret; + + TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest)); + ++ /* FIXME: Implement progress dialog */ ++ + ret = MoveFileExW(src, dest, MOVEFILE_REPLACE_EXISTING); + + /* MOVEFILE_REPLACE_EXISTING fails with dirs, so try MoveFile */ +@@ -614,6 +634,7 @@ static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest) + * Copies a file. Also triggers a change notify if one exists. + * + * PARAMS ++ * op [I] file operation context + * src [I] path to source file to move + * dest [I] path to target file to move to + * bFailIfExists [I] if TRUE, the target file will not be overwritten if +@@ -622,13 +643,15 @@ static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest) + * RETURNS + * ERROR_SUCCESS if successful + */ +-static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists) ++static DWORD SHNotifyCopyFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists) + { + BOOL ret; + DWORD attribs; + + TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : ""); + ++ /* FIXME: Update progress dialog */ ++ + /* Destination file may already exist with read only attribute */ + attribs = GetFileAttributesW(dest); + if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY)) +@@ -904,30 +927,6 @@ int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp) + return retCode; + } + +-#define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026 +- +-typedef struct +-{ +- DWORD attributes; +- LPWSTR szDirectory; +- LPWSTR szFilename; +- LPWSTR szFullPath; +- BOOL bFromWildcard; +- BOOL bFromRelative; +- BOOL bExists; +-} FILE_ENTRY; +- +-typedef struct +-{ +- FILE_ENTRY *feFiles; +- DWORD num_alloc; +- DWORD dwNumFiles; +- BOOL bAnyFromWildcard; +- BOOL bAnyDirectories; +- BOOL bAnyDontExist; +-} FILE_LIST; +- +- + static inline void grow_list(FILE_LIST *list) + { + FILE_ENTRY *new = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list->feFiles, +@@ -1091,7 +1090,7 @@ static void destroy_file_list(FILE_LIST *flList) + static void copy_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWSTR szDestPath) + { + WCHAR szFrom[MAX_PATH], szTo[MAX_PATH]; +- SHFILEOPSTRUCTW fileOp; ++ FILE_LIST flFromNew, flToNew; + + static const WCHAR wildCardFiles[] = {'*','.','*',0}; + +@@ -1119,17 +1118,16 @@ static void copy_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWST + PathCombineW(szFrom, feFrom->szFullPath, wildCardFiles); + szFrom[lstrlenW(szFrom) + 1] = '\0'; + +- fileOp = *op->req; +- fileOp.pFrom = szFrom; +- fileOp.pTo = szTo; +- fileOp.fFlags &= ~FOF_MULTIDESTFILES; /* we know we're copying to one dir */ ++ ZeroMemory(&flFromNew, sizeof(FILE_LIST)); ++ ZeroMemory(&flToNew, sizeof(FILE_LIST)); ++ parse_file_list(&flFromNew, szFrom); ++ parse_file_list(&flToNew, szTo); + +- /* 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; ++ /* we know we're copying to one dir */ ++ copy_files(op, FALSE, &flFromNew, &flToNew); + +- SHFileOperationW(&fileOp); ++ destroy_file_list(&flFromNew); ++ destroy_file_list(&flToNew); + } + + static BOOL copy_file_to_file(FILE_OPERATION *op, const WCHAR *szFrom, const WCHAR *szTo) +@@ -1140,7 +1138,7 @@ static BOOL copy_file_to_file(FILE_OPERATION *op, const WCHAR *szFrom, const WCH + return FALSE; + } + +- return SHNotifyCopyFileW(szFrom, szTo, FALSE) == 0; ++ return SHNotifyCopyFileW(op, szFrom, szTo, FALSE) == 0; + } + + /* copy a file or directory to another directory */ +@@ -1180,7 +1178,7 @@ static void create_dest_dirs(LPCWSTR szDestDir) + } + + /* the FO_COPY operation */ +-static DWORD copy_files(FILE_OPERATION *op, const FILE_LIST *flFrom, FILE_LIST *flTo) ++static DWORD copy_files(FILE_OPERATION *op, BOOL multidest, const FILE_LIST *flFrom, FILE_LIST *flTo) + { + DWORD i; + const FILE_ENTRY *entryToCopy; +@@ -1203,7 +1201,7 @@ static DWORD copy_files(FILE_OPERATION *op, const FILE_LIST *flFrom, FILE_LIST * + fileDest = &flTo->feFiles[0]; + } + +- if (op->req->fFlags & FOF_MULTIDESTFILES) ++ if (multidest) + { + if (flFrom->bAnyFromWildcard) + return ERROR_CANCELLED; +@@ -1255,8 +1253,7 @@ static DWORD copy_files(FILE_OPERATION *op, const FILE_LIST *flFrom, FILE_LIST * + { + entryToCopy = &flFrom->feFiles[i]; + +- if ((op->req->fFlags & FOF_MULTIDESTFILES) && +- flTo->dwNumFiles > 1) ++ if (multidest && flTo->dwNumFiles > 1) + { + fileDest = &flTo->feFiles[i]; + } +@@ -1328,7 +1325,7 @@ static BOOL confirm_delete_list(HWND hWnd, DWORD fFlags, BOOL fTrash, const FILE + } + + /* the FO_DELETE operation */ +-static DWORD delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom) ++static DWORD delete_files(FILE_OPERATION *op, const FILE_LIST *flFrom) + { + const FILE_ENTRY *fileEntry; + DWORD i, ret; +@@ -1338,13 +1335,13 @@ static DWORD delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom) + return ERROR_SUCCESS; + + /* Windows also checks only the first item */ +- bTrash = (lpFileOp->fFlags & FOF_ALLOWUNDO) ++ bTrash = (op->req->fFlags & FOF_ALLOWUNDO) + && TRASH_CanTrashFile(flFrom->feFiles[0].szFullPath); + +- if (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (!bTrash && lpFileOp->fFlags & FOF_WANTNUKEWARNING)) +- if (!confirm_delete_list(lpFileOp->hwnd, lpFileOp->fFlags, bTrash, flFrom)) ++ if (!(op->req->fFlags & FOF_NOCONFIRMATION) || (!bTrash && op->req->fFlags & FOF_WANTNUKEWARNING)) ++ if (!confirm_delete_list(op->req->hwnd, op->req->fFlags, bTrash, flFrom)) + { +- lpFileOp->fAnyOperationsAborted = TRUE; ++ op->req->fAnyOperationsAborted = TRUE; + return 0; + } + +@@ -1353,7 +1350,7 @@ static DWORD delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom) + fileEntry = &flFrom->feFiles[i]; + + if (!IsAttribFile(fileEntry->attributes) && +- (lpFileOp->fFlags & FOF_FILESONLY && fileEntry->bFromWildcard)) ++ (op->req->fFlags & FOF_FILESONLY && fileEntry->bFromWildcard)) + continue; + + if (bTrash) +@@ -1363,14 +1360,14 @@ static DWORD delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom) + continue; + + /* 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, NULL); ++ if (!(op->req->fFlags & FOF_NOCONFIRMATION) || (op->req->fFlags & FOF_WANTNUKEWARNING)) ++ bDelete = SHELL_ConfirmDialogW(op->req->hwnd, ASK_CANT_TRASH_ITEM, fileEntry->szFullPath, NULL); + else + bDelete = TRUE; + + if (!bDelete) + { +- lpFileOp->fAnyOperationsAborted = TRUE; ++ op->req->fAnyOperationsAborted = TRUE; + break; + } + } +@@ -1380,7 +1377,7 @@ static DWORD delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom) + ret = DeleteFileW(fileEntry->szFullPath) ? + ERROR_SUCCESS : GetLastError(); + else +- ret = SHELL_DeleteDirectoryW(lpFileOp->hwnd, fileEntry->szFullPath, FALSE); ++ ret = SHELL_DeleteDirectoryW(op, fileEntry->szFullPath, FALSE); + + if (ret) + return ret; +@@ -1389,10 +1386,10 @@ static DWORD delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom) + return ERROR_SUCCESS; + } + +-static void move_dir_to_dir(LPSHFILEOPSTRUCTW lpFileOp, const FILE_ENTRY *feFrom, LPCWSTR szDestPath) ++static void move_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWSTR szDestPath) + { + WCHAR szFrom[MAX_PATH], szTo[MAX_PATH]; +- SHFILEOPSTRUCTW fileOp; ++ FILE_LIST flFromNew, flToNew; + + static const WCHAR wildCardFiles[] = {'*','.','*',0}; + +@@ -1407,28 +1404,33 @@ static void move_dir_to_dir(LPSHFILEOPSTRUCTW lpFileOp, const FILE_ENTRY *feFrom + lstrcpyW(szTo, szDestPath); + szTo[lstrlenW(szDestPath) + 1] = '\0'; + +- fileOp = *lpFileOp; +- fileOp.pFrom = szFrom; +- fileOp.pTo = szTo; ++ ZeroMemory(&flFromNew, sizeof(FILE_LIST)); ++ ZeroMemory(&flToNew, sizeof(FILE_LIST)); ++ ++ parse_file_list(&flFromNew, szFrom); ++ parse_file_list(&flToNew, szTo); + +- SHFileOperationW(&fileOp); ++ move_files(op, FALSE, &flFromNew, &flToNew); ++ ++ destroy_file_list(&flFromNew); ++ destroy_file_list(&flToNew); + } + + /* moves a file or directory to another directory */ +-static void move_to_dir(LPSHFILEOPSTRUCTW lpFileOp, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo) ++static void move_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo) + { + WCHAR szDestPath[MAX_PATH]; + + PathCombineW(szDestPath, feTo->szFullPath, feFrom->szFilename); + + if (IsAttribFile(feFrom->attributes)) +- SHNotifyMoveFileW(feFrom->szFullPath, szDestPath); +- else if (!(lpFileOp->fFlags & FOF_FILESONLY && feFrom->bFromWildcard)) +- move_dir_to_dir(lpFileOp, feFrom, szDestPath); ++ SHNotifyMoveFileW(op, feFrom->szFullPath, szDestPath); ++ else if (!(op->req->fFlags & FOF_FILESONLY && feFrom->bFromWildcard)) ++ move_dir_to_dir(op, feFrom, szDestPath); + } + + /* the FO_MOVE operation */ +-static DWORD move_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, const FILE_LIST *flTo) ++static DWORD move_files(FILE_OPERATION *op, BOOL multidest, const FILE_LIST *flFrom, const FILE_LIST *flTo) + { + DWORD i; + INT mismatched = 0; +@@ -1441,14 +1443,12 @@ static DWORD move_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, con + if (!flTo->dwNumFiles) + return ERROR_FILE_NOT_FOUND; + +- if (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) && +- flTo->dwNumFiles > 1 && flFrom->dwNumFiles > 1) ++ if (!multidest && flTo->dwNumFiles > 1 && flFrom->dwNumFiles > 1) + { + return ERROR_CANCELLED; + } + +- if (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) && +- !flFrom->bAnyDirectories && ++ if (!multidest && !flFrom->bAnyDirectories && + flFrom->dwNumFiles > flTo->dwNumFiles) + { + return ERROR_CANCELLED; +@@ -1457,7 +1457,7 @@ static DWORD move_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, con + if (!PathFileExistsW(flTo->feFiles[0].szDirectory)) + return ERROR_CANCELLED; + +- if (lpFileOp->fFlags & FOF_MULTIDESTFILES) ++ if (multidest) + mismatched = flFrom->dwNumFiles - flTo->dwNumFiles; + + fileDest = &flTo->feFiles[0]; +@@ -1468,7 +1468,7 @@ static DWORD move_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, con + if (!PathFileExistsW(fileDest->szDirectory)) + return ERROR_CANCELLED; + +- if (lpFileOp->fFlags & FOF_MULTIDESTFILES) ++ if (multidest) + { + if (i >= flTo->dwNumFiles) + break; +@@ -1482,9 +1482,9 @@ static DWORD move_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, con + } + + if (fileDest->bExists && IsAttribDir(fileDest->attributes)) +- move_to_dir(lpFileOp, entryToMove, fileDest); ++ move_to_dir(op, entryToMove, fileDest); + else +- SHNotifyMoveFileW(entryToMove->szFullPath, fileDest->szFullPath); ++ SHNotifyMoveFileW(op, entryToMove->szFullPath, fileDest->szFullPath); + } + + if (mismatched > 0) +@@ -1499,7 +1499,7 @@ static DWORD move_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, con + } + + /* the FO_RENAME files */ +-static DWORD rename_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, const FILE_LIST *flTo) ++static DWORD rename_files(FILE_OPERATION *op, const FILE_LIST *flFrom, const FILE_LIST *flTo) + { + const FILE_ENTRY *feFrom; + const FILE_ENTRY *feTo; +@@ -1521,7 +1521,7 @@ static DWORD rename_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, c + if (feTo->bExists) + return ERROR_ALREADY_EXISTS; + +- return SHNotifyMoveFileW(feFrom->szFullPath, feTo->szFullPath); ++ return SHNotifyMoveFileW(op, feFrom->szFullPath, feTo->szFullPath); + } + + /* alert the user if an unsupported flag is used */ +@@ -1568,16 +1568,16 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) + switch (lpFileOp->wFunc) + { + case FO_COPY: +- ret = copy_files(&op, &flFrom, &flTo); ++ ret = copy_files(&op, op.req->fFlags & FOF_MULTIDESTFILES, &flFrom, &flTo); + break; + case FO_DELETE: +- ret = delete_files(lpFileOp, &flFrom); ++ ret = delete_files(&op, &flFrom); + break; + case FO_MOVE: +- ret = move_files(lpFileOp, &flFrom, &flTo); ++ ret = move_files(&op, op.req->fFlags & FOF_MULTIDESTFILES, &flFrom, &flTo); + break; + case FO_RENAME: +- ret = rename_files(lpFileOp, &flFrom, &flTo); ++ ret = rename_files(&op, &flFrom, &flTo); + break; + default: + ret = ERROR_INVALID_PARAMETER; +-- +2.3.0 + diff --git a/patches/shell32-Progress_Dialog/0003-shell32-Implement-file-operation-progress-dialog.patch b/patches/shell32-Progress_Dialog/0003-shell32-Implement-file-operation-progress-dialog.patch new file mode 100644 index 00000000..93fe3568 --- /dev/null +++ b/patches/shell32-Progress_Dialog/0003-shell32-Implement-file-operation-progress-dialog.patch @@ -0,0 +1,453 @@ +From a6f9101ab518d9cf5a9ab34533ba1d684ee61d8b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Fri, 27 Feb 2015 01:04:33 +0100 +Subject: shell32: Implement file operation progress dialog. + +Based on a patch by Huw Campbell. +--- + dlls/shell32/shell32.rc | 7 ++ + dlls/shell32/shlfileop.c | 277 +++++++++++++++++++++++++++++++++++++++++++++-- + dlls/shell32/shresdef.h | 8 ++ + 3 files changed, 285 insertions(+), 7 deletions(-) + +diff --git a/dlls/shell32/shell32.rc b/dlls/shell32/shell32.rc +index 37acbe7..dd054fb 100644 +--- a/dlls/shell32/shell32.rc ++++ b/dlls/shell32/shell32.rc +@@ -184,6 +184,13 @@ 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?" + ++ IDS_FILEOP_COPYING "Copying" ++ IDS_FILEOP_MOVING "Moving" ++ IDS_FILEOP_DELETING "Deleting" ++ IDS_FILEOP_FROM_TO "From %1 to %2" ++ IDS_FILEOP_FROM "From %1" ++ IDS_FILEOP_PREFLIGHT "Preflight" ++ + /* message box strings */ + IDS_RESTART_TITLE "Restart" + IDS_RESTART_PROMPT "Do you want to simulate a Windows reboot?" +diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c +index ed8ff38..cef2246 100644 +--- a/dlls/shell32/shlfileop.c ++++ b/dlls/shell32/shlfileop.c +@@ -65,6 +65,10 @@ typedef struct + DWORD dwYesToAllMask; + BOOL bManyItems; + BOOL bCancelled; ++ IProgressDialog *progress; ++ ULARGE_INTEGER completedSize; ++ ULARGE_INTEGER totalSize; ++ WCHAR szBuilderString[64]; + } FILE_OPERATION; + + typedef struct +@@ -103,6 +107,12 @@ static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly); + static DWORD copy_files(FILE_OPERATION *op, BOOL multidest, const FILE_LIST *flFrom, FILE_LIST *flTo); + static DWORD move_files(FILE_OPERATION *op, BOOL multidest, const FILE_LIST *flFrom, const FILE_LIST *flTo); + ++static void progressbar_calc_totalsize(FILE_OPERATION *op, const FILE_LIST *from); ++static void progressbar_update_title(FILE_OPERATION *op); ++static void progressbar_update_files(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dst); ++static DWORD CALLBACK progressbar_copy_routine(LARGE_INTEGER total_size, LARGE_INTEGER total_transferred, LARGE_INTEGER stream_size, ++ LARGE_INTEGER stream_transferred, DWORD stream_number, DWORD reason, HANDLE src_file, HANDLE dst_file, LPVOID user); ++ + /* 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}; +@@ -395,6 +405,13 @@ static DWORD SHELL_DeleteDirectoryW(FILE_OPERATION *op, LPCWSTR pszDir, BOOL bSh + ret = SHELL_DeleteDirectoryW(op, szTemp, FALSE); + else + ret = SHNotifyDeleteFileW(op, szTemp); ++ ++ /* Check if dialog was cancelled in the meantime */ ++ if (op->progress != NULL) ++ op->bCancelled |= IProgressDialog_HasUserCancelled(op->progress); ++ if (op->bCancelled) ++ break; ++ + } while (!ret && FindNextFileW(hFind, &wfd)); + } + FindClose(hFind); +@@ -548,10 +565,22 @@ static DWORD SHNotifyDeleteFileA(FILE_OPERATION *op, LPCSTR path) + static DWORD SHNotifyDeleteFileW(FILE_OPERATION *op, LPCWSTR path) + { + BOOL ret; ++ LARGE_INTEGER filesize; ++ filesize.QuadPart = 0; + + TRACE("(%s)\n", debugstr_w(path)); + +- /* FIXME: Implement progress dialog - op can also be zero! */ ++ /* Warning: can also be called with empty op */ ++ if (op) ++ { ++ WIN32_FILE_ATTRIBUTE_DATA info; ++ progressbar_update_files(op, path, NULL); ++ if (GetFileAttributesExW(path, GetFileExInfoStandard, &info)) ++ { ++ filesize.u.HighPart = info.nFileSizeHigh; ++ filesize.u.LowPart = info.nFileSizeLow; ++ } ++ } + + ret = DeleteFileW(path); + if (!ret) +@@ -564,6 +593,14 @@ static DWORD SHNotifyDeleteFileW(FILE_OPERATION *op, LPCWSTR path) + } + if (ret) + { ++ if (op) ++ { ++ /* There is no progress while deleting a file, ++ * simply report full file size when we are done. */ ++ progressbar_copy_routine(filesize, filesize, filesize, filesize, 0, ++ CALLBACK_STREAM_SWITCH, NULL, NULL, op); ++ } ++ + SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, path, NULL); + return ERROR_SUCCESS; + } +@@ -598,9 +635,10 @@ static DWORD SHNotifyMoveFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest) + + TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest)); + +- /* FIXME: Implement progress dialog */ ++ progressbar_update_files(op, src, dest); + +- ret = MoveFileExW(src, dest, MOVEFILE_REPLACE_EXISTING); ++ ret = MoveFileWithProgressW(src, dest, progressbar_copy_routine, ++ op, MOVEFILE_REPLACE_EXISTING); + + /* MOVEFILE_REPLACE_EXISTING fails with dirs, so try MoveFile */ + if (!ret) +@@ -650,14 +688,15 @@ static DWORD SHNotifyCopyFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BO + + TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : ""); + +- /* FIXME: Update progress dialog */ ++ progressbar_update_files(op, src, dest); + + /* Destination file may already exist with read only attribute */ + attribs = GetFileAttributesW(dest); + if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY)) + SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY); + +- ret = CopyFileW(src, dest, bFailIfExists); ++ ret = CopyFileExW(src, dest, progressbar_copy_routine, op, ++ &op->bCancelled, bFailIfExists); + if (ret) + { + SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, dest, NULL); +@@ -1293,6 +1332,8 @@ static DWORD copy_files(FILE_OPERATION *op, BOOL multidest, const FILE_LIST *flF + } + + /* Vista return code. XP would return e.g. ERROR_FILE_NOT_FOUND, ERROR_ALREADY_EXISTS */ ++ if (op->progress != NULL) ++ op->bCancelled |= IProgressDialog_HasUserCancelled(op->progress); + if (op->bCancelled) + return ERROR_CANCELLED; + } +@@ -1374,13 +1415,17 @@ static DWORD delete_files(FILE_OPERATION *op, const FILE_LIST *flFrom) + + /* delete the file or directory */ + if (IsAttribFile(fileEntry->attributes)) +- ret = DeleteFileW(fileEntry->szFullPath) ? +- ERROR_SUCCESS : GetLastError(); ++ ret = SHNotifyDeleteFileW(op, fileEntry->szFullPath); + else + ret = SHELL_DeleteDirectoryW(op, fileEntry->szFullPath, FALSE); + + if (ret) + return ret; ++ ++ if (op->progress != NULL) ++ op->bCancelled |= IProgressDialog_HasUserCancelled(op->progress); ++ if (op->bCancelled) ++ return ERROR_CANCELLED; + } + + return ERROR_SUCCESS; +@@ -1485,6 +1530,11 @@ static DWORD move_files(FILE_OPERATION *op, BOOL multidest, const FILE_LIST *flF + move_to_dir(op, entryToMove, fileDest); + else + SHNotifyMoveFileW(op, entryToMove->szFullPath, fileDest->szFullPath); ++ ++ if (op->progress != NULL) ++ op->bCancelled |= IProgressDialog_HasUserCancelled(op->progress); ++ if (op->bCancelled) ++ return ERROR_CANCELLED; + } + + if (mismatched > 0) +@@ -1544,6 +1594,7 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) + { + FILE_OPERATION op; + FILE_LIST flFrom, flTo; ++ HRESULT co_ret = E_FAIL; + int ret = 0; + + if (!lpFileOp) +@@ -1562,9 +1613,31 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) + + ZeroMemory(&op, sizeof(op)); + op.req = lpFileOp; ++ op.totalSize.QuadPart = 0; ++ op.completedSize.QuadPart = 0; + op.bManyItems = (flFrom.dwNumFiles > 1); + lpFileOp->fAnyOperationsAborted = FALSE; + ++ if (lpFileOp->wFunc != FO_RENAME && !(lpFileOp->fFlags & FOF_SILENT)) ++ { ++ co_ret = CoInitialize(NULL); ++ ret = CoCreateInstance(&CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, ++ &IID_IProgressDialog, (void**)&op.progress); ++ if (SUCCEEDED(ret)) ++ { ++ IProgressDialog_StartProgressDialog(op.progress, op.req->hwnd, NULL, ++ PROGDLG_NORMAL | PROGDLG_AUTOTIME, NULL); ++ ++ progressbar_update_title(&op); ++ progressbar_calc_totalsize(&op, &flFrom); ++ } ++ else ++ { ++ FIXME("Failed to create progress dialog\n"); ++ op.progress = NULL; ++ } ++ } ++ + switch (lpFileOp->wFunc) + { + case FO_COPY: +@@ -1584,6 +1657,12 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) + break; + } + ++ if (op.progress) ++ { ++ IProgressDialog_StopProgressDialog(op.progress); ++ IProgressDialog_Release(op.progress); ++ } ++ + destroy_file_list(&flFrom); + + if (lpFileOp->wFunc != FO_DELETE) +@@ -1592,6 +1671,9 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) + if (ret == ERROR_CANCELLED) + lpFileOp->fAnyOperationsAborted = TRUE; + ++ if (SUCCEEDED(co_ret)) ++ CoUninitialize(); ++ + return ret; + } + +@@ -1822,3 +1904,184 @@ HRESULT WINAPI SHPathPrepareForWriteW(HWND hwnd, IUnknown *modless, LPCWSTR path + else + return HRESULT_FROM_WIN32(ERROR_DIRECTORY); + } ++ ++static BOOL progressbar_calc_size(FILE_OPERATION *op, LPWSTR buf, BOOL is_folder, DWORD *ticks) ++{ ++ WIN32_FIND_DATAW wfd; ++ HANDLE find; ++ UINT i = strlenW(buf); ++ WCHAR *file = buf + i; ++ size_t size = MAX_PATH - i; ++ ++ if (size < 3) ++ return FALSE; ++ ++ if (is_folder) ++ { ++ *file++ = '\\'; ++ size--; ++ ++ file[0] = '*'; ++ file[1] = 0; ++ } ++ else ++ { ++ file[0] = 0; ++ } ++ ++ find = FindFirstFileW(buf, &wfd); ++ if (find == INVALID_HANDLE_VALUE) ++ { ++ WARN("FindFirstFileW %s failed\n", debugstr_w(buf)); ++ return FALSE; ++ } ++ ++ do ++ { ++ if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ++ { ++ if (wfd.cFileName[0] == '.') ++ { ++ if (wfd.cFileName[1] == 0) continue; ++ if (wfd.cFileName[1] == '.' && wfd.cFileName[2] == 0) continue; ++ } ++ ++ if (!lstrcpynW(file, wfd.cFileName, size)) continue; ++ progressbar_calc_size(op, buf, TRUE, ticks); ++ } ++ else ++ { ++ LARGE_INTEGER filesize; ++ filesize.u.LowPart = wfd.nFileSizeLow; ++ filesize.u.HighPart = wfd.nFileSizeHigh; ++ op->totalSize.QuadPart += filesize.QuadPart; ++ } ++ ++ if (GetTickCount() - *ticks > (DWORD) 500) ++ { ++ if (op->progress != NULL) ++ op->bCancelled |= IProgressDialog_HasUserCancelled(op->progress); ++ if (op->bCancelled) ++ break; ++ *ticks = GetTickCount(); ++ } ++ ++ } ++ while (FindNextFileW(find, &wfd)); ++ ++ FindClose(find); ++ return TRUE; ++} ++ ++static void progressbar_calc_totalsize(FILE_OPERATION *op, const FILE_LIST *from) ++{ ++ WCHAR filename[MAX_PATH]; ++ DWORD ticks = GetTickCount(); ++ UINT i; ++ ++ op->totalSize.QuadPart = 0; ++ ++ for (i = 0; i < from->dwNumFiles && !op->bCancelled; i++) ++ { ++ if (!lstrcpynW(filename, from->feFiles[i].szFullPath, sizeof(filename)/sizeof(filename[0]))) ++ continue; ++ progressbar_calc_size(op, filename, IsAttribDir(from->feFiles[i].attributes), &ticks); ++ } ++} ++ ++static void progressbar_update_title(FILE_OPERATION *op) ++{ ++ WCHAR buf[64]; ++ UINT title_id, builder_id; ++ ++ if (op->progress == NULL) ++ return; ++ ++ switch (op->req->wFunc) ++ { ++ case FO_COPY: ++ title_id = IDS_FILEOP_COPYING; ++ builder_id = IDS_FILEOP_FROM_TO; ++ break; ++ ++ case FO_DELETE: ++ title_id = IDS_FILEOP_DELETING; ++ builder_id = IDS_FILEOP_FROM; ++ break; ++ ++ case FO_MOVE: ++ title_id = IDS_FILEOP_MOVING; ++ builder_id = IDS_FILEOP_FROM_TO; ++ break; ++ ++ default: ++ return; ++ } ++ ++ LoadStringW(shell32_hInstance, title_id, buf, sizeof(buf)/sizeof(WCHAR)); ++ IProgressDialog_SetTitle(op->progress, buf); ++ ++ LoadStringW(shell32_hInstance, builder_id, op->szBuilderString, ++ sizeof(op->szBuilderString)/sizeof(WCHAR)); ++ ++ LoadStringW(shell32_hInstance, IDS_FILEOP_PREFLIGHT, buf, sizeof(buf)/sizeof(WCHAR)); ++ IProgressDialog_SetLine(op->progress, 1, buf, FALSE, NULL); ++} ++ ++static void progressbar_update_files(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dst) ++{ ++ LPWSTR src_file, dst_file; ++ WCHAR src_dir[64], dst_dir[64], final[260]; ++ DWORD_PTR args[2] = {0, 0}; ++ ++ if (!op->progress || !src || (op->req->wFunc == FO_MOVE && !dst)) ++ return; ++ ++ if (op->req->wFunc != FO_COPY && ++ op->req->wFunc != FO_MOVE && ++ op->req->wFunc != FO_DELETE) ++ { ++ return; ++ } ++ ++ src_file = PathFindFileNameW(src); ++ lstrcpynW(src_dir, src, min(sizeof(src_dir) / sizeof(WCHAR) - 1, src_file - src)); ++ args[0] = (DWORD_PTR)&src_dir; ++ ++ if (op->req->wFunc == FO_MOVE || ++ op->req->wFunc == FO_COPY) ++ { ++ if (PathIsDirectoryW(dst)) ++ args[1] = (DWORD_PTR)&dst; ++ else ++ { ++ dst_file = PathFindFileNameW(dst); ++ lstrcpynW(dst_dir, dst, min(sizeof(dst_dir) / sizeof(WCHAR) - 1, dst_file - dst)); ++ args[1] = (DWORD_PTR)&dst_dir; ++ } ++ } ++ ++ FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, op->szBuilderString, ++ 0, 0, final, sizeof(final)/sizeof(final[0]), (__ms_va_list *)&args); ++ ++ IProgressDialog_SetLine(op->progress, 1, src_file, FALSE, NULL); ++ IProgressDialog_SetLine(op->progress, 2, final, FALSE, NULL); ++} ++ ++static DWORD CALLBACK progressbar_copy_routine(LARGE_INTEGER total_size, LARGE_INTEGER total_transferred, LARGE_INTEGER stream_size, ++ LARGE_INTEGER stream_transferred, DWORD stream_number, DWORD reason, HANDLE src_file, HANDLE dst_file, LPVOID user) ++{ ++ FILE_OPERATION *op = (FILE_OPERATION *)user; ++ ++ if (!op->progress) ++ return PROGRESS_CONTINUE; ++ ++ if (reason == CALLBACK_STREAM_SWITCH) ++ op->completedSize.QuadPart += total_size.QuadPart; ++ ++ IProgressDialog_SetProgress64(op->progress, op->completedSize.QuadPart - total_size.QuadPart + ++ total_transferred.QuadPart, op->totalSize.QuadPart); ++ ++ op->bCancelled |= IProgressDialog_HasUserCancelled(op->progress); ++ return op->bCancelled ? PROGRESS_CANCEL : PROGRESS_CONTINUE; ++} +diff --git a/dlls/shell32/shresdef.h b/dlls/shell32/shresdef.h +index 183a75e..8ee525a 100644 +--- a/dlls/shell32/shresdef.h ++++ b/dlls/shell32/shresdef.h +@@ -149,6 +149,14 @@ + #define IDM_RECYCLEBIN_RESTORE 301 + #define IDM_RECYCLEBIN_ERASE 302 + ++/* Strings for file operations */ ++#define IDS_FILEOP_COPYING 333 ++#define IDS_FILEOP_MOVING 334 ++#define IDS_FILEOP_DELETING 335 ++#define IDS_FILEOP_FROM_TO 336 ++#define IDS_FILEOP_FROM 337 ++#define IDS_FILEOP_PREFLIGHT 338 ++ + /* Note: this string is referenced from the registry*/ + #define IDS_RECYCLEBIN_FOLDER_NAME 8964 + +-- +2.3.0 + diff --git a/patches/shell32-Progress_Dialog/definition b/patches/shell32-Progress_Dialog/definition new file mode 100644 index 00000000..d3238760 --- /dev/null +++ b/patches/shell32-Progress_Dialog/definition @@ -0,0 +1,2 @@ +Fixes: Support for shell32 file operation progress dialog +Depends: kernel32-CopyFileEx diff --git a/patches/shell32-SHFileOperation/0001-shell32-Choose-return-value-for-SHFileOperationW-dep.patch b/patches/shell32-SHFileOperation/0001-shell32-Choose-return-value-for-SHFileOperationW-dep.patch index 5007d895..cf76de51 100644 --- a/patches/shell32-SHFileOperation/0001-shell32-Choose-return-value-for-SHFileOperationW-dep.patch +++ b/patches/shell32-SHFileOperation/0001-shell32-Choose-return-value-for-SHFileOperationW-dep.patch @@ -1,4 +1,4 @@ -From 3bd2667c70cd1b9ef472d353ffe16220823cdc35 Mon Sep 17 00:00:00 2001 +From 838dbfc163ed83706e88e309201d84197e6ebee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Thu, 31 Jul 2014 04:52:01 +0200 Subject: shell32: Choose return value for SHFileOperationW depending on @@ -9,19 +9,19 @@ Subject: shell32: Choose return value for SHFileOperationW depending on 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c -index 62d7880..249970a 100644 +index cef2246..290102a 100644 --- a/dlls/shell32/shlfileop.c +++ b/dlls/shell32/shlfileop.c -@@ -1022,7 +1022,7 @@ static HRESULT parse_file_list(FILE_LIST *flList, LPCWSTR szFiles) +@@ -1060,7 +1060,7 @@ static HRESULT parse_file_list(FILE_LIST *flList, LPCWSTR szFiles) /* empty list */ if (!szFiles[0]) - return ERROR_ACCESS_DENIED; + return ERROR_ACCESS_DENIED; /* S_OK for Windows 95/98 */ - + flList->feFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, flList->num_alloc * sizeof(FILE_ENTRY)); -@@ -1555,7 +1555,19 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) +@@ -1606,7 +1606,19 @@ int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp) ZeroMemory(&flTo, sizeof(FILE_LIST)); if ((ret = parse_file_list(&flFrom, lpFileOp->pFrom))) @@ -42,5 +42,5 @@ index 62d7880..249970a 100644 if (lpFileOp->wFunc != FO_DELETE) parse_file_list(&flTo, lpFileOp->pTo); -- -1.9.1 +2.3.0 diff --git a/patches/shell32-SHFileOperation/definition b/patches/shell32-SHFileOperation/definition index e10ca0f1..28f10ac3 100644 --- a/patches/shell32-SHFileOperation/definition +++ b/patches/shell32-SHFileOperation/definition @@ -1 +1,2 @@ Fixes: [37916] Anno 1602 installer depends on Windows 98 behavior of SHFileOperationW +Depends: shell32-Progress_Dialog