summaryrefslogtreecommitdiff
path: root/zen/IFileOperation
diff options
context:
space:
mode:
Diffstat (limited to 'zen/IFileOperation')
-rw-r--r--zen/IFileOperation/FileOperation_Vista.vcxproj244
-rw-r--r--zen/IFileOperation/dll_main.cpp25
-rw-r--r--zen/IFileOperation/file_op.cpp349
-rw-r--r--zen/IFileOperation/file_op.h76
4 files changed, 694 insertions, 0 deletions
diff --git a/zen/IFileOperation/FileOperation_Vista.vcxproj b/zen/IFileOperation/FileOperation_Vista.vcxproj
new file mode 100644
index 00000000..a387dcb5
--- /dev/null
+++ b/zen/IFileOperation/FileOperation_Vista.vcxproj
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Vista IFileOperation</ProjectName>
+ <ProjectGuid>{70394AEF-5897-4911-AFA1-82EAF0581EFA}</ProjectGuid>
+ <RootNamespace>ShadowDll</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">FileOperation_$(Platform)</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">FileOperation_$(Platform)</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">FileOperation_$(Platform)</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">FileOperation_$(Platform)</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <BuildLog>
+ <Path>$(IntDir)Build.html</Path>
+ </BuildLog>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <ProfileGuidedDatabase>
+ </ProfileGuidedDatabase>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <BuildLog>
+ <Path>$(IntDir)Build.html</Path>
+ </BuildLog>
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <ProfileGuidedDatabase>
+ </ProfileGuidedDatabase>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <BuildLog>
+ <Path>$(IntDir)Build.html</Path>
+ </BuildLog>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <ProfileGuidedDatabase>
+ </ProfileGuidedDatabase>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <BuildLog>
+ <Path>$(IntDir)Build.html</Path>
+ </BuildLog>
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <ProfileGuidedDatabase>
+ </ProfileGuidedDatabase>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="dll_main.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </PrecompiledHeader>
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ </PrecompiledHeader>
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </PrecompiledHeader>
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ </PrecompiledHeader>
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
+ </ClCompile>
+ <ClCompile Include="file_op.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="file_op.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/zen/IFileOperation/dll_main.cpp b/zen/IFileOperation/dll_main.cpp
new file mode 100644
index 00000000..46c65311
--- /dev/null
+++ b/zen/IFileOperation/dll_main.cpp
@@ -0,0 +1,25 @@
+// **************************************************************************
+// * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+//optional: add init/teardown logic here
+BOOL APIENTRY DllMain(HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return TRUE;
+}
diff --git a/zen/IFileOperation/file_op.cpp b/zen/IFileOperation/file_op.cpp
new file mode 100644
index 00000000..7c75a8e8
--- /dev/null
+++ b/zen/IFileOperation/file_op.cpp
@@ -0,0 +1,349 @@
+// **************************************************************************
+// * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#include "file_op.h"
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#define WIN32_LEAN_AND_MEAN
+#include <zen/com_ptr.h>
+#include <zen/com_error.h>
+#include <zen/scope_guard.h>
+
+#include <boost/thread/tss.hpp>
+
+#include <RestartManager.h>
+#pragma comment(lib, "Rstrtmgr.lib")
+
+#define STRICT_TYPED_ITEMIDS //better type safety for IDLists
+#include <Shlobj.h>
+#include <shobjidl.h>
+#include <shellapi.h> //shell constants such as FO_* values
+
+using namespace zen;
+
+
+namespace
+{
+void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
+ size_t fileNo) //size of fileNames array
+{
+ ComPtr<IFileOperation> fileOp;
+ ZEN_CHECK_COM(::CoCreateInstance(CLSID_FileOperation, //throw ComError
+ nullptr,
+ CLSCTX_ALL,
+ IID_PPV_ARGS(fileOp.init())));
+
+ // Set the operation flags. Turn off all UI
+ // from being shown to the user during the
+ // operation. This includes error, confirmation
+ // and progress dialogs.
+ ZEN_CHECK_COM(fileOp->SetOperationFlags(FOF_ALLOWUNDO | //throw ComError
+ FOF_NOCONFIRMATION |
+ FOF_SILENT |
+ FOF_NOERRORUI |
+ FOFX_EARLYFAILURE |
+ FOF_NO_CONNECTED_ELEMENTS));
+
+ int operationCount = 0;
+
+ for (size_t i = 0; i < fileNo; ++i)
+ {
+ //create file/folder item object
+ ComPtr<IShellItem> psiFile;
+ HRESULT hr = ::SHCreateItemFromParsingName(fileNames[i],
+ nullptr,
+ 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;
+ throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + fileNames[i] + L"\".", hr);
+ }
+
+ ZEN_CHECK_COM(fileOp->DeleteItem(psiFile.get(), nullptr));
+
+ ++operationCount;
+ }
+
+ if (operationCount == 0) //calling PerformOperations() without anything to do would result in E_UNEXPECTED
+ return;
+
+ //perform actual operations
+ ZEN_CHECK_COM(fileOp->PerformOperations());
+
+ //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors!
+ BOOL pfAnyOperationsAborted = FALSE;
+ ZEN_CHECK_COM(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted));
+
+ if (pfAnyOperationsAborted == TRUE)
+ throw ComError(L"Operation did not complete successfully.");
+}
+
+
+void copyFile(const wchar_t* sourceFile, //throw ComError
+ const wchar_t* targetFile)
+{
+ ComPtr<IFileOperation> fileOp;
+ ZEN_CHECK_COM(::CoCreateInstance(CLSID_FileOperation, //throw ComError
+ nullptr,
+ CLSCTX_ALL,
+ IID_PPV_ARGS(fileOp.init())));
+
+ // Set the operation flags. Turn off all UI
+ // from being shown to the user during the
+ // operation. This includes error, confirmation
+ // and progress dialogs.
+ ZEN_CHECK_COM(fileOp->SetOperationFlags(FOF_NOCONFIRMATION | //throw ComError
+ FOF_SILENT |
+ FOFX_EARLYFAILURE |
+ FOF_NOERRORUI));
+ //create source object
+ ComPtr<IShellItem> psiSourceFile;
+ {
+ HRESULT hr = ::SHCreateItemFromParsingName(sourceFile,
+ nullptr,
+ IID_PPV_ARGS(psiSourceFile.init()));
+ if (FAILED(hr))
+ throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + sourceFile + L"\".", hr);
+ }
+
+ const size_t pos = std::wstring(targetFile).find_last_of(L'\\');
+ if (pos == std::wstring::npos)
+ throw ComError(L"Target filename does not contain a path separator.");
+
+ const std::wstring targetFolder(targetFile, pos);
+ const std::wstring targetFileNameShort = targetFile + pos + 1;
+
+ //create target folder object
+ ComPtr<IShellItem> psiTargetFolder;
+ {
+ HRESULT hr = ::SHCreateItemFromParsingName(targetFolder.c_str(),
+ nullptr,
+ IID_PPV_ARGS(psiTargetFolder.init()));
+ if (FAILED(hr))
+ throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\"" + targetFolder + L"\".", hr);
+ }
+
+ //schedule file copy operation
+ ZEN_CHECK_COM(fileOp->CopyItem(psiSourceFile.get(), psiTargetFolder.get(), targetFileNameShort.c_str(), nullptr));
+
+ //perform actual operations
+ ZEN_CHECK_COM(fileOp->PerformOperations());
+
+ //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors!
+ BOOL pfAnyOperationsAborted = FALSE;
+ ZEN_CHECK_COM(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted));
+
+ if (pfAnyOperationsAborted == TRUE)
+ throw ComError(L"Operation did not complete successfully.");
+}
+
+
+void getFolderClsid(const wchar_t* dirname, CLSID& pathCLSID) //throw ComError
+{
+ ComPtr<IShellFolder> desktopFolder;
+ ZEN_CHECK_COM(::SHGetDesktopFolder(desktopFolder.init())); //throw ComError
+
+ PIDLIST_RELATIVE pidlFolder = nullptr;
+ ZEN_CHECK_COM(desktopFolder->ParseDisplayName(nullptr, // [in] HWND hwnd,
+ nullptr, // [in] IBindCtx *pbc,
+ const_cast<LPWSTR>(dirname), // [in] LPWSTR pszDisplayName,
+ nullptr, // [out] ULONG *pchEaten,
+ &pidlFolder, // [out] PIDLIST_RELATIVE* ppidl,
+ nullptr)); // [in, out] ULONG *pdwAttributes
+ ZEN_ON_SCOPE_EXIT(::ILFree(pidlFolder)); //older version: ::CoTaskMemFree
+
+ ComPtr<IPersist> persistFolder;
+ ZEN_CHECK_COM(desktopFolder->BindToObject(pidlFolder, // [in] PCUIDLIST_RELATIVE pidl,
+ nullptr, // [in] IBindCtx *pbc,
+ IID_PPV_ARGS(persistFolder.init()))); //throw ComError
+
+ ZEN_CHECK_COM(persistFolder->GetClassID(&pathCLSID)); //throw ComError
+}
+
+
+struct Win32Error
+{
+ Win32Error(DWORD errorCode) : errorCode_(errorCode) {}
+ DWORD errorCode_;
+};
+
+std::vector<std::wstring> getLockingProcesses(const wchar_t* filename) //throw Win32Error
+{
+ wchar_t sessionKey[CCH_RM_SESSION_KEY + 1] = {}; //fixes two bugs: http://blogs.msdn.com/b/oldnewthing/archive/2012/02/17/10268840.aspx
+ DWORD sessionHandle = 0;
+ DWORD rv1 = ::RmStartSession(&sessionHandle, //__out DWORD *pSessionHandle,
+ 0, //__reserved DWORD dwSessionFlags,
+ sessionKey); //__out WCHAR strSessionKey[ ]
+ if (rv1 != ERROR_SUCCESS)
+ throw Win32Error(rv1);
+ ZEN_ON_SCOPE_EXIT(::RmEndSession(sessionHandle));
+
+ DWORD rv2 = ::RmRegisterResources(sessionHandle, //__in DWORD dwSessionHandle,
+ 1, //__in UINT nFiles,
+ &filename, //__in_opt LPCWSTR rgsFilenames[ ],
+ 0, //__in UINT nApplications,
+ nullptr, //__in_opt RM_UNIQUE_PROCESS rgApplications[ ],
+ 0, //__in UINT nServices,
+ nullptr); //__in_opt LPCWSTR rgsServiceNames[ ]
+ if (rv2 != ERROR_SUCCESS)
+ throw Win32Error(rv2);
+
+ UINT procInfoSize = 0;
+ UINT procInfoSizeNeeded = 0;
+ DWORD rebootReasons = 0;
+ ::RmGetList(sessionHandle, &procInfoSizeNeeded, &procInfoSize, nullptr, &rebootReasons); //get procInfoSizeNeeded
+ //fails with "access denied" for C:\pagefile.sys!
+
+ if (procInfoSizeNeeded == 0)
+ return std::vector<std::wstring>();
+
+ procInfoSize = procInfoSizeNeeded;
+ std::vector<RM_PROCESS_INFO> procInfo(procInfoSize);
+
+ DWORD rv3 = ::RmGetList(sessionHandle, //__in DWORD dwSessionHandle,
+ &procInfoSizeNeeded, //__out UINT *pnProcInfoNeeded,
+ &procInfoSize, //__inout UINT *pnProcInfo,
+ &procInfo[0], //__inout_opt RM_PROCESS_INFO rgAffectedApps[ ],
+ &rebootReasons); //__out LPDWORD lpdwRebootReasons
+ if (rv3 != ERROR_SUCCESS)
+ throw Win32Error(rv3);
+ procInfo.resize(procInfoSize);
+
+ std::vector<std::wstring> output;
+ for (auto iter = procInfo.begin(); iter != procInfo.end(); ++iter)
+ {
+ std::wstring processName = iter->strAppName;
+
+ //try to get process path
+ HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, //__in DWORD dwDesiredAccess,
+ false, //__in BOOL bInheritHandle,
+ iter->Process.dwProcessId); //__in DWORD dwProcessId
+ if (hProcess)
+ {
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hProcess));
+
+ FILETIME creationTime = {};
+ FILETIME exitTime = {};
+ FILETIME kernelTime = {};
+ FILETIME userTime = {};
+ if (::GetProcessTimes(hProcess, //__in HANDLE hProcess,
+ &creationTime, //__out LPFILETIME lpCreationTime,
+ &exitTime, //__out LPFILETIME lpExitTime,
+ &kernelTime, //__out LPFILETIME lpKernelTime,
+ &userTime)) //__out LPFILETIME lpUserTime
+ if (::CompareFileTime(&iter->Process.ProcessStartTime, &creationTime) == 0)
+ {
+ DWORD bufferSize = MAX_PATH;
+ std::vector<wchar_t> buffer(bufferSize);
+ if (::QueryFullProcessImageName(hProcess, //__in HANDLE hProcess,
+ 0, //__in DWORD dwFlags,
+ &buffer[0], //__out LPTSTR lpExeName,
+ &bufferSize)) //__inout PDWORD lpdwSize
+ if (bufferSize < buffer.size())
+ processName += std::wstring(L" - ") + L"\"" + &buffer[0] + L"\"";
+ }
+ }
+ output.push_back(processName);
+ }
+ return output;
+}
+
+
+boost::thread_specific_ptr<std::wstring> lastErrorMessage; //use "thread_local" in C++11
+}
+
+
+bool fileop::moveToRecycleBin(const wchar_t* fileNames[], size_t fileNo) //size of fileNames array
+{
+ try
+ {
+ ::moveToRecycleBin(fileNames, fileNo); //throw ComError
+ return true;
+ }
+ catch (const ComError& e)
+ {
+ lastErrorMessage.reset(new std::wstring(e.toString()));
+ return false;
+ }
+}
+
+
+bool fileop::copyFile(const wchar_t* sourceFile,
+ const wchar_t* targetFile)
+{
+ try
+ {
+ ::copyFile(sourceFile, targetFile); //throw ComError
+ return true;
+ }
+ catch (const ComError& e)
+ {
+ lastErrorMessage.reset(new std::wstring(e.toString()));
+ return false;
+ }
+}
+
+
+bool fileop::checkRecycler(const wchar_t* dirname, bool& isRecycler)
+{
+ try
+ {
+ CLSID clsid = {};
+ getFolderClsid(dirname, clsid); //throw ComError
+ isRecycler = ::IsEqualCLSID(clsid, CLSID_RecycleBin) == TRUE; //silence perf warning
+ return true;
+ }
+ catch (const ComError& e)
+ {
+ lastErrorMessage.reset(new std::wstring(e.toString()));
+ return false;
+ }
+}
+
+
+const wchar_t* fileop::getLastError()
+{
+ return !lastErrorMessage.get() ? L"" : lastErrorMessage->c_str();
+}
+
+
+bool fileop::getLockingProcesses(const wchar_t* filename, const wchar_t*& procList)
+{
+ try
+ {
+ std::vector<std::wstring> result = ::getLockingProcesses(filename); //throw Win32Error
+
+ std::wstring buffer;
+ for (auto iter = result.begin(); iter != result.end(); ++iter)
+ {
+ buffer += *iter;
+ buffer += L'\n';
+ }
+ if (!buffer.empty())
+ buffer.resize(buffer.size() - 1); //remove last line break
+
+ auto tmp = new wchar_t [buffer.size() + 1]; //bad_alloc ?
+ ::wmemcpy(tmp, buffer.c_str(), buffer.size() + 1); //include 0-termination
+ procList = tmp; //ownership passed
+
+ return true;
+ }
+ catch (const Win32Error& e)
+ {
+ lastErrorMessage.reset(new std::wstring(formatWin32Msg(e.errorCode_)));
+ return false;
+ }
+}
+
+
+void fileop::freeString(const wchar_t* str)
+{
+ delete [] str;
+}
diff --git a/zen/IFileOperation/file_op.h b/zen/IFileOperation/file_op.h
new file mode 100644
index 00000000..fb157301
--- /dev/null
+++ b/zen/IFileOperation/file_op.h
@@ -0,0 +1,76 @@
+// **************************************************************************
+// * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef RECYCLER_DLL_H
+#define RECYCLER_DLL_H
+
+#ifdef FILE_OP_DLL_EXPORTS
+#define FILE_OP_DLL_API extern "C" __declspec(dllexport)
+#else
+#define FILE_OP_DLL_API extern "C" __declspec(dllimport)
+#endif
+
+#include <zen/build_info.h>
+
+
+namespace fileop
+{
+/*--------------
+ |declarations|
+ --------------*/
+
+//COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize
+//minimum OS: Windows Vista or later
+
+FILE_OP_DLL_API
+bool moveToRecycleBin(const wchar_t* fileNames[],
+ size_t fileNo); //size of fileNames array
+
+FILE_OP_DLL_API
+bool copyFile(const wchar_t* sourceFile,
+ const wchar_t* targetFile);
+
+FILE_OP_DLL_API
+bool checkRecycler(const wchar_t* dirname, bool& isRecycler); //returns false on error
+
+FILE_OP_DLL_API
+bool getLockingProcesses(const wchar_t* filename, const wchar_t*& procList); //get list of processes as single string, call freeString(procList) after use!
+
+FILE_OP_DLL_API
+void freeString(const wchar_t* str);
+
+//get last error message if any of the functions above fail
+FILE_OP_DLL_API
+const wchar_t* getLastError(); //no nullptr check required!
+
+/*----------
+ |typedefs|
+ ----------*/
+typedef bool (*FunType_moveToRecycleBin)(const wchar_t* fileNames[], size_t fileNo);
+typedef bool (*FunType_copyFile)(const wchar_t* sourceFile, const wchar_t* targetFile);
+typedef bool (*FunType_checkRecycler)(const wchar_t* dirname, bool& isRecycler);
+typedef bool (*FunType_getLockingProcesses)(const wchar_t* filename, const wchar_t*& procList);
+typedef void (*FunType_freeString)(const wchar_t* str);
+typedef const wchar_t* (*FunType_getLastError)();
+
+/*--------------
+ |symbol names|
+ --------------*/
+//(use const pointers to ensure internal linkage)
+const char funName_moveToRecycleBin [] = "moveToRecycleBin";
+const char funName_copyFile [] = "copyFile";
+const char funName_checkRecycler [] = "checkRecycler";
+const char funName_getLockingProcesses[] = "getLockingProcesses";
+const char funName_freeString [] = "freeString";
+const char funName_getLastError [] = "getLastError";
+
+/*---------------
+ |library names|
+ ---------------*/
+inline const wchar_t* getDllName() { return zen::is64BitBuild ? L"FileOperation_x64.dll" : L"FileOperation_Win32.dll"; }
+}
+
+#endif //RECYCLER_DLL_H
bgstack15