1 | //===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines things specific to Windows implementations. In addition to |
10 | // providing some helpers for working with win32 APIs, this header wraps |
11 | // <windows.h> with some portability macros. Always include WindowsSupport.h |
12 | // instead of including <windows.h> directly. |
13 | // |
14 | //===----------------------------------------------------------------------===// |
15 | |
16 | //===----------------------------------------------------------------------===// |
17 | //=== WARNING: Implementation here must contain only generic Win32 code that |
18 | //=== is guaranteed to work on *all* Win32 variants. |
19 | //===----------------------------------------------------------------------===// |
20 | |
21 | #ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H |
22 | #define LLVM_SUPPORT_WINDOWSSUPPORT_H |
23 | |
24 | // mingw-w64 tends to define it as 0x0502 in its headers. |
25 | #undef _WIN32_WINNT |
26 | #undef _WIN32_IE |
27 | |
28 | // Require at least Windows 7 API. |
29 | #define _WIN32_WINNT 0x0601 |
30 | #define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed. |
31 | #define WIN32_LEAN_AND_MEAN |
32 | #ifndef NOMINMAX |
33 | #define NOMINMAX |
34 | #endif |
35 | |
36 | #include "llvm/ADT/SmallVector.h" |
37 | #include "llvm/ADT/StringExtras.h" |
38 | #include "llvm/ADT/StringRef.h" |
39 | #include "llvm/ADT/Twine.h" |
40 | #include "llvm/Config/llvm-config.h" // Get build system configuration settings |
41 | #include "llvm/Support/Allocator.h" |
42 | #include "llvm/Support/Chrono.h" |
43 | #include "llvm/Support/Compiler.h" |
44 | #include "llvm/Support/ErrorHandling.h" |
45 | #include "llvm/Support/VersionTuple.h" |
46 | #include <cassert> |
47 | #include <string> |
48 | #include <system_error> |
49 | #include <windows.h> |
50 | |
51 | // Must be included after windows.h |
52 | #include <wincrypt.h> |
53 | |
54 | namespace llvm { |
55 | |
56 | /// Determines if the program is running on Windows 8 or newer. This |
57 | /// reimplements one of the helpers in the Windows 8.1 SDK, which are intended |
58 | /// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't |
59 | /// yet have VersionHelpers.h, so we have our own helper. |
60 | bool RunningWindows8OrGreater(); |
61 | |
62 | /// Determines if the program is running on Windows 11 or Windows Server 2022. |
63 | bool RunningWindows11OrGreater(); |
64 | |
65 | /// Returns the Windows version as Major.Minor.0.BuildNumber. Uses |
66 | /// RtlGetVersion or GetVersionEx under the hood depending on what is available. |
67 | /// GetVersionEx is deprecated, but this API exposes the build number which can |
68 | /// be useful for working around certain kernel bugs. |
69 | llvm::VersionTuple GetWindowsOSVersion(); |
70 | |
71 | bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix); |
72 | |
73 | // Include GetLastError() in a fatal error message. |
74 | [[noreturn]] inline void ReportLastErrorFatal(const char *Msg) { |
75 | std::string ErrMsg; |
76 | MakeErrMsg(ErrMsg: &ErrMsg, prefix: Msg); |
77 | llvm::report_fatal_error(reason: Twine(ErrMsg)); |
78 | } |
79 | |
80 | template <typename HandleTraits> |
81 | class ScopedHandle { |
82 | typedef typename HandleTraits::handle_type handle_type; |
83 | handle_type Handle; |
84 | |
85 | ScopedHandle(const ScopedHandle &other) = delete; |
86 | void operator=(const ScopedHandle &other) = delete; |
87 | public: |
88 | ScopedHandle() |
89 | : Handle(HandleTraits::GetInvalid()) {} |
90 | |
91 | explicit ScopedHandle(handle_type h) |
92 | : Handle(h) {} |
93 | |
94 | ~ScopedHandle() { |
95 | if (HandleTraits::IsValid(Handle)) |
96 | HandleTraits::Close(Handle); |
97 | } |
98 | |
99 | handle_type take() { |
100 | handle_type t = Handle; |
101 | Handle = HandleTraits::GetInvalid(); |
102 | return t; |
103 | } |
104 | |
105 | ScopedHandle &operator=(handle_type h) { |
106 | if (HandleTraits::IsValid(Handle)) |
107 | HandleTraits::Close(Handle); |
108 | Handle = h; |
109 | return *this; |
110 | } |
111 | |
112 | // True if Handle is valid. |
113 | explicit operator bool() const { |
114 | return HandleTraits::IsValid(Handle) ? true : false; |
115 | } |
116 | |
117 | operator handle_type() const { |
118 | return Handle; |
119 | } |
120 | }; |
121 | |
122 | struct CommonHandleTraits { |
123 | typedef HANDLE handle_type; |
124 | |
125 | static handle_type GetInvalid() { |
126 | return INVALID_HANDLE_VALUE; |
127 | } |
128 | |
129 | static void Close(handle_type h) { |
130 | ::CloseHandle(h); |
131 | } |
132 | |
133 | static bool IsValid(handle_type h) { |
134 | return h != GetInvalid(); |
135 | } |
136 | }; |
137 | |
138 | struct JobHandleTraits : CommonHandleTraits { |
139 | static handle_type GetInvalid() { |
140 | return NULL; |
141 | } |
142 | }; |
143 | |
144 | struct CryptContextTraits : CommonHandleTraits { |
145 | typedef HCRYPTPROV handle_type; |
146 | |
147 | static handle_type GetInvalid() { |
148 | return 0; |
149 | } |
150 | |
151 | static void Close(handle_type h) { |
152 | ::CryptReleaseContext(h, 0); |
153 | } |
154 | |
155 | static bool IsValid(handle_type h) { |
156 | return h != GetInvalid(); |
157 | } |
158 | }; |
159 | |
160 | struct RegTraits : CommonHandleTraits { |
161 | typedef HKEY handle_type; |
162 | |
163 | static handle_type GetInvalid() { |
164 | return NULL; |
165 | } |
166 | |
167 | static void Close(handle_type h) { |
168 | ::RegCloseKey(h); |
169 | } |
170 | |
171 | static bool IsValid(handle_type h) { |
172 | return h != GetInvalid(); |
173 | } |
174 | }; |
175 | |
176 | struct FindHandleTraits : CommonHandleTraits { |
177 | static void Close(handle_type h) { |
178 | ::FindClose(h); |
179 | } |
180 | }; |
181 | |
182 | struct FileHandleTraits : CommonHandleTraits {}; |
183 | |
184 | typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle; |
185 | typedef ScopedHandle<FileHandleTraits> ScopedFileHandle; |
186 | typedef ScopedHandle<CryptContextTraits> ScopedCryptContext; |
187 | typedef ScopedHandle<RegTraits> ScopedRegHandle; |
188 | typedef ScopedHandle<FindHandleTraits> ScopedFindHandle; |
189 | typedef ScopedHandle<JobHandleTraits> ScopedJobHandle; |
190 | |
191 | template <class T> |
192 | class SmallVectorImpl; |
193 | |
194 | template <class T> |
195 | typename SmallVectorImpl<T>::const_pointer |
196 | c_str(SmallVectorImpl<T> &str) { |
197 | str.push_back(0); |
198 | str.pop_back(); |
199 | return str.data(); |
200 | } |
201 | |
202 | namespace sys { |
203 | |
204 | inline std::chrono::nanoseconds toDuration(FILETIME Time) { |
205 | ULARGE_INTEGER TimeInteger; |
206 | TimeInteger.LowPart = Time.dwLowDateTime; |
207 | TimeInteger.HighPart = Time.dwHighDateTime; |
208 | |
209 | // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) |
210 | return std::chrono::nanoseconds(100 * TimeInteger.QuadPart); |
211 | } |
212 | |
213 | inline TimePoint<> toTimePoint(FILETIME Time) { |
214 | ULARGE_INTEGER TimeInteger; |
215 | TimeInteger.LowPart = Time.dwLowDateTime; |
216 | TimeInteger.HighPart = Time.dwHighDateTime; |
217 | |
218 | // Adjust for different epoch |
219 | TimeInteger.QuadPart -= 11644473600ll * 10000000; |
220 | |
221 | // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) |
222 | return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart)); |
223 | } |
224 | |
225 | inline FILETIME toFILETIME(TimePoint<> TP) { |
226 | ULARGE_INTEGER TimeInteger; |
227 | TimeInteger.QuadPart = TP.time_since_epoch().count() / 100; |
228 | TimeInteger.QuadPart += 11644473600ll * 10000000; |
229 | |
230 | FILETIME Time; |
231 | Time.dwLowDateTime = TimeInteger.LowPart; |
232 | Time.dwHighDateTime = TimeInteger.HighPart; |
233 | return Time; |
234 | } |
235 | |
236 | namespace windows { |
237 | // Returns command line arguments. Unlike arguments given to main(), |
238 | // this function guarantees that the returned arguments are encoded in |
239 | // UTF-8 regardless of the current code page setting. |
240 | std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args, |
241 | BumpPtrAllocator &Alloc); |
242 | |
243 | /// Convert UTF-8 path to a suitable UTF-16 path for use with the Win32 Unicode |
244 | /// File API. |
245 | std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16, |
246 | size_t MaxPathLen = MAX_PATH); |
247 | |
248 | } // end namespace windows |
249 | } // end namespace sys |
250 | } // end namespace llvm. |
251 | |
252 | #endif |
253 | |