// ************************************************************************** // * 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 #include #include #include // Included for shell constants such as FO_* values #include // Required for necessary shell dependencies #include #include 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 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 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 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 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 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); }