1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // system_utils_win.cpp: Implementation of OS-specific functions for Windows
8
9 #include "system_utils.h"
10
11 #include <fileapi.h>
12 #include <stdarg.h>
13 #include <windows.h>
14 #include <algorithm>
15 #include <array>
16 #include <vector>
17
18 namespace angle
19 {
20
21 namespace
22 {
23
GetPath(HMODULE module)24 std::string GetPath(HMODULE module)
25 {
26 std::array<wchar_t, MAX_PATH> executableFileBuf;
27 DWORD executablePathLen = GetModuleFileNameW(module, executableFileBuf.data(),
28 static_cast<DWORD>(executableFileBuf.size()));
29 return Narrow(executablePathLen > 0 ? executableFileBuf.data() : L"");
30 }
31
GetDirectory(HMODULE module)32 std::string GetDirectory(HMODULE module)
33 {
34 std::string executablePath = GetPath(module);
35 return StripFilenameFromPath(executablePath);
36 }
37
38 } // anonymous namespace
39
GetExecutablePath()40 std::string GetExecutablePath()
41 {
42 return GetPath(nullptr);
43 }
44
GetExecutableDirectory()45 std::string GetExecutableDirectory()
46 {
47 return GetDirectory(nullptr);
48 }
49
GetSharedLibraryExtension()50 const char *GetSharedLibraryExtension()
51 {
52 return "dll";
53 }
54
GetCWD()55 Optional<std::string> GetCWD()
56 {
57 std::array<wchar_t, MAX_PATH> pathBuf;
58 DWORD result = GetCurrentDirectoryW(static_cast<DWORD>(pathBuf.size()), pathBuf.data());
59 if (result == 0)
60 {
61 return Optional<std::string>::Invalid();
62 }
63 return Narrow(pathBuf.data());
64 }
65
SetCWD(const char * dirName)66 bool SetCWD(const char *dirName)
67 {
68 return (SetCurrentDirectoryW(Widen(dirName).c_str()) == TRUE);
69 }
70
GetPathSeparatorForEnvironmentVar()71 const char *GetPathSeparatorForEnvironmentVar()
72 {
73 return ";";
74 }
75
GetCurrentSystemTime()76 double GetCurrentSystemTime()
77 {
78 LARGE_INTEGER frequency = {};
79 QueryPerformanceFrequency(&frequency);
80
81 LARGE_INTEGER curTime;
82 QueryPerformanceCounter(&curTime);
83
84 return static_cast<double>(curTime.QuadPart) / frequency.QuadPart;
85 }
86
GetCurrentProcessCpuTime()87 double GetCurrentProcessCpuTime()
88 {
89 FILETIME creationTime = {};
90 FILETIME exitTime = {};
91 FILETIME kernelTime = {};
92 FILETIME userTime = {};
93
94 // Note this will not give accurate results if the current thread is
95 // scheduled for less than the tick rate, which is often 15 ms. In that
96 // case, GetProcessTimes will not return different values, making it
97 // possible to end up with 0 ms for a process that takes 93% of a core
98 // (14/15 ms)! An alternative is QueryProcessCycleTime but there is no
99 // simple way to convert cycles back to seconds, and on top of that, it's
100 // not supported pre-Windows Vista.
101
102 // Returns 100-ns intervals, so we want to divide by 1e7 to get seconds
103 GetProcessTimes(GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime);
104
105 ULARGE_INTEGER kernelInt64;
106 kernelInt64.LowPart = kernelTime.dwLowDateTime;
107 kernelInt64.HighPart = kernelTime.dwHighDateTime;
108 double systemTimeSeconds = static_cast<double>(kernelInt64.QuadPart) * 1e-7;
109
110 ULARGE_INTEGER userInt64;
111 userInt64.LowPart = userTime.dwLowDateTime;
112 userInt64.HighPart = userTime.dwHighDateTime;
113 double userTimeSeconds = static_cast<double>(userInt64.QuadPart) * 1e-7;
114
115 return systemTimeSeconds + userTimeSeconds;
116 }
117
IsDirectory(const char * filename)118 bool IsDirectory(const char *filename)
119 {
120 WIN32_FILE_ATTRIBUTE_DATA fileInformation;
121
122 BOOL result =
123 GetFileAttributesExW(Widen(filename).c_str(), GetFileExInfoStandard, &fileInformation);
124 if (result)
125 {
126 DWORD attribs = fileInformation.dwFileAttributes;
127 return (attribs != INVALID_FILE_ATTRIBUTES) && ((attribs & FILE_ATTRIBUTE_DIRECTORY) > 0);
128 }
129
130 return false;
131 }
132
IsDebuggerAttached()133 bool IsDebuggerAttached()
134 {
135 return !!::IsDebuggerPresent();
136 }
137
BreakDebugger()138 void BreakDebugger()
139 {
140 __debugbreak();
141 }
142
GetExecutableExtension()143 const char *GetExecutableExtension()
144 {
145 return ".exe";
146 }
147
GetPathSeparator()148 char GetPathSeparator()
149 {
150 return '\\';
151 }
152
GetModuleDirectory()153 std::string GetModuleDirectory()
154 {
155 // GetModuleHandleEx is unavailable on UWP
156 #if !defined(ANGLE_IS_WINUWP)
157 static int placeholderSymbol = 0;
158 HMODULE module = nullptr;
159 if (GetModuleHandleExW(
160 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
161 reinterpret_cast<LPCWSTR>(&placeholderSymbol), &module))
162 {
163 return GetDirectory(module);
164 }
165 #endif
166 return GetDirectory(nullptr);
167 }
168
GetRootDirectory()169 std::string GetRootDirectory()
170 {
171 return "C:\\";
172 }
173
CreateDirectories(const std::string & path)174 bool CreateDirectories(const std::string &path)
175 {
176 // First sanitize path so we can use "/" as universal path separator
177 std::string sanitizedPath(path);
178 MakeForwardSlashThePathSeparator(sanitizedPath);
179
180 size_t pos = 0;
181 do
182 {
183 pos = sanitizedPath.find("/", pos);
184 std::string checkPath(sanitizedPath.substr(0, pos));
185 if (!checkPath.empty() && !IsDirectory(checkPath.c_str()))
186 {
187 if (!CreateDirectoryW(Widen(checkPath).c_str(), nullptr))
188 {
189 return false;
190 }
191 }
192 if (pos == std::string::npos)
193 {
194 break;
195 }
196 ++pos;
197 } while (true);
198 return true;
199 }
200
MakeForwardSlashThePathSeparator(std::string & path)201 void MakeForwardSlashThePathSeparator(std::string &path)
202 {
203 std::replace(path.begin(), path.end(), '\\', '/');
204 return;
205 }
206
GetTempDirectory()207 Optional<std::string> GetTempDirectory()
208 {
209 char tempDirOut[MAX_PATH + 1];
210 GetTempPathA(MAX_PATH + 1, tempDirOut);
211 std::string tempDir = std::string(tempDirOut);
212
213 if (tempDir.length() < 0 || tempDir.length() > MAX_PATH)
214 {
215 return Optional<std::string>::Invalid();
216 }
217
218 if (tempDir.length() > 0 && tempDir.back() == '\\')
219 {
220 tempDir.pop_back();
221 }
222
223 return tempDir;
224 }
225
CreateTemporaryFileInDirectory(const std::string & directory)226 Optional<std::string> CreateTemporaryFileInDirectory(const std::string &directory)
227 {
228 char fileName[MAX_PATH + 1];
229 if (GetTempFileNameA(directory.c_str(), "ANGLE", 0, fileName) == 0)
230 return Optional<std::string>::Invalid();
231
232 return std::string(fileName);
233 }
234
GetLibraryPath(void * libraryHandle)235 std::string GetLibraryPath(void *libraryHandle)
236 {
237 if (!libraryHandle)
238 {
239 return "";
240 }
241
242 std::array<wchar_t, MAX_PATH> buffer;
243 if (GetModuleFileNameW(reinterpret_cast<HMODULE>(libraryHandle), buffer.data(),
244 buffer.size()) == 0)
245 {
246 return "";
247 }
248
249 return Narrow(buffer.data());
250 }
251
GetLibrarySymbol(void * libraryHandle,const char * symbolName)252 void *GetLibrarySymbol(void *libraryHandle, const char *symbolName)
253 {
254 if (!libraryHandle)
255 {
256 fprintf(stderr, "Module was not loaded\n");
257 return nullptr;
258 }
259
260 return reinterpret_cast<void *>(
261 GetProcAddress(reinterpret_cast<HMODULE>(libraryHandle), symbolName));
262 }
263
CloseSystemLibrary(void * libraryHandle)264 void CloseSystemLibrary(void *libraryHandle)
265 {
266 if (libraryHandle)
267 {
268 FreeLibrary(reinterpret_cast<HMODULE>(libraryHandle));
269 }
270 }
Narrow(const std::wstring_view & utf16)271 std::string Narrow(const std::wstring_view &utf16)
272 {
273 if (utf16.empty())
274 {
275 return {};
276 }
277 int requiredSize = WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.size()),
278 nullptr, 0, nullptr, nullptr);
279 std::string utf8(requiredSize, '\0');
280 WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.size()), &utf8[0],
281 requiredSize, nullptr, nullptr);
282 return utf8;
283 }
284
Widen(const std::string_view & utf8)285 std::wstring Widen(const std::string_view &utf8)
286 {
287 if (utf8.empty())
288 {
289 return {};
290 }
291 int requiredSize =
292 MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), nullptr, 0);
293 std::wstring utf16(requiredSize, L'\0');
294 MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), &utf16[0],
295 requiredSize);
296 return utf16;
297 }
298
SetCurrentThreadName(const char * name)299 void SetCurrentThreadName(const char *name)
300 {
301 // Not implemented
302 }
303 } // namespace angle
304