diff options
Diffstat (limited to 'zen/IFileOperation/file_op.cpp')
-rw-r--r-- | zen/IFileOperation/file_op.cpp | 171 |
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; } } |