Fix value renaming. Cleanup code, fix a few leaks.
[wine/multimedia.git] / programs / winecfg / libraries.c
blob7dbcb8eae11ef1161c8222fa83b5eaefb83c836e
1 /*
2 * WineCfg libraries tabsheet
4 * Copyright 2004 Robert van Herk
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define NONAMELESSUNION
23 #include <windows.h>
24 #include <commdlg.h>
25 #include <wine/debug.h>
26 #include <stdio.h>
27 #include "winecfg.h"
28 #include "resource.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
32 typedef enum _DLGMODE
34 DLL,
35 APP,
36 GLOBAL,
37 } DLGMODE;
39 typedef enum _DLLMODE {
40 BUILTIN,
41 NATIVE
42 } DLLMODE;
44 typedef struct _DLLOVERRIDE
46 char* lpcKey; /*The actual dll name*/
47 DLLMODE mode;
48 } DLLOVERRIDE, *LPDLLOVERRIDE;
50 static LPDLLOVERRIDE CreateDLLOverride(char* lpcKey)
52 LPDLLOVERRIDE out = HeapAlloc(GetProcessHeap(),0,sizeof(DLLOVERRIDE));
53 out->lpcKey = strdup (lpcKey);
54 return out;
57 static VOID FreeDLLOverride(LPDLLOVERRIDE ldo)
59 if (ldo->lpcKey)
60 free(ldo->lpcKey);
61 HeapFree(GetProcessHeap(),0,ldo);
64 typedef struct _APPL
66 BOOL isGlobal;
67 char* lpcApplication;
68 char* lpcSection; /*Registry section*/
69 } APPL, *LPAPPL;
71 static LPAPPL CreateAppl(BOOL isGlobal, char* application, char* section)
73 LPAPPL out;
74 out = HeapAlloc(GetProcessHeap(),0,sizeof(APPL));
75 out->lpcApplication = strdup(application);
76 out->lpcSection = strdup(section);
77 out->isGlobal = isGlobal;
78 return out;
81 static VOID FreeAppl(LPAPPL lpAppl)
83 if (lpAppl->lpcApplication)
84 free(lpAppl->lpcApplication); /* The strings were strdup-ped, so we use "free" */
85 if (lpAppl->lpcSection)
86 free(lpAppl->lpcSection);
87 HeapFree(GetProcessHeap(),0,lpAppl);
90 typedef struct _ITEMTAG
92 LPAPPL lpAppl;
93 LPDLLOVERRIDE lpDo;
94 } ITEMTAG, *LPITEMTAG;
96 static LPITEMTAG CreateItemTag()
98 LPITEMTAG out;
99 out = HeapAlloc(GetProcessHeap(),0,sizeof(ITEMTAG));
100 out->lpAppl = 0;
101 out->lpDo = 0;
102 return out;
105 static VOID FreeItemTag(LPITEMTAG lpit)
107 if (lpit->lpAppl)
108 FreeAppl(lpit->lpAppl);
109 if (lpit->lpDo)
110 FreeDLLOverride(lpit->lpDo);
111 HeapFree(GetProcessHeap(),0,lpit);
114 static VOID UpdateDLLList(HWND hDlg, char* dll)
116 /*Add if it isn't already in*/
117 if (SendDlgItemMessage(hDlg, IDC_DLLLIST, CB_FINDSTRING, 1, (LPARAM) dll) == CB_ERR)
118 SendDlgItemMessage(hDlg,IDC_DLLLIST,CB_ADDSTRING,0,(LPARAM) dll);
121 static VOID LoadLibrarySettings(LPAPPL appl /*DON'T FREE, treeview will own this*/, HWND hDlg, HWND hwndTV)
123 HKEY key;
124 int i;
125 DWORD size;
126 DWORD readSize;
127 char name [255];
128 char read [255];
129 LPITEMTAG lpIt;
130 TVINSERTSTRUCT tis;
131 HTREEITEM hParent;
132 LPDLLOVERRIDE lpdo;
134 WINE_TRACE("opening %s\n", appl->lpcSection);
135 if (RegOpenKey (configKey, appl->lpcSection, &key) == ERROR_SUCCESS)
137 i = 0;
138 size = 255;
139 readSize = 255;
141 lpIt = CreateItemTag();
142 lpIt->lpAppl = appl;
144 tis.hParent = NULL;
145 tis.hInsertAfter = TVI_LAST;
146 tis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
147 tis.u.item.pszText = appl->lpcApplication;
148 tis.u.item.lParam = (LPARAM)lpIt;
149 hParent = TreeView_InsertItem(hwndTV,&tis);
150 tis.hParent = hParent;
152 while (RegEnumValue(key, i, name, &size, NULL, NULL, read, &readSize) == ERROR_SUCCESS)
154 WINE_TRACE("Reading value %s, namely %s\n", name, read);
156 lpIt = CreateItemTag();
157 lpdo = CreateDLLOverride(name);
158 lpIt->lpDo = lpdo;
159 tis.u.item.lParam = (LPARAM)lpIt;
160 tis.u.item.pszText = name;
161 if (strncmp (read, "built", 5) == 0)
162 lpdo->mode = BUILTIN;
163 else
164 lpdo->mode = NATIVE;
166 TreeView_InsertItem(hwndTV,&tis);
167 UpdateDLLList(hDlg, name);
168 i ++; size = 255; readSize = 255;
170 RegCloseKey(key);
174 static VOID SetEnabledDLLControls(HWND dialog, DLGMODE dlgmode)
176 if (dlgmode == DLL) {
177 enable(IDC_RAD_BUILTIN);
178 enable(IDC_RAD_NATIVE);
179 enable(IDC_DLLS_REMOVEDLL);
180 } else {
181 disable(IDC_RAD_BUILTIN);
182 disable(IDC_RAD_NATIVE);
183 disable(IDC_DLLS_REMOVEDLL);
186 if (dlgmode == APP) {
187 enable(IDC_DLLS_REMOVEAPP);
189 else {
190 disable(IDC_DLLS_REMOVEAPP);
194 static VOID OnInitLibrariesDlg(HWND hDlg)
196 HWND hwndTV;
197 LPAPPL lpAppl;
198 HKEY applKey;
199 int i;
200 DWORD size;
201 char appl [255];
202 char lpcKey [255];
203 FILETIME ft;
205 hwndTV = GetDlgItem(hDlg,IDC_TREE_DLLS);
206 lpAppl = CreateAppl(TRUE,"Global DLL Overrides", "DllOverrides");
207 LoadLibrarySettings(lpAppl, hDlg, hwndTV);
209 /*And now the application specific stuff:*/
210 if (RegOpenKey(configKey, "AppDefaults", &applKey) == ERROR_SUCCESS) {
211 i = 0;
212 size = 255;
213 while (RegEnumKeyEx(applKey, i, appl, &size, NULL, NULL, NULL, &ft) == ERROR_SUCCESS)
215 sprintf(lpcKey, "AppDefaults\\%s\\DllOverrides", appl);
216 lpAppl = CreateAppl(FALSE,appl, lpcKey);
217 LoadLibrarySettings(lpAppl, hDlg, hwndTV);
218 i++; size = 255;
220 RegCloseKey(applKey);
223 SetEnabledDLLControls(hDlg, GLOBAL);
226 static VOID OnTreeViewChangeItem(HWND hDlg, HWND hTV)
228 TVITEM ti;
229 LPITEMTAG lpit;
231 ti.mask = TVIF_PARAM;
232 ti.hItem = TreeView_GetSelection(hTV);
233 if (TreeView_GetItem (hTV, &ti))
235 lpit = (LPITEMTAG) ti.lParam;
236 if (lpit->lpDo)
238 WINE_TRACE("%s\n", lpit->lpDo->lpcKey);
239 if (lpit->lpDo->mode == BUILTIN) {
240 CheckRadioButton(hDlg, IDC_RAD_BUILTIN, IDC_RAD_NATIVE, IDC_RAD_BUILTIN);
241 } else {
242 CheckRadioButton(hDlg, IDC_RAD_BUILTIN, IDC_RAD_NATIVE, IDC_RAD_NATIVE);
244 SetEnabledDLLControls(hDlg, DLL);
245 } else {
246 if (lpit->lpAppl)
248 if (lpit->lpAppl->isGlobal == TRUE)
249 SetEnabledDLLControls(hDlg, GLOBAL);
250 else
251 SetEnabledDLLControls(hDlg, APP);
257 static VOID SetDLLMode(HWND hDlg, DLLMODE mode)
259 HWND hTV;
260 TVITEM ti;
261 LPITEMTAG lpit;
262 char* cMode;
263 TVITEM tiPar;
264 LPITEMTAG lpitPar;
266 hTV = GetDlgItem(hDlg, IDC_TREE_DLLS);
267 ti.mask = TVIF_PARAM;
268 ti.hItem = TreeView_GetSelection(hTV);
269 if (TreeView_GetItem (hTV, &ti))
271 lpit = (LPITEMTAG) ti.lParam;
272 if (lpit->lpDo)
274 lpit->lpDo->mode = mode;
275 if (mode == NATIVE)
276 cMode = "native, builtin";
277 else
278 cMode = "builtin, native";
280 /*Find parent, so we can read registry section*/
281 tiPar.mask = TVIF_PARAM;
282 tiPar.hItem = TreeView_GetParent(hTV, ti.hItem);
283 if (TreeView_GetItem(hTV,&tiPar))
285 lpitPar = (LPITEMTAG) tiPar.lParam;
286 if (lpitPar->lpAppl)
288 addTransaction(lpitPar->lpAppl->lpcSection, lpit->lpDo->lpcKey, ACTION_SET, cMode);
295 static VOID OnBuiltinClick(HWND hDlg)
297 SetDLLMode(hDlg, BUILTIN);
300 static VOID OnNativeClick(HWND hDlg)
302 SetDLLMode(hDlg, NATIVE);
305 static VOID OnTreeViewDeleteItem(NMTREEVIEW* nmt)
307 FreeItemTag((LPITEMTAG)(nmt->itemOld.lParam));
310 static VOID OnAddDLLClick(HWND hDlg)
312 HWND hTV;
313 TVITEM ti;
314 LPITEMTAG lpit;
315 LPITEMTAG lpitNew;
316 TVITEM childti;
317 char dll [255];
318 BOOL doAdd;
319 TVINSERTSTRUCT tis;
321 hTV = GetDlgItem(hDlg, IDC_TREE_DLLS);
322 ti.mask = TVIF_PARAM;
323 ti.hItem = TreeView_GetSelection(hTV);
324 if (TreeView_GetItem (hTV, &ti))
326 lpit = (LPITEMTAG) ti.lParam;
327 if (lpit->lpDo) { /*Is this a DLL override (that is: a subitem), then find the parent*/
328 ti.hItem = TreeView_GetParent(hTV, ti.hItem);
329 if (TreeView_GetItem(hTV,&ti)) {
330 lpit = (LPITEMTAG) ti.lParam;
331 } else return;
333 } else return;
334 /*Now we should have an parent item*/
335 if (lpit->lpAppl)
337 lpitNew = CreateItemTag();
338 SendDlgItemMessage(hDlg,IDC_DLLLIST,WM_GETTEXT,(WPARAM)255, (LPARAM) dll);
339 if (strlen(dll) > 0) {
340 /*Is the dll already in the list? If so, don't do it*/
341 doAdd = TRUE;
342 childti.mask = TVIF_PARAM;
343 if ((childti.hItem = TreeView_GetNextItem(hTV, ti.hItem, TVGN_CHILD))) {
344 /*Retrieved first child*/
345 while (TreeView_GetItem (hTV, &childti))
347 if (strcmp(((LPITEMTAG)childti.lParam)->lpDo->lpcKey,dll) == 0) {
348 doAdd = FALSE;
349 break;
351 childti.hItem = TreeView_GetNextItem(hTV, childti.hItem, TVGN_NEXT);
354 if (doAdd)
356 lpitNew->lpDo = CreateDLLOverride(dll);
357 lpitNew->lpDo->mode = NATIVE;
358 tis.hInsertAfter = TVI_LAST;
359 tis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
360 tis.u.item.pszText = dll;
361 tis.u.item.lParam = (LPARAM)lpitNew;
362 tis.hParent = ti.hItem;
363 TreeView_InsertItem(hTV,&tis);
364 UpdateDLLList(hDlg, dll);
365 addTransaction(lpit->lpAppl->lpcSection, dll, ACTION_SET, "native, builtin");
366 } else MessageBox(hDlg, "A DLL with that name is already in this list...", "", MB_OK | MB_ICONINFORMATION);
368 } else return;
371 static VOID OnRemoveDLLClick(HWND hDlg)
373 HWND hTV;
374 TVITEM ti;
375 LPITEMTAG lpit;
376 TVITEM tiPar;
377 LPITEMTAG lpitPar;
379 hTV = GetDlgItem(hDlg, IDC_TREE_DLLS);
380 ti.mask = TVIF_PARAM;
381 ti.hItem = TreeView_GetSelection(hTV);
382 if (TreeView_GetItem (hTV, &ti)) {
383 lpit = (LPITEMTAG) ti.lParam;
384 if (lpit->lpDo)
386 /*Find parent for section*/
387 tiPar.mask = TVIF_PARAM;
388 tiPar.hItem = TreeView_GetParent(hTV, ti.hItem);
389 if (TreeView_GetItem(hTV,&tiPar))
391 lpitPar = (LPITEMTAG) tiPar.lParam;
392 if (lpitPar->lpAppl)
394 addTransaction(lpitPar->lpAppl->lpcSection, lpit->lpDo->lpcKey, ACTION_REMOVE, NULL);
395 TreeView_DeleteItem(hTV,ti.hItem);
402 static VOID OnAddApplicationClick(HWND hDlg)
404 char szFileTitle [255];
405 char szFile [255];
406 char lpcKey [255];
408 TVINSERTSTRUCT tis;
409 LPITEMTAG lpit;
410 OPENFILENAME ofn = { sizeof(OPENFILENAME),
411 0, /*hInst*/0, "Wine Programs (*.exe,*.exe.so)\0*.exe;*.exe.so\0", NULL, 0, 0, NULL,
412 0, NULL, 0, NULL, NULL,
413 OFN_SHOWHELP, 0, 0, NULL, 0, NULL };
415 ofn.lpstrFileTitle = szFileTitle;
416 ofn.lpstrFileTitle[0] = '\0';
417 ofn.nMaxFileTitle = sizeof(szFileTitle);
418 ofn.lpstrFile = szFile;
419 ofn.lpstrFile[0] = '\0';
420 ofn.nMaxFile = sizeof(szFile);
422 if (GetOpenFileName(&ofn))
424 tis.hParent = NULL;
425 tis.hInsertAfter = TVI_LAST;
426 tis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
427 tis.u.item.pszText = szFileTitle;
428 lpit = CreateItemTag();
429 sprintf(lpcKey, "AppDefaults\\%s\\DllOverrides", szFileTitle);
430 lpit->lpAppl = CreateAppl(FALSE,szFileTitle,lpcKey);
431 tis.u.item.lParam = (LPARAM)lpit;
432 TreeView_InsertItem(GetDlgItem(hDlg,IDC_TREE_DLLS), &tis);
433 setConfigValue(lpcKey,NULL,NULL);
437 static VOID OnRemoveApplicationClick(HWND hDlg)
439 HWND hTV;
440 TVITEM ti;
441 LPITEMTAG lpit;
443 hTV = GetDlgItem(hDlg, IDC_TREE_DLLS);
444 ti.mask = TVIF_PARAM;
445 ti.hItem = TreeView_GetSelection(hTV);
446 if (TreeView_GetItem (hTV, &ti)) {
447 lpit = (LPITEMTAG) ti.lParam;
448 if (lpit->lpAppl)
450 addTransaction(lpit->lpAppl->lpcSection, NULL, ACTION_REMOVE, NULL);
451 TreeView_DeleteItem(hTV,ti.hItem);
456 INT_PTR CALLBACK
457 LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
459 switch (uMsg)
461 case WM_INITDIALOG:
462 OnInitLibrariesDlg(hDlg);
463 break;
464 case WM_NOTIFY:
465 switch (((LPNMHDR)lParam)->code) {
466 case TVN_SELCHANGED: {
467 switch(LOWORD(wParam)) {
468 case IDC_TREE_DLLS:
469 OnTreeViewChangeItem(hDlg, GetDlgItem(hDlg,IDC_TREE_DLLS));
470 break;
473 break;
474 case TVN_DELETEITEM:
475 OnTreeViewDeleteItem ((LPNMTREEVIEW)lParam);
476 break;
478 break;
479 case WM_COMMAND:
480 switch(HIWORD(wParam)) {
481 case BN_CLICKED:
482 switch(LOWORD(wParam)) {
483 case IDC_RAD_BUILTIN:
484 OnBuiltinClick(hDlg);
485 break;
486 case IDC_RAD_NATIVE:
487 OnNativeClick(hDlg);
488 break;
489 case IDC_DLLS_ADDAPP:
490 OnAddApplicationClick(hDlg);
491 break;
492 case IDC_DLLS_REMOVEAPP:
493 OnRemoveApplicationClick(hDlg);
494 break;
495 case IDC_DLLS_ADDDLL:
496 OnAddDLLClick(hDlg);
497 break;
498 case IDC_DLLS_REMOVEDLL:
499 OnRemoveDLLClick(hDlg);
500 break;
502 break;
504 break;
507 return 0;