diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2020-02-06 10:17:52 +0100 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2020-02-07 12:21:13 +0100 |
commit | e79979ba40992d5ae8e12084f91c0d06f158a4df (patch) | |
tree | c5fff38dad539a324bb0147b1136fad2a6768d40 /src/corelib/io | |
parent | 5c520f4b0ad4b539dc0184c764ca9f12c98730d9 (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/corelib/io')
-rw-r--r-- | src/corelib/io/qfilesystemengine_win.cpp | 132 |
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 |