libraries.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. /*
  2. * WineCfg libraries tabsheet
  3. *
  4. * Copyright 2004 Robert van Herk
  5. * Copyright 2004 Mike Hearn
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  20. *
  21. */
  22. #define WIN32_LEAN_AND_MEAN
  23. #include <windows.h>
  24. #include <commdlg.h>
  25. #include <stdio.h>
  26. #include <assert.h>
  27. #include <stdlib.h>
  28. #include "winecfg.h"
  29. #include "resource.h"
  30. #include "wine/debug.h"
  31. WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
  32. #ifdef __i386__
  33. static const WCHAR pe_dir[] = L"\\i386-windows";
  34. #elif defined __x86_64__
  35. static const WCHAR pe_dir[] = L"\\x86_64-windows";
  36. #elif defined __arm__
  37. static const WCHAR pe_dir[] = L"\\arm-windows";
  38. #elif defined __aarch64__
  39. static const WCHAR pe_dir[] = L"\\aarch64-windows";
  40. #else
  41. static const WCHAR pe_dir[] = L"";
  42. #endif
  43. /* dlls that shouldn't be configured anything other than builtin; list must be sorted*/
  44. static const WCHAR * const builtin_only[] =
  45. {
  46. L"advapi32",
  47. L"capi2032",
  48. L"dbghelp",
  49. L"ddraw",
  50. L"gdi32",
  51. L"gphoto2.ds",
  52. L"icmp",
  53. L"iphlpapi",
  54. L"kernel32",
  55. L"l3codeca.acm",
  56. L"mountmgr.sys",
  57. L"mswsock",
  58. L"ntdll",
  59. L"ntoskrnl.exe",
  60. L"opengl32",
  61. L"sane.ds",
  62. L"secur32",
  63. L"twain_32",
  64. L"unicows",
  65. L"user32",
  66. L"vdmdbg",
  67. L"w32skrnl",
  68. L"winmm",
  69. L"wintab32",
  70. L"wnaspi32",
  71. L"wow32",
  72. L"ws2_32",
  73. L"wsock32",
  74. };
  75. enum dllmode
  76. {
  77. BUILTIN_NATIVE,
  78. NATIVE_BUILTIN,
  79. BUILTIN,
  80. NATIVE,
  81. DISABLE,
  82. UNKNOWN /* Special value indicating an erroneous DLL override mode */
  83. };
  84. struct dll
  85. {
  86. WCHAR *name;
  87. enum dllmode mode;
  88. };
  89. static const WCHAR emptyW[1];
  90. /* Convert a registry string to a dllmode */
  91. static enum dllmode string_to_mode(const WCHAR *in)
  92. {
  93. int i, j, len;
  94. WCHAR *out;
  95. enum dllmode res;
  96. len = wcslen(in);
  97. out = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
  98. /* remove the spaces */
  99. for (i = j = 0; i <= len; ++i) {
  100. if (in[i] != ' ') {
  101. out[j++] = in[i];
  102. }
  103. }
  104. /* parse the string */
  105. res = UNKNOWN;
  106. if (wcscmp(out, L"builtin,native") == 0) res = BUILTIN_NATIVE;
  107. if (wcscmp(out, L"native,builtin") == 0) res = NATIVE_BUILTIN;
  108. if (wcscmp(out, L"builtin") == 0) res = BUILTIN;
  109. if (wcscmp(out, L"native") == 0) res = NATIVE;
  110. if (wcscmp(out, L"") == 0) res = DISABLE;
  111. HeapFree(GetProcessHeap(), 0, out);
  112. return res;
  113. }
  114. /* Convert a dllmode to a registry string. */
  115. static const WCHAR* mode_to_string(enum dllmode mode)
  116. {
  117. switch( mode )
  118. {
  119. case NATIVE: return L"native";
  120. case BUILTIN: return L"builtin";
  121. case NATIVE_BUILTIN: return L"native,builtin";
  122. case BUILTIN_NATIVE: return L"builtin,native";
  123. case DISABLE: return L"";
  124. default: return L"";
  125. }
  126. }
  127. /* Convert a dllmode to a pretty string for display. TODO: use translations. */
  128. static const WCHAR* mode_to_label(enum dllmode mode)
  129. {
  130. static WCHAR buffer[256];
  131. UINT id = 0;
  132. switch( mode )
  133. {
  134. case NATIVE: id = IDS_DLL_NATIVE; break;
  135. case BUILTIN: id = IDS_DLL_BUILTIN; break;
  136. case NATIVE_BUILTIN: id = IDS_DLL_NATIVE_BUILTIN; break;
  137. case BUILTIN_NATIVE: id = IDS_DLL_BUILTIN_NATIVE; break;
  138. case DISABLE: id = IDS_DLL_DISABLED; break;
  139. default: return L"??";
  140. }
  141. if (!LoadStringW( GetModuleHandleW(NULL), id, buffer, ARRAY_SIZE(buffer) )) buffer[0] = 0;
  142. return buffer;
  143. }
  144. /* Convert a control id (IDC_ constant) to a dllmode */
  145. static enum dllmode id_to_mode(DWORD id)
  146. {
  147. switch( id )
  148. {
  149. case IDC_RAD_BUILTIN: return BUILTIN;
  150. case IDC_RAD_NATIVE: return NATIVE;
  151. case IDC_RAD_NATIVE_BUILTIN: return NATIVE_BUILTIN;
  152. case IDC_RAD_BUILTIN_NATIVE: return BUILTIN_NATIVE;
  153. case IDC_RAD_DISABLE: return DISABLE;
  154. default: assert( FALSE ); return 0; /* should not be reached */
  155. }
  156. }
  157. /* Convert a dllmode to a control id (IDC_ constant) */
  158. static DWORD mode_to_id(enum dllmode mode)
  159. {
  160. switch( mode )
  161. {
  162. case BUILTIN: return IDC_RAD_BUILTIN;
  163. case NATIVE: return IDC_RAD_NATIVE;
  164. case NATIVE_BUILTIN: return IDC_RAD_NATIVE_BUILTIN;
  165. case BUILTIN_NATIVE: return IDC_RAD_BUILTIN_NATIVE;
  166. case DISABLE: return IDC_RAD_DISABLE;
  167. default: return IDC_RAD_BUILTIN_NATIVE;
  168. }
  169. }
  170. /* helper for is_builtin_only */
  171. static int __cdecl compare_dll( const void *ptr1, const void *ptr2 )
  172. {
  173. const WCHAR * const *name1 = ptr1;
  174. const WCHAR * const *name2 = ptr2;
  175. return wcscmp( *name1, *name2 );
  176. }
  177. /* check if dll is recommended as builtin only */
  178. static inline BOOL is_builtin_only( const WCHAR *name )
  179. {
  180. const WCHAR *ext = wcsrchr( name, '.' );
  181. if (ext)
  182. {
  183. if (!wcscmp( ext, L".vxd" ) ||
  184. !wcscmp( ext, L".drv" ) ||
  185. !wcscmp( ext, L".tlb" ))
  186. return TRUE;
  187. }
  188. if (!wcsncmp( name, L"wine", 4 )) return TRUE;
  189. return bsearch( &name, builtin_only, ARRAY_SIZE(builtin_only),
  190. sizeof(builtin_only[0]), compare_dll ) != NULL;
  191. }
  192. /* check if dll should be offered in the drop-down list */
  193. static BOOL show_dll_in_list( const WCHAR *name )
  194. {
  195. const WCHAR *ext = wcsrchr( name, '.' );
  196. if (ext)
  197. {
  198. /* skip 16-bit dlls */
  199. if (wcslen(ext) > 2 && !wcscmp( ext + wcslen(ext) - 2, L"16" )) return FALSE;
  200. /* skip exes */
  201. if (!wcscmp( ext, L".exe" )) return FALSE;
  202. }
  203. /* skip dlls that should always be builtin */
  204. return !is_builtin_only( name );
  205. }
  206. static void set_controls_from_selection(HWND dialog)
  207. {
  208. /* FIXME: display/update some information about the selected dll (purpose, recommended load order) maybe? */
  209. }
  210. static void clear_settings(HWND dialog)
  211. {
  212. int count = SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0);
  213. int i;
  214. WINE_TRACE("count=%d\n", count);
  215. for (i = 0; i < count; i++)
  216. {
  217. struct dll *dll = (struct dll *) SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, 0, 0);
  218. SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_DELETESTRING, 0, 0);
  219. HeapFree(GetProcessHeap(), 0, dll->name);
  220. HeapFree(GetProcessHeap(), 0, dll);
  221. }
  222. }
  223. /* load the list of available libraries from a given dir */
  224. static void load_library_list_from_dir( HWND dialog, const WCHAR *dir_path, int check_subdirs )
  225. {
  226. static const WCHAR * const ext[] = { L".dll", L".dll.so", L".so", L"" };
  227. WCHAR *buffer, *p, name[256];
  228. unsigned int i;
  229. HANDLE handle;
  230. WIN32_FIND_DATAW data;
  231. buffer = HeapAlloc( GetProcessHeap(), 0, (wcslen(dir_path) + 10) * sizeof(WCHAR) + 2 * sizeof(name) );
  232. wcscpy( buffer, dir_path );
  233. wcscat( buffer, L"\\*" );
  234. buffer[1] = '\\'; /* change \??\ to \\?\ */
  235. p = buffer + wcslen(buffer) - 1;
  236. if ((handle = FindFirstFileW( buffer, &data )) == INVALID_HANDLE_VALUE)
  237. {
  238. HeapFree( GetProcessHeap(), 0, buffer );
  239. return;
  240. }
  241. do
  242. {
  243. size_t len = wcslen(data.cFileName);
  244. if (len > ARRAY_SIZE(name)) continue;
  245. if (check_subdirs)
  246. {
  247. if (!wcscmp( data.cFileName, L"." )) continue;
  248. if (!wcscmp( data.cFileName, L".." )) continue;
  249. if (!show_dll_in_list( data.cFileName )) continue;
  250. for (i = 0; i < ARRAY_SIZE( ext ); i++)
  251. {
  252. swprintf( p, 2 * ARRAY_SIZE(name) + 10, L"%s\\%s%s", data.cFileName, data.cFileName, ext[i] );
  253. if (GetFileAttributesW( buffer ) != INVALID_FILE_ATTRIBUTES)
  254. {
  255. SendDlgItemMessageW( dialog, IDC_DLLCOMBO, CB_ADDSTRING, 0, (LPARAM)data.cFileName );
  256. break;
  257. }
  258. }
  259. }
  260. else
  261. {
  262. for (i = 0; i < ARRAY_SIZE( ext ); i++)
  263. {
  264. if (!ext[i][0]) continue;
  265. if (len > wcslen(ext[i]) && !wcscmp( data.cFileName + len - wcslen(ext[i]), ext[i]))
  266. {
  267. len -= wcslen( ext[i] );
  268. memcpy( name, data.cFileName, len * sizeof(WCHAR) );
  269. name[len] = 0;
  270. if (!show_dll_in_list( name )) continue;
  271. SendDlgItemMessageW( dialog, IDC_DLLCOMBO, CB_ADDSTRING, 0, (LPARAM)name );
  272. }
  273. }
  274. }
  275. } while (FindNextFileW( handle, &data ));
  276. FindClose( handle );
  277. HeapFree( GetProcessHeap(), 0, buffer );
  278. }
  279. /* load the list of available libraries */
  280. static void load_library_list( HWND dialog )
  281. {
  282. unsigned int i = 0;
  283. WCHAR item1[256], item2[256], var[32], path[MAX_PATH];
  284. HCURSOR old_cursor = SetCursor( LoadCursorW(0, (LPWSTR)IDC_WAIT) );
  285. if (GetEnvironmentVariableW( L"WINEBUILDDIR", path, MAX_PATH ))
  286. {
  287. WCHAR *dir = HeapAlloc( GetProcessHeap(), 0, wcslen(path) * sizeof(WCHAR) + sizeof(L"\\dlls") );
  288. wcscpy( dir, path );
  289. wcscat( dir, L"\\dlls" );
  290. load_library_list_from_dir( dialog, dir, TRUE );
  291. HeapFree( GetProcessHeap(), 0, dir );
  292. }
  293. for (;;)
  294. {
  295. swprintf( var, ARRAY_SIZE(var), L"WINEDLLDIR%u", i++ );
  296. if (!GetEnvironmentVariableW( var, path, MAX_PATH )) break;
  297. load_library_list_from_dir( dialog, path, FALSE );
  298. wcscat( path, pe_dir );
  299. load_library_list_from_dir( dialog, path, FALSE );
  300. }
  301. /* get rid of duplicate entries */
  302. SendDlgItemMessageW( dialog, IDC_DLLCOMBO, CB_GETLBTEXT, 0, (LPARAM)item1 );
  303. i = 1;
  304. while (SendDlgItemMessageW( dialog, IDC_DLLCOMBO, CB_GETLBTEXT, i, (LPARAM)item2 ) >= 0)
  305. {
  306. if (!wcscmp( item1, item2 ))
  307. {
  308. SendDlgItemMessageW( dialog, IDC_DLLCOMBO, CB_DELETESTRING, i, 0 );
  309. }
  310. else
  311. {
  312. wcscpy( item1, item2 );
  313. i++;
  314. }
  315. }
  316. SetCursor( old_cursor );
  317. }
  318. static void load_library_settings(HWND dialog)
  319. {
  320. WCHAR **overrides = enumerate_values(config_key, keypath(L"DllOverrides"));
  321. WCHAR **p;
  322. int sel, count = 0;
  323. sel = SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
  324. WINE_TRACE("sel=%d\n", sel);
  325. clear_settings(dialog);
  326. if (!overrides || *overrides == NULL)
  327. {
  328. set_controls_from_selection(dialog);
  329. disable(IDC_DLLS_EDITDLL);
  330. disable(IDC_DLLS_REMOVEDLL);
  331. HeapFree(GetProcessHeap(), 0, overrides);
  332. return;
  333. }
  334. enable(IDC_DLLS_EDITDLL);
  335. enable(IDC_DLLS_REMOVEDLL);
  336. for (p = overrides; *p != NULL; p++)
  337. {
  338. int index, len;
  339. WCHAR *str, *value;
  340. const WCHAR *label;
  341. struct dll *dll;
  342. value = get_reg_key(config_key, keypath(L"DllOverrides"), *p, NULL);
  343. label = mode_to_label(string_to_mode(value));
  344. len = wcslen(*p) + 2 + wcslen(label) + 2;
  345. str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
  346. swprintf( str, len, L"%s (%s)", *p, label );
  347. dll = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dll));
  348. dll->name = *p;
  349. dll->mode = string_to_mode(value);
  350. index = SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_ADDSTRING, (WPARAM) -1, (LPARAM) str);
  351. SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_SETITEMDATA, index, (LPARAM) dll);
  352. HeapFree(GetProcessHeap(), 0, str);
  353. count++;
  354. }
  355. HeapFree(GetProcessHeap(), 0, overrides);
  356. /* restore the previous selection, if possible */
  357. if (sel >= count - 1) sel = count - 1;
  358. else if (sel == -1) sel = 0;
  359. SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_SETCURSEL, sel, 0);
  360. set_controls_from_selection(dialog);
  361. }
  362. /* Called when the application is initialized (cannot reinit!) */
  363. static void init_libsheet(HWND dialog)
  364. {
  365. /* clear the add dll controls */
  366. SendDlgItemMessageW(dialog, IDC_DLLCOMBO, WM_SETTEXT, 1, (LPARAM)emptyW);
  367. load_library_list( dialog );
  368. disable(IDC_DLLS_ADDDLL);
  369. }
  370. static void on_add_combo_change(HWND dialog)
  371. {
  372. WCHAR buffer[1024];
  373. int sel, len;
  374. SendDlgItemMessageW(dialog, IDC_DLLCOMBO, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
  375. /* if lib was chosen from combobox, we receive an empty buffer, check manually */
  376. sel=SendDlgItemMessageW(dialog, IDC_DLLCOMBO, CB_GETCURSEL, 0, 0);
  377. len=SendDlgItemMessageW(dialog, IDC_DLLCOMBO, CB_GETLBTEXTLEN, sel, 0);
  378. if (buffer[0] || len>0)
  379. {
  380. enable(IDC_DLLS_ADDDLL)
  381. SendMessageW(GetParent(dialog), DM_SETDEFID, IDC_DLLS_ADDDLL, 0);
  382. }
  383. else
  384. {
  385. disable(IDC_DLLS_ADDDLL);
  386. SendMessageW(GetParent(dialog), DM_SETDEFID, IDOK, 0);
  387. }
  388. }
  389. static void set_dllmode(HWND dialog, DWORD id)
  390. {
  391. enum dllmode mode;
  392. struct dll *dll;
  393. int sel;
  394. const WCHAR *str;
  395. mode = id_to_mode(id);
  396. sel = SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
  397. if (sel == -1) return;
  398. dll = (struct dll *) SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0);
  399. str = mode_to_string(mode);
  400. WINE_TRACE("Setting %s to %s\n", debugstr_w(dll->name), debugstr_w(str));
  401. SendMessageW(GetParent(dialog), PSM_CHANGED, 0, 0);
  402. set_reg_key(config_key, keypath(L"DllOverrides"), dll->name, str);
  403. load_library_settings(dialog); /* ... and refresh */
  404. }
  405. static void on_add_click(HWND dialog)
  406. {
  407. WCHAR buffer[1024], *ptr;
  408. buffer[0] = 0;
  409. SendDlgItemMessageW(dialog, IDC_DLLCOMBO, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM) buffer);
  410. if (wcslen(buffer) > 4)
  411. {
  412. ptr = buffer + wcslen(buffer) - 4;
  413. if (!wcsicmp(ptr, L".dll"))
  414. {
  415. WINE_TRACE("Stripping dll extension\n");
  416. *ptr = '\0';
  417. }
  418. }
  419. /* check if dll is in the builtin-only list */
  420. if (!(ptr = wcsrchr( buffer, '\\' )))
  421. {
  422. ptr = buffer;
  423. if (*ptr == '*') ptr++;
  424. }
  425. else ptr++;
  426. if (is_builtin_only( ptr ))
  427. {
  428. MSGBOXPARAMSW params;
  429. params.cbSize = sizeof(params);
  430. params.hwndOwner = dialog;
  431. params.hInstance = GetModuleHandleW( NULL );
  432. params.lpszText = MAKEINTRESOURCEW( IDS_DLL_WARNING );
  433. params.lpszCaption = MAKEINTRESOURCEW( IDS_DLL_WARNING_CAPTION );
  434. params.dwStyle = MB_ICONWARNING | MB_YESNO;
  435. params.lpszIcon = NULL;
  436. params.dwContextHelpId = 0;
  437. params.lpfnMsgBoxCallback = NULL;
  438. params.dwLanguageId = 0;
  439. if (MessageBoxIndirectW( &params ) != IDYES) return;
  440. }
  441. SendDlgItemMessageW(dialog, IDC_DLLCOMBO, WM_SETTEXT, 0, (LPARAM)emptyW);
  442. disable(IDC_DLLS_ADDDLL);
  443. SendMessageW(GetParent(dialog), DM_SETDEFID, IDOK, 0);
  444. WINE_TRACE("Adding %s as native, builtin\n", debugstr_w(buffer));
  445. SendMessageW(GetParent(dialog), PSM_CHANGED, 0, 0);
  446. set_reg_key(config_key, keypath(L"DllOverrides"), buffer, L"native,builtin");
  447. load_library_settings(dialog);
  448. SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_SELECTSTRING, 0, (LPARAM) buffer);
  449. set_controls_from_selection(dialog);
  450. }
  451. static INT_PTR CALLBACK loadorder_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  452. {
  453. static WORD sel;
  454. switch(uMsg)
  455. {
  456. case WM_INITDIALOG:
  457. CheckRadioButton(hwndDlg, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, lParam);
  458. sel = lParam;
  459. return TRUE;
  460. case WM_COMMAND:
  461. if(HIWORD(wParam) != BN_CLICKED) break;
  462. switch (LOWORD(wParam))
  463. {
  464. case IDC_RAD_BUILTIN:
  465. case IDC_RAD_NATIVE:
  466. case IDC_RAD_BUILTIN_NATIVE:
  467. case IDC_RAD_NATIVE_BUILTIN:
  468. case IDC_RAD_DISABLE:
  469. sel = LOWORD(wParam);
  470. return TRUE;
  471. case IDOK:
  472. EndDialog(hwndDlg, sel);
  473. return TRUE;
  474. case IDCANCEL:
  475. EndDialog(hwndDlg, wParam);
  476. return TRUE;
  477. }
  478. }
  479. return FALSE;
  480. }
  481. static void on_edit_click(HWND hwnd)
  482. {
  483. INT_PTR ret;
  484. int index = SendDlgItemMessageW(hwnd, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
  485. struct dll *dll;
  486. DWORD id;
  487. /* if no override is selected the edit button should be disabled... */
  488. assert(index != -1);
  489. dll = (struct dll *) SendDlgItemMessageW(hwnd, IDC_DLLS_LIST, LB_GETITEMDATA, index, 0);
  490. id = mode_to_id(dll->mode);
  491. ret = DialogBoxParamW(0, MAKEINTRESOURCEW(IDD_LOADORDER), hwnd, loadorder_dlgproc, id);
  492. if(ret != IDCANCEL)
  493. set_dllmode(hwnd, ret);
  494. }
  495. static void on_remove_click(HWND dialog)
  496. {
  497. int sel = SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
  498. struct dll *dll;
  499. if (sel == LB_ERR) return;
  500. dll = (struct dll *) SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0);
  501. SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_DELETESTRING, sel, 0);
  502. SendMessageW(GetParent(dialog), PSM_CHANGED, 0, 0);
  503. set_reg_key(config_key, keypath(L"DllOverrides"), dll->name, NULL);
  504. HeapFree(GetProcessHeap(), 0, dll->name);
  505. HeapFree(GetProcessHeap(), 0, dll);
  506. if (SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0) > 0)
  507. SendDlgItemMessageW(dialog, IDC_DLLS_LIST, LB_SETCURSEL, max(sel - 1, 0), 0);
  508. else
  509. {
  510. disable(IDC_DLLS_EDITDLL);
  511. disable(IDC_DLLS_REMOVEDLL);
  512. }
  513. set_controls_from_selection(dialog);
  514. }
  515. INT_PTR CALLBACK
  516. LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  517. {
  518. switch (uMsg)
  519. {
  520. case WM_INITDIALOG:
  521. init_libsheet(hDlg);
  522. break;
  523. case WM_SHOWWINDOW:
  524. set_window_title(hDlg);
  525. break;
  526. case WM_NOTIFY:
  527. switch (((LPNMHDR)lParam)->code) {
  528. case PSN_SETACTIVE:
  529. load_library_settings(hDlg);
  530. break;
  531. }
  532. break;
  533. case WM_COMMAND:
  534. switch(HIWORD(wParam)) {
  535. case CBN_EDITCHANGE:
  536. if (LOWORD(wParam) == IDC_DLLCOMBO)
  537. on_add_combo_change(hDlg);
  538. break;
  539. case CBN_SETFOCUS:
  540. if (LOWORD(wParam) == IDC_DLLCOMBO)
  541. on_add_combo_change(hDlg);
  542. break;
  543. case CBN_KILLFOCUS:
  544. if (LOWORD(wParam) == IDC_DLLCOMBO)
  545. SendMessageW(GetParent(hDlg), DM_SETDEFID, IDOK, 0);
  546. break;
  547. case BN_CLICKED:
  548. switch(LOWORD(wParam)) {
  549. case IDC_DLLS_ADDDLL:
  550. on_add_click(hDlg);
  551. break;
  552. case IDC_DLLS_EDITDLL:
  553. on_edit_click(hDlg);
  554. break;
  555. case IDC_DLLS_REMOVEDLL:
  556. on_remove_click(hDlg);
  557. break;
  558. }
  559. break;
  560. case LBN_SELCHANGE:
  561. if(LOWORD(wParam) == IDC_DLLCOMBO)
  562. on_add_combo_change(hDlg);
  563. else
  564. set_controls_from_selection(hDlg);
  565. break;
  566. }
  567. break;
  568. }
  569. return 0;
  570. }