diff options
Diffstat (limited to 'graphics/asymptote/win32helpers.cc')
-rw-r--r-- | graphics/asymptote/win32helpers.cc | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/graphics/asymptote/win32helpers.cc b/graphics/asymptote/win32helpers.cc new file mode 100644 index 0000000000..c8a5cfe65e --- /dev/null +++ b/graphics/asymptote/win32helpers.cc @@ -0,0 +1,240 @@ +/** + * @file win32helpers.cc + * @brief Windows-specific utility functions + * @author Supakorn "Jamie" Rassameemasmuang (jamievlin [at] outlook.com) + */ + +#if defined(_WIN32) +#include "win32helpers.h" +#include "errormsg.h" +#include <shellapi.h> + +using camp::reportError; + +namespace camp::w32 +{ + +bool checkShellExecuteResult(INT_PTR const shellExecResult, bool const reportWarning) +{ + switch (shellExecResult) + { + // see https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea + // ERROR_FILE_NOT_FOUND and ERROR_PATH_NOT_FOUND shares the same error code as + // SE_ERR_FNF and SE_ERR_PNF, respectively + case 0: + case ERROR_BAD_FORMAT: + case SE_ERR_ACCESSDENIED: + case SE_ERR_ASSOCINCOMPLETE: + case SE_ERR_DDEBUSY: + case SE_ERR_DDEFAIL: + case SE_ERR_DDETIMEOUT: + case SE_ERR_DLLNOTFOUND: + case SE_ERR_FNF: + case SE_ERR_NOASSOC: + case SE_ERR_OOM: + case SE_ERR_PNF: + case SE_ERR_SHARE: + { + if (reportWarning) + { + DWORD const errorCode= GetLastError(); + ostringstream msg; + msg << "Error code: 0x" << std::hex << errorCode << std::dec << "; message: " << getErrorMessage(errorCode); + camp::reportWarning(msg.str()); + } + } + return false; + default: + return true; + } +} + +void reportAndFailWithLastError(string const& message) +{ + DWORD errorCode= GetLastError(); + ostringstream msg; + msg << message << "; error code = 0x" << std::hex << errorCode << std::dec + << "; Windows Message: " << getErrorMessage(errorCode); + reportError(msg); +} + +void checkResult(BOOL result, string const& message) +{ + if (!result) + { + reportAndFailWithLastError(message); + } +} + +void checkLStatus(LSTATUS result, string const& message) +{ + checkResult(result == ERROR_SUCCESS, message); +} + +bool isProcessRunning(DWORD const& pid) +{ + if (pid == 0) + { + return true; // system idle is always running + } + + HandleRaiiWrapper const processHandle(OpenProcess(PROCESS_QUERY_INFORMATION, false, pid)); + if (processHandle.getHandle() == nullptr) + { + // handle not in system, returns false + return false; + } + + DWORD exitCode=999; + if (GetExitCodeProcess(processHandle.getHandle(), &exitCode)) + { + if (exitCode == STILL_ACTIVE) + { + return true; + } + else + { + return false; + } + } + + return false; +} + +#pragma region RegKeyWrapper + +RegKeyWrapper::RegKeyWrapper(HKEY const& regKey) + : key(regKey) +{ +} +RegKeyWrapper::RegKeyWrapper() : key(nullptr) +{ +} +RegKeyWrapper::~RegKeyWrapper() +{ + closeExistingKey(); +} +RegKeyWrapper::RegKeyWrapper(RegKeyWrapper&& other) noexcept + : key(std::exchange(other.key, nullptr)) +{ +} + +RegKeyWrapper& RegKeyWrapper::operator=(RegKeyWrapper&& other) noexcept +{ + if (this != &other) + { + closeExistingKey(); + this->key = std::exchange(other.key, nullptr); + } + return *this; +} + +HKEY RegKeyWrapper::getKey() const +{ + return key; +} + +void RegKeyWrapper::closeExistingKey() +{ + if (this->key != nullptr) + { + RegCloseKey(this->key); + this->key = nullptr; + } +} + +PHKEY RegKeyWrapper::put() +{ + closeExistingKey(); + return &(this->key); +} +void RegKeyWrapper::release() +{ + this->key = nullptr; +} + +#pragma endregion + +#pragma region HandleRaiiWrapper + +HandleRaiiWrapper::HandleRaiiWrapper(HANDLE const& handle) + : hd(handle) +{ +} + +HandleRaiiWrapper::~HandleRaiiWrapper() +{ + if (hd) + { + if (!CloseHandle(hd)) + { + cerr << "Warning: Cannot close handle" << endl; + } + } +} + +HandleRaiiWrapper::HandleRaiiWrapper(HandleRaiiWrapper&& other) noexcept +: hd(std::exchange(other.hd, nullptr)) +{ +} + +HANDLE HandleRaiiWrapper::getHandle() const +{ + return hd; +} + +LPHANDLE HandleRaiiWrapper::put() +{ + if (hd) + { + w32::checkResult(CloseHandle(hd)); + hd = nullptr; + } + + return &hd; +} + +#pragma endregion + +string buildWindowsCmd(const mem::vector<string>& command) +{ + ostringstream out; + for (auto it= command.begin(); it != command.end(); ++it) + { + out << '"' << *it << '"'; + if (std::next(it) != command.end()) + { + out << ' '; + } + } + + return out.str(); +} + +string getErrorMessage(DWORD const& errorCode) +{ + LPSTR messageOut= nullptr; + auto ret = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast<LPSTR>(&messageOut), + 0, + nullptr + ); + + if (ret == 0) + { + return "Cannot determine error message"; + } + + string retString(messageOut); + LocalFree(messageOut); + + return retString; +} + +}// namespace camp::w32 + +#endif |