diff --git a/include/stdex/chrono.hpp b/include/stdex/chrono.hpp index 01512b873..73c045c29 100644 --- a/include/stdex/chrono.hpp +++ b/include/stdex/chrono.hpp @@ -6,10 +6,8 @@ #pragma once #include "sal.hpp" +#include "system.hpp" #include -#ifdef _WIN32 -#include -#endif #include #include diff --git a/include/stdex/endian.hpp b/include/stdex/endian.hpp index 1cc96c11f..d1f6a5d86 100644 --- a/include/stdex/endian.hpp +++ b/include/stdex/endian.hpp @@ -5,10 +5,8 @@ #pragma once -#ifdef _WIN32 -#include -#endif #include "sal.hpp" +#include "system.hpp" #include #include diff --git a/include/stdex/parser.hpp b/include/stdex/parser.hpp index ccf4194be..b7f76a78b 100644 --- a/include/stdex/parser.hpp +++ b/include/stdex/parser.hpp @@ -10,6 +10,7 @@ #include "sal.hpp" #include "sgml.hpp" #include "string.hpp" +#include "system.hpp" #include #include #include diff --git a/include/stdex/system.hpp b/include/stdex/system.hpp new file mode 100644 index 000000000..467d27420 --- /dev/null +++ b/include/stdex/system.hpp @@ -0,0 +1,204 @@ +/* + SPDX-License-Identifier: MIT + Copyright © 2023 Amebis +*/ + +#pragma once + +#ifdef _WIN32 +#define NOMINMAX // Collides with std::min/max +#include +#include +#include +#else +#include +#endif +#include "sal.hpp" +#include +#include + +// In case somebody #included before us and didn't #define NOMINMAX +#ifdef _WIN32 +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif +#endif + +namespace stdex +{ + /// + /// Operating system handle + /// +#if defined(_WIN32) + using sys_handle = HANDLE; + const sys_handle invalid_handle = INVALID_HANDLE_VALUE; +#else + using sys_handle = int; + const sys_handle invalid_handle = (sys_handle)-1; +#endif + + /// + /// Character type for system functions + /// +#if defined(_WIN32) + using sys_char = TCHAR; +#else + using sys_char = char; +#define _T(x) x +#endif + + /// + /// Operating system object (file, pipe, anything with an OS handle etc.) + /// + class sys_object + { + public: + sys_object(_In_opt_ sys_handle h = invalid_handle) : m_h(h) {} + + sys_object(_In_ const sys_object& other) : m_h(other.m_h != invalid_handle ? duplicate(other.m_h, false) : invalid_handle) {} + + sys_object& operator =(_In_ const sys_object& other) + { + if (this != std::addressof(other)) { + if (m_h != invalid_handle) + close(m_h); + m_h = other.m_h != invalid_handle ? duplicate(other.m_h, false) : invalid_handle; + } + return *this; + } + + sys_object(_Inout_ sys_object&& other) noexcept : m_h(other.m_h) + { + other.m_h = invalid_handle; + } + + sys_object& operator =(_Inout_ sys_object&& other) noexcept + { + if (this != std::addressof(other)) { + if (m_h != invalid_handle) + close(m_h); + m_h = other.m_h; + other.m_h = invalid_handle; + } + return *this; + } + + virtual ~sys_object() + { + if (m_h != invalid_handle) + close(m_h); + } + + /// + /// Closes object + /// + virtual void close() + { + if (m_h != invalid_handle) { + close(m_h); + m_h = invalid_handle; + } + } + + /// + /// Returns true if object is valid + /// + inline operator bool() const noexcept { return m_h != invalid_handle; } + + /// + /// Returns object handle + /// + inline sys_handle get() const noexcept { return m_h; } + + protected: + /// + /// Closes object + /// + static void close(sys_handle h) + { +#ifdef _WIN32 + if (CloseHandle(h) || GetLastError() == ERROR_INVALID_HANDLE) +#else + if (close(h) >= 0 || errno == EBADF) +#endif + return; + throw std::runtime_error("failed to close handle"); + } + + /// + /// Duplicates given object + /// + static sys_handle duplicate(_In_ sys_handle h, _In_ bool inherit) + { + sys_handle h_new; +#ifdef _WIN32 + HANDLE process = GetCurrentProcess(); + if (DuplicateHandle(process, h, process, &h_new, 0, inherit, DUPLICATE_SAME_ACCESS)) +#else + UNREFERENCED_PARAMETER(inherit); + if ((h_new = dup(h)) >= 0) +#endif + return h_new; + throw std::runtime_error("failed to duplicate handle"); + } + + protected: + sys_handle m_h; + }; + +#ifdef _WIN32 + template + class safearray_accessor + { + public: + safearray_accessor(_In_ LPSAFEARRAY sa) : m_sa(sa) + { + HRESULT hr = SafeArrayAccessData(sa, reinterpret_cast(&m_data)); + if (FAILED(hr)) + throw std::invalid_argument("SafeArrayAccessData failed"); + } + + ~safearray_accessor() + { + SafeArrayUnaccessData(m_sa); + } + + T* data() const { return m_data; } + + protected: + LPSAFEARRAY m_sa; + T* m_data; + }; + + /// + /// Deleter for unique_ptr using SafeArrayDestroy + /// + struct SafeArrayDestroy_delete + { + /// + /// Delete a pointer + /// + void operator()(_In_ LPSAFEARRAY sa) const + { + SafeArrayDestroy(sa); + } + }; + + /// + /// Deleter for unique_ptr using SysFreeString + /// + struct SysFreeString_delete + { + /// + /// Delete a pointer + /// + void operator()(_In_ BSTR sa) const + { + SysFreeString(sa); + } + }; +#endif +} diff --git a/include/stdex/unicode.hpp b/include/stdex/unicode.hpp index 378b026fd..2a4521b7c 100644 --- a/include/stdex/unicode.hpp +++ b/include/stdex/unicode.hpp @@ -6,10 +6,8 @@ #pragma once #include "sal.hpp" +#include "system.hpp" #include -#ifdef _WIN32 -#include -#endif #include #include