Cbeam
Loading...
Searching...
No Matches
windows_config.hpp
Go to the documentation of this file.
1/*
2Copyright (c) 2025 acrion innovations GmbH
3Authors: Stefan Zipproth, s.zipproth@acrion.ch
4
5This file is part of Cbeam, see https://github.com/acrion/cbeam and https://cbeam.org
6
7Cbeam is offered under a commercial and under the AGPL license.
8For commercial licensing, contact us at https://acrion.ch/sales. For AGPL licensing, see below.
9
10AGPL licensing:
11
12Cbeam is free software: you can redistribute it and/or modify
13it under the terms of the GNU Affero General Public License as published by
14the Free Software Foundation, either version 3 of the License, or
15(at your option) any later version.
16
17Cbeam is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20GNU Affero General Public License for more details.
21
22You should have received a copy of the GNU Affero General Public License
23along with Cbeam. If not, see <https://www.gnu.org/licenses/>.
24*/
25
34
35#pragma once
36
37#ifdef _WIN32
38 #ifndef WINVER
39 #define WINVER 0x0A00
40 #endif
41 #ifndef _WIN32_WINNT
42 #define _WIN32_WINNT 0x0A00
43 #endif
44 #ifndef WIN32_LEAN_AND_MEAN
45 #define WIN32_LEAN_AND_MEAN
46 #endif
47 #ifndef NOMINMAX
48 #define NOMINMAX
49 #endif
50
51 #include <windows.h>
52
53 #include <string>
54
55namespace cbeam::platform
56{
66 inline std::string get_last_windows_error_message()
67 {
68 std::string message;
69
70 for (int attempts = 0; attempts < 2; ++attempts)
71 {
72 DWORD error_code = GetLastError(); // Get the last error code.
73 LPSTR message_buffer = nullptr;
74
75 const size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
76 NULL,
77 error_code,
78 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
79 (LPSTR)&message_buffer,
80 0,
81 NULL);
82
83 if (size > 0)
84 {
85 message = {message_buffer, size};
86 }
87 else
88 {
89 // This compiles to the documentation of `FormatMessageA`: "To get extended error information, call GetLastError".
90 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagea
91 // But we only make 1 further attempt to avoid an infinite loop.
92 error_code = GetLastError();
93 }
94
95 // The documentation does not define if there are error cases with allocated buffer ("If the function fails, the return value is zero")
96 // So we assume that a changed value of message_buffer means that it points to allocated memory.
97 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagea
98 if (message_buffer)
99 {
100 LocalFree(message_buffer);
101 }
102 }
103
104 if (message.empty())
105 {
106 // get_last_windows_error_message is not meant to detect if there was an error, but is based on the assumption that there was an error.
107 // Detecting generically if there was an error is impossible, because
108 // (1) "some functions set the last-error code to 0 on success and others do not"
109 // (2) some functions do not set the error code if they fail ("Most functions that set the thread's last-error code set it when they fail.")
110 // https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
111 message = "unknown error";
112 }
113
114 return message;
115 }
116
117 inline std::string get_last_windows_error_message()
118 {
119 DWORD error_code = GetLastError(); // we do not check if error_code == 0, because according to documentation "some functions set the last-error code to 0 on success and others do not" https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
120
121 LPSTR message_buffer = nullptr;
122 size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
123 NULL,
124 error_code,
125 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
126 (LPSTR)&message_buffer,
127 0,
128 NULL);
129
130 if (size > 0)
131 {
132 std::string message(message_buffer, size);
133 LocalFree(message_buffer);
134 return message;
135 }
136 else
137 {
138 // This compiles to the documentation of `FormatMessageA`: "To get extended error information, call GetLastError".
139 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagea
141 }
142 }
143}
144#endif
Groups platform-specific helpers for Windows, Linux, and macOS. These utilities detect CPU architectu...
Definition clock_precision.hpp:42
std::string get_last_windows_error_message()
Retrieves a descriptive error message for the last Windows API error.
Definition windows_config.hpp:66