summaryrefslogtreecommitdiff
path: root/zen/IFileOperation/file_op.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/IFileOperation/file_op.cpp')
-rw-r--r--zen/IFileOperation/file_op.cpp171
1 files changed, 87 insertions, 84 deletions
diff --git a/zen/IFileOperation/file_op.cpp b/zen/IFileOperation/file_op.cpp
index 8816b502..218c6f99 100644
--- a/zen/IFileOperation/file_op.cpp
+++ b/zen/IFileOperation/file_op.cpp
@@ -31,13 +31,7 @@ using namespace zen;
namespace
{
-struct Win32Error
-{
- Win32Error(DWORD errorCode) : errorCode_(errorCode) {}
- DWORD errorCode_;
-};
-
-std::vector<std::wstring> getLockingProcesses(const wchar_t* filename); //throw Win32Error
+std::vector<std::wstring> getLockingProcesses(const wchar_t* filename); //throw SysError
class RecyclerProgressCallback : public IFileOperationProgressSink
@@ -167,13 +161,13 @@ private:
};
-void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
+void moveToRecycleBin(const wchar_t* fileNames[], //throw SysError
size_t fileCount,
fileop::RecyclerCallback callback,
void* sink)
{
ComPtr<IFileOperation> fileOp;
- ZEN_COM_CHECK(::CoCreateInstance(CLSID_FileOperation, //throw ComError
+ ZEN_COM_CHECK(::CoCreateInstance(CLSID_FileOperation, //throw SysError
nullptr,
CLSCTX_ALL,
IID_PPV_ARGS(fileOp.init())));
@@ -196,7 +190,7 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
ComPtr<RecyclerProgressCallback> opProgress;
*opProgress.init() = new (std::nothrow) RecyclerProgressCallback(callback, sink);
if (!opProgress)
- throw ComError(L"Error creating RecyclerProgressCallback.", E_OUTOFMEMORY);
+ throw SysError(formatComError(L"Error creating RecyclerProgressCallback.", E_OUTOFMEMORY));
DWORD callbackID = 0;
ZEN_COM_CHECK(fileOp->Advise(opProgress.get(), &callbackID));
@@ -214,10 +208,10 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
{
continueExecution = callback(fileNames[i], sink); //should not throw!
}
- catch (...) { throw ComError(L"Unexpected exception in callback.", E_UNEXPECTED); }
+ catch (...) { throw SysError(formatComError(L"Unexpected exception in callback.", E_UNEXPECTED)); }
if (!continueExecution)
- throw ComError(L"Operation cancelled.", HRESULT_FROM_WIN32(ERROR_CANCELLED));
+ throw SysError(formatComError(L"Operation cancelled.", HRESULT_FROM_WIN32(ERROR_CANCELLED)));
}
//create file/folder item object
@@ -235,7 +229,7 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
if (!somethingExists(fileNames[i]))
continue;
}
- throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\'" + fileNames[i] + L"\'.", hr);
+ throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\'" + fileNames[i] + L"\'.", hr));
}
ZEN_COM_CHECK(fileOp->DeleteItem(psiFile.get(), nullptr));
@@ -251,24 +245,22 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
{
ZEN_COM_CHECK(fileOp->PerformOperations());
}
- catch (const ComError&)
+ catch (const SysError&)
{
//first let's check if we have more detailed error information available
if (const std::pair<std::wstring, HRESULT>* lastError = opProgress->getLastError())
{
- try //create an even better error message if we detect a locking issue:
+ std::vector<std::wstring> processes; //create an even better error message if we detect a locking issue:
+ try { processes = getLockingProcesses(lastError->first.c_str()); /*throw SysError*/ }
+ catch (const SysError&) {}
+
+ if (!processes.empty())
{
- std::vector<std::wstring> processes = getLockingProcesses(lastError->first.c_str()); //throw Win32Error
- if (!processes.empty())
- {
- std::wstring msg = L"The file \'" + lastError->first + L"\' is locked by another process:";
- std::for_each(processes.begin(), processes.end(), [&](const std::wstring& proc) { msg += L'\n'; msg += proc; });
- throw ComError(msg); //message is already descriptive enough, no need to add the HRESULT code
- }
+ std::wstring errorMsg = L"The file \'" + lastError->first + L"\' is locked by another process:";
+ std::for_each(processes.begin(), processes.end(), [&](const std::wstring& proc) { errorMsg += L'\n'; errorMsg += proc; });
+ throw SysError(errorMsg); //message is descriptive enough, no need to evaluate HRESULT!
}
- catch (const Win32Error&) {}
-
- throw ComError(std::wstring(L"Error during \"PerformOperations\" for file:\n") + L"\'" + lastError->first + L"\'.", lastError->second);
+ throw SysError(formatComError(std::wstring(L"Error during \"PerformOperations\" for file:\n") + L"\'" + lastError->first + L"\'.", lastError->second));
}
throw;
}
@@ -278,15 +270,15 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
ZEN_COM_CHECK(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted));
if (pfAnyOperationsAborted == TRUE)
- throw ComError(L"Operation did not complete successfully.");
+ throw SysError(L"Operation did not complete successfully.");
}
-void copyFile(const wchar_t* sourceFile, //throw ComError
+void copyFile(const wchar_t* sourceFile, //throw SysError
const wchar_t* targetFile)
{
ComPtr<IFileOperation> fileOp;
- ZEN_COM_CHECK(::CoCreateInstance(CLSID_FileOperation, //throw ComError
+ ZEN_COM_CHECK(::CoCreateInstance(CLSID_FileOperation, //throw SysError
nullptr,
CLSCTX_ALL,
IID_PPV_ARGS(fileOp.init())));
@@ -295,7 +287,7 @@ void copyFile(const wchar_t* sourceFile, //throw ComError
// from being shown to the user during the
// operation. This includes error, confirmation
// and progress dialogs.
- ZEN_COM_CHECK(fileOp->SetOperationFlags(FOF_NOCONFIRMATION | //throw ComError
+ ZEN_COM_CHECK(fileOp->SetOperationFlags(FOF_NOCONFIRMATION | //throw SysError
FOF_SILENT |
FOFX_EARLYFAILURE |
FOF_NOERRORUI));
@@ -306,12 +298,12 @@ void copyFile(const wchar_t* sourceFile, //throw ComError
nullptr,
IID_PPV_ARGS(psiSourceFile.init()));
if (FAILED(hr))
- throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\'" + sourceFile + L"\'.", hr);
+ throw SysError(formatComError(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.");
+ throw SysError(L"Target filename does not contain a path separator.");
const std::wstring targetFolder(targetFile, pos);
const std::wstring targetFileNameShort = targetFile + pos + 1;
@@ -323,7 +315,7 @@ void copyFile(const wchar_t* sourceFile, //throw ComError
nullptr,
IID_PPV_ARGS(psiTargetFolder.init()));
if (FAILED(hr))
- throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\'" + targetFolder + L"\'.", hr);
+ throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\'" + targetFolder + L"\'.", hr));
}
//schedule file copy operation
@@ -337,14 +329,14 @@ void copyFile(const wchar_t* sourceFile, //throw ComError
ZEN_COM_CHECK(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted));
if (pfAnyOperationsAborted == TRUE)
- throw ComError(L"Operation did not complete successfully.");
+ throw SysError(L"Operation did not complete successfully.");
}
-void getFolderClsid(const wchar_t* dirname, CLSID& pathCLSID) //throw ComError
+void getFolderClsid(const wchar_t* dirname, CLSID& pathCLSID) //throw SysError
{
ComPtr<IShellFolder> desktopFolder;
- ZEN_COM_CHECK(::SHGetDesktopFolder(desktopFolder.init())); //throw ComError
+ ZEN_COM_CHECK(::SHGetDesktopFolder(desktopFolder.init())); //throw SysError
PIDLIST_RELATIVE pidlFolder = nullptr;
ZEN_COM_CHECK(desktopFolder->ParseDisplayName(nullptr, // [in] HWND hwnd,
@@ -358,53 +350,64 @@ void getFolderClsid(const wchar_t* dirname, CLSID& pathCLSID) //throw ComError
ComPtr<IPersist> persistFolder;
ZEN_COM_CHECK(desktopFolder->BindToObject(pidlFolder, // [in] PCUIDLIST_RELATIVE pidl,
nullptr, // [in] IBindCtx *pbc,
- IID_PPV_ARGS(persistFolder.init()))); //throw ComError
+ IID_PPV_ARGS(persistFolder.init()))); //throw SysError
- ZEN_COM_CHECK(persistFolder->GetClassID(&pathCLSID)); //throw ComError
+ ZEN_COM_CHECK(persistFolder->GetClassID(&pathCLSID)); //throw SysError
}
-std::vector<std::wstring> getLockingProcesses(const wchar_t* filename) //throw Win32Error
+std::vector<std::wstring> getLockingProcesses(const wchar_t* filename) //throw SysError
{
- 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);
+ {
+ wchar_t sessionKey[CCH_RM_SESSION_KEY + 1] = {}; //fixes two bugs: http://blogs.msdn.com/b/oldnewthing/archive/2012/02/17/10268840.aspx
+ DWORD rv1 = ::RmStartSession(&sessionHandle, //__out DWORD *pSessionHandle,
+ 0, //__reserved DWORD dwSessionFlags,
+ sessionKey); //__out WCHAR strSessionKey[ ]
+ if (rv1 != ERROR_SUCCESS)
+ throw SysError(formatSystemError(L"RmStartSession", 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);
+ {
+ 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 SysError(formatSystemError(L"RmRegisterResources", rv2));
+ }
+
+ std::vector<RM_PROCESS_INFO> procInfo;
+ {
+ UINT procInfoSize = 0;
+ UINT procInfoSizeNeeded = 0;
+ DWORD rebootReasons = 0;
+ DWORD rv3 = ::RmGetList(sessionHandle, &procInfoSizeNeeded, &procInfoSize, nullptr, &rebootReasons); //get procInfoSizeNeeded
+ if (rv3 == ERROR_SUCCESS)
+ return std::vector<std::wstring>();
+ if (rv3 != ERROR_MORE_DATA)
+ throw SysError(formatSystemError(L"RmGetList", rv3));
+ //C:\pagefile.sys fails with ERROR_SHARING_VIOLATION!
+
+ if (procInfoSizeNeeded == 0)
+ return std::vector<std::wstring>();
+
+ procInfoSize = procInfoSizeNeeded;
+ procInfo.resize(procInfoSizeNeeded);
+
+ 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 SysError(formatSystemError(L"RmGetList", rv3));
+ procInfo.resize(procInfoSize);
+ }
std::vector<std::wstring> output;
for (auto iter = procInfo.begin(); iter != procInfo.end(); ++iter)
@@ -437,7 +440,7 @@ std::vector<std::wstring> getLockingProcesses(const wchar_t* filename) //throw W
&buffer[0], //__out LPTSTR lpExeName,
&bufferSize)) //__inout PDWORD lpdwSize
if (bufferSize < buffer.size())
- processName += std::wstring(L" - ") + L"\'" + &buffer[0] + L"\'";
+ processName += std::wstring(L", ") + L"\'" + &buffer[0] + L"\'";
}
}
output.push_back(processName);
@@ -457,10 +460,10 @@ bool fileop::moveToRecycleBin(const wchar_t* fileNames[],
{
try
{
- ::moveToRecycleBin(fileNames, fileCount, callback, sink); //throw ComError
+ ::moveToRecycleBin(fileNames, fileCount, callback, sink); //throw SysError
return true;
}
- catch (const ComError& e)
+ catch (const SysError& e)
{
lastErrorMessage.reset(new std::wstring(e.toString()));
return false;
@@ -473,10 +476,10 @@ bool fileop::copyFile(const wchar_t* sourceFile,
{
try
{
- ::copyFile(sourceFile, targetFile); //throw ComError
+ ::copyFile(sourceFile, targetFile); //throw SysError
return true;
}
- catch (const ComError& e)
+ catch (const SysError& e)
{
lastErrorMessage.reset(new std::wstring(e.toString()));
return false;
@@ -489,11 +492,11 @@ bool fileop::checkRecycler(const wchar_t* dirname, bool& isRecycler)
try
{
CLSID clsid = {};
- getFolderClsid(dirname, clsid); //throw ComError
+ getFolderClsid(dirname, clsid); //throw SysError
isRecycler = ::IsEqualCLSID(clsid, CLSID_RecycleBin) == TRUE; //silence perf warning
return true;
}
- catch (const ComError& e)
+ catch (const SysError& e)
{
lastErrorMessage.reset(new std::wstring(e.toString()));
return false;
@@ -511,7 +514,7 @@ bool fileop::getLockingProcesses(const wchar_t* filename, const wchar_t*& procLi
{
try
{
- std::vector<std::wstring> processes = ::getLockingProcesses(filename); //throw Win32Error
+ std::vector<std::wstring> processes = ::getLockingProcesses(filename); //throw SysError
std::wstring buffer;
std::for_each(processes.begin(), processes.end(), [&](const std::wstring& proc) { buffer += proc; buffer += L'\n'; });
@@ -524,9 +527,9 @@ bool fileop::getLockingProcesses(const wchar_t* filename, const wchar_t*& procLi
return true;
}
- catch (const Win32Error& e)
+ catch (const SysError& e)
{
- lastErrorMessage.reset(new std::wstring(formatWin32Msg(e.errorCode_)));
+ lastErrorMessage.reset(new std::wstring(e.toString()));
return false;
}
}
bgstack15