diff options
Diffstat (limited to 'lib/IFileOperation/file_op.cpp')
-rw-r--r-- | lib/IFileOperation/file_op.cpp | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/lib/IFileOperation/file_op.cpp b/lib/IFileOperation/file_op.cpp new file mode 100644 index 00000000..10eac5de --- /dev/null +++ b/lib/IFileOperation/file_op.cpp @@ -0,0 +1,240 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#include "file_op.h" +#define WIN32_LEAN_AND_MEAN +#include <zen/win.h> +#include <zen/com_ptr.h> +#include <zen/com_error.h> + +#include <Shellapi.h> // Included for shell constants such as FO_* values +#include <shobjidl.h> // Required for necessary shell dependencies +#include <algorithm> +#include <string> + +using namespace zen; + + +namespace fileop +{ +inline +void copyString(const std::wstring& input, wchar_t* buffer, size_t bufferSize) +{ + if (bufferSize > 0) + { + //size_t endPos = input.copy(buffer, bufferSize - 1); + //buffer[endPos] = 0; + const size_t maxSize = std::min(input.length(), bufferSize - 1); + std::copy(input.begin(), input.begin() + maxSize, buffer); + buffer[maxSize] = 0; + } +} + +std::wstring lastErrorMessage; //this should really be thread-local!!! +} + + +bool fileop::moveToRecycleBin(const wchar_t* fileNames[], + size_t fileNo) //size of fileNames array +{ + HRESULT hr; + + // Create the IFileOperation interface + ComPtr<IFileOperation> fileOp; + hr = ::CoCreateInstance(CLSID_FileOperation, + NULL, + CLSCTX_ALL, + IID_PPV_ARGS(fileOp.init())); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"CoCreateInstance\".", hr); + return false; + } + + // Set the operation flags. Turn off all UI + // from being shown to the user during the + // operation. This includes error, confirmation + // and progress dialogs. + hr = fileOp->SetOperationFlags(FOF_ALLOWUNDO | + FOF_NOCONFIRMATION | + FOF_SILENT | + FOFX_EARLYFAILURE | + FOF_NOERRORUI); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"SetOperationFlags\".", hr); + return false; + } + + int operationCount = 0; + + for (size_t i = 0; i < fileNo; ++i) + { + //create file/folder item object + ComPtr<IShellItem> psiFile; + hr = ::SHCreateItemFromParsingName(fileNames[i], + NULL, + IID_PPV_ARGS(psiFile.init())); + if (FAILED(hr)) + { + if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || //file not existing anymore + hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) + continue; + + std::wstring message(L"Error calling \"SHCreateItemFromParsingName\" for file:\n"); + message += std::wstring(L"\"") + fileNames[i] + L"\"."; + + lastErrorMessage = generateErrorMsg(message, hr); + return false; + } + + hr = fileOp->DeleteItem(psiFile.get(), NULL); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"DeleteItem\".", hr); + return false; + } + + ++operationCount; + } + + if (operationCount == 0) //calling PerformOperations() without anything to do results in E_UNEXPECTED + return true; + + //perform actual operations + hr = fileOp->PerformOperations(); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"PerformOperations\".", hr); + return false; + } + + //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors! + BOOL pfAnyOperationsAborted = FALSE; + hr = fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"GetAnyOperationsAborted\".", hr); + return false; + } + + if (pfAnyOperationsAborted == TRUE) + { + lastErrorMessage = L"Operation did not complete successfully."; + return false; + } + + return true; +} + + +bool fileop::copyFile(const wchar_t* sourceFile, + const wchar_t* targetFile) +{ + HRESULT hr; + + // Create the IFileOperation interface + ComPtr<IFileOperation> fileOp; + hr = ::CoCreateInstance(CLSID_FileOperation, + NULL, + CLSCTX_ALL, + IID_PPV_ARGS(fileOp.init())); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"CoCreateInstance\".", hr); + return false; + } + + // Set the operation flags. Turn off all UI + // from being shown to the user during the + // operation. This includes error, confirmation + // and progress dialogs. + hr = fileOp->SetOperationFlags(FOF_NOCONFIRMATION | + FOF_SILENT | + FOFX_EARLYFAILURE | + FOF_NOERRORUI); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"SetOperationFlags\".", hr); + return false; + } + + //create source object + ComPtr<IShellItem> psiSourceFile; + hr = ::SHCreateItemFromParsingName(sourceFile, + NULL, + IID_PPV_ARGS(psiSourceFile.init())); + if (FAILED(hr)) + { + std::wstring message(L"Error calling \"SHCreateItemFromParsingName\" for file:\n"); + message += std::wstring(L"\"") + sourceFile + L"\"."; + lastErrorMessage = generateErrorMsg(message, hr); + return false; + } + + const size_t pos = std::wstring(targetFile).find_last_of(L'\\'); + if (pos == std::wstring::npos) + { + lastErrorMessage = L"Target filename does not contain a path separator."; + return false; + } + + const std::wstring targetFolder(targetFile, pos); + const std::wstring targetFileNameShort = targetFile + pos + 1; + + //create target folder object + ComPtr<IShellItem> psiTargetFolder; + hr = ::SHCreateItemFromParsingName(targetFolder.c_str(), + NULL, + IID_PPV_ARGS(psiTargetFolder.init())); + if (FAILED(hr)) + { + std::wstring message(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n"); + message += std::wstring(L"\"") + targetFolder + L"\"."; + lastErrorMessage = generateErrorMsg(message, hr); + return false; + } + + //schedule file copy operation + hr = fileOp->CopyItem(psiSourceFile.get(), psiTargetFolder.get(), targetFileNameShort.c_str(), NULL); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"CopyItem\".", hr); + return false; + } + + //perform actual operations + hr = fileOp->PerformOperations(); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"PerformOperations\".", hr); + return false; + } + + //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors! + BOOL pfAnyOperationsAborted = FALSE; + hr = fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted); + if (FAILED(hr)) + { + lastErrorMessage = generateErrorMsg(L"Error calling \"GetAnyOperationsAborted\".", hr); + return false; + } + + if (pfAnyOperationsAborted == TRUE) + { + lastErrorMessage = L"Operation did not complete successfully."; + return false; + } + + return true; +} + + +//if any of the functions above returns 'false', this message returns last error +void fileop::getLastError(wchar_t* errorMessage, size_t errorBufferLen) +{ + copyString(lastErrorMessage, errorMessage, errorBufferLen); +} |