winecfg.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. /*
  2. * WineCfg configuration management
  3. *
  4. * Copyright 2002 Jaco Greeff
  5. * Copyright 2003 Dimitrie O. Paun
  6. * Copyright 2003-2004 Mike Hearn
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  21. *
  22. * TODO:
  23. * - Use unicode
  24. * - Icons in listviews/icons
  25. * - Better add app dialog, scan c: for EXE files and add to list in background
  26. * - Use [GNOME] HIG style groupboxes rather than win32 style (looks nicer, imho)
  27. *
  28. */
  29. #define WIN32_LEAN_AND_MEAN
  30. #include <assert.h>
  31. #include <stdio.h>
  32. #include <limits.h>
  33. #include <windows.h>
  34. #include <winreg.h>
  35. #include <wine/unicode.h>
  36. #include <wine/debug.h>
  37. #include <wine/list.h>
  38. WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
  39. #include "winecfg.h"
  40. #include "resource.h"
  41. static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
  42. HKEY config_key = NULL;
  43. HMENU hPopupMenus = 0;
  44. /* this is called from the WM_SHOWWINDOW handlers of each tab page.
  45. *
  46. * it's a nasty hack, necessary because the property sheet insists on resetting the window title
  47. * to the title of the tab, which is utterly useless. dropping the property sheet is on the todo list.
  48. */
  49. void set_window_title(HWND dialog)
  50. {
  51. WCHAR newtitle[256];
  52. /* update the window title */
  53. if (current_app)
  54. {
  55. WCHAR apptitle[256];
  56. LoadStringW(GetModuleHandleW(NULL), IDS_WINECFG_TITLE_APP, apptitle, ARRAY_SIZE(apptitle));
  57. wsprintfW (newtitle, apptitle, current_app);
  58. }
  59. else
  60. {
  61. LoadStringW(GetModuleHandleW(NULL), IDS_WINECFG_TITLE, newtitle, ARRAY_SIZE(newtitle));
  62. }
  63. WINE_TRACE("setting title to %s\n", wine_dbgstr_w (newtitle));
  64. SendMessageW (GetParent(dialog), PSM_SETTITLEW, 0, (LPARAM) newtitle);
  65. }
  66. WCHAR* load_string (UINT id)
  67. {
  68. WCHAR buf[1024];
  69. int len;
  70. WCHAR* newStr;
  71. LoadStringW(GetModuleHandleW(NULL), id, buf, ARRAY_SIZE(buf));
  72. len = lstrlenW (buf);
  73. newStr = HeapAlloc (GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR));
  74. memcpy (newStr, buf, len * sizeof (WCHAR));
  75. newStr[len] = 0;
  76. return newStr;
  77. }
  78. /**
  79. * get_config_key: Retrieves a configuration value from the registry
  80. *
  81. * char *subkey : the name of the config section
  82. * char *name : the name of the config value
  83. * char *default : if the key isn't found, return this value instead
  84. *
  85. * Returns a buffer holding the value if successful, NULL if
  86. * not. Caller is responsible for releasing the result.
  87. *
  88. */
  89. static WCHAR *get_config_key (HKEY root, const WCHAR *subkey, const WCHAR *name, const WCHAR *def)
  90. {
  91. LPWSTR buffer = NULL;
  92. DWORD len;
  93. HKEY hSubKey = NULL;
  94. DWORD res;
  95. WINE_TRACE("subkey=%s, name=%s, def=%s\n", wine_dbgstr_w(subkey),
  96. wine_dbgstr_w(name), wine_dbgstr_w(def));
  97. res = RegOpenKeyExW(root, subkey, 0, MAXIMUM_ALLOWED, &hSubKey);
  98. if (res != ERROR_SUCCESS)
  99. {
  100. if (res == ERROR_FILE_NOT_FOUND)
  101. {
  102. WINE_TRACE("Section key not present - using default\n");
  103. return def ? strdupW(def) : NULL;
  104. }
  105. else
  106. {
  107. WINE_ERR("RegOpenKey failed on wine config key (res=%d)\n", res);
  108. }
  109. goto end;
  110. }
  111. res = RegQueryValueExW(hSubKey, name, NULL, NULL, NULL, &len);
  112. if (res == ERROR_FILE_NOT_FOUND)
  113. {
  114. WINE_TRACE("Value not present - using default\n");
  115. buffer = def ? strdupW(def) : NULL;
  116. goto end;
  117. } else if (res != ERROR_SUCCESS)
  118. {
  119. WINE_ERR("Couldn't query value's length (res=%d)\n", res);
  120. goto end;
  121. }
  122. buffer = HeapAlloc(GetProcessHeap(), 0, len + sizeof(WCHAR));
  123. RegQueryValueExW(hSubKey, name, NULL, NULL, (LPBYTE) buffer, &len);
  124. WINE_TRACE("buffer=%s\n", wine_dbgstr_w(buffer));
  125. end:
  126. RegCloseKey(hSubKey);
  127. return buffer;
  128. }
  129. /**
  130. * set_config_key: convenience wrapper to set a key/value pair
  131. *
  132. * const char *subKey : the name of the config section
  133. * const char *valueName : the name of the config value
  134. * const char *value : the value to set the configuration key to
  135. *
  136. * Returns 0 on success, non-zero otherwise
  137. *
  138. * If valueName or value is NULL, an empty section will be created
  139. */
  140. static int set_config_key(HKEY root, const WCHAR *subkey, REGSAM access, const WCHAR *name, const void *value, DWORD type)
  141. {
  142. DWORD res = 1;
  143. HKEY key = NULL;
  144. WINE_TRACE("subkey=%s: name=%s, value=%p, type=%d\n", wine_dbgstr_w(subkey),
  145. wine_dbgstr_w(name), value, type);
  146. assert( subkey != NULL );
  147. if (subkey[0])
  148. {
  149. res = RegCreateKeyExW( root, subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
  150. access, NULL, &key, NULL );
  151. if (res != ERROR_SUCCESS) goto end;
  152. }
  153. else key = root;
  154. if (name == NULL || value == NULL) goto end;
  155. switch (type)
  156. {
  157. case REG_SZ: res = RegSetValueExW(key, name, 0, REG_SZ, value, (lstrlenW(value)+1)*sizeof(WCHAR)); break;
  158. case REG_DWORD: res = RegSetValueExW(key, name, 0, REG_DWORD, value, sizeof(DWORD)); break;
  159. }
  160. if (res != ERROR_SUCCESS) goto end;
  161. res = 0;
  162. end:
  163. if (key && key != root) RegCloseKey(key);
  164. if (res != 0)
  165. WINE_ERR("Unable to set configuration key %s in section %s, res=%d\n",
  166. wine_dbgstr_w(name), wine_dbgstr_w(subkey), res);
  167. return res;
  168. }
  169. /* ========================================================================= */
  170. /* This code exists for the following reasons:
  171. *
  172. * - It makes working with the registry easier
  173. * - By storing a mini cache of the registry, we can more easily implement
  174. * cancel/revert and apply. The 'settings list' is an overlay on top of
  175. * the actual registry data that we can write out at will.
  176. *
  177. * Rather than model a tree in memory, we simply store each absolute (rooted
  178. * at the config key) path.
  179. *
  180. */
  181. struct setting
  182. {
  183. struct list entry;
  184. HKEY root; /* the key on which path is rooted */
  185. WCHAR *path; /* path in the registry rooted at root */
  186. WCHAR *name; /* name of the registry value. if null, this means delete the key */
  187. WCHAR *value; /* contents of the registry value. if null, this means delete the value */
  188. DWORD type; /* type of registry value. REG_SZ or REG_DWORD for now */
  189. };
  190. static struct list settings = LIST_INIT(settings);
  191. static void free_setting(struct setting *setting)
  192. {
  193. assert( setting != NULL );
  194. assert( setting->path );
  195. WINE_TRACE("destroying %p: %s\n", setting,
  196. wine_dbgstr_w(setting->path));
  197. HeapFree(GetProcessHeap(), 0, setting->path);
  198. HeapFree(GetProcessHeap(), 0, setting->name);
  199. HeapFree(GetProcessHeap(), 0, setting->value);
  200. list_remove(&setting->entry);
  201. HeapFree(GetProcessHeap(), 0, setting);
  202. }
  203. /**
  204. * Returns the contents of the value at path. If not in the settings
  205. * list, it will be fetched from the registry - failing that, the
  206. * default will be used.
  207. *
  208. * If already in the list, the contents as given there will be
  209. * returned. You are expected to HeapFree the result.
  210. */
  211. WCHAR *get_reg_keyW(HKEY root, const WCHAR *path, const WCHAR *name, const WCHAR *def)
  212. {
  213. struct list *cursor;
  214. struct setting *s;
  215. WCHAR *val;
  216. WINE_TRACE("path=%s, name=%s, def=%s\n", wine_dbgstr_w(path),
  217. wine_dbgstr_w(name), wine_dbgstr_w(def));
  218. /* check if it's in the list */
  219. LIST_FOR_EACH( cursor, &settings )
  220. {
  221. s = LIST_ENTRY(cursor, struct setting, entry);
  222. if (root != s->root) continue;
  223. if (lstrcmpiW(path, s->path) != 0) continue;
  224. if (!s->name) continue;
  225. if (lstrcmpiW(name, s->name) != 0) continue;
  226. WINE_TRACE("found %s:%s in settings list, returning %s\n",
  227. wine_dbgstr_w(path), wine_dbgstr_w(name),
  228. wine_dbgstr_w(s->value));
  229. return s->value ? strdupW(s->value) : NULL;
  230. }
  231. /* no, so get from the registry */
  232. val = get_config_key(root, path, name, def);
  233. WINE_TRACE("returning %s\n", wine_dbgstr_w(val));
  234. return val;
  235. }
  236. char *get_reg_key(HKEY root, const char *path, const char *name, const char *def)
  237. {
  238. WCHAR *wpath, *wname, *wdef = NULL, *wRet = NULL;
  239. char *szRet = NULL;
  240. int len;
  241. WINE_TRACE("path=%s, name=%s, def=%s\n", path, name, def);
  242. wpath = HeapAlloc(GetProcessHeap(), 0, (strlen(path)+1)*sizeof(WCHAR));
  243. wname = HeapAlloc(GetProcessHeap(), 0, (strlen(name)+1)*sizeof(WCHAR));
  244. MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, strlen(path)+1);
  245. MultiByteToWideChar(CP_ACP, 0, name, -1, wname, strlen(name)+1);
  246. if (def)
  247. {
  248. wdef = HeapAlloc(GetProcessHeap(), 0, (strlen(def)+1)*sizeof(WCHAR));
  249. MultiByteToWideChar(CP_ACP, 0, def, -1, wdef, strlen(def)+1);
  250. }
  251. wRet = get_reg_keyW(root, wpath, wname, wdef);
  252. len = WideCharToMultiByte(CP_ACP, 0, wRet, -1, NULL, 0, NULL, NULL);
  253. if (len)
  254. {
  255. szRet = HeapAlloc(GetProcessHeap(), 0, len);
  256. WideCharToMultiByte(CP_ACP, 0, wRet, -1, szRet, len, NULL, NULL);
  257. }
  258. HeapFree(GetProcessHeap(), 0, wpath);
  259. HeapFree(GetProcessHeap(), 0, wname);
  260. HeapFree(GetProcessHeap(), 0, wdef);
  261. HeapFree(GetProcessHeap(), 0, wRet);
  262. return szRet;
  263. }
  264. /**
  265. * Used to set a registry key.
  266. *
  267. * path is rooted at the config key, ie use "Version" or
  268. * "AppDefaults\\fooapp.exe\\Version". You can use keypath()
  269. * to get such a string.
  270. *
  271. * name is the value name, or NULL to delete the path.
  272. *
  273. * value is what to set the value to, or NULL to delete it.
  274. *
  275. * type is REG_SZ or REG_DWORD.
  276. *
  277. * These values will be copied when necessary.
  278. */
  279. static void set_reg_key_ex(HKEY root, const WCHAR *path, const WCHAR *name, const void *value, DWORD type)
  280. {
  281. struct list *cursor;
  282. struct setting *s;
  283. assert( path != NULL );
  284. WINE_TRACE("path=%s, name=%s, value=%s\n", wine_dbgstr_w(path),
  285. wine_dbgstr_w(name), wine_dbgstr_w(value));
  286. /* firstly, see if we already set this setting */
  287. LIST_FOR_EACH( cursor, &settings )
  288. {
  289. struct setting *s = LIST_ENTRY(cursor, struct setting, entry);
  290. if (root != s->root) continue;
  291. if (lstrcmpiW(s->path, path) != 0) continue;
  292. if ((s->name && name) && lstrcmpiW(s->name, name) != 0) continue;
  293. /* are we attempting a double delete? */
  294. if (!s->name && !name) return;
  295. /* do we want to undelete this key? */
  296. if (!s->name && name) s->name = strdupW(name);
  297. /* yes, we have already set it, so just replace the content and return */
  298. HeapFree(GetProcessHeap(), 0, s->value);
  299. s->type = type;
  300. switch (type)
  301. {
  302. case REG_SZ:
  303. s->value = value ? strdupW(value) : NULL;
  304. break;
  305. case REG_DWORD:
  306. s->value = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
  307. memcpy( s->value, value, sizeof(DWORD) );
  308. break;
  309. }
  310. /* are we deleting this key? this won't remove any of the
  311. * children from the overlay so if the user adds it again in
  312. * that session it will appear to undelete the settings, but
  313. * in reality only the settings actually modified by the user
  314. * in that session will be restored. we might want to fix this
  315. * corner case in future by actually deleting all the children
  316. * here so that once it's gone, it's gone.
  317. */
  318. if (!name) s->name = NULL;
  319. return;
  320. }
  321. /* otherwise add a new setting for it */
  322. s = HeapAlloc(GetProcessHeap(), 0, sizeof(struct setting));
  323. s->root = root;
  324. s->path = strdupW(path);
  325. s->name = name ? strdupW(name) : NULL;
  326. s->type = type;
  327. switch (type)
  328. {
  329. case REG_SZ:
  330. s->value = value ? strdupW(value) : NULL;
  331. break;
  332. case REG_DWORD:
  333. s->value = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
  334. memcpy( s->value, value, sizeof(DWORD) );
  335. break;
  336. }
  337. list_add_tail(&settings, &s->entry);
  338. }
  339. void set_reg_key(HKEY root, const char *path, const char *name, const char *value)
  340. {
  341. WCHAR *wpath, *wname = NULL, *wvalue = NULL;
  342. wpath = HeapAlloc(GetProcessHeap(), 0, (strlen(path)+1)*sizeof(WCHAR));
  343. MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, strlen(path)+1);
  344. if (name)
  345. {
  346. wname = HeapAlloc(GetProcessHeap(), 0, (strlen(name)+1)*sizeof(WCHAR));
  347. MultiByteToWideChar(CP_ACP, 0, name, -1, wname, strlen(name)+1);
  348. }
  349. if (value)
  350. {
  351. wvalue = HeapAlloc(GetProcessHeap(), 0, (strlen(value)+1)*sizeof(WCHAR));
  352. MultiByteToWideChar(CP_ACP, 0, value, -1, wvalue, strlen(value)+1);
  353. }
  354. set_reg_key_ex(root, wpath, wname, wvalue, REG_SZ);
  355. HeapFree(GetProcessHeap(), 0, wpath);
  356. HeapFree(GetProcessHeap(), 0, wname);
  357. HeapFree(GetProcessHeap(), 0, wvalue);
  358. }
  359. void set_reg_key_dword(HKEY root, const char *path, const char *name, DWORD value)
  360. {
  361. WCHAR *wpath, *wname;
  362. wpath = HeapAlloc(GetProcessHeap(), 0, (strlen(path)+1)*sizeof(WCHAR));
  363. wname = HeapAlloc(GetProcessHeap(), 0, (strlen(name)+1)*sizeof(WCHAR));
  364. MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, strlen(path)+1);
  365. MultiByteToWideChar(CP_ACP, 0, name, -1, wname, strlen(name)+1);
  366. set_reg_key_ex(root, wpath, wname, &value, REG_DWORD);
  367. HeapFree(GetProcessHeap(), 0, wpath);
  368. HeapFree(GetProcessHeap(), 0, wname);
  369. }
  370. void set_reg_keyW(HKEY root, const WCHAR *path, const WCHAR *name, const WCHAR *value)
  371. {
  372. set_reg_key_ex(root, path, name, value, REG_SZ);
  373. }
  374. void set_reg_key_dwordW(HKEY root, const WCHAR *path, const WCHAR *name, DWORD value)
  375. {
  376. set_reg_key_ex(root, path, name, &value, REG_DWORD);
  377. }
  378. /**
  379. * enumerates the value names at the given path, taking into account
  380. * the changes in the settings list.
  381. *
  382. * you are expected to HeapFree each element of the array, which is null
  383. * terminated, as well as the array itself.
  384. */
  385. static WCHAR **enumerate_valuesW(HKEY root, WCHAR *path)
  386. {
  387. HKEY key;
  388. DWORD res, i = 0, valueslen = 0;
  389. WCHAR **values = NULL;
  390. struct list *cursor;
  391. res = RegOpenKeyExW(root, path, 0, MAXIMUM_ALLOWED, &key);
  392. if (res == ERROR_SUCCESS)
  393. {
  394. while (TRUE)
  395. {
  396. WCHAR name[1024];
  397. DWORD namesize = ARRAY_SIZE(name);
  398. BOOL removed = FALSE;
  399. /* find out the needed size, allocate a buffer, read the value */
  400. if ((res = RegEnumValueW(key, i, name, &namesize, NULL, NULL, NULL, NULL)) != ERROR_SUCCESS)
  401. break;
  402. WINE_TRACE("name=%s\n", wine_dbgstr_w(name));
  403. /* check if this value name has been removed in the settings list */
  404. LIST_FOR_EACH( cursor, &settings )
  405. {
  406. struct setting *s = LIST_ENTRY(cursor, struct setting, entry);
  407. if (lstrcmpiW(s->path, path) != 0) continue;
  408. if (lstrcmpiW(s->name, name) != 0) continue;
  409. if (!s->value)
  410. {
  411. WINE_TRACE("this key has been removed, so skipping\n");
  412. removed = TRUE;
  413. break;
  414. }
  415. }
  416. if (removed) /* this value was deleted by the user, so don't include it */
  417. {
  418. i++;
  419. continue;
  420. }
  421. /* grow the array if necessary, add buffer to it, iterate */
  422. if (values) values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(WCHAR*) * (valueslen + 1));
  423. else values = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR*));
  424. values[valueslen++] = strdupW(name);
  425. WINE_TRACE("valueslen is now %d\n", valueslen);
  426. i++;
  427. }
  428. }
  429. else
  430. {
  431. WINE_WARN("failed opening registry key %s, res=0x%x\n",
  432. wine_dbgstr_w(path), res);
  433. }
  434. WINE_TRACE("adding settings in list but not registry\n");
  435. /* now we have to add the values that aren't in the registry but are in the settings list */
  436. LIST_FOR_EACH( cursor, &settings )
  437. {
  438. struct setting *setting = LIST_ENTRY(cursor, struct setting, entry);
  439. BOOL found = FALSE;
  440. if (lstrcmpiW(setting->path, path) != 0) continue;
  441. if (!setting->value) continue;
  442. for (i = 0; i < valueslen; i++)
  443. {
  444. if (lstrcmpiW(setting->name, values[i]) == 0)
  445. {
  446. found = TRUE;
  447. break;
  448. }
  449. }
  450. if (found) continue;
  451. WINE_TRACE("%s in list but not registry\n", wine_dbgstr_w(setting->name));
  452. /* otherwise it's been set by the user but isn't in the registry */
  453. if (values) values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(WCHAR*) * (valueslen + 1));
  454. else values = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR*));
  455. values[valueslen++] = strdupW(setting->name);
  456. }
  457. WINE_TRACE("adding null terminator\n");
  458. if (values)
  459. {
  460. values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(WCHAR*) * (valueslen + 1));
  461. values[valueslen] = NULL;
  462. }
  463. RegCloseKey(key);
  464. return values;
  465. }
  466. char **enumerate_values(HKEY root, char *path)
  467. {
  468. WCHAR *wpath;
  469. WCHAR **wret;
  470. char **ret=NULL;
  471. int i=0, len=0, size;
  472. wpath = HeapAlloc(GetProcessHeap(), 0, (strlen(path)+1)*sizeof(WCHAR));
  473. MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, strlen(path)+1);
  474. wret = enumerate_valuesW(root, wpath);
  475. if (wret)
  476. {
  477. for(len=0; wret[len]; len++);
  478. ret = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(char*));
  479. /* convert WCHAR ** to char ** and HeapFree each WCHAR * element on our way */
  480. for (i=0; i<len; i++)
  481. {
  482. size = WideCharToMultiByte(CP_ACP, 0, wret[i], -1, NULL, 0, NULL, NULL);
  483. if(size)
  484. {
  485. ret[i] = HeapAlloc(GetProcessHeap(), 0, size);
  486. WideCharToMultiByte(CP_ACP, 0, wret[i], -1, ret[i], size, NULL, NULL);
  487. HeapFree(GetProcessHeap(), 0, wret[i]);
  488. }
  489. }
  490. ret[len] = NULL;
  491. }
  492. HeapFree(GetProcessHeap(), 0, wpath);
  493. HeapFree(GetProcessHeap(), 0, wret);
  494. return ret;
  495. }
  496. /**
  497. * returns true if the given key/value pair exists in the registry or
  498. * has been written to.
  499. */
  500. BOOL reg_key_exists(HKEY root, const char *path, const char *name)
  501. {
  502. char *val = get_reg_key(root, path, name, NULL);
  503. if (val)
  504. {
  505. HeapFree(GetProcessHeap(), 0, val);
  506. return TRUE;
  507. }
  508. return FALSE;
  509. }
  510. static void process_setting(struct setting *s)
  511. {
  512. static const WCHAR softwareW[] = {'S','o','f','t','w','a','r','e','\\'};
  513. HKEY key;
  514. BOOL needs_wow64 = (is_win64 && s->root == HKEY_LOCAL_MACHINE && s->path &&
  515. !strncmpiW(s->path, softwareW, ARRAY_SIZE(softwareW)));
  516. if (s->value)
  517. {
  518. WINE_TRACE("Setting %s:%s to '%s'\n", wine_dbgstr_w(s->path),
  519. wine_dbgstr_w(s->name), wine_dbgstr_w(s->value));
  520. set_config_key(s->root, s->path, MAXIMUM_ALLOWED, s->name, s->value, s->type);
  521. if (needs_wow64)
  522. {
  523. WINE_TRACE("Setting 32-bit %s:%s to '%s'\n", wine_dbgstr_w(s->path),
  524. wine_dbgstr_w(s->name), wine_dbgstr_w(s->value));
  525. set_config_key(s->root, s->path, MAXIMUM_ALLOWED | KEY_WOW64_32KEY, s->name, s->value, s->type);
  526. }
  527. }
  528. else
  529. {
  530. WINE_TRACE("Removing %s:%s\n", wine_dbgstr_w(s->path), wine_dbgstr_w(s->name));
  531. if (!RegOpenKeyExW( s->root, s->path, 0, MAXIMUM_ALLOWED, &key ))
  532. {
  533. /* NULL name means remove that path/section entirely */
  534. if (s->name) RegDeleteValueW( key, s->name );
  535. else
  536. {
  537. RegDeleteTreeW( key, NULL );
  538. RegDeleteKeyW( s->root, s->path );
  539. }
  540. RegCloseKey( key );
  541. }
  542. if (needs_wow64)
  543. {
  544. WINE_TRACE("Removing 32-bit %s:%s\n", wine_dbgstr_w(s->path), wine_dbgstr_w(s->name));
  545. if (!RegOpenKeyExW( s->root, s->path, 0, MAXIMUM_ALLOWED | KEY_WOW64_32KEY, &key ))
  546. {
  547. if (s->name) RegDeleteValueW( key, s->name );
  548. else
  549. {
  550. RegDeleteTreeW( key, NULL );
  551. RegDeleteKeyExW( s->root, s->path, KEY_WOW64_32KEY, 0 );
  552. }
  553. RegCloseKey( key );
  554. }
  555. }
  556. }
  557. }
  558. void apply(void)
  559. {
  560. if (list_empty(&settings)) return; /* we will be called for each page when the user clicks OK */
  561. WINE_TRACE("()\n");
  562. while (!list_empty(&settings))
  563. {
  564. struct setting *s = (struct setting *) list_head(&settings);
  565. process_setting(s);
  566. free_setting(s);
  567. }
  568. }
  569. /* ================================== utility functions ============================ */
  570. WCHAR* current_app = NULL; /* the app we are currently editing, or NULL if editing global */
  571. /* returns a registry key path suitable for passing to addTransaction */
  572. char *keypath(const char *section)
  573. {
  574. static char *result = NULL;
  575. HeapFree(GetProcessHeap(), 0, result);
  576. if (current_app)
  577. {
  578. result = HeapAlloc(GetProcessHeap(), 0, strlen("AppDefaults\\") + lstrlenW(current_app)*2 + 2 /* \\ */ + strlen(section) + 1 /* terminator */);
  579. wsprintfA(result, "AppDefaults\\%ls", current_app);
  580. if (section[0]) sprintf( result + strlen(result), "\\%s", section );
  581. }
  582. else
  583. {
  584. result = strdupA(section);
  585. }
  586. return result;
  587. }
  588. WCHAR *keypathW(const WCHAR *section)
  589. {
  590. static const WCHAR appdefaultsW[] = {'A','p','p','D','e','f','a','u','l','t','s','\\',0};
  591. static WCHAR *result = NULL;
  592. HeapFree(GetProcessHeap(), 0, result);
  593. if (current_app)
  594. {
  595. DWORD len = sizeof(appdefaultsW) + (lstrlenW(current_app) + lstrlenW(section) + 1) * sizeof(WCHAR);
  596. result = HeapAlloc(GetProcessHeap(), 0, len );
  597. lstrcpyW( result, appdefaultsW );
  598. lstrcatW( result, current_app );
  599. if (section[0])
  600. {
  601. len = lstrlenW(result);
  602. result[len++] = '\\';
  603. lstrcpyW( result + len, section );
  604. }
  605. }
  606. else
  607. {
  608. result = strdupW(section);
  609. }
  610. return result;
  611. }
  612. void PRINTERROR(void)
  613. {
  614. LPSTR msg;
  615. FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
  616. 0, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
  617. (LPSTR)&msg, 0, NULL);
  618. /* eliminate trailing newline, is this a Wine bug? */
  619. *(strrchr(msg, '\r')) = '\0';
  620. WINE_TRACE("error: '%s'\n", msg);
  621. }
  622. BOOL initialize(HINSTANCE hInstance)
  623. {
  624. DWORD res = RegCreateKeyA(HKEY_CURRENT_USER, WINE_KEY_ROOT, &config_key);
  625. if (res != ERROR_SUCCESS) {
  626. WINE_ERR("RegOpenKey failed on wine config key (%d)\n", res);
  627. return TRUE;
  628. }
  629. return FALSE;
  630. }