Put the .spec.o file first and the so libraries last on the link
[wine.git] / programs / winecfg / libraries.c
blob3d5da0bc4bb03a8ee342e2c2667a4d2858b81d6e
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_NATIVE,
41 NATIVE_BUILTIN,
42 BUILTIN,
43 NATIVE,
44 DISABLE,
45 UNKNOWN /*Special value indicating an erronous DLL override mode*/
46 } DLLMODE;
48 static void removeSpaces(char* in, char* out)
50 int i,j;
51 j = 0;
52 for (i = 0; i < strlen(in); i++)
54 if (in[i] != ' ')
56 out[j] = in[i];
57 j++;
60 out[j] = 0;
63 static DLLMODE Str2DLLMode(char* c)
65 /*Parse a string into a DLLMode*/
66 char* d = HeapAlloc(GetProcessHeap(), 0, sizeof(c));
67 removeSpaces(c,d);
68 if (strcmp (d, "builtin,native") == 0) {
69 return BUILTIN_NATIVE;
70 } else
71 if (strcmp (d, "native,builtin") == 0) {
72 return NATIVE_BUILTIN;
73 } else
74 if (strcmp (d, "native") == 0){
75 return NATIVE;
76 } else
77 if (strcmp (d, "builtin") == 0) {
78 return BUILTIN;
79 } else
80 if (strcmp (d, "") == 0) {
81 return DISABLE;
82 } else
83 return UNKNOWN;
86 static char* DLLMode2Str(DLLMODE mode)
88 char* res;
89 switch (mode) {
90 case NATIVE:
91 res = "native";
92 break;
93 case BUILTIN:
94 res = "builtin";
95 break;
96 case NATIVE_BUILTIN:
97 res = "native, builtin";
98 break;
99 case BUILTIN_NATIVE:
100 res = "builtin, native";
101 break;
102 case DISABLE:
103 res = "";
104 break;
105 default:
106 res = "unknown";
108 return strdup(res);
111 typedef struct _DLLOVERRIDE
113 char* lpcKey; /*The actual dll name*/
114 DLLMODE mode;
115 } DLLOVERRIDE, *LPDLLOVERRIDE;
117 static LPDLLOVERRIDE CreateDLLOverride(char* lpcKey)
119 LPDLLOVERRIDE out = HeapAlloc(GetProcessHeap(),0,sizeof(DLLOVERRIDE));
120 out->lpcKey = strdup (lpcKey);
121 return out;
124 static VOID FreeDLLOverride(LPDLLOVERRIDE ldo)
126 if (ldo->lpcKey)
127 free(ldo->lpcKey);
128 HeapFree(GetProcessHeap(),0,ldo);
131 typedef struct _APPL
133 BOOL isGlobal;
134 char* lpcApplication;
135 char* lpcSection; /*Registry section*/
136 } APPL, *LPAPPL;
138 static LPAPPL CreateAppl(BOOL isGlobal, char* application, char* section)
140 LPAPPL out;
141 out = HeapAlloc(GetProcessHeap(),0,sizeof(APPL));
142 out->lpcApplication = strdup(application);
143 out->lpcSection = strdup(section);
144 out->isGlobal = isGlobal;
145 return out;
148 static VOID FreeAppl(LPAPPL lpAppl)
150 if (lpAppl->lpcApplication)
151 free(lpAppl->lpcApplication); /* The strings were strdup-ped, so we use "free" */
152 if (lpAppl->lpcSection)
153 free(lpAppl->lpcSection);
154 HeapFree(GetProcessHeap(),0,lpAppl);
157 typedef struct _ITEMTAG
159 LPAPPL lpAppl;
160 LPDLLOVERRIDE lpDo;
161 } ITEMTAG, *LPITEMTAG;
163 static LPITEMTAG CreateItemTag()
165 LPITEMTAG out;
166 out = HeapAlloc(GetProcessHeap(),0,sizeof(ITEMTAG));
167 out->lpAppl = 0;
168 out->lpDo = 0;
169 return out;
172 static VOID FreeItemTag(LPITEMTAG lpit)
174 if (lpit->lpAppl)
175 FreeAppl(lpit->lpAppl);
176 if (lpit->lpDo)
177 FreeDLLOverride(lpit->lpDo);
178 HeapFree(GetProcessHeap(),0,lpit);
181 static VOID UpdateDLLList(HWND hDlg, char* dll)
183 /*Add if it isn't already in*/
184 if (SendDlgItemMessage(hDlg, IDC_DLLLIST, CB_FINDSTRING, 1, (LPARAM) dll) == CB_ERR)
185 SendDlgItemMessage(hDlg,IDC_DLLLIST,CB_ADDSTRING,0,(LPARAM) dll);
188 static VOID LoadLibrarySettings(LPAPPL appl /*DON'T FREE, treeview will own this*/, HWND hDlg, HWND hwndTV)
190 HKEY key;
191 int i;
192 DWORD size;
193 DWORD readSize;
194 char name [255];
195 char read [255];
196 LPITEMTAG lpIt;
197 TVINSERTSTRUCT tis;
198 HTREEITEM hParent;
199 LPDLLOVERRIDE lpdo;
201 WINE_TRACE("opening %s\n", appl->lpcSection);
202 if (RegOpenKey (configKey, appl->lpcSection, &key) == ERROR_SUCCESS)
204 i = 0;
205 size = 255;
206 readSize = 255;
208 lpIt = CreateItemTag();
209 lpIt->lpAppl = appl;
211 tis.hParent = NULL;
212 tis.hInsertAfter = TVI_LAST;
213 tis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
214 tis.u.item.pszText = appl->lpcApplication;
215 tis.u.item.lParam = (LPARAM)lpIt;
216 hParent = TreeView_InsertItem(hwndTV,&tis);
217 tis.hParent = hParent;
219 while (RegEnumValue(key, i, name, &size, NULL, NULL, read, &readSize) == ERROR_SUCCESS)
221 WINE_TRACE("Reading value %s, namely %s\n", name, read);
223 lpIt = CreateItemTag();
224 lpdo = CreateDLLOverride(name);
225 lpIt->lpDo = lpdo;
226 tis.u.item.lParam = (LPARAM)lpIt;
227 tis.u.item.pszText = name;
229 lpdo->mode = Str2DLLMode(read);
231 TreeView_InsertItem(hwndTV,&tis);
232 UpdateDLLList(hDlg, name);
233 i ++; size = 255; readSize = 255;
235 RegCloseKey(key);
239 static VOID SetEnabledDLLControls(HWND dialog, DLGMODE dlgmode)
241 if (dlgmode == DLL) {
242 enable(IDC_RAD_BUILTIN);
243 enable(IDC_RAD_NATIVE);
244 enable(IDC_RAD_BUILTIN_NATIVE);
245 enable(IDC_RAD_NATIVE_BUILTIN);
246 enable(IDC_RAD_DISABLE);
247 enable(IDC_DLLS_REMOVEDLL);
248 } else {
249 disable(IDC_RAD_BUILTIN);
250 disable(IDC_RAD_NATIVE);
251 disable(IDC_RAD_BUILTIN_NATIVE);
252 disable(IDC_RAD_NATIVE_BUILTIN);
253 disable(IDC_RAD_DISABLE);
254 disable(IDC_DLLS_REMOVEDLL);
257 if (dlgmode == APP) {
258 enable(IDC_DLLS_REMOVEAPP);
260 else {
261 disable(IDC_DLLS_REMOVEAPP);
265 static VOID OnInitLibrariesDlg(HWND hDlg)
267 HWND hwndTV;
268 LPAPPL lpAppl;
269 HKEY applKey;
270 int i;
271 DWORD size;
272 char appl [255];
273 char lpcKey [255];
274 FILETIME ft;
276 hwndTV = GetDlgItem(hDlg,IDC_TREE_DLLS);
277 lpAppl = CreateAppl(TRUE,"Global DLL Overrides", "DllOverrides");
278 LoadLibrarySettings(lpAppl, hDlg, hwndTV);
280 /*And now the application specific stuff:*/
281 if (RegOpenKey(configKey, "AppDefaults", &applKey) == ERROR_SUCCESS) {
282 i = 0;
283 size = 255;
284 while (RegEnumKeyEx(applKey, i, appl, &size, NULL, NULL, NULL, &ft) == ERROR_SUCCESS)
286 sprintf(lpcKey, "AppDefaults\\%s\\DllOverrides", appl);
287 lpAppl = CreateAppl(FALSE,appl, lpcKey);
288 LoadLibrarySettings(lpAppl, hDlg, hwndTV);
289 i++; size = 255;
291 RegCloseKey(applKey);
294 SetEnabledDLLControls(hDlg, GLOBAL);
297 static VOID OnTreeViewChangeItem(HWND hDlg, HWND hTV)
299 TVITEM ti;
300 LPITEMTAG lpit;
301 int buttonId;
303 ti.mask = TVIF_PARAM;
304 ti.hItem = TreeView_GetSelection(hTV);
305 if (TreeView_GetItem (hTV, &ti))
307 lpit = (LPITEMTAG) ti.lParam;
308 if (lpit->lpDo)
310 WINE_TRACE("%s\n", lpit->lpDo->lpcKey);
311 buttonId = IDC_RAD_BUILTIN;
312 switch (lpit->lpDo->mode)
314 case NATIVE:
315 buttonId = IDC_RAD_NATIVE;
316 break;
317 case BUILTIN:
318 buttonId = IDC_RAD_BUILTIN;
319 break;
320 case NATIVE_BUILTIN:
321 buttonId = IDC_RAD_NATIVE_BUILTIN;
322 break;
323 case BUILTIN_NATIVE:
324 buttonId = IDC_RAD_BUILTIN_NATIVE;
325 break;
326 case DISABLE:
327 buttonId = IDC_RAD_DISABLE;
328 break;
329 case UNKNOWN:
330 buttonId = -1;
331 break;
333 CheckRadioButton(hDlg, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, buttonId);
334 SetEnabledDLLControls(hDlg, DLL);
335 } else {
336 if (lpit->lpAppl)
338 if (lpit->lpAppl->isGlobal == TRUE)
339 SetEnabledDLLControls(hDlg, GLOBAL);
340 else
341 SetEnabledDLLControls(hDlg, APP);
347 static VOID SetDLLMode(HWND hDlg, DLLMODE mode)
349 HWND hTV;
350 TVITEM ti;
351 LPITEMTAG lpit;
352 char* cMode;
353 TVITEM tiPar;
354 LPITEMTAG lpitPar;
356 hTV = GetDlgItem(hDlg, IDC_TREE_DLLS);
357 ti.mask = TVIF_PARAM;
358 ti.hItem = TreeView_GetSelection(hTV);
359 if (TreeView_GetItem (hTV, &ti))
361 lpit = (LPITEMTAG) ti.lParam;
362 if (lpit->lpDo)
364 lpit->lpDo->mode = mode;
365 cMode = DLLMode2Str (mode);
366 /*Find parent, so we can read registry section*/
367 tiPar.mask = TVIF_PARAM;
368 tiPar.hItem = TreeView_GetParent(hTV, ti.hItem);
369 if (TreeView_GetItem(hTV,&tiPar))
371 lpitPar = (LPITEMTAG) tiPar.lParam;
372 if (lpitPar->lpAppl)
374 addTransaction(lpitPar->lpAppl->lpcSection, lpit->lpDo->lpcKey, ACTION_SET, cMode);
377 free(cMode);
382 static VOID OnBuiltinClick(HWND hDlg)
384 SetDLLMode(hDlg, BUILTIN);
387 static VOID OnNativeClick(HWND hDlg)
389 SetDLLMode(hDlg, NATIVE);
392 static VOID OnBuiltinNativeClick(HWND hDlg)
394 SetDLLMode(hDlg, BUILTIN_NATIVE);
397 static VOID OnNativeBuiltinClick(HWND hDlg)
399 SetDLLMode(hDlg, NATIVE_BUILTIN);
402 static VOID OnDisableClick(HWND hDlg)
404 SetDLLMode(hDlg, DISABLE);
407 static VOID OnTreeViewDeleteItem(NMTREEVIEW* nmt)
409 FreeItemTag((LPITEMTAG)(nmt->itemOld.lParam));
412 static VOID OnAddDLLClick(HWND hDlg)
414 HWND hTV;
415 TVITEM ti;
416 LPITEMTAG lpit;
417 LPITEMTAG lpitNew;
418 TVITEM childti;
419 char dll [255];
420 BOOL doAdd;
421 TVINSERTSTRUCT tis;
423 hTV = GetDlgItem(hDlg, IDC_TREE_DLLS);
424 ti.mask = TVIF_PARAM;
425 ti.hItem = TreeView_GetSelection(hTV);
426 if (TreeView_GetItem (hTV, &ti))
428 lpit = (LPITEMTAG) ti.lParam;
429 if (lpit->lpDo) { /*Is this a DLL override (that is: a subitem), then find the parent*/
430 ti.hItem = TreeView_GetParent(hTV, ti.hItem);
431 if (TreeView_GetItem(hTV,&ti)) {
432 lpit = (LPITEMTAG) ti.lParam;
433 } else return;
435 } else return;
436 /*Now we should have an parent item*/
437 if (lpit->lpAppl)
439 lpitNew = CreateItemTag();
440 SendDlgItemMessage(hDlg,IDC_DLLLIST,WM_GETTEXT,(WPARAM)255, (LPARAM) dll);
441 if (strlen(dll) > 0) {
442 /*Is the dll already in the list? If so, don't do it*/
443 doAdd = TRUE;
444 childti.mask = TVIF_PARAM;
445 if ((childti.hItem = TreeView_GetNextItem(hTV, ti.hItem, TVGN_CHILD))) {
446 /*Retrieved first child*/
447 while (TreeView_GetItem (hTV, &childti))
449 if (strcmp(((LPITEMTAG)childti.lParam)->lpDo->lpcKey,dll) == 0) {
450 doAdd = FALSE;
451 break;
453 childti.hItem = TreeView_GetNextItem(hTV, childti.hItem, TVGN_NEXT);
456 if (doAdd)
458 lpitNew->lpDo = CreateDLLOverride(dll);
459 lpitNew->lpDo->mode = NATIVE;
460 tis.hInsertAfter = TVI_LAST;
461 tis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
462 tis.u.item.pszText = dll;
463 tis.u.item.lParam = (LPARAM)lpitNew;
464 tis.hParent = ti.hItem;
465 TreeView_InsertItem(hTV,&tis);
466 UpdateDLLList(hDlg, dll);
467 addTransaction(lpit->lpAppl->lpcSection, dll, ACTION_SET, "native");
468 } else MessageBox(hDlg, "A DLL with that name is already in this list...", "", MB_OK | MB_ICONINFORMATION);
470 } else return;
473 static VOID OnRemoveDLLClick(HWND hDlg)
475 HWND hTV;
476 TVITEM ti;
477 LPITEMTAG lpit;
478 TVITEM tiPar;
479 LPITEMTAG lpitPar;
481 hTV = GetDlgItem(hDlg, IDC_TREE_DLLS);
482 ti.mask = TVIF_PARAM;
483 ti.hItem = TreeView_GetSelection(hTV);
484 if (TreeView_GetItem (hTV, &ti)) {
485 lpit = (LPITEMTAG) ti.lParam;
486 if (lpit->lpDo)
488 /*Find parent for section*/
489 tiPar.mask = TVIF_PARAM;
490 tiPar.hItem = TreeView_GetParent(hTV, ti.hItem);
491 if (TreeView_GetItem(hTV,&tiPar))
493 lpitPar = (LPITEMTAG) tiPar.lParam;
494 if (lpitPar->lpAppl)
496 addTransaction(lpitPar->lpAppl->lpcSection, lpit->lpDo->lpcKey, ACTION_REMOVE, NULL);
497 TreeView_DeleteItem(hTV,ti.hItem);
504 static VOID OnAddApplicationClick(HWND hDlg)
506 char szFileTitle [255];
507 char szFile [255];
508 char lpcKey [255];
510 TVINSERTSTRUCT tis;
511 LPITEMTAG lpit;
512 OPENFILENAME ofn = { sizeof(OPENFILENAME),
513 0, /*hInst*/0, "Wine Programs (*.exe,*.exe.so)\0*.exe;*.exe.so\0", NULL, 0, 0, NULL,
514 0, NULL, 0, NULL, NULL,
515 OFN_SHOWHELP, 0, 0, NULL, 0, NULL };
517 ofn.lpstrFileTitle = szFileTitle;
518 ofn.lpstrFileTitle[0] = '\0';
519 ofn.nMaxFileTitle = sizeof(szFileTitle);
520 ofn.lpstrFile = szFile;
521 ofn.lpstrFile[0] = '\0';
522 ofn.nMaxFile = sizeof(szFile);
524 if (GetOpenFileName(&ofn))
526 tis.hParent = NULL;
527 tis.hInsertAfter = TVI_LAST;
528 tis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
529 tis.u.item.pszText = szFileTitle;
530 lpit = CreateItemTag();
531 sprintf(lpcKey, "AppDefaults\\%s\\DllOverrides", szFileTitle);
532 lpit->lpAppl = CreateAppl(FALSE,szFileTitle,lpcKey);
533 tis.u.item.lParam = (LPARAM)lpit;
534 TreeView_InsertItem(GetDlgItem(hDlg,IDC_TREE_DLLS), &tis);
535 setConfigValue(lpcKey,NULL,NULL);
539 static VOID OnRemoveApplicationClick(HWND hDlg)
541 HWND hTV;
542 TVITEM ti;
543 LPITEMTAG lpit;
545 hTV = GetDlgItem(hDlg, IDC_TREE_DLLS);
546 ti.mask = TVIF_PARAM;
547 ti.hItem = TreeView_GetSelection(hTV);
548 if (TreeView_GetItem (hTV, &ti)) {
549 lpit = (LPITEMTAG) ti.lParam;
550 if (lpit->lpAppl)
552 addTransaction(lpit->lpAppl->lpcSection, NULL, ACTION_REMOVE, NULL);
553 TreeView_DeleteItem(hTV,ti.hItem);
558 INT_PTR CALLBACK
559 LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
561 switch (uMsg)
563 case WM_INITDIALOG:
564 OnInitLibrariesDlg(hDlg);
565 break;
566 case WM_NOTIFY:
567 switch (((LPNMHDR)lParam)->code) {
568 case TVN_SELCHANGED: {
569 switch(LOWORD(wParam)) {
570 case IDC_TREE_DLLS:
571 OnTreeViewChangeItem(hDlg, GetDlgItem(hDlg,IDC_TREE_DLLS));
572 break;
575 break;
576 case TVN_DELETEITEM:
577 OnTreeViewDeleteItem ((LPNMTREEVIEW)lParam);
578 break;
580 break;
581 case WM_COMMAND:
582 switch(HIWORD(wParam)) {
583 case BN_CLICKED:
584 switch(LOWORD(wParam)) {
585 case IDC_RAD_BUILTIN:
586 OnBuiltinClick(hDlg);
587 break;
588 case IDC_RAD_NATIVE:
589 OnNativeClick(hDlg);
590 break;
591 case IDC_RAD_BUILTIN_NATIVE:
592 OnBuiltinNativeClick(hDlg);
593 break;
594 case IDC_RAD_NATIVE_BUILTIN:
595 OnNativeBuiltinClick(hDlg);
596 break;
597 case IDC_RAD_DISABLE:
598 OnDisableClick(hDlg);
599 break;
600 case IDC_DLLS_ADDAPP:
601 OnAddApplicationClick(hDlg);
602 break;
603 case IDC_DLLS_REMOVEAPP:
604 OnRemoveApplicationClick(hDlg);
605 break;
606 case IDC_DLLS_ADDDLL:
607 OnAddDLLClick(hDlg);
608 break;
609 case IDC_DLLS_REMOVEDLL:
610 OnRemoveDLLClick(hDlg);
611 break;
613 break;
615 break;
618 return 0;