summaryrefslogtreecommitdiff
path: root/lib/IFileOperation/file_op.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:15:16 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:15:16 +0200
commitbd6336c629841c6db3a6ca53a936d629d34db53b (patch)
tree3721ef997864108df175ce677a8a7d4342a6f1d2 /lib/IFileOperation/file_op.cpp
parent4.0 (diff)
downloadFreeFileSync-bd6336c629841c6db3a6ca53a936d629d34db53b.tar.gz
FreeFileSync-bd6336c629841c6db3a6ca53a936d629d34db53b.tar.bz2
FreeFileSync-bd6336c629841c6db3a6ca53a936d629d34db53b.zip
4.1
Diffstat (limited to 'lib/IFileOperation/file_op.cpp')
-rw-r--r--lib/IFileOperation/file_op.cpp240
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);
+}
bgstack15