Added patch for support of shell32 file operation progress dialog.

This commit is contained in:
Sebastian Lackner
2015-02-27 02:12:30 +01:00
parent cc1368ba9e
commit e01d563654
9 changed files with 2030 additions and 7 deletions

View File

@@ -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]:**

1
debian/changelog vendored
View File

@@ -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).

View File

@@ -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:

View File

@@ -0,0 +1,453 @@
From a6f9101ab518d9cf5a9ab34533ba1d684ee61d8b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
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

View File

@@ -0,0 +1,2 @@
Fixes: Support for shell32 file operation progress dialog
Depends: kernel32-CopyFileEx

View File

@@ -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?= <michael@fds-team.de>
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

View File

@@ -1 +1,2 @@
Fixes: [37916] Anno 1602 installer depends on Windows 98 behavior of SHFileOperationW
Depends: shell32-Progress_Dialog