summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2020-02-06 10:17:52 +0100
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2020-02-07 12:21:13 +0100
commite79979ba40992d5ae8e12084f91c0d06f158a4df (patch)
treec5fff38dad539a324bb0147b1136fad2a6768d40 /src
parent5c520f4b0ad4b539dc0184c764ca9f12c98730d9 (diff)
On Windows 7, fall back to SHFileOperation to avoid confirmation dialogs
Moving a file to the trash should preferably done via IFileOperation. However, the implementation on Windows 7 ignores the operation flags that request the shell not to show any confirmation dialogs or other UI elements. SHFileOperation is an old API that doesn't show any UI, but has the limitation that it doesn't report the location of the file in the trash after the move. So an application cannot restore the file, but the user can do so via Explorer. Overall, the better compromise is to not have dialogs at the expense of not being able to report the new path. This allows us to run the unit test on Windows 7 as well. Change-Id: Ib8e651a69e2c6750f668b52d2a70925d156cc8ae Fixes: QTBUG-81927 Reviewed-by: Vitaly Fanaskov <vitaly.fanaskov@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp132
1 files changed, 69 insertions, 63 deletions
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 71a0e36693..36d43e9cb7 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -1546,73 +1546,79 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
// we need the "display name" of the file, so can't use nativeFilePath
const QString sourcePath = QDir::toNativeSeparators(source.filePath());
+ /*
+ Windows 7 insists on showing confirmation dialogs and ignores the respective
+ flags set on IFileOperation. Fall back to SHFileOperation, even if it doesn't
+ give us the new location of the file.
+ */
+ if (QOperatingSystemVersion::current() > QOperatingSystemVersion::Windows7) {
# if defined(__IFileOperation_INTERFACE_DEFINED__)
- CoInitialize(NULL);
- IFileOperation *pfo = nullptr;
- IShellItem *deleteItem = nullptr;
- FileOperationProgressSink *sink = nullptr;
- HRESULT hres = E_FAIL;
-
- auto coUninitialize = qScopeGuard([&](){
- if (sink)
- sink->Release();
- if (deleteItem)
- deleteItem->Release();
- if (pfo)
- pfo->Release();
- CoUninitialize();
+ CoInitialize(NULL);
+ IFileOperation *pfo = nullptr;
+ IShellItem *deleteItem = nullptr;
+ FileOperationProgressSink *sink = nullptr;
+ HRESULT hres = E_FAIL;
+
+ auto coUninitialize = qScopeGuard([&](){
+ if (sink)
+ sink->Release();
+ if (deleteItem)
+ deleteItem->Release();
+ if (pfo)
+ pfo->Release();
+ CoUninitialize();
+ if (!SUCCEEDED(hres))
+ error = QSystemError(hres, QSystemError::NativeError);
+ });
+
+ hres = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
+ if (!pfo)
+ return false;
+ pfo->SetOperationFlags(FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE | FOF_NOCONFIRMATION
+ | FOF_SILENT | FOF_NOERRORUI);
+ hres = SHCreateItemFromParsingName(reinterpret_cast<const wchar_t*>(sourcePath.utf16()),
+ nullptr, IID_PPV_ARGS(&deleteItem));
+ if (!deleteItem)
+ return false;
+ sink = new FileOperationProgressSink;
+ hres = pfo->DeleteItem(deleteItem, static_cast<IFileOperationProgressSink*>(sink));
+ if (!SUCCEEDED(hres))
+ return false;
+ hres = pfo->PerformOperations();
if (!SUCCEEDED(hres))
- error = QSystemError(hres, QSystemError::NativeError);
- });
+ return false;
+ newLocation = QFileSystemEntry(sink->targetPath);
- hres = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
- if (!pfo)
- return false;
- pfo->SetOperationFlags(FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE | FOF_NOCONFIRMATION
- | FOF_SILENT | FOF_NOERRORUI);
- hres = SHCreateItemFromParsingName(reinterpret_cast<const wchar_t*>(sourcePath.utf16()),
- nullptr, IID_PPV_ARGS(&deleteItem));
- if (!deleteItem)
- return false;
- sink = new FileOperationProgressSink;
- hres = pfo->DeleteItem(deleteItem, static_cast<IFileOperationProgressSink*>(sink));
- if (!SUCCEEDED(hres))
- return false;
- hres = pfo->PerformOperations();
- if (!SUCCEEDED(hres))
- return false;
- newLocation = QFileSystemEntry(sink->targetPath);
-
-# else // no IFileOperation in SDK (mingw, likely) - fall back to SHFileOperation
-
- // double null termination needed, so can't use QString::utf16
- QVarLengthArray<wchar_t, MAX_PATH + 1> winFile(sourcePath.length() + 2);
- sourcePath.toWCharArray(winFile.data());
- winFile[sourcePath.length()] = wchar_t{};
- winFile[sourcePath.length() + 1] = wchar_t{};
-
- SHFILEOPSTRUCTW operation;
- operation.hwnd = nullptr;
- operation.wFunc = FO_DELETE;
- operation.pFrom = winFile.constData();
- operation.pTo = nullptr;
- operation.fFlags = FOF_ALLOWUNDO | FOF_NO_UI;
- operation.fAnyOperationsAborted = FALSE;
- operation.hNameMappings = nullptr;
- operation.lpszProgressTitle = nullptr;
-
- int result = SHFileOperation(&operation);
- if (result != 0) {
- error = QSystemError(result, QSystemError::NativeError);
- return false;
+# endif // no IFileOperation in SDK (mingw, likely) - fall back to SHFileOperation
+ } else {
+ // double null termination needed, so can't use QString::utf16
+ QVarLengthArray<wchar_t, MAX_PATH + 1> winFile(sourcePath.length() + 2);
+ sourcePath.toWCharArray(winFile.data());
+ winFile[sourcePath.length()] = wchar_t{};
+ winFile[sourcePath.length() + 1] = wchar_t{};
+
+ SHFILEOPSTRUCTW operation;
+ operation.hwnd = nullptr;
+ operation.wFunc = FO_DELETE;
+ operation.pFrom = winFile.constData();
+ operation.pTo = nullptr;
+ operation.fFlags = FOF_ALLOWUNDO | FOF_NO_UI;
+ operation.fAnyOperationsAborted = FALSE;
+ operation.hNameMappings = nullptr;
+ operation.lpszProgressTitle = nullptr;
+
+ int result = SHFileOperation(&operation);
+ if (result != 0) {
+ error = QSystemError(result, QSystemError::NativeError);
+ return false;
+ }
+ /*
+ This implementation doesn't let us know where the file ended up, even if
+ we would specify FOF_WANTMAPPINGHANDLE | FOF_RENAMEONCOLLISION, as
+ FOF_RENAMEONCOLLISION has no effect unless files are moved, copied, or renamed.
+ */
+ Q_UNUSED(newLocation);
}
- /*
- This implementation doesn't let us know where the file ended up, even if
- we would specify FOF_WANTMAPPINGHANDLE | FOF_RENAMEONCOLLISION, as
- FOF_RENAMEONCOLLISION has no effect unless files are moved, copied, or renamed.
- */
- Q_UNUSED(newLocation);
-# endif // IFileOperation fallback
return true;
#else // Q_OS_WINRT