diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:19:49 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:19:49 +0200 |
commit | c8e0e909b4a8d18319fc65434a10dc446434817c (patch) | |
tree | eee91e7d2ce229dd043811eae8f1e2bd78061916 /zen/IFileOperation | |
parent | 5.2 (diff) | |
download | FreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.tar.gz FreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.tar.bz2 FreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.zip |
5.3
Diffstat (limited to 'zen/IFileOperation')
-rw-r--r-- | zen/IFileOperation/FileOperation_Vista.vcxproj | 244 | ||||
-rw-r--r-- | zen/IFileOperation/dll_main.cpp | 25 | ||||
-rw-r--r-- | zen/IFileOperation/file_op.cpp | 349 | ||||
-rw-r--r-- | zen/IFileOperation/file_op.h | 76 |
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 |