Niceties for getting the last error on windows

This commit is contained in:
Kovid Goyal 2023-01-28 12:21:34 +05:30
parent 795c4c6061
commit 467af44edb
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -5,12 +5,15 @@
*/
#pragma once
#include <string>
#define PY_SSIZE_T_CLEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <Python.h>
#include <memory>
#include <comdef.h>
#include <system_error>
#include "../cpp_binding.h"
static inline PyObject*
@ -24,6 +27,46 @@ set_error_from_hresult(PyObject *exc_type, const char *file, const int line, con
}
#define error_from_hresult(hr, ...) set_error_from_hresult(PyExc_OSError, __FILE__, __LINE__, hr, __VA_ARGS__)
// trim from end (in place)
template<typename T>
static inline void
rtrim(std::basic_string<T> &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](T ch) {
switch (ch) { case ' ': case '\t': case '\n': case '\r': case '\v': case '\f': return false; }
return true;
}).base(), s.end());
}
static inline std::wstring
get_last_error(std::wstring const & prefix = L"") {
auto ec = GetLastError();
LPWSTR buf;
DWORD n;
if ((n = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
ec,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&buf),
0, NULL)) == 0) {
auto error_code{ ::GetLastError() };
throw std::system_error(error_code, std::system_category(), "Failed to retrieve error message string.");
}
auto deleter = [](void* p) { ::LocalFree(p); };
std::unique_ptr<WCHAR, decltype(deleter)> ptrBuffer(buf, deleter);
auto msg = std::wstring(buf, n);
std::wstring ans = prefix;
if (prefix.size() > 0) {
ans += L": ";
}
rtrim(msg);
ans += L"Code: " + std::to_wstring(ec) + L" Message: " + msg;
return ans;
}
class scoped_com_initializer { // {{{
public:
scoped_com_initializer() : m_succeded(false), hr(0) {
@ -67,6 +110,7 @@ typedef generic_raii<void*, mapping_raii_free> mapping_raii;
static inline HANDLE invalid_handle_value_getter(void) { return INVALID_HANDLE_VALUE; }
static inline void close_handle(HANDLE x) { CloseHandle(x); }
typedef generic_raii<HANDLE, close_handle, invalid_handle_value_getter> handle_raii;
typedef generic_raii<HANDLE, close_handle> handle_raii_null;
struct prop_variant : PROPVARIANT {
prop_variant(VARTYPE vt=VT_EMPTY) noexcept : PROPVARIANT{} { PropVariantInit(this); this->vt = vt; }