| /* |
| * WineCfg libraries tabsheet |
| * |
| * Copyright 2004 Robert van Herk |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| */ |
| |
| #define NONAMELESSUNION |
| #include <windows.h> |
| #include <commdlg.h> |
| #include <wine/debug.h> |
| #include <stdio.h> |
| #include "winecfg.h" |
| #include "resource.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(winecfg); |
| |
| typedef enum _DLGMODE |
| { |
| DLL, |
| APP, |
| GLOBAL, |
| } DLGMODE; |
| |
| typedef enum _DLLMODE { |
| BUILTIN_NATIVE, |
| NATIVE_BUILTIN, |
| BUILTIN, |
| NATIVE, |
| DISABLE, |
| UNKNOWN /*Special value indicating an erronous DLL override mode*/ |
| } DLLMODE; |
| |
| static void removeSpaces(char* in, char* out) |
| { |
| int i,j; |
| j = 0; |
| for (i = 0; i < strlen(in); i++) |
| { |
| if (in[i] != ' ') |
| { |
| out[j] = in[i]; |
| j++; |
| } |
| } |
| out[j] = 0; |
| } |
| |
| static DLLMODE Str2DLLMode(char* c) |
| { |
| /*Parse a string into a DLLMode*/ |
| char* d = HeapAlloc(GetProcessHeap(), 0, sizeof(c)); |
| removeSpaces(c,d); |
| if (strcmp (d, "builtin,native") == 0) { |
| return BUILTIN_NATIVE; |
| } else |
| if (strcmp (d, "native,builtin") == 0) { |
| return NATIVE_BUILTIN; |
| } else |
| if (strcmp (d, "native") == 0){ |
| return NATIVE; |
| } else |
| if (strcmp (d, "builtin") == 0) { |
| return BUILTIN; |
| } else |
| if (strcmp (d, "") == 0) { |
| return DISABLE; |
| } else |
| return UNKNOWN; |
| } |
| |
| static char* DLLMode2Str(DLLMODE mode) |
| { |
| char* res; |
| switch (mode) { |
| case NATIVE: |
| res = "native"; |
| break; |
| case BUILTIN: |
| res = "builtin"; |
| break; |
| case NATIVE_BUILTIN: |
| res = "native, builtin"; |
| break; |
| case BUILTIN_NATIVE: |
| res = "builtin, native"; |
| break; |
| case DISABLE: |
| res = ""; |
| break; |
| default: |
| res = "unknown"; |
| } |
| return strdup(res); |
| } |
| |
| typedef struct _DLLOVERRIDE |
| { |
| char* lpcKey; /*The actual dll name*/ |
| DLLMODE mode; |
| } DLLOVERRIDE, *LPDLLOVERRIDE; |
| |
| static LPDLLOVERRIDE CreateDLLOverride(char* lpcKey) |
| { |
| LPDLLOVERRIDE out = HeapAlloc(GetProcessHeap(),0,sizeof(DLLOVERRIDE)); |
| out->lpcKey = strdup (lpcKey); |
| return out; |
| } |
| |
| static VOID FreeDLLOverride(LPDLLOVERRIDE ldo) |
| { |
| if (ldo->lpcKey) |
| free(ldo->lpcKey); |
| HeapFree(GetProcessHeap(),0,ldo); |
| } |
| |
| typedef struct _APPL |
| { |
| BOOL isGlobal; |
| char* lpcApplication; |
| char* lpcSection; /*Registry section*/ |
| } APPL, *LPAPPL; |
| |
| static LPAPPL CreateAppl(BOOL isGlobal, char* application, char* section) |
| { |
| LPAPPL out; |
| out = HeapAlloc(GetProcessHeap(),0,sizeof(APPL)); |
| out->lpcApplication = strdup(application); |
| out->lpcSection = strdup(section); |
| out->isGlobal = isGlobal; |
| return out; |
| } |
| |
| static VOID FreeAppl(LPAPPL lpAppl) |
| { |
| if (lpAppl->lpcApplication) |
| free(lpAppl->lpcApplication); /* The strings were strdup-ped, so we use "free" */ |
| if (lpAppl->lpcSection) |
| free(lpAppl->lpcSection); |
| HeapFree(GetProcessHeap(),0,lpAppl); |
| } |
| |
| typedef struct _ITEMTAG |
| { |
| LPAPPL lpAppl; |
| LPDLLOVERRIDE lpDo; |
| } ITEMTAG, *LPITEMTAG; |
| |
| static LPITEMTAG CreateItemTag() |
| { |
| LPITEMTAG out; |
| out = HeapAlloc(GetProcessHeap(),0,sizeof(ITEMTAG)); |
| out->lpAppl = 0; |
| out->lpDo = 0; |
| return out; |
| } |
| |
| static VOID FreeItemTag(LPITEMTAG lpit) |
| { |
| if (lpit->lpAppl) |
| FreeAppl(lpit->lpAppl); |
| if (lpit->lpDo) |
| FreeDLLOverride(lpit->lpDo); |
| HeapFree(GetProcessHeap(),0,lpit); |
| } |
| |
| static VOID UpdateDLLList(HWND hDlg, char* dll) |
| { |
| /*Add if it isn't already in*/ |
| if (SendDlgItemMessage(hDlg, IDC_DLLLIST, CB_FINDSTRING, 1, (LPARAM) dll) == CB_ERR) |
| SendDlgItemMessage(hDlg,IDC_DLLLIST,CB_ADDSTRING,0,(LPARAM) dll); |
| } |
| |
| static VOID LoadLibrarySettings(LPAPPL appl /*DON'T FREE, treeview will own this*/, HWND hDlg, HWND hwndTV) |
| { |
| HKEY key; |
| int i; |
| DWORD size; |
| DWORD readSize; |
| char name [255]; |
| char read [255]; |
| LPITEMTAG lpIt; |
| TVINSERTSTRUCT tis; |
| HTREEITEM hParent; |
| LPDLLOVERRIDE lpdo; |
| |
| WINE_TRACE("opening %s\n", appl->lpcSection); |
| if (RegOpenKey (configKey, appl->lpcSection, &key) == ERROR_SUCCESS) |
| { |
| i = 0; |
| size = 255; |
| readSize = 255; |
| |
| lpIt = CreateItemTag(); |
| lpIt->lpAppl = appl; |
| |
| tis.hParent = NULL; |
| tis.hInsertAfter = TVI_LAST; |
| tis.u.item.mask = TVIF_TEXT | TVIF_PARAM; |
| tis.u.item.pszText = appl->lpcApplication; |
| tis.u.item.lParam = (LPARAM)lpIt; |
| hParent = TreeView_InsertItem(hwndTV,&tis); |
| tis.hParent = hParent; |
| |
| while (RegEnumValue(key, i, name, &size, NULL, NULL, read, &readSize) == ERROR_SUCCESS) |
| { |
| WINE_TRACE("Reading value %s, namely %s\n", name, read); |
| |
| lpIt = CreateItemTag(); |
| lpdo = CreateDLLOverride(name); |
| lpIt->lpDo = lpdo; |
| tis.u.item.lParam = (LPARAM)lpIt; |
| tis.u.item.pszText = name; |
| |
| lpdo->mode = Str2DLLMode(read); |
| |
| TreeView_InsertItem(hwndTV,&tis); |
| UpdateDLLList(hDlg, name); |
| i ++; size = 255; readSize = 255; |
| } |
| RegCloseKey(key); |
| } |
| } |
| |
| static VOID SetEnabledDLLControls(HWND dialog, DLGMODE dlgmode) |
| { |
| if (dlgmode == DLL) { |
| enable(IDC_RAD_BUILTIN); |
| enable(IDC_RAD_NATIVE); |
| enable(IDC_RAD_BUILTIN_NATIVE); |
| enable(IDC_RAD_NATIVE_BUILTIN); |
| enable(IDC_RAD_DISABLE); |
| enable(IDC_DLLS_REMOVEDLL); |
| } else { |
| disable(IDC_RAD_BUILTIN); |
| disable(IDC_RAD_NATIVE); |
| disable(IDC_RAD_BUILTIN_NATIVE); |
| disable(IDC_RAD_NATIVE_BUILTIN); |
| disable(IDC_RAD_DISABLE); |
| disable(IDC_DLLS_REMOVEDLL); |
| } |
| |
| if (dlgmode == APP) { |
| enable(IDC_DLLS_REMOVEAPP); |
| } |
| else { |
| disable(IDC_DLLS_REMOVEAPP); |
| } |
| } |
| |
| static VOID OnInitLibrariesDlg(HWND hDlg) |
| { |
| HWND hwndTV; |
| LPAPPL lpAppl; |
| HKEY applKey; |
| int i; |
| DWORD size; |
| char appl [255]; |
| char lpcKey [255]; |
| FILETIME ft; |
| |
| hwndTV = GetDlgItem(hDlg,IDC_TREE_DLLS); |
| lpAppl = CreateAppl(TRUE,"Global DLL Overrides", "DllOverrides"); |
| LoadLibrarySettings(lpAppl, hDlg, hwndTV); |
| |
| /*And now the application specific stuff:*/ |
| if (RegOpenKey(configKey, "AppDefaults", &applKey) == ERROR_SUCCESS) { |
| i = 0; |
| size = 255; |
| while (RegEnumKeyEx(applKey, i, appl, &size, NULL, NULL, NULL, &ft) == ERROR_SUCCESS) |
| { |
| sprintf(lpcKey, "AppDefaults\\%s\\DllOverrides", appl); |
| lpAppl = CreateAppl(FALSE,appl, lpcKey); |
| LoadLibrarySettings(lpAppl, hDlg, hwndTV); |
| i++; size = 255; |
| } |
| RegCloseKey(applKey); |
| } |
| |
| SetEnabledDLLControls(hDlg, GLOBAL); |
| } |
| |
| static VOID OnTreeViewChangeItem(HWND hDlg, HWND hTV) |
| { |
| TVITEM ti; |
| LPITEMTAG lpit; |
| int buttonId; |
| |
| ti.mask = TVIF_PARAM; |
| ti.hItem = TreeView_GetSelection(hTV); |
| if (TreeView_GetItem (hTV, &ti)) |
| { |
| lpit = (LPITEMTAG) ti.lParam; |
| if (lpit->lpDo) |
| { |
| WINE_TRACE("%s\n", lpit->lpDo->lpcKey); |
| buttonId = IDC_RAD_BUILTIN; |
| switch (lpit->lpDo->mode) |
| { |
| case NATIVE: |
| buttonId = IDC_RAD_NATIVE; |
| break; |
| case BUILTIN: |
| buttonId = IDC_RAD_BUILTIN; |
| break; |
| case NATIVE_BUILTIN: |
| buttonId = IDC_RAD_NATIVE_BUILTIN; |
| break; |
| case BUILTIN_NATIVE: |
| buttonId = IDC_RAD_BUILTIN_NATIVE; |
| break; |
| case DISABLE: |
| buttonId = IDC_RAD_DISABLE; |
| break; |
| case UNKNOWN: |
| buttonId = -1; |
| break; |
| } |
| CheckRadioButton(hDlg, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, buttonId); |
| SetEnabledDLLControls(hDlg, DLL); |
| } else { |
| if (lpit->lpAppl) |
| { |
| if (lpit->lpAppl->isGlobal == TRUE) |
| SetEnabledDLLControls(hDlg, GLOBAL); |
| else |
| SetEnabledDLLControls(hDlg, APP); |
| } |
| } |
| } |
| } |
| |
| static VOID SetDLLMode(HWND hDlg, DLLMODE mode) |
| { |
| HWND hTV; |
| TVITEM ti; |
| LPITEMTAG lpit; |
| char* cMode; |
| TVITEM tiPar; |
| LPITEMTAG lpitPar; |
| |
| hTV = GetDlgItem(hDlg, IDC_TREE_DLLS); |
| ti.mask = TVIF_PARAM; |
| ti.hItem = TreeView_GetSelection(hTV); |
| if (TreeView_GetItem (hTV, &ti)) |
| { |
| lpit = (LPITEMTAG) ti.lParam; |
| if (lpit->lpDo) |
| { |
| lpit->lpDo->mode = mode; |
| cMode = DLLMode2Str (mode); |
| /*Find parent, so we can read registry section*/ |
| tiPar.mask = TVIF_PARAM; |
| tiPar.hItem = TreeView_GetParent(hTV, ti.hItem); |
| if (TreeView_GetItem(hTV,&tiPar)) |
| { |
| lpitPar = (LPITEMTAG) tiPar.lParam; |
| if (lpitPar->lpAppl) |
| { |
| addTransaction(lpitPar->lpAppl->lpcSection, lpit->lpDo->lpcKey, ACTION_SET, cMode); |
| } |
| } |
| free(cMode); |
| } |
| } |
| } |
| |
| static VOID OnBuiltinClick(HWND hDlg) |
| { |
| SetDLLMode(hDlg, BUILTIN); |
| } |
| |
| static VOID OnNativeClick(HWND hDlg) |
| { |
| SetDLLMode(hDlg, NATIVE); |
| } |
| |
| static VOID OnBuiltinNativeClick(HWND hDlg) |
| { |
| SetDLLMode(hDlg, BUILTIN_NATIVE); |
| } |
| |
| static VOID OnNativeBuiltinClick(HWND hDlg) |
| { |
| SetDLLMode(hDlg, NATIVE_BUILTIN); |
| } |
| |
| static VOID OnDisableClick(HWND hDlg) |
| { |
| SetDLLMode(hDlg, DISABLE); |
| } |
| |
| static VOID OnTreeViewDeleteItem(NMTREEVIEW* nmt) |
| { |
| FreeItemTag((LPITEMTAG)(nmt->itemOld.lParam)); |
| } |
| |
| static VOID OnAddDLLClick(HWND hDlg) |
| { |
| HWND hTV; |
| TVITEM ti; |
| LPITEMTAG lpit; |
| LPITEMTAG lpitNew; |
| TVITEM childti; |
| char dll [255]; |
| BOOL doAdd; |
| TVINSERTSTRUCT tis; |
| |
| hTV = GetDlgItem(hDlg, IDC_TREE_DLLS); |
| ti.mask = TVIF_PARAM; |
| ti.hItem = TreeView_GetSelection(hTV); |
| if (TreeView_GetItem (hTV, &ti)) |
| { |
| lpit = (LPITEMTAG) ti.lParam; |
| if (lpit->lpDo) { /*Is this a DLL override (that is: a subitem), then find the parent*/ |
| ti.hItem = TreeView_GetParent(hTV, ti.hItem); |
| if (TreeView_GetItem(hTV,&ti)) { |
| lpit = (LPITEMTAG) ti.lParam; |
| } else return; |
| } |
| } else return; |
| /*Now we should have an parent item*/ |
| if (lpit->lpAppl) |
| { |
| lpitNew = CreateItemTag(); |
| SendDlgItemMessage(hDlg,IDC_DLLLIST,WM_GETTEXT,(WPARAM)255, (LPARAM) dll); |
| if (strlen(dll) > 0) { |
| /*Is the dll already in the list? If so, don't do it*/ |
| doAdd = TRUE; |
| childti.mask = TVIF_PARAM; |
| if ((childti.hItem = TreeView_GetNextItem(hTV, ti.hItem, TVGN_CHILD))) { |
| /*Retrieved first child*/ |
| while (TreeView_GetItem (hTV, &childti)) |
| { |
| if (strcmp(((LPITEMTAG)childti.lParam)->lpDo->lpcKey,dll) == 0) { |
| doAdd = FALSE; |
| break; |
| } |
| childti.hItem = TreeView_GetNextItem(hTV, childti.hItem, TVGN_NEXT); |
| } |
| } |
| if (doAdd) |
| { |
| lpitNew->lpDo = CreateDLLOverride(dll); |
| lpitNew->lpDo->mode = NATIVE; |
| tis.hInsertAfter = TVI_LAST; |
| tis.u.item.mask = TVIF_TEXT | TVIF_PARAM; |
| tis.u.item.pszText = dll; |
| tis.u.item.lParam = (LPARAM)lpitNew; |
| tis.hParent = ti.hItem; |
| TreeView_InsertItem(hTV,&tis); |
| UpdateDLLList(hDlg, dll); |
| addTransaction(lpit->lpAppl->lpcSection, dll, ACTION_SET, "native"); |
| } else MessageBox(hDlg, "A DLL with that name is already in this list...", "", MB_OK | MB_ICONINFORMATION); |
| } |
| } else return; |
| } |
| |
| static VOID OnRemoveDLLClick(HWND hDlg) |
| { |
| HWND hTV; |
| TVITEM ti; |
| LPITEMTAG lpit; |
| TVITEM tiPar; |
| LPITEMTAG lpitPar; |
| |
| hTV = GetDlgItem(hDlg, IDC_TREE_DLLS); |
| ti.mask = TVIF_PARAM; |
| ti.hItem = TreeView_GetSelection(hTV); |
| if (TreeView_GetItem (hTV, &ti)) { |
| lpit = (LPITEMTAG) ti.lParam; |
| if (lpit->lpDo) |
| { |
| /*Find parent for section*/ |
| tiPar.mask = TVIF_PARAM; |
| tiPar.hItem = TreeView_GetParent(hTV, ti.hItem); |
| if (TreeView_GetItem(hTV,&tiPar)) |
| { |
| lpitPar = (LPITEMTAG) tiPar.lParam; |
| if (lpitPar->lpAppl) |
| { |
| addTransaction(lpitPar->lpAppl->lpcSection, lpit->lpDo->lpcKey, ACTION_REMOVE, NULL); |
| TreeView_DeleteItem(hTV,ti.hItem); |
| } |
| } |
| } |
| } |
| } |
| |
| static VOID OnAddApplicationClick(HWND hDlg) |
| { |
| char szFileTitle [255]; |
| char szFile [255]; |
| char lpcKey [255]; |
| |
| TVINSERTSTRUCT tis; |
| LPITEMTAG lpit; |
| OPENFILENAME ofn = { sizeof(OPENFILENAME), |
| 0, /*hInst*/0, "Wine Programs (*.exe,*.exe.so)\0*.exe;*.exe.so\0", NULL, 0, 0, NULL, |
| 0, NULL, 0, NULL, NULL, |
| OFN_SHOWHELP, 0, 0, NULL, 0, NULL }; |
| |
| ofn.lpstrFileTitle = szFileTitle; |
| ofn.lpstrFileTitle[0] = '\0'; |
| ofn.nMaxFileTitle = sizeof(szFileTitle); |
| ofn.lpstrFile = szFile; |
| ofn.lpstrFile[0] = '\0'; |
| ofn.nMaxFile = sizeof(szFile); |
| |
| if (GetOpenFileName(&ofn)) |
| { |
| tis.hParent = NULL; |
| tis.hInsertAfter = TVI_LAST; |
| tis.u.item.mask = TVIF_TEXT | TVIF_PARAM; |
| tis.u.item.pszText = szFileTitle; |
| lpit = CreateItemTag(); |
| sprintf(lpcKey, "AppDefaults\\%s\\DllOverrides", szFileTitle); |
| lpit->lpAppl = CreateAppl(FALSE,szFileTitle,lpcKey); |
| tis.u.item.lParam = (LPARAM)lpit; |
| TreeView_InsertItem(GetDlgItem(hDlg,IDC_TREE_DLLS), &tis); |
| setConfigValue(lpcKey,NULL,NULL); |
| } |
| } |
| |
| static VOID OnRemoveApplicationClick(HWND hDlg) |
| { |
| HWND hTV; |
| TVITEM ti; |
| LPITEMTAG lpit; |
| |
| hTV = GetDlgItem(hDlg, IDC_TREE_DLLS); |
| ti.mask = TVIF_PARAM; |
| ti.hItem = TreeView_GetSelection(hTV); |
| if (TreeView_GetItem (hTV, &ti)) { |
| lpit = (LPITEMTAG) ti.lParam; |
| if (lpit->lpAppl) |
| { |
| addTransaction(lpit->lpAppl->lpcSection, NULL, ACTION_REMOVE, NULL); |
| TreeView_DeleteItem(hTV,ti.hItem); |
| } |
| } |
| } |
| |
| INT_PTR CALLBACK |
| LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) |
| { |
| switch (uMsg) |
| { |
| case WM_INITDIALOG: |
| OnInitLibrariesDlg(hDlg); |
| break; |
| case WM_NOTIFY: |
| switch (((LPNMHDR)lParam)->code) { |
| case TVN_SELCHANGED: { |
| switch(LOWORD(wParam)) { |
| case IDC_TREE_DLLS: |
| OnTreeViewChangeItem(hDlg, GetDlgItem(hDlg,IDC_TREE_DLLS)); |
| break; |
| } |
| } |
| break; |
| case TVN_DELETEITEM: |
| OnTreeViewDeleteItem ((LPNMTREEVIEW)lParam); |
| break; |
| } |
| break; |
| case WM_COMMAND: |
| switch(HIWORD(wParam)) { |
| case BN_CLICKED: |
| switch(LOWORD(wParam)) { |
| case IDC_RAD_BUILTIN: |
| OnBuiltinClick(hDlg); |
| break; |
| case IDC_RAD_NATIVE: |
| OnNativeClick(hDlg); |
| break; |
| case IDC_RAD_BUILTIN_NATIVE: |
| OnBuiltinNativeClick(hDlg); |
| break; |
| case IDC_RAD_NATIVE_BUILTIN: |
| OnNativeBuiltinClick(hDlg); |
| break; |
| case IDC_RAD_DISABLE: |
| OnDisableClick(hDlg); |
| break; |
| case IDC_DLLS_ADDAPP: |
| OnAddApplicationClick(hDlg); |
| break; |
| case IDC_DLLS_REMOVEAPP: |
| OnRemoveApplicationClick(hDlg); |
| break; |
| case IDC_DLLS_ADDDLL: |
| OnAddDLLClick(hDlg); |
| break; |
| case IDC_DLLS_REMOVEDLL: |
| OnRemoveDLLClick(hDlg); |
| break; |
| } |
| break; |
| } |
| break; |
| } |
| |
| return 0; |
| } |