summaryrefslogtreecommitdiff
path: root/graphics/asymptote/win32helpers.cc
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/asymptote/win32helpers.cc')
-rw-r--r--graphics/asymptote/win32helpers.cc240
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