platform-windows.c 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  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 && ver.revis == 0) {
  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;
  668. RegCloseKey(key);
  669. }
  670. }
  671. *info = ver;
  672. }
  673. struct os_inhibit_info {
  674. bool active;
  675. };
  676. os_inhibit_t *os_inhibit_sleep_create(const char *reason)
  677. {
  678. UNUSED_PARAMETER(reason);
  679. return bzalloc(sizeof(struct os_inhibit_info));
  680. }
  681. bool os_inhibit_sleep_set_active(os_inhibit_t *info, bool active)
  682. {
  683. if (!info)
  684. return false;
  685. if (info->active == active)
  686. return false;
  687. if (active) {
  688. SetThreadExecutionState(
  689. ES_CONTINUOUS |
  690. ES_SYSTEM_REQUIRED |
  691. ES_AWAYMODE_REQUIRED |
  692. ES_DISPLAY_REQUIRED);
  693. } else {
  694. SetThreadExecutionState(ES_CONTINUOUS);
  695. }
  696. info->active = active;
  697. return true;
  698. }
  699. void os_inhibit_sleep_destroy(os_inhibit_t *info)
  700. {
  701. if (info) {
  702. os_inhibit_sleep_set_active(info, false);
  703. bfree(info);
  704. }
  705. }
  706. void os_breakpoint(void)
  707. {
  708. __debugbreak();
  709. }
  710. DWORD num_logical_cores(ULONG_PTR mask)
  711. {
  712. DWORD left_shift = sizeof(ULONG_PTR) * 8 - 1;
  713. DWORD bit_set_count = 0;
  714. ULONG_PTR bit_test = (ULONG_PTR)1 << left_shift;
  715. for (DWORD i = 0; i <= left_shift; ++i) {
  716. bit_set_count += ((mask & bit_test) ? 1 : 0);
  717. bit_test /= 2;
  718. }
  719. return bit_set_count;
  720. }
  721. static int physical_cores = 0;
  722. static int logical_cores = 0;
  723. static bool core_count_initialized = false;
  724. static void os_get_cores_internal(void)
  725. {
  726. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION info = NULL, temp = NULL;
  727. DWORD len = 0;
  728. if (core_count_initialized)
  729. return;
  730. core_count_initialized = true;
  731. GetLogicalProcessorInformation(info, &len);
  732. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  733. return;
  734. info = malloc(len);
  735. if (GetLogicalProcessorInformation(info, &len)) {
  736. DWORD num = len / sizeof(*info);
  737. temp = info;
  738. for (DWORD i = 0; i < num; i++) {
  739. if (temp->Relationship == RelationProcessorCore) {
  740. ULONG_PTR mask = temp->ProcessorMask;
  741. physical_cores++;
  742. logical_cores += num_logical_cores(mask);
  743. }
  744. temp++;
  745. }
  746. }
  747. free(info);
  748. }
  749. int os_get_physical_cores(void)
  750. {
  751. if (!core_count_initialized)
  752. os_get_cores_internal();
  753. return physical_cores;
  754. }
  755. int os_get_logical_cores(void)
  756. {
  757. if (!core_count_initialized)
  758. os_get_cores_internal();
  759. return logical_cores;
  760. }
  761. static inline bool os_get_sys_memory_usage_internal(MEMORYSTATUSEX *msex)
  762. {
  763. if (!GlobalMemoryStatusEx(msex))
  764. return false;
  765. return true;
  766. }
  767. uint64_t os_get_sys_free_size(void)
  768. {
  769. MEMORYSTATUSEX msex = {sizeof(MEMORYSTATUSEX)};
  770. if (!os_get_sys_memory_usage_internal(&msex))
  771. return 0;
  772. return msex.ullAvailPhys;
  773. }
  774. static inline bool os_get_proc_memory_usage_internal(PROCESS_MEMORY_COUNTERS *pmc)
  775. {
  776. if (!GetProcessMemoryInfo(GetCurrentProcess(), pmc, sizeof(*pmc)))
  777. return false;
  778. return true;
  779. }
  780. bool os_get_proc_memory_usage(os_proc_memory_usage_t *usage)
  781. {
  782. PROCESS_MEMORY_COUNTERS pmc = {sizeof(PROCESS_MEMORY_COUNTERS)};
  783. if (!os_get_proc_memory_usage_internal(&pmc))
  784. return false;
  785. usage->resident_size = pmc.WorkingSetSize;
  786. usage->virtual_size = pmc.PagefileUsage;
  787. return true;
  788. }
  789. uint64_t os_get_proc_resident_size(void)
  790. {
  791. PROCESS_MEMORY_COUNTERS pmc = {sizeof(PROCESS_MEMORY_COUNTERS)};
  792. if (!os_get_proc_memory_usage_internal(&pmc))
  793. return 0;
  794. return pmc.WorkingSetSize;
  795. }
  796. uint64_t os_get_proc_virtual_size(void)
  797. {
  798. PROCESS_MEMORY_COUNTERS pmc = {sizeof(PROCESS_MEMORY_COUNTERS)};
  799. if (!os_get_proc_memory_usage_internal(&pmc))
  800. return 0;
  801. return pmc.PagefileUsage;
  802. }
  803. uint64_t os_get_free_disk_space(const char *dir)
  804. {
  805. wchar_t *wdir = NULL;
  806. if (!os_utf8_to_wcs_ptr(dir, 0, &wdir))
  807. return 0;
  808. ULARGE_INTEGER free;
  809. bool success = !!GetDiskFreeSpaceExW(wdir, &free, NULL, NULL);
  810. bfree(wdir);
  811. return success ? free.QuadPart : 0;
  812. }