platform-windows.c 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. /*
  2. * Copyright (c) 2013 Hugh Bailey <[email protected]>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #define PSAPI_VERSION 1
  17. #include <windows.h>
  18. #include <mmsystem.h>
  19. #include <shellapi.h>
  20. #include <shlobj.h>
  21. #include <intrin.h>
  22. #include <psapi.h>
  23. #include "base.h"
  24. #include "platform.h"
  25. #include "darray.h"
  26. #include "dstr.h"
  27. #include "windows/win-version.h"
  28. #include "../../deps/w32-pthreads/pthread.h"
  29. static bool have_clockfreq = false;
  30. static LARGE_INTEGER clock_freq;
  31. static uint32_t winver = 0;
  32. static inline uint64_t get_clockfreq(void)
  33. {
  34. if (!have_clockfreq)
  35. QueryPerformanceFrequency(&clock_freq);
  36. return clock_freq.QuadPart;
  37. }
  38. static inline uint32_t get_winver(void)
  39. {
  40. if (!winver) {
  41. struct win_version_info ver;
  42. get_win_ver(&ver);
  43. winver = (ver.major << 16) | ver.minor;
  44. }
  45. return winver;
  46. }
  47. void *os_dlopen(const char *path)
  48. {
  49. struct dstr dll_name;
  50. wchar_t *wpath;
  51. wchar_t *wpath_slash;
  52. HMODULE h_library = NULL;
  53. if (!path)
  54. return NULL;
  55. dstr_init_copy(&dll_name, path);
  56. dstr_replace(&dll_name, "\\", "/");
  57. if (!dstr_find(&dll_name, ".dll"))
  58. dstr_cat(&dll_name, ".dll");
  59. os_utf8_to_wcs_ptr(dll_name.array, 0, &wpath);
  60. /* to make module dependency issues easier to deal with, allow
  61. * dynamically loaded libraries on windows to search for dependent
  62. * libraries that are within the library's own directory */
  63. wpath_slash = wcsrchr(wpath, L'/');
  64. if (wpath_slash) {
  65. *wpath_slash = 0;
  66. SetDllDirectoryW(wpath);
  67. *wpath_slash = L'/';
  68. }
  69. h_library = LoadLibraryW(wpath);
  70. bfree(wpath);
  71. dstr_free(&dll_name);
  72. if (wpath_slash)
  73. SetDllDirectoryW(NULL);
  74. if (!h_library) {
  75. DWORD error = GetLastError();
  76. char *message = NULL;
  77. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
  78. FORMAT_MESSAGE_IGNORE_INSERTS |
  79. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  80. NULL, error,
  81. MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  82. (LPSTR)&message, 0, NULL);
  83. blog(LOG_INFO, "LoadLibrary failed for '%s': %s (%lu)",
  84. path, message, error);
  85. if (message)
  86. LocalFree(message);
  87. }
  88. return h_library;
  89. }
  90. void *os_dlsym(void *module, const char *func)
  91. {
  92. void *handle;
  93. handle = (void*)GetProcAddress(module, func);
  94. return handle;
  95. }
  96. void os_dlclose(void *module)
  97. {
  98. FreeLibrary(module);
  99. }
  100. union time_data {
  101. FILETIME ft;
  102. unsigned long long val;
  103. };
  104. struct os_cpu_usage_info {
  105. union time_data last_time, last_sys_time, last_user_time;
  106. DWORD core_count;
  107. };
  108. os_cpu_usage_info_t *os_cpu_usage_info_start(void)
  109. {
  110. struct os_cpu_usage_info *info = bzalloc(sizeof(*info));
  111. SYSTEM_INFO si;
  112. FILETIME dummy;
  113. GetSystemInfo(&si);
  114. GetSystemTimeAsFileTime(&info->last_time.ft);
  115. GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
  116. &info->last_sys_time.ft, &info->last_user_time.ft);
  117. info->core_count = si.dwNumberOfProcessors;
  118. return info;
  119. }
  120. double os_cpu_usage_info_query(os_cpu_usage_info_t *info)
  121. {
  122. union time_data cur_time, cur_sys_time, cur_user_time;
  123. FILETIME dummy;
  124. double percent;
  125. if (!info)
  126. return 0.0;
  127. GetSystemTimeAsFileTime(&cur_time.ft);
  128. GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
  129. &cur_sys_time.ft, &cur_user_time.ft);
  130. percent = (double)(cur_sys_time.val - info->last_sys_time.val +
  131. (cur_user_time.val - info->last_user_time.val));
  132. percent /= (double)(cur_time.val - info->last_time.val);
  133. percent /= (double)info->core_count;
  134. info->last_time.val = cur_time.val;
  135. info->last_sys_time.val = cur_sys_time.val;
  136. info->last_user_time.val = cur_user_time.val;
  137. return percent * 100.0;
  138. }
  139. void os_cpu_usage_info_destroy(os_cpu_usage_info_t *info)
  140. {
  141. if (info)
  142. bfree(info);
  143. }
  144. bool os_sleepto_ns(uint64_t time_target)
  145. {
  146. uint64_t t = os_gettime_ns();
  147. uint32_t milliseconds;
  148. if (t >= time_target)
  149. return false;
  150. milliseconds = (uint32_t)((time_target - t)/1000000);
  151. if (milliseconds > 1)
  152. Sleep(milliseconds-1);
  153. for (;;) {
  154. t = os_gettime_ns();
  155. if (t >= time_target)
  156. return true;
  157. #if 0
  158. Sleep(1);
  159. #else
  160. Sleep(0);
  161. #endif
  162. }
  163. }
  164. void os_sleep_ms(uint32_t duration)
  165. {
  166. /* windows 8+ appears to have decreased sleep precision */
  167. if (get_winver() >= 0x0602 && duration > 0)
  168. duration--;
  169. Sleep(duration);
  170. }
  171. uint64_t os_gettime_ns(void)
  172. {
  173. LARGE_INTEGER current_time;
  174. double time_val;
  175. QueryPerformanceCounter(&current_time);
  176. time_val = (double)current_time.QuadPart;
  177. time_val *= 1000000000.0;
  178. time_val /= (double)get_clockfreq();
  179. return (uint64_t)time_val;
  180. }
  181. /* returns [folder]\[name] on windows */
  182. static int os_get_path_internal(char *dst, size_t size, const char *name,
  183. int folder)
  184. {
  185. wchar_t path_utf16[MAX_PATH];
  186. SHGetFolderPathW(NULL, folder, NULL, SHGFP_TYPE_CURRENT,
  187. path_utf16);
  188. if (os_wcs_to_utf8(path_utf16, 0, dst, size) != 0) {
  189. if (!name || !*name) {
  190. return (int)strlen(dst);
  191. }
  192. if (strcat_s(dst, size, "\\") == 0) {
  193. if (strcat_s(dst, size, name) == 0) {
  194. return (int)strlen(dst);
  195. }
  196. }
  197. }
  198. return -1;
  199. }
  200. static char *os_get_path_ptr_internal(const char *name, int folder)
  201. {
  202. char *ptr;
  203. wchar_t path_utf16[MAX_PATH];
  204. struct dstr path;
  205. SHGetFolderPathW(NULL, folder, NULL, SHGFP_TYPE_CURRENT,
  206. path_utf16);
  207. os_wcs_to_utf8_ptr(path_utf16, 0, &ptr);
  208. dstr_init_move_array(&path, ptr);
  209. dstr_cat(&path, "\\");
  210. dstr_cat(&path, name);
  211. return path.array;
  212. }
  213. int os_get_config_path(char *dst, size_t size, const char *name)
  214. {
  215. return os_get_path_internal(dst, size, name, CSIDL_APPDATA);
  216. }
  217. char *os_get_config_path_ptr(const char *name)
  218. {
  219. return os_get_path_ptr_internal(name, CSIDL_APPDATA);
  220. }
  221. int os_get_program_data_path(char *dst, size_t size, const char *name)
  222. {
  223. return os_get_path_internal(dst, size, name, CSIDL_COMMON_APPDATA);
  224. }
  225. char *os_get_program_data_path_ptr(const char *name)
  226. {
  227. return os_get_path_ptr_internal(name, CSIDL_COMMON_APPDATA);
  228. }
  229. bool os_file_exists(const char *path)
  230. {
  231. WIN32_FIND_DATAW wfd;
  232. HANDLE hFind;
  233. wchar_t *path_utf16;
  234. if (!os_utf8_to_wcs_ptr(path, 0, &path_utf16))
  235. return false;
  236. hFind = FindFirstFileW(path_utf16, &wfd);
  237. if (hFind != INVALID_HANDLE_VALUE)
  238. FindClose(hFind);
  239. bfree(path_utf16);
  240. return hFind != INVALID_HANDLE_VALUE;
  241. }
  242. size_t os_get_abs_path(const char *path, char *abspath, size_t size)
  243. {
  244. wchar_t wpath[512];
  245. wchar_t wabspath[512];
  246. size_t out_len = 0;
  247. size_t len;
  248. if (!abspath)
  249. return 0;
  250. len = os_utf8_to_wcs(path, 0, wpath, 512);
  251. if (!len)
  252. return 0;
  253. if (_wfullpath(wabspath, wpath, 512) != NULL)
  254. out_len = os_wcs_to_utf8(wabspath, 0, abspath, size);
  255. return out_len;
  256. }
  257. char *os_get_abs_path_ptr(const char *path)
  258. {
  259. char *ptr = bmalloc(512);
  260. if (!os_get_abs_path(path, ptr, 512)) {
  261. bfree(ptr);
  262. ptr = NULL;
  263. }
  264. return ptr;
  265. }
  266. struct os_dir {
  267. HANDLE handle;
  268. WIN32_FIND_DATA wfd;
  269. bool first;
  270. struct os_dirent out;
  271. };
  272. os_dir_t *os_opendir(const char *path)
  273. {
  274. struct dstr path_str = {0};
  275. struct os_dir *dir = NULL;
  276. WIN32_FIND_DATA wfd;
  277. HANDLE handle;
  278. wchar_t *w_path;
  279. dstr_copy(&path_str, path);
  280. dstr_cat(&path_str, "/*.*");
  281. if (os_utf8_to_wcs_ptr(path_str.array, path_str.len, &w_path) > 0) {
  282. handle = FindFirstFileW(w_path, &wfd);
  283. if (handle != INVALID_HANDLE_VALUE) {
  284. dir = bzalloc(sizeof(struct os_dir));
  285. dir->handle = handle;
  286. dir->first = true;
  287. dir->wfd = wfd;
  288. }
  289. bfree(w_path);
  290. }
  291. dstr_free(&path_str);
  292. return dir;
  293. }
  294. static inline bool is_dir(WIN32_FIND_DATA *wfd)
  295. {
  296. return !!(wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  297. }
  298. struct os_dirent *os_readdir(os_dir_t *dir)
  299. {
  300. if (!dir)
  301. return NULL;
  302. if (dir->first) {
  303. dir->first = false;
  304. } else {
  305. if (!FindNextFileW(dir->handle, &dir->wfd))
  306. return NULL;
  307. }
  308. os_wcs_to_utf8(dir->wfd.cFileName, 0, dir->out.d_name,
  309. sizeof(dir->out.d_name));
  310. dir->out.directory = is_dir(&dir->wfd);
  311. return &dir->out;
  312. }
  313. void os_closedir(os_dir_t *dir)
  314. {
  315. if (dir) {
  316. FindClose(dir->handle);
  317. bfree(dir);
  318. }
  319. }
  320. int64_t os_get_free_space(const char *path)
  321. {
  322. ULARGE_INTEGER remainingSpace;
  323. char abs_path[512];
  324. wchar_t w_abs_path[512];
  325. if (os_get_abs_path(path, abs_path, 512) > 0) {
  326. if (os_utf8_to_wcs(abs_path, 0, w_abs_path, 512) > 0) {
  327. BOOL success = GetDiskFreeSpaceExW(w_abs_path,
  328. (PULARGE_INTEGER)&remainingSpace,
  329. NULL, NULL);
  330. if (success)
  331. return (int64_t)remainingSpace.QuadPart;
  332. }
  333. }
  334. return -1;
  335. }
  336. static void make_globent(struct os_globent *ent, WIN32_FIND_DATA *wfd,
  337. const char *pattern)
  338. {
  339. struct dstr name = {0};
  340. struct dstr path = {0};
  341. char *slash;
  342. dstr_from_wcs(&name, wfd->cFileName);
  343. dstr_copy(&path, pattern);
  344. slash = strrchr(path.array, '/');
  345. if (slash)
  346. dstr_resize(&path, slash + 1 - path.array);
  347. else
  348. dstr_free(&path);
  349. dstr_cat_dstr(&path, &name);
  350. ent->path = path.array;
  351. ent->directory = is_dir(wfd);
  352. dstr_free(&name);
  353. }
  354. int os_glob(const char *pattern, int flags, os_glob_t **pglob)
  355. {
  356. DARRAY(struct os_globent) files;
  357. HANDLE handle;
  358. WIN32_FIND_DATA wfd;
  359. int ret = -1;
  360. wchar_t *w_path;
  361. da_init(files);
  362. if (os_utf8_to_wcs_ptr(pattern, 0, &w_path) > 0) {
  363. handle = FindFirstFileW(w_path, &wfd);
  364. if (handle != INVALID_HANDLE_VALUE) {
  365. do {
  366. struct os_globent ent = {0};
  367. make_globent(&ent, &wfd, pattern);
  368. if (ent.path)
  369. da_push_back(files, &ent);
  370. } while (FindNextFile(handle, &wfd));
  371. FindClose(handle);
  372. *pglob = bmalloc(sizeof(**pglob));
  373. (*pglob)->gl_pathc = files.num;
  374. (*pglob)->gl_pathv = files.array;
  375. ret = 0;
  376. }
  377. bfree(w_path);
  378. }
  379. if (ret != 0)
  380. *pglob = NULL;
  381. UNUSED_PARAMETER(flags);
  382. return ret;
  383. }
  384. void os_globfree(os_glob_t *pglob)
  385. {
  386. if (pglob) {
  387. for (size_t i = 0; i < pglob->gl_pathc; i++)
  388. bfree(pglob->gl_pathv[i].path);
  389. bfree(pglob->gl_pathv);
  390. bfree(pglob);
  391. }
  392. }
  393. int os_unlink(const char *path)
  394. {
  395. wchar_t *w_path;
  396. bool success;
  397. os_utf8_to_wcs_ptr(path, 0, &w_path);
  398. if (!w_path)
  399. return -1;
  400. success = !!DeleteFileW(w_path);
  401. bfree(w_path);
  402. return success ? 0 : -1;
  403. }
  404. int os_rmdir(const char *path)
  405. {
  406. wchar_t *w_path;
  407. bool success;
  408. os_utf8_to_wcs_ptr(path, 0, &w_path);
  409. if (!w_path)
  410. return -1;
  411. success = !!RemoveDirectoryW(w_path);
  412. bfree(w_path);
  413. return success ? 0 : -1;
  414. }
  415. int os_mkdir(const char *path)
  416. {
  417. wchar_t *path_utf16;
  418. BOOL success;
  419. if (!os_utf8_to_wcs_ptr(path, 0, &path_utf16))
  420. return MKDIR_ERROR;
  421. success = CreateDirectory(path_utf16, NULL);
  422. bfree(path_utf16);
  423. if (!success)
  424. return (GetLastError() == ERROR_ALREADY_EXISTS) ?
  425. MKDIR_EXISTS : MKDIR_ERROR;
  426. return MKDIR_SUCCESS;
  427. }
  428. int os_rename(const char *old_path, const char *new_path)
  429. {
  430. wchar_t *old_path_utf16 = NULL;
  431. wchar_t *new_path_utf16 = NULL;
  432. int code = -1;
  433. if (!os_utf8_to_wcs_ptr(old_path, 0, &old_path_utf16)) {
  434. return -1;
  435. }
  436. if (!os_utf8_to_wcs_ptr(new_path, 0, &new_path_utf16)) {
  437. goto error;
  438. }
  439. code = MoveFileExW(old_path_utf16, new_path_utf16,
  440. MOVEFILE_REPLACE_EXISTING) ? 0 : -1;
  441. error:
  442. bfree(old_path_utf16);
  443. bfree(new_path_utf16);
  444. return code;
  445. }
  446. int os_safe_replace(const char *target, const char *from, const char *backup)
  447. {
  448. wchar_t *wtarget = NULL;
  449. wchar_t *wfrom = NULL;
  450. wchar_t *wbackup = NULL;
  451. int code = -1;
  452. if (!target || !from)
  453. return -1;
  454. if (!os_utf8_to_wcs_ptr(target, 0, &wtarget))
  455. return -1;
  456. if (!os_utf8_to_wcs_ptr(from, 0, &wfrom))
  457. goto fail;
  458. if (backup && !os_utf8_to_wcs_ptr(backup, 0, &wbackup))
  459. goto fail;
  460. if (ReplaceFileW(wtarget, wfrom, wbackup, 0, NULL, NULL)) {
  461. code = 0;
  462. } else if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  463. code = MoveFileExW(wfrom, wtarget, MOVEFILE_REPLACE_EXISTING)
  464. ? 0 : -1;
  465. }
  466. fail:
  467. bfree(wtarget);
  468. bfree(wfrom);
  469. bfree(wbackup);
  470. return code;
  471. }
  472. BOOL WINAPI DllMain(HINSTANCE hinst_dll, DWORD reason, LPVOID reserved)
  473. {
  474. switch (reason) {
  475. case DLL_PROCESS_ATTACH:
  476. timeBeginPeriod(1);
  477. #ifdef PTW32_STATIC_LIB
  478. pthread_win32_process_attach_np();
  479. #endif
  480. break;
  481. case DLL_PROCESS_DETACH:
  482. timeEndPeriod(1);
  483. #ifdef PTW32_STATIC_LIB
  484. pthread_win32_process_detach_np();
  485. #endif
  486. break;
  487. case DLL_THREAD_ATTACH:
  488. #ifdef PTW32_STATIC_LIB
  489. pthread_win32_thread_attach_np();
  490. #endif
  491. break;
  492. case DLL_THREAD_DETACH:
  493. #ifdef PTW32_STATIC_LIB
  494. pthread_win32_thread_detach_np();
  495. #endif
  496. break;
  497. }
  498. UNUSED_PARAMETER(hinst_dll);
  499. UNUSED_PARAMETER(reserved);
  500. return true;
  501. }
  502. os_performance_token_t *os_request_high_performance(const char *reason)
  503. {
  504. UNUSED_PARAMETER(reason);
  505. return NULL;
  506. }
  507. void os_end_high_performance(os_performance_token_t *token)
  508. {
  509. UNUSED_PARAMETER(token);
  510. }
  511. int os_copyfile(const char *file_in, const char *file_out)
  512. {
  513. wchar_t *file_in_utf16 = NULL;
  514. wchar_t *file_out_utf16 = NULL;
  515. int code = -1;
  516. if (!os_utf8_to_wcs_ptr(file_in, 0, &file_in_utf16)) {
  517. return -1;
  518. }
  519. if (!os_utf8_to_wcs_ptr(file_out, 0, &file_out_utf16)) {
  520. goto error;
  521. }
  522. code = CopyFileW(file_in_utf16, file_out_utf16, true) ? 0 : -1;
  523. error:
  524. bfree(file_in_utf16);
  525. bfree(file_out_utf16);
  526. return code;
  527. }
  528. char *os_getcwd(char *path, size_t size)
  529. {
  530. wchar_t *path_w;
  531. DWORD len;
  532. len = GetCurrentDirectoryW(0, NULL);
  533. if (!len)
  534. return NULL;
  535. path_w = bmalloc((len + 1) * sizeof(wchar_t));
  536. GetCurrentDirectoryW(len + 1, path_w);
  537. os_wcs_to_utf8(path_w, (size_t)len, path, size);
  538. bfree(path_w);
  539. return path;
  540. }
  541. int os_chdir(const char *path)
  542. {
  543. wchar_t *path_w = NULL;
  544. size_t size;
  545. int ret;
  546. size = os_utf8_to_wcs_ptr(path, 0, &path_w);
  547. if (!path_w)
  548. return -1;
  549. ret = SetCurrentDirectoryW(path_w) ? 0 : -1;
  550. bfree(path_w);
  551. return ret;
  552. }
  553. typedef DWORD (WINAPI *get_file_version_info_size_w_t)(
  554. LPCWSTR module,
  555. LPDWORD unused);
  556. typedef BOOL (WINAPI *get_file_version_info_w_t)(
  557. LPCWSTR module,
  558. DWORD unused,
  559. DWORD len,
  560. LPVOID data);
  561. typedef BOOL (WINAPI *ver_query_value_w_t)(
  562. LPVOID data,
  563. LPCWSTR subblock,
  564. LPVOID *buf,
  565. PUINT sizeout);
  566. static get_file_version_info_size_w_t get_file_version_info_size = NULL;
  567. static get_file_version_info_w_t get_file_version_info = NULL;
  568. static ver_query_value_w_t ver_query_value = NULL;
  569. static bool ver_initialized = false;
  570. static bool ver_initialize_success = false;
  571. static bool initialize_version_functions(void)
  572. {
  573. HMODULE ver = GetModuleHandleW(L"version");
  574. ver_initialized = true;
  575. if (!ver) {
  576. ver = LoadLibraryW(L"version");
  577. if (!ver) {
  578. blog(LOG_ERROR, "Failed to load windows "
  579. "version library");
  580. return false;
  581. }
  582. }
  583. get_file_version_info_size = (get_file_version_info_size_w_t)
  584. GetProcAddress(ver, "GetFileVersionInfoSizeW");
  585. get_file_version_info = (get_file_version_info_w_t)
  586. GetProcAddress(ver, "GetFileVersionInfoW");
  587. ver_query_value = (ver_query_value_w_t)
  588. GetProcAddress(ver, "VerQueryValueW");
  589. if (!get_file_version_info_size ||
  590. !get_file_version_info ||
  591. !ver_query_value) {
  592. blog(LOG_ERROR, "Failed to load windows version "
  593. "functions");
  594. return false;
  595. }
  596. ver_initialize_success = true;
  597. return true;
  598. }
  599. bool get_dll_ver(const wchar_t *lib, struct win_version_info *ver_info)
  600. {
  601. VS_FIXEDFILEINFO *info = NULL;
  602. UINT len = 0;
  603. BOOL success;
  604. LPVOID data;
  605. DWORD size;
  606. char utf8_lib[512];
  607. if (!ver_initialized && !initialize_version_functions())
  608. return false;
  609. if (!ver_initialize_success)
  610. return false;
  611. os_wcs_to_utf8(lib, 0, utf8_lib, sizeof(utf8_lib));
  612. size = get_file_version_info_size(lib, NULL);
  613. if (!size) {
  614. blog(LOG_ERROR, "Failed to get %s version info size", utf8_lib);
  615. return false;
  616. }
  617. data = bmalloc(size);
  618. if (!get_file_version_info(lib, 0, size, data)) {
  619. blog(LOG_ERROR, "Failed to get %s version info", utf8_lib);
  620. bfree(data);
  621. return false;
  622. }
  623. success = ver_query_value(data, L"\\", (LPVOID*)&info, &len);
  624. if (!success || !info || !len) {
  625. blog(LOG_ERROR, "Failed to get %s version info value", utf8_lib);
  626. bfree(data);
  627. return false;
  628. }
  629. ver_info->major = (int)HIWORD(info->dwFileVersionMS);
  630. ver_info->minor = (int)LOWORD(info->dwFileVersionMS);
  631. ver_info->build = (int)HIWORD(info->dwFileVersionLS);
  632. ver_info->revis = (int)LOWORD(info->dwFileVersionLS);
  633. bfree(data);
  634. return true;
  635. }
  636. bool is_64_bit_windows(void)
  637. {
  638. #if defined(_WIN64)
  639. return true;
  640. #elif defined(_WIN32)
  641. BOOL b64 = false;
  642. return IsWow64Process(GetCurrentProcess(), &b64) && b64;
  643. #endif
  644. }
  645. #define WINVER_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
  646. void get_win_ver(struct win_version_info *info)
  647. {
  648. static struct win_version_info ver = {0};
  649. static bool got_version = false;
  650. if (!info)
  651. return;
  652. if (!got_version) {
  653. get_dll_ver(L"kernel32", &ver);
  654. got_version = true;
  655. if (ver.major == 10) {
  656. HKEY key;
  657. DWORD size, win10_revision;
  658. LSTATUS status;
  659. status = RegOpenKeyW(HKEY_LOCAL_MACHINE,
  660. WINVER_REG_KEY, &key);
  661. if (status != ERROR_SUCCESS)
  662. return;
  663. size = sizeof(win10_revision);
  664. status = RegQueryValueExW(key, L"UBR", NULL, NULL,
  665. (LPBYTE)&win10_revision, &size);
  666. if (status == ERROR_SUCCESS)
  667. ver.revis = (int)win10_revision > ver.revis ?
  668. (int)win10_revision : ver.revis;
  669. RegCloseKey(key);
  670. }
  671. }
  672. *info = ver;
  673. }
  674. struct os_inhibit_info {
  675. bool active;
  676. };
  677. os_inhibit_t *os_inhibit_sleep_create(const char *reason)
  678. {
  679. UNUSED_PARAMETER(reason);
  680. return bzalloc(sizeof(struct os_inhibit_info));
  681. }
  682. bool os_inhibit_sleep_set_active(os_inhibit_t *info, bool active)
  683. {
  684. if (!info)
  685. return false;
  686. if (info->active == active)
  687. return false;
  688. if (active) {
  689. SetThreadExecutionState(
  690. ES_CONTINUOUS |
  691. ES_SYSTEM_REQUIRED |
  692. ES_AWAYMODE_REQUIRED |
  693. ES_DISPLAY_REQUIRED);
  694. } else {
  695. SetThreadExecutionState(ES_CONTINUOUS);
  696. }
  697. info->active = active;
  698. return true;
  699. }
  700. void os_inhibit_sleep_destroy(os_inhibit_t *info)
  701. {
  702. if (info) {
  703. os_inhibit_sleep_set_active(info, false);
  704. bfree(info);
  705. }
  706. }
  707. void os_breakpoint(void)
  708. {
  709. __debugbreak();
  710. }
  711. DWORD num_logical_cores(ULONG_PTR mask)
  712. {
  713. DWORD left_shift = sizeof(ULONG_PTR) * 8 - 1;
  714. DWORD bit_set_count = 0;
  715. ULONG_PTR bit_test = (ULONG_PTR)1 << left_shift;
  716. for (DWORD i = 0; i <= left_shift; ++i) {
  717. bit_set_count += ((mask & bit_test) ? 1 : 0);
  718. bit_test /= 2;
  719. }
  720. return bit_set_count;
  721. }
  722. static int physical_cores = 0;
  723. static int logical_cores = 0;
  724. static bool core_count_initialized = false;
  725. static void os_get_cores_internal(void)
  726. {
  727. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION info = NULL, temp = NULL;
  728. DWORD len = 0;
  729. if (core_count_initialized)
  730. return;
  731. core_count_initialized = true;
  732. GetLogicalProcessorInformation(info, &len);
  733. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  734. return;
  735. info = malloc(len);
  736. if (GetLogicalProcessorInformation(info, &len)) {
  737. DWORD num = len / sizeof(*info);
  738. temp = info;
  739. for (DWORD i = 0; i < num; i++) {
  740. if (temp->Relationship == RelationProcessorCore) {
  741. ULONG_PTR mask = temp->ProcessorMask;
  742. physical_cores++;
  743. logical_cores += num_logical_cores(mask);
  744. }
  745. temp++;
  746. }
  747. }
  748. free(info);
  749. }
  750. int os_get_physical_cores(void)
  751. {
  752. if (!core_count_initialized)
  753. os_get_cores_internal();
  754. return physical_cores;
  755. }
  756. int os_get_logical_cores(void)
  757. {
  758. if (!core_count_initialized)
  759. os_get_cores_internal();
  760. return logical_cores;
  761. }
  762. static inline bool os_get_sys_memory_usage_internal(MEMORYSTATUSEX *msex)
  763. {
  764. if (!GlobalMemoryStatusEx(msex))
  765. return false;
  766. return true;
  767. }
  768. uint64_t os_get_sys_free_size(void)
  769. {
  770. MEMORYSTATUSEX msex = {sizeof(MEMORYSTATUSEX)};
  771. if (!os_get_sys_memory_usage_internal(&msex))
  772. return 0;
  773. return msex.ullAvailPhys;
  774. }
  775. static inline bool os_get_proc_memory_usage_internal(PROCESS_MEMORY_COUNTERS *pmc)
  776. {
  777. if (!GetProcessMemoryInfo(GetCurrentProcess(), pmc, sizeof(*pmc)))
  778. return false;
  779. return true;
  780. }
  781. bool os_get_proc_memory_usage(os_proc_memory_usage_t *usage)
  782. {
  783. PROCESS_MEMORY_COUNTERS pmc = {sizeof(PROCESS_MEMORY_COUNTERS)};
  784. if (!os_get_proc_memory_usage_internal(&pmc))
  785. return false;
  786. usage->resident_size = pmc.WorkingSetSize;
  787. usage->virtual_size = pmc.PagefileUsage;
  788. return true;
  789. }
  790. uint64_t os_get_proc_resident_size(void)
  791. {
  792. PROCESS_MEMORY_COUNTERS pmc = {sizeof(PROCESS_MEMORY_COUNTERS)};
  793. if (!os_get_proc_memory_usage_internal(&pmc))
  794. return 0;
  795. return pmc.WorkingSetSize;
  796. }
  797. uint64_t os_get_proc_virtual_size(void)
  798. {
  799. PROCESS_MEMORY_COUNTERS pmc = {sizeof(PROCESS_MEMORY_COUNTERS)};
  800. if (!os_get_proc_memory_usage_internal(&pmc))
  801. return 0;
  802. return pmc.PagefileUsage;
  803. }
  804. uint64_t os_get_free_disk_space(const char *dir)
  805. {
  806. wchar_t *wdir = NULL;
  807. if (!os_utf8_to_wcs_ptr(dir, 0, &wdir))
  808. return 0;
  809. ULARGE_INTEGER free;
  810. bool success = !!GetDiskFreeSpaceExW(wdir, &free, NULL, NULL);
  811. bfree(wdir);
  812. return success ? free.QuadPart : 0;
  813. }