platform-windows.c 21 KB

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