obs-windows.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290
  1. /******************************************************************************
  2. Copyright (C) 2023 by Lain Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "util/windows/win-registry.h"
  15. #include "util/windows/win-version.h"
  16. #include "util/platform.h"
  17. #include "util/dstr.h"
  18. #include "obs.h"
  19. #include "obs-internal.h"
  20. #include <windows.h>
  21. #include <wscapi.h>
  22. #include <iwscapi.h>
  23. static uint32_t win_ver = 0;
  24. static uint32_t win_build = 0;
  25. const char *get_module_extension(void)
  26. {
  27. return ".dll";
  28. }
  29. static const char *module_bin[] = {"../../obs-plugins/64bit"};
  30. static const char *module_data[] = {"../../data/obs-plugins/%module%"};
  31. static const int module_patterns_size =
  32. sizeof(module_bin) / sizeof(module_bin[0]);
  33. void add_default_module_paths(void)
  34. {
  35. for (int i = 0; i < module_patterns_size; i++)
  36. obs_add_module_path(module_bin[i], module_data[i]);
  37. }
  38. /* on windows, points to [base directory]/data/libobs */
  39. char *find_libobs_data_file(const char *file)
  40. {
  41. struct dstr path;
  42. dstr_init(&path);
  43. if (check_path(file, "../../data/libobs/", &path))
  44. return path.array;
  45. dstr_free(&path);
  46. return NULL;
  47. }
  48. static void log_processor_info(void)
  49. {
  50. HKEY key;
  51. wchar_t data[1024];
  52. char *str = NULL;
  53. DWORD size, speed;
  54. LSTATUS status;
  55. memset(data, 0, sizeof(data));
  56. status = RegOpenKeyW(
  57. HKEY_LOCAL_MACHINE,
  58. L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &key);
  59. if (status != ERROR_SUCCESS)
  60. return;
  61. size = sizeof(data);
  62. status = RegQueryValueExW(key, L"ProcessorNameString", NULL, NULL,
  63. (LPBYTE)data, &size);
  64. if (status == ERROR_SUCCESS) {
  65. os_wcs_to_utf8_ptr(data, 0, &str);
  66. blog(LOG_INFO, "CPU Name: %s", str);
  67. bfree(str);
  68. }
  69. size = sizeof(speed);
  70. status = RegQueryValueExW(key, L"~MHz", NULL, NULL, (LPBYTE)&speed,
  71. &size);
  72. if (status == ERROR_SUCCESS)
  73. blog(LOG_INFO, "CPU Speed: %ldMHz", speed);
  74. RegCloseKey(key);
  75. }
  76. static void log_processor_cores(void)
  77. {
  78. blog(LOG_INFO, "Physical Cores: %d, Logical Cores: %d",
  79. os_get_physical_cores(), os_get_logical_cores());
  80. }
  81. static void log_emulation_status(void)
  82. {
  83. if (os_get_emulation_status()) {
  84. blog(LOG_WARNING, "Windows ARM64: Running with x64 emulation");
  85. }
  86. }
  87. static void log_available_memory(void)
  88. {
  89. MEMORYSTATUSEX ms;
  90. ms.dwLength = sizeof(ms);
  91. GlobalMemoryStatusEx(&ms);
  92. #ifdef _WIN64
  93. const char *note = "";
  94. #else
  95. const char *note = " (NOTE: 32bit programs cannot use more than 3gb)";
  96. #endif
  97. blog(LOG_INFO, "Physical Memory: %luMB Total, %luMB Free%s",
  98. (DWORD)(ms.ullTotalPhys / 1048576),
  99. (DWORD)(ms.ullAvailPhys / 1048576), note);
  100. }
  101. static void log_lenovo_vantage(void)
  102. {
  103. SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  104. if (!manager)
  105. return;
  106. SC_HANDLE service =
  107. OpenService(manager, L"FBNetFilter", SERVICE_QUERY_STATUS);
  108. if (service) {
  109. blog(LOG_WARNING,
  110. "Lenovo Vantage / Legion Edge is installed. The \"Network Boost\" "
  111. "feature must be disabled when streaming with OBS.");
  112. CloseServiceHandle(service);
  113. }
  114. CloseServiceHandle(manager);
  115. }
  116. static void log_conflicting_software(void)
  117. {
  118. log_lenovo_vantage();
  119. }
  120. extern const char *get_win_release_id();
  121. static void log_windows_version(void)
  122. {
  123. struct win_version_info ver;
  124. get_win_ver(&ver);
  125. const char *release_id = get_win_release_id();
  126. bool b64 = is_64_bit_windows();
  127. const char *windows_bitness = b64 ? "64" : "32";
  128. bool arm64 = is_arm64_windows();
  129. const char *arm64_windows = arm64 ? "ARM " : "";
  130. blog(LOG_INFO,
  131. "Windows Version: %d.%d Build %d (release: %s; revision: %d; %s%s-bit)",
  132. ver.major, ver.minor, ver.build, release_id, ver.revis,
  133. arm64_windows, windows_bitness);
  134. }
  135. static void log_admin_status(void)
  136. {
  137. SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
  138. PSID admin_group;
  139. BOOL success;
  140. success = AllocateAndInitializeSid(&auth, 2,
  141. SECURITY_BUILTIN_DOMAIN_RID,
  142. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0,
  143. 0, 0, &admin_group);
  144. if (success) {
  145. if (!CheckTokenMembership(NULL, admin_group, &success))
  146. success = false;
  147. FreeSid(admin_group);
  148. }
  149. blog(LOG_INFO, "Running as administrator: %s",
  150. success ? "true" : "false");
  151. }
  152. #define WIN10_GAME_BAR_REG_KEY \
  153. L"Software\\Microsoft\\Windows\\CurrentVersion\\GameDVR"
  154. #define WIN10_GAME_DVR_POLICY_REG_KEY \
  155. L"SOFTWARE\\Policies\\Microsoft\\Windows\\GameDVR"
  156. #define WIN10_GAME_DVR_REG_KEY L"System\\GameConfigStore"
  157. #define WIN10_GAME_MODE_REG_KEY L"Software\\Microsoft\\GameBar"
  158. static void log_gaming_features(void)
  159. {
  160. if (win_ver < 0xA00)
  161. return;
  162. struct reg_dword game_bar_enabled;
  163. struct reg_dword game_dvr_allowed;
  164. struct reg_dword game_dvr_enabled;
  165. struct reg_dword game_dvr_bg_recording;
  166. struct reg_dword game_mode_enabled;
  167. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_BAR_REG_KEY,
  168. L"AppCaptureEnabled", &game_bar_enabled);
  169. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_DVR_POLICY_REG_KEY,
  170. L"AllowGameDVR", &game_dvr_allowed);
  171. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_DVR_REG_KEY,
  172. L"GameDVR_Enabled", &game_dvr_enabled);
  173. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_BAR_REG_KEY,
  174. L"HistoricalCaptureEnabled", &game_dvr_bg_recording);
  175. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY,
  176. L"AutoGameModeEnabled", &game_mode_enabled);
  177. if (game_mode_enabled.status != ERROR_SUCCESS) {
  178. get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY,
  179. L"AllowAutoGameMode", &game_mode_enabled);
  180. }
  181. blog(LOG_INFO, "Windows 10/11 Gaming Features:");
  182. if (game_bar_enabled.status == ERROR_SUCCESS) {
  183. blog(LOG_INFO, "\tGame Bar: %s",
  184. (bool)game_bar_enabled.return_value ? "On" : "Off");
  185. }
  186. if (game_dvr_allowed.status == ERROR_SUCCESS) {
  187. blog(LOG_INFO, "\tGame DVR Allowed: %s",
  188. (bool)game_dvr_allowed.return_value ? "Yes" : "No");
  189. }
  190. if (game_dvr_enabled.status == ERROR_SUCCESS) {
  191. blog(LOG_INFO, "\tGame DVR: %s",
  192. (bool)game_dvr_enabled.return_value ? "On" : "Off");
  193. }
  194. if (game_dvr_bg_recording.status == ERROR_SUCCESS) {
  195. blog(LOG_INFO, "\tGame DVR Background Recording: %s",
  196. (bool)game_dvr_bg_recording.return_value ? "On" : "Off");
  197. }
  198. if (game_mode_enabled.status == ERROR_SUCCESS) {
  199. blog(LOG_INFO, "\tGame Mode: %s",
  200. (bool)game_mode_enabled.return_value ? "On" : "Off");
  201. } else if (win_build >= 19042) {
  202. // On by default in newer Windows 10 builds (no registry key set)
  203. blog(LOG_INFO, "\tGame Mode: Probably On (no reg key set)");
  204. }
  205. }
  206. static const char *get_str_for_state(int state)
  207. {
  208. switch (state) {
  209. case WSC_SECURITY_PRODUCT_STATE_ON:
  210. return "enabled";
  211. case WSC_SECURITY_PRODUCT_STATE_OFF:
  212. return "disabled";
  213. case WSC_SECURITY_PRODUCT_STATE_SNOOZED:
  214. return "temporarily disabled";
  215. case WSC_SECURITY_PRODUCT_STATE_EXPIRED:
  216. return "expired";
  217. default:
  218. return "unknown";
  219. }
  220. }
  221. static const char *get_str_for_type(int type)
  222. {
  223. switch (type) {
  224. case WSC_SECURITY_PROVIDER_ANTIVIRUS:
  225. return "AV";
  226. case WSC_SECURITY_PROVIDER_FIREWALL:
  227. return "FW";
  228. case WSC_SECURITY_PROVIDER_ANTISPYWARE:
  229. return "ASW";
  230. default:
  231. return "unknown";
  232. }
  233. }
  234. static void log_security_products_by_type(IWSCProductList *prod_list, int type)
  235. {
  236. HRESULT hr;
  237. LONG count = 0;
  238. IWscProduct *prod;
  239. BSTR name;
  240. WSC_SECURITY_PRODUCT_STATE prod_state;
  241. hr = prod_list->lpVtbl->Initialize(prod_list, type);
  242. if (FAILED(hr))
  243. return;
  244. hr = prod_list->lpVtbl->get_Count(prod_list, &count);
  245. if (FAILED(hr)) {
  246. prod_list->lpVtbl->Release(prod_list);
  247. return;
  248. }
  249. for (int i = 0; i < count; i++) {
  250. hr = prod_list->lpVtbl->get_Item(prod_list, i, &prod);
  251. if (FAILED(hr))
  252. continue;
  253. hr = prod->lpVtbl->get_ProductName(prod, &name);
  254. if (FAILED(hr))
  255. continue;
  256. hr = prod->lpVtbl->get_ProductState(prod, &prod_state);
  257. if (FAILED(hr)) {
  258. SysFreeString(name);
  259. continue;
  260. }
  261. char *product_name;
  262. os_wcs_to_utf8_ptr(name, 0, &product_name);
  263. blog(LOG_INFO, "\t%s: %s (%s)", product_name,
  264. get_str_for_state(prod_state), get_str_for_type(type));
  265. bfree(product_name);
  266. SysFreeString(name);
  267. prod->lpVtbl->Release(prod);
  268. }
  269. prod_list->lpVtbl->Release(prod_list);
  270. }
  271. static void log_security_products(void)
  272. {
  273. IWSCProductList *prod_list = NULL;
  274. HMODULE h_wsc;
  275. HRESULT hr;
  276. /* We load the DLL rather than import wcsapi.lib because the clsid /
  277. * iid only exists on Windows 8 or higher. */
  278. h_wsc = LoadLibraryW(L"wscapi.dll");
  279. if (!h_wsc)
  280. return;
  281. const CLSID *prod_list_clsid =
  282. (const CLSID *)GetProcAddress(h_wsc, "CLSID_WSCProductList");
  283. const IID *prod_list_iid =
  284. (const IID *)GetProcAddress(h_wsc, "IID_IWSCProductList");
  285. if (prod_list_clsid && prod_list_iid) {
  286. blog(LOG_INFO, "Sec. Software Status:");
  287. hr = CoCreateInstance(prod_list_clsid, NULL,
  288. CLSCTX_INPROC_SERVER, prod_list_iid,
  289. &prod_list);
  290. if (!FAILED(hr)) {
  291. log_security_products_by_type(
  292. prod_list, WSC_SECURITY_PROVIDER_ANTIVIRUS);
  293. }
  294. hr = CoCreateInstance(prod_list_clsid, NULL,
  295. CLSCTX_INPROC_SERVER, prod_list_iid,
  296. &prod_list);
  297. if (!FAILED(hr)) {
  298. log_security_products_by_type(
  299. prod_list, WSC_SECURITY_PROVIDER_FIREWALL);
  300. }
  301. hr = CoCreateInstance(prod_list_clsid, NULL,
  302. CLSCTX_INPROC_SERVER, prod_list_iid,
  303. &prod_list);
  304. if (!FAILED(hr)) {
  305. log_security_products_by_type(
  306. prod_list, WSC_SECURITY_PROVIDER_ANTISPYWARE);
  307. }
  308. }
  309. FreeLibrary(h_wsc);
  310. }
  311. void log_system_info(void)
  312. {
  313. struct win_version_info ver;
  314. get_win_ver(&ver);
  315. win_ver = (ver.major << 8) | ver.minor;
  316. win_build = ver.build;
  317. log_processor_info();
  318. log_processor_cores();
  319. log_available_memory();
  320. log_windows_version();
  321. log_emulation_status();
  322. log_admin_status();
  323. log_gaming_features();
  324. log_security_products();
  325. log_conflicting_software();
  326. }
  327. struct obs_hotkeys_platform {
  328. int vk_codes[OBS_KEY_LAST_VALUE];
  329. };
  330. static int get_virtual_key(obs_key_t key)
  331. {
  332. switch (key) {
  333. case OBS_KEY_RETURN:
  334. return VK_RETURN;
  335. case OBS_KEY_ESCAPE:
  336. return VK_ESCAPE;
  337. case OBS_KEY_TAB:
  338. return VK_TAB;
  339. case OBS_KEY_BACKTAB:
  340. return VK_OEM_BACKTAB;
  341. case OBS_KEY_BACKSPACE:
  342. return VK_BACK;
  343. case OBS_KEY_INSERT:
  344. return VK_INSERT;
  345. case OBS_KEY_DELETE:
  346. return VK_DELETE;
  347. case OBS_KEY_PAUSE:
  348. return VK_PAUSE;
  349. case OBS_KEY_PRINT:
  350. return VK_SNAPSHOT;
  351. case OBS_KEY_CLEAR:
  352. return VK_CLEAR;
  353. case OBS_KEY_HOME:
  354. return VK_HOME;
  355. case OBS_KEY_END:
  356. return VK_END;
  357. case OBS_KEY_LEFT:
  358. return VK_LEFT;
  359. case OBS_KEY_UP:
  360. return VK_UP;
  361. case OBS_KEY_RIGHT:
  362. return VK_RIGHT;
  363. case OBS_KEY_DOWN:
  364. return VK_DOWN;
  365. case OBS_KEY_PAGEUP:
  366. return VK_PRIOR;
  367. case OBS_KEY_PAGEDOWN:
  368. return VK_NEXT;
  369. case OBS_KEY_SHIFT:
  370. return VK_SHIFT;
  371. case OBS_KEY_CONTROL:
  372. return VK_CONTROL;
  373. case OBS_KEY_ALT:
  374. return VK_MENU;
  375. case OBS_KEY_CAPSLOCK:
  376. return VK_CAPITAL;
  377. case OBS_KEY_NUMLOCK:
  378. return VK_NUMLOCK;
  379. case OBS_KEY_SCROLLLOCK:
  380. return VK_SCROLL;
  381. case OBS_KEY_F1:
  382. return VK_F1;
  383. case OBS_KEY_F2:
  384. return VK_F2;
  385. case OBS_KEY_F3:
  386. return VK_F3;
  387. case OBS_KEY_F4:
  388. return VK_F4;
  389. case OBS_KEY_F5:
  390. return VK_F5;
  391. case OBS_KEY_F6:
  392. return VK_F6;
  393. case OBS_KEY_F7:
  394. return VK_F7;
  395. case OBS_KEY_F8:
  396. return VK_F8;
  397. case OBS_KEY_F9:
  398. return VK_F9;
  399. case OBS_KEY_F10:
  400. return VK_F10;
  401. case OBS_KEY_F11:
  402. return VK_F11;
  403. case OBS_KEY_F12:
  404. return VK_F12;
  405. case OBS_KEY_F13:
  406. return VK_F13;
  407. case OBS_KEY_F14:
  408. return VK_F14;
  409. case OBS_KEY_F15:
  410. return VK_F15;
  411. case OBS_KEY_F16:
  412. return VK_F16;
  413. case OBS_KEY_F17:
  414. return VK_F17;
  415. case OBS_KEY_F18:
  416. return VK_F18;
  417. case OBS_KEY_F19:
  418. return VK_F19;
  419. case OBS_KEY_F20:
  420. return VK_F20;
  421. case OBS_KEY_F21:
  422. return VK_F21;
  423. case OBS_KEY_F22:
  424. return VK_F22;
  425. case OBS_KEY_F23:
  426. return VK_F23;
  427. case OBS_KEY_F24:
  428. return VK_F24;
  429. case OBS_KEY_SPACE:
  430. return VK_SPACE;
  431. case OBS_KEY_APOSTROPHE:
  432. return VK_OEM_7;
  433. case OBS_KEY_PLUS:
  434. return VK_OEM_PLUS;
  435. case OBS_KEY_COMMA:
  436. return VK_OEM_COMMA;
  437. case OBS_KEY_MINUS:
  438. return VK_OEM_MINUS;
  439. case OBS_KEY_PERIOD:
  440. return VK_OEM_PERIOD;
  441. case OBS_KEY_SLASH:
  442. return VK_OEM_2;
  443. case OBS_KEY_0:
  444. return '0';
  445. case OBS_KEY_1:
  446. return '1';
  447. case OBS_KEY_2:
  448. return '2';
  449. case OBS_KEY_3:
  450. return '3';
  451. case OBS_KEY_4:
  452. return '4';
  453. case OBS_KEY_5:
  454. return '5';
  455. case OBS_KEY_6:
  456. return '6';
  457. case OBS_KEY_7:
  458. return '7';
  459. case OBS_KEY_8:
  460. return '8';
  461. case OBS_KEY_9:
  462. return '9';
  463. case OBS_KEY_NUMASTERISK:
  464. return VK_MULTIPLY;
  465. case OBS_KEY_NUMPLUS:
  466. return VK_ADD;
  467. case OBS_KEY_NUMMINUS:
  468. return VK_SUBTRACT;
  469. case OBS_KEY_NUMPERIOD:
  470. return VK_DECIMAL;
  471. case OBS_KEY_NUMSLASH:
  472. return VK_DIVIDE;
  473. case OBS_KEY_NUM0:
  474. return VK_NUMPAD0;
  475. case OBS_KEY_NUM1:
  476. return VK_NUMPAD1;
  477. case OBS_KEY_NUM2:
  478. return VK_NUMPAD2;
  479. case OBS_KEY_NUM3:
  480. return VK_NUMPAD3;
  481. case OBS_KEY_NUM4:
  482. return VK_NUMPAD4;
  483. case OBS_KEY_NUM5:
  484. return VK_NUMPAD5;
  485. case OBS_KEY_NUM6:
  486. return VK_NUMPAD6;
  487. case OBS_KEY_NUM7:
  488. return VK_NUMPAD7;
  489. case OBS_KEY_NUM8:
  490. return VK_NUMPAD8;
  491. case OBS_KEY_NUM9:
  492. return VK_NUMPAD9;
  493. case OBS_KEY_SEMICOLON:
  494. return VK_OEM_1;
  495. case OBS_KEY_A:
  496. return 'A';
  497. case OBS_KEY_B:
  498. return 'B';
  499. case OBS_KEY_C:
  500. return 'C';
  501. case OBS_KEY_D:
  502. return 'D';
  503. case OBS_KEY_E:
  504. return 'E';
  505. case OBS_KEY_F:
  506. return 'F';
  507. case OBS_KEY_G:
  508. return 'G';
  509. case OBS_KEY_H:
  510. return 'H';
  511. case OBS_KEY_I:
  512. return 'I';
  513. case OBS_KEY_J:
  514. return 'J';
  515. case OBS_KEY_K:
  516. return 'K';
  517. case OBS_KEY_L:
  518. return 'L';
  519. case OBS_KEY_M:
  520. return 'M';
  521. case OBS_KEY_N:
  522. return 'N';
  523. case OBS_KEY_O:
  524. return 'O';
  525. case OBS_KEY_P:
  526. return 'P';
  527. case OBS_KEY_Q:
  528. return 'Q';
  529. case OBS_KEY_R:
  530. return 'R';
  531. case OBS_KEY_S:
  532. return 'S';
  533. case OBS_KEY_T:
  534. return 'T';
  535. case OBS_KEY_U:
  536. return 'U';
  537. case OBS_KEY_V:
  538. return 'V';
  539. case OBS_KEY_W:
  540. return 'W';
  541. case OBS_KEY_X:
  542. return 'X';
  543. case OBS_KEY_Y:
  544. return 'Y';
  545. case OBS_KEY_Z:
  546. return 'Z';
  547. case OBS_KEY_BRACKETLEFT:
  548. return VK_OEM_4;
  549. case OBS_KEY_BACKSLASH:
  550. return VK_OEM_5;
  551. case OBS_KEY_BRACKETRIGHT:
  552. return VK_OEM_6;
  553. case OBS_KEY_ASCIITILDE:
  554. return VK_OEM_3;
  555. case OBS_KEY_HENKAN:
  556. return VK_CONVERT;
  557. case OBS_KEY_MUHENKAN:
  558. return VK_NONCONVERT;
  559. case OBS_KEY_KANJI:
  560. return VK_KANJI;
  561. case OBS_KEY_TOUROKU:
  562. return VK_OEM_FJ_TOUROKU;
  563. case OBS_KEY_MASSYO:
  564. return VK_OEM_FJ_MASSHOU;
  565. case OBS_KEY_HANGUL:
  566. return VK_HANGUL;
  567. case OBS_KEY_BACKSLASH_RT102:
  568. return VK_OEM_102;
  569. case OBS_KEY_MOUSE1:
  570. return VK_LBUTTON;
  571. case OBS_KEY_MOUSE2:
  572. return VK_RBUTTON;
  573. case OBS_KEY_MOUSE3:
  574. return VK_MBUTTON;
  575. case OBS_KEY_MOUSE4:
  576. return VK_XBUTTON1;
  577. case OBS_KEY_MOUSE5:
  578. return VK_XBUTTON2;
  579. case OBS_KEY_VK_CANCEL:
  580. return VK_CANCEL;
  581. case OBS_KEY_0x07:
  582. return 0x07;
  583. case OBS_KEY_0x0A:
  584. return 0x0A;
  585. case OBS_KEY_0x0B:
  586. return 0x0B;
  587. case OBS_KEY_0x0E:
  588. return 0x0E;
  589. case OBS_KEY_0x0F:
  590. return 0x0F;
  591. case OBS_KEY_0x16:
  592. return 0x16;
  593. case OBS_KEY_VK_JUNJA:
  594. return VK_JUNJA;
  595. case OBS_KEY_VK_FINAL:
  596. return VK_FINAL;
  597. case OBS_KEY_0x1A:
  598. return 0x1A;
  599. case OBS_KEY_VK_ACCEPT:
  600. return VK_ACCEPT;
  601. case OBS_KEY_VK_MODECHANGE:
  602. return VK_MODECHANGE;
  603. case OBS_KEY_VK_SELECT:
  604. return VK_SELECT;
  605. case OBS_KEY_VK_PRINT:
  606. return VK_PRINT;
  607. case OBS_KEY_VK_EXECUTE:
  608. return VK_EXECUTE;
  609. case OBS_KEY_VK_HELP:
  610. return VK_HELP;
  611. case OBS_KEY_0x30:
  612. return 0x30;
  613. case OBS_KEY_0x31:
  614. return 0x31;
  615. case OBS_KEY_0x32:
  616. return 0x32;
  617. case OBS_KEY_0x33:
  618. return 0x33;
  619. case OBS_KEY_0x34:
  620. return 0x34;
  621. case OBS_KEY_0x35:
  622. return 0x35;
  623. case OBS_KEY_0x36:
  624. return 0x36;
  625. case OBS_KEY_0x37:
  626. return 0x37;
  627. case OBS_KEY_0x38:
  628. return 0x38;
  629. case OBS_KEY_0x39:
  630. return 0x39;
  631. case OBS_KEY_0x3A:
  632. return 0x3A;
  633. case OBS_KEY_0x3B:
  634. return 0x3B;
  635. case OBS_KEY_0x3C:
  636. return 0x3C;
  637. case OBS_KEY_0x3D:
  638. return 0x3D;
  639. case OBS_KEY_0x3E:
  640. return 0x3E;
  641. case OBS_KEY_0x3F:
  642. return 0x3F;
  643. case OBS_KEY_0x40:
  644. return 0x40;
  645. case OBS_KEY_0x41:
  646. return 0x41;
  647. case OBS_KEY_0x42:
  648. return 0x42;
  649. case OBS_KEY_0x43:
  650. return 0x43;
  651. case OBS_KEY_0x44:
  652. return 0x44;
  653. case OBS_KEY_0x45:
  654. return 0x45;
  655. case OBS_KEY_0x46:
  656. return 0x46;
  657. case OBS_KEY_0x47:
  658. return 0x47;
  659. case OBS_KEY_0x48:
  660. return 0x48;
  661. case OBS_KEY_0x49:
  662. return 0x49;
  663. case OBS_KEY_0x4A:
  664. return 0x4A;
  665. case OBS_KEY_0x4B:
  666. return 0x4B;
  667. case OBS_KEY_0x4C:
  668. return 0x4C;
  669. case OBS_KEY_0x4D:
  670. return 0x4D;
  671. case OBS_KEY_0x4E:
  672. return 0x4E;
  673. case OBS_KEY_0x4F:
  674. return 0x4F;
  675. case OBS_KEY_0x50:
  676. return 0x50;
  677. case OBS_KEY_0x51:
  678. return 0x51;
  679. case OBS_KEY_0x52:
  680. return 0x52;
  681. case OBS_KEY_0x53:
  682. return 0x53;
  683. case OBS_KEY_0x54:
  684. return 0x54;
  685. case OBS_KEY_0x55:
  686. return 0x55;
  687. case OBS_KEY_0x56:
  688. return 0x56;
  689. case OBS_KEY_0x57:
  690. return 0x57;
  691. case OBS_KEY_0x58:
  692. return 0x58;
  693. case OBS_KEY_0x59:
  694. return 0x59;
  695. case OBS_KEY_0x5A:
  696. return 0x5A;
  697. case OBS_KEY_VK_LWIN:
  698. return VK_LWIN;
  699. case OBS_KEY_VK_RWIN:
  700. return VK_RWIN;
  701. case OBS_KEY_VK_APPS:
  702. return VK_APPS;
  703. case OBS_KEY_0x5E:
  704. return 0x5E;
  705. case OBS_KEY_VK_SLEEP:
  706. return VK_SLEEP;
  707. case OBS_KEY_VK_SEPARATOR:
  708. return VK_SEPARATOR;
  709. case OBS_KEY_0x88:
  710. return 0x88;
  711. case OBS_KEY_0x89:
  712. return 0x89;
  713. case OBS_KEY_0x8A:
  714. return 0x8A;
  715. case OBS_KEY_0x8B:
  716. return 0x8B;
  717. case OBS_KEY_0x8C:
  718. return 0x8C;
  719. case OBS_KEY_0x8D:
  720. return 0x8D;
  721. case OBS_KEY_0x8E:
  722. return 0x8E;
  723. case OBS_KEY_0x8F:
  724. return 0x8F;
  725. case OBS_KEY_VK_OEM_FJ_JISHO:
  726. return VK_OEM_FJ_JISHO;
  727. case OBS_KEY_VK_OEM_FJ_LOYA:
  728. return VK_OEM_FJ_LOYA;
  729. case OBS_KEY_VK_OEM_FJ_ROYA:
  730. return VK_OEM_FJ_ROYA;
  731. case OBS_KEY_0x97:
  732. return 0x97;
  733. case OBS_KEY_0x98:
  734. return 0x98;
  735. case OBS_KEY_0x99:
  736. return 0x99;
  737. case OBS_KEY_0x9A:
  738. return 0x9A;
  739. case OBS_KEY_0x9B:
  740. return 0x9B;
  741. case OBS_KEY_0x9C:
  742. return 0x9C;
  743. case OBS_KEY_0x9D:
  744. return 0x9D;
  745. case OBS_KEY_0x9E:
  746. return 0x9E;
  747. case OBS_KEY_0x9F:
  748. return 0x9F;
  749. case OBS_KEY_VK_LSHIFT:
  750. return VK_LSHIFT;
  751. case OBS_KEY_VK_RSHIFT:
  752. return VK_RSHIFT;
  753. case OBS_KEY_VK_LCONTROL:
  754. return VK_LCONTROL;
  755. case OBS_KEY_VK_RCONTROL:
  756. return VK_RCONTROL;
  757. case OBS_KEY_VK_LMENU:
  758. return VK_LMENU;
  759. case OBS_KEY_VK_RMENU:
  760. return VK_RMENU;
  761. case OBS_KEY_VK_BROWSER_BACK:
  762. return VK_BROWSER_BACK;
  763. case OBS_KEY_VK_BROWSER_FORWARD:
  764. return VK_BROWSER_FORWARD;
  765. case OBS_KEY_VK_BROWSER_REFRESH:
  766. return VK_BROWSER_REFRESH;
  767. case OBS_KEY_VK_BROWSER_STOP:
  768. return VK_BROWSER_STOP;
  769. case OBS_KEY_VK_BROWSER_SEARCH:
  770. return VK_BROWSER_SEARCH;
  771. case OBS_KEY_VK_BROWSER_FAVORITES:
  772. return VK_BROWSER_FAVORITES;
  773. case OBS_KEY_VK_BROWSER_HOME:
  774. return VK_BROWSER_HOME;
  775. case OBS_KEY_VK_VOLUME_MUTE:
  776. return VK_VOLUME_MUTE;
  777. case OBS_KEY_VK_VOLUME_DOWN:
  778. return VK_VOLUME_DOWN;
  779. case OBS_KEY_VK_VOLUME_UP:
  780. return VK_VOLUME_UP;
  781. case OBS_KEY_VK_MEDIA_NEXT_TRACK:
  782. return VK_MEDIA_NEXT_TRACK;
  783. case OBS_KEY_VK_MEDIA_PREV_TRACK:
  784. return VK_MEDIA_PREV_TRACK;
  785. case OBS_KEY_VK_MEDIA_STOP:
  786. return VK_MEDIA_STOP;
  787. case OBS_KEY_VK_MEDIA_PLAY_PAUSE:
  788. return VK_MEDIA_PLAY_PAUSE;
  789. case OBS_KEY_VK_LAUNCH_MAIL:
  790. return VK_LAUNCH_MAIL;
  791. case OBS_KEY_VK_LAUNCH_MEDIA_SELECT:
  792. return VK_LAUNCH_MEDIA_SELECT;
  793. case OBS_KEY_VK_LAUNCH_APP1:
  794. return VK_LAUNCH_APP1;
  795. case OBS_KEY_VK_LAUNCH_APP2:
  796. return VK_LAUNCH_APP2;
  797. case OBS_KEY_0xB8:
  798. return 0xB8;
  799. case OBS_KEY_0xB9:
  800. return 0xB9;
  801. case OBS_KEY_0xC1:
  802. return 0xC1;
  803. case OBS_KEY_0xC2:
  804. return 0xC2;
  805. case OBS_KEY_0xC3:
  806. return 0xC3;
  807. case OBS_KEY_0xC4:
  808. return 0xC4;
  809. case OBS_KEY_0xC5:
  810. return 0xC5;
  811. case OBS_KEY_0xC6:
  812. return 0xC6;
  813. case OBS_KEY_0xC7:
  814. return 0xC7;
  815. case OBS_KEY_0xC8:
  816. return 0xC8;
  817. case OBS_KEY_0xC9:
  818. return 0xC9;
  819. case OBS_KEY_0xCA:
  820. return 0xCA;
  821. case OBS_KEY_0xCB:
  822. return 0xCB;
  823. case OBS_KEY_0xCC:
  824. return 0xCC;
  825. case OBS_KEY_0xCD:
  826. return 0xCD;
  827. case OBS_KEY_0xCE:
  828. return 0xCE;
  829. case OBS_KEY_0xCF:
  830. return 0xCF;
  831. case OBS_KEY_0xD0:
  832. return 0xD0;
  833. case OBS_KEY_0xD1:
  834. return 0xD1;
  835. case OBS_KEY_0xD2:
  836. return 0xD2;
  837. case OBS_KEY_0xD3:
  838. return 0xD3;
  839. case OBS_KEY_0xD4:
  840. return 0xD4;
  841. case OBS_KEY_0xD5:
  842. return 0xD5;
  843. case OBS_KEY_0xD6:
  844. return 0xD6;
  845. case OBS_KEY_0xD7:
  846. return 0xD7;
  847. case OBS_KEY_0xD8:
  848. return 0xD8;
  849. case OBS_KEY_0xD9:
  850. return 0xD9;
  851. case OBS_KEY_0xDA:
  852. return 0xDA;
  853. case OBS_KEY_VK_OEM_8:
  854. return VK_OEM_8;
  855. case OBS_KEY_0xE0:
  856. return 0xE0;
  857. case OBS_KEY_VK_OEM_AX:
  858. return VK_OEM_AX;
  859. case OBS_KEY_VK_ICO_HELP:
  860. return VK_ICO_HELP;
  861. case OBS_KEY_VK_ICO_00:
  862. return VK_ICO_00;
  863. case OBS_KEY_VK_PROCESSKEY:
  864. return VK_PROCESSKEY;
  865. case OBS_KEY_VK_ICO_CLEAR:
  866. return VK_ICO_CLEAR;
  867. case OBS_KEY_VK_PACKET:
  868. return VK_PACKET;
  869. case OBS_KEY_0xE8:
  870. return 0xE8;
  871. case OBS_KEY_VK_OEM_RESET:
  872. return VK_OEM_RESET;
  873. case OBS_KEY_VK_OEM_JUMP:
  874. return VK_OEM_JUMP;
  875. case OBS_KEY_VK_OEM_PA1:
  876. return VK_OEM_PA1;
  877. case OBS_KEY_VK_OEM_PA2:
  878. return VK_OEM_PA2;
  879. case OBS_KEY_VK_OEM_PA3:
  880. return VK_OEM_PA3;
  881. case OBS_KEY_VK_OEM_WSCTRL:
  882. return VK_OEM_WSCTRL;
  883. case OBS_KEY_VK_OEM_CUSEL:
  884. return VK_OEM_CUSEL;
  885. case OBS_KEY_VK_OEM_ATTN:
  886. return VK_OEM_ATTN;
  887. case OBS_KEY_VK_OEM_FINISH:
  888. return VK_OEM_FINISH;
  889. case OBS_KEY_VK_OEM_COPY:
  890. return VK_OEM_COPY;
  891. case OBS_KEY_VK_OEM_AUTO:
  892. return VK_OEM_AUTO;
  893. case OBS_KEY_VK_OEM_ENLW:
  894. return VK_OEM_ENLW;
  895. case OBS_KEY_VK_ATTN:
  896. return VK_ATTN;
  897. case OBS_KEY_VK_CRSEL:
  898. return VK_CRSEL;
  899. case OBS_KEY_VK_EXSEL:
  900. return VK_EXSEL;
  901. case OBS_KEY_VK_EREOF:
  902. return VK_EREOF;
  903. case OBS_KEY_VK_PLAY:
  904. return VK_PLAY;
  905. case OBS_KEY_VK_ZOOM:
  906. return VK_ZOOM;
  907. case OBS_KEY_VK_NONAME:
  908. return VK_NONAME;
  909. case OBS_KEY_VK_PA1:
  910. return VK_PA1;
  911. case OBS_KEY_VK_OEM_CLEAR:
  912. return VK_OEM_CLEAR;
  913. /* TODO: Implement keys for non-US keyboards */
  914. default:;
  915. }
  916. return 0;
  917. }
  918. bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
  919. {
  920. hotkeys->platform_context = bzalloc(sizeof(obs_hotkeys_platform_t));
  921. for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++)
  922. hotkeys->platform_context->vk_codes[i] = get_virtual_key(i);
  923. return true;
  924. }
  925. void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
  926. {
  927. bfree(hotkeys->platform_context);
  928. hotkeys->platform_context = NULL;
  929. }
  930. static bool vk_down(DWORD vk)
  931. {
  932. short state = GetAsyncKeyState(vk);
  933. bool down = (state & 0x8000) != 0;
  934. return down;
  935. }
  936. bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *context,
  937. obs_key_t key)
  938. {
  939. if (key == OBS_KEY_META) {
  940. return vk_down(VK_LWIN) || vk_down(VK_RWIN);
  941. }
  942. UNUSED_PARAMETER(context);
  943. return vk_down(obs_key_to_virtual_key(key));
  944. }
  945. void obs_key_to_str(obs_key_t key, struct dstr *str)
  946. {
  947. wchar_t name[128] = L"";
  948. UINT scan_code;
  949. int vk;
  950. if (key == OBS_KEY_NONE) {
  951. return;
  952. } else if (key >= OBS_KEY_F13 && key <= OBS_KEY_F24) {
  953. dstr_printf(str, "F%d", (int)(key - OBS_KEY_F13 + 13));
  954. return;
  955. } else if (key >= OBS_KEY_MOUSE1 && key <= OBS_KEY_MOUSE29) {
  956. if (obs->hotkeys.translations[key]) {
  957. dstr_copy(str, obs->hotkeys.translations[key]);
  958. } else {
  959. dstr_printf(str, "Mouse %d",
  960. (int)(key - OBS_KEY_MOUSE1 + 1));
  961. }
  962. return;
  963. }
  964. if (key == OBS_KEY_PAUSE) {
  965. dstr_copy(str, obs_get_hotkey_translation(key, "Pause"));
  966. return;
  967. } else if (key == OBS_KEY_META) {
  968. dstr_copy(str, obs_get_hotkey_translation(key, "Windows"));
  969. return;
  970. }
  971. vk = obs_key_to_virtual_key(key);
  972. scan_code = MapVirtualKey(vk, 0) << 16;
  973. switch (vk) {
  974. case VK_HOME:
  975. case VK_END:
  976. case VK_LEFT:
  977. case VK_UP:
  978. case VK_RIGHT:
  979. case VK_DOWN:
  980. case VK_PRIOR:
  981. case VK_NEXT:
  982. case VK_INSERT:
  983. case VK_DELETE:
  984. case VK_NUMLOCK:
  985. scan_code |= 0x01000000;
  986. }
  987. if ((key < OBS_KEY_VK_CANCEL || key > OBS_KEY_VK_OEM_CLEAR) &&
  988. scan_code != 0 && GetKeyNameTextW(scan_code, name, 128) != 0) {
  989. dstr_from_wcs(str, name);
  990. } else if (key != OBS_KEY_NONE) {
  991. dstr_copy(str, obs_key_to_name(key));
  992. }
  993. }
  994. obs_key_t obs_key_from_virtual_key(int code)
  995. {
  996. obs_hotkeys_platform_t *platform = obs->hotkeys.platform_context;
  997. for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
  998. if (platform->vk_codes[i] == code) {
  999. return (obs_key_t)i;
  1000. }
  1001. }
  1002. return OBS_KEY_NONE;
  1003. }
  1004. int obs_key_to_virtual_key(obs_key_t key)
  1005. {
  1006. if (key == OBS_KEY_META)
  1007. return VK_LWIN;
  1008. return obs->hotkeys.platform_context->vk_codes[(int)key];
  1009. }
  1010. static inline void add_combo_key(obs_key_t key, struct dstr *str)
  1011. {
  1012. struct dstr key_str = {0};
  1013. obs_key_to_str(key, &key_str);
  1014. if (!dstr_is_empty(&key_str)) {
  1015. if (!dstr_is_empty(str)) {
  1016. dstr_cat(str, " + ");
  1017. }
  1018. dstr_cat_dstr(str, &key_str);
  1019. }
  1020. dstr_free(&key_str);
  1021. }
  1022. void obs_key_combination_to_str(obs_key_combination_t combination,
  1023. struct dstr *str)
  1024. {
  1025. if ((combination.modifiers & INTERACT_CONTROL_KEY) != 0) {
  1026. add_combo_key(OBS_KEY_CONTROL, str);
  1027. }
  1028. if ((combination.modifiers & INTERACT_COMMAND_KEY) != 0) {
  1029. add_combo_key(OBS_KEY_META, str);
  1030. }
  1031. if ((combination.modifiers & INTERACT_ALT_KEY) != 0) {
  1032. add_combo_key(OBS_KEY_ALT, str);
  1033. }
  1034. if ((combination.modifiers & INTERACT_SHIFT_KEY) != 0) {
  1035. add_combo_key(OBS_KEY_SHIFT, str);
  1036. }
  1037. if (combination.key != OBS_KEY_NONE) {
  1038. add_combo_key(combination.key, str);
  1039. }
  1040. }
  1041. bool sym_initialize_called = false;
  1042. void reset_win32_symbol_paths(void)
  1043. {
  1044. static BOOL(WINAPI * sym_initialize_w)(HANDLE, const wchar_t *, BOOL);
  1045. static BOOL(WINAPI * sym_set_search_path_w)(HANDLE, const wchar_t *);
  1046. static bool funcs_initialized = false;
  1047. static bool initialize_success = false;
  1048. struct obs_module *module = obs->first_module;
  1049. struct dstr path_str = {0};
  1050. DARRAY(char *) paths;
  1051. wchar_t *path_str_w = NULL;
  1052. char *abspath;
  1053. da_init(paths);
  1054. if (!funcs_initialized) {
  1055. HMODULE mod;
  1056. funcs_initialized = true;
  1057. mod = LoadLibraryW(L"DbgHelp");
  1058. if (!mod)
  1059. return;
  1060. sym_initialize_w =
  1061. (void *)GetProcAddress(mod, "SymInitializeW");
  1062. sym_set_search_path_w =
  1063. (void *)GetProcAddress(mod, "SymSetSearchPathW");
  1064. if (!sym_initialize_w || !sym_set_search_path_w) {
  1065. FreeLibrary(mod);
  1066. return;
  1067. }
  1068. initialize_success = true;
  1069. // Leaks 'mod' once.
  1070. }
  1071. if (!initialize_success)
  1072. return;
  1073. abspath = os_get_abs_path_ptr(".");
  1074. if (abspath)
  1075. da_push_back(paths, &abspath);
  1076. while (module) {
  1077. bool found = false;
  1078. struct dstr path = {0};
  1079. char *path_end;
  1080. dstr_copy(&path, module->bin_path);
  1081. dstr_replace(&path, "/", "\\");
  1082. path_end = strrchr(path.array, '\\');
  1083. if (!path_end) {
  1084. module = module->next;
  1085. dstr_free(&path);
  1086. continue;
  1087. }
  1088. *path_end = 0;
  1089. abspath = os_get_abs_path_ptr(path.array);
  1090. if (abspath) {
  1091. for (size_t i = 0; i < paths.num; i++) {
  1092. const char *existing_path = paths.array[i];
  1093. if (astrcmpi(abspath, existing_path) == 0) {
  1094. found = true;
  1095. break;
  1096. }
  1097. }
  1098. if (!found) {
  1099. da_push_back(paths, &abspath);
  1100. } else {
  1101. bfree(abspath);
  1102. }
  1103. }
  1104. dstr_free(&path);
  1105. module = module->next;
  1106. }
  1107. for (size_t i = 0; i < paths.num; i++) {
  1108. const char *path = paths.array[i];
  1109. if (path && *path) {
  1110. if (i != 0)
  1111. dstr_cat(&path_str, ";");
  1112. dstr_cat(&path_str, paths.array[i]);
  1113. }
  1114. }
  1115. if (path_str.array) {
  1116. os_utf8_to_wcs_ptr(path_str.array, path_str.len, &path_str_w);
  1117. if (path_str_w) {
  1118. if (!sym_initialize_called) {
  1119. sym_initialize_w(GetCurrentProcess(),
  1120. path_str_w, false);
  1121. sym_initialize_called = true;
  1122. } else {
  1123. sym_set_search_path_w(GetCurrentProcess(),
  1124. path_str_w);
  1125. }
  1126. bfree(path_str_w);
  1127. }
  1128. }
  1129. for (size_t i = 0; i < paths.num; i++)
  1130. bfree(paths.array[i]);
  1131. dstr_free(&path_str);
  1132. da_free(paths);
  1133. }
  1134. extern void initialize_crash_handler(void);
  1135. void obs_init_win32_crash_handler(void)
  1136. {
  1137. initialize_crash_handler();
  1138. }
  1139. bool initialize_com(void)
  1140. {
  1141. const HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
  1142. const bool success = SUCCEEDED(hr);
  1143. if (!success)
  1144. blog(LOG_ERROR, "CoInitializeEx failed: 0x%08X", hr);
  1145. return success;
  1146. }
  1147. void uninitialize_com(void)
  1148. {
  1149. CoUninitialize();
  1150. }