mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-09-13 09:17:20 -07:00
Added patch for support of shell32 file operation progress dialog.
This commit is contained in:
parent
cc1368ba9e
commit
e01d563654
@ -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
1
debian/changelog
vendored
@ -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).
|
||||
|
@ -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:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,527 @@
|
||||
From 8442c70f08cd95cf592ec4232489ea93c5d0a038 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
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
|
||||
|
@ -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
|
||||
|
2
patches/shell32-Progress_Dialog/definition
Normal file
2
patches/shell32-Progress_Dialog/definition
Normal file
@ -0,0 +1,2 @@
|
||||
Fixes: Support for shell32 file operation progress dialog
|
||||
Depends: kernel32-CopyFileEx
|
@ -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
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
Fixes: [37916] Anno 1602 installer depends on Windows 98 behavior of SHFileOperationW
|
||||
Depends: shell32-Progress_Dialog
|
||||
|
Loading…
Reference in New Issue
Block a user