blob: 3d5da0bc4bb03a8ee342e2c2667a4d2858b81d6e [file] [log] [blame]
/*
* 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;
}