platform-windows.c 21 KB

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