winecfg: new internal api, libraries tab work

Mike Hearn mike at navi.cx
Sat Sep 25 11:36:14 CDT 2004


Mike Hearn <mike at navi.cx>
- rewrite the transaction system to be based on a settings overlay,
  to have a nicer API, and to actually work (always a bonus)
- change the libraries page to be based on a listbox rather than a
  treeview, clean up and shrink the code
- add accelerator keys to the libraries page, focus management
- make the window title reflect what the user is currently editing
- remove bogus root warning
- remove some unused control IDs in resource.h
- start converting the x11drv dialog to kernel_style from javaStyle
- bugfixing
                                                                                           

-------------- next part --------------
--- programs/winecfg.working/winecfg.c	2004-08-25 19:16:30.000000000 +0100
+++ programs/winecfg/winecfg.c	2004-09-20 21:54:25.042422688 +0100
@@ -19,23 +19,6 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * TODO:   (in rough order of priority)
- *   - A mind bogglingly vast amount of stuff
- *
- *   - Implement autodetect for drive configuration
- *   - Figure out whether we need the virtual vs real drive selection stuff at the top of the property page
- *   - Implement explicit mode vs instant-apply mode
- *   - DLL editing
- *   - Multimedia page
- *   - Settings migration code (from old configs)
- *   - Clean up resource.h, it's a bog
- *
- *   Minor things that should be done someday:
- *   - Make the desktop size UI a combo box, with a Custom option, so it's more obvious what you might want to choose here
- *
- * BUGS:
- *   - x11drv page triggers key writes on entry
- *
  */
 
 #include <assert.h>
@@ -44,49 +27,70 @@
 #include <windows.h>
 #include <winreg.h>
 #include <wine/debug.h>
+#include <wine/list.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
 
 #include "winecfg.h"
 
-HKEY configKey = NULL;
+HKEY config_key = NULL;
 
 
-int initialize(void) {
-    DWORD res = RegCreateKey(HKEY_LOCAL_MACHINE, WINE_KEY_ROOT, &configKey);
-    if (res != ERROR_SUCCESS) {
-	WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res);
-	return 1;
+
+/* this is called from the WM_SHOWWINDOW handlers of each tab page.
+ *
+ * it's a nasty hack, necessary because the property sheet insists on resetting the window title
+ * to the title of the tab, which is utterly useless. dropping the property sheet is on the todo list.
+ */
+void set_window_title(HWND dialog)
+{
+    char *newtitle;
+
+    /* update the window title  */
+    if (currentApp)
+    {
+        char *template = "Wine Configuration for %s";
+        newtitle = HeapAlloc(GetProcessHeap(), 0, strlen(template) + strlen(currentApp) + 1);
+        sprintf(newtitle, template, currentApp);
     }
-    return 0;
+    else
+    {
+        newtitle = strdupA("Wine Configuration");
+    }
+
+    WINE_TRACE("setting title to %s\n", newtitle);
+    SendMessage(GetParent(dialog), PSM_SETTITLE, 0, (LPARAM) newtitle);
+    HeapFree(GetProcessHeap(), 0, newtitle);
 }
 
 
-/*****************************************************************************
- * getConfigValue: Retrieves a configuration value from the registry
+/**
+ * getkey: Retrieves a configuration value from the registry
  *
- * const char *subKey : the name of the config section
- * const char *valueName : the name of the config value
- * const char *defaultResult : if the key isn't found, return this value instead
+ * char *subkey : the name of the config section
+ * char *name : the name of the config value
+ * char *default : if the key isn't found, return this value instead
  *
- * Returns a buffer holding the value if successful, NULL if not. Caller is responsible for freeing the result.
+ * Returns a buffer holding the value if successful, NULL if
+ * not. Caller is responsible for releasing the result.
  *
  */
-char *getConfigValue (const char *subkey, const char *valueName, const char *defaultResult)
+static char *getkey (char *subkey, char *name, char *def)
 {
-    char *buffer = NULL;
-    DWORD dataLength;
+    LPBYTE buffer = NULL;
+    DWORD len;
     HKEY hSubKey = NULL;
     DWORD res;
 
-    WINE_TRACE("subkey=%s, valueName=%s, defaultResult=%s\n", subkey, valueName, defaultResult);
+    WINE_TRACE("subkey=%s, name=%s, def=%s\n", subkey, name, def);
 
-    res = RegOpenKeyEx( configKey, subkey, 0, KEY_ALL_ACCESS, &hSubKey );
-    if(res != ERROR_SUCCESS)  {
-        if( res==ERROR_FILE_NOT_FOUND )
+    res = RegOpenKeyEx(config_key, subkey, 0, KEY_READ, &hSubKey);
+    if (res != ERROR_SUCCESS)
+    {
+        if (res == ERROR_FILE_NOT_FOUND)
         {
             WINE_TRACE("Section key not present - using default\n");
-            return defaultResult ? strdup(defaultResult) : NULL;
+            return def ? strdupA(def) : NULL;
         }
         else
         {
@@ -95,192 +99,367 @@
         goto end;
     }
 
-    res = RegQueryValueExA( hSubKey, valueName, NULL, NULL, NULL, &dataLength);
-    if( res == ERROR_FILE_NOT_FOUND ) {
+    res = RegQueryValueExA(hSubKey, name, NULL, NULL, NULL, &len);
+    if (res == ERROR_FILE_NOT_FOUND)
+    {
         WINE_TRACE("Value not present - using default\n");
-        buffer = defaultResult ? strdup(defaultResult) : NULL;
+        buffer = def ? strdupA(def) : NULL;
 	goto end;
-    } else if( res!=ERROR_SUCCESS )  {
-        WINE_ERR("Couldn't query value's length (res=%ld)\n", res );
-        goto end;
-    }
-
-    buffer = malloc(dataLength);
-    if( buffer==NULL )
+    } else if (res != ERROR_SUCCESS)
     {
-        WINE_ERR("Couldn't allocate %lu bytes for the value\n", dataLength );
+        WINE_ERR("Couldn't query value's length (res=%ld)\n", res);
         goto end;
     }
-    
-    RegQueryValueEx(hSubKey, valueName, NULL, NULL, (LPBYTE)buffer, &dataLength);
-    
+
+    buffer = HeapAlloc(GetProcessHeap(), 0, len + 1);
+
+    RegQueryValueEx(hSubKey, name, NULL, NULL, buffer, &len);
+
+    WINE_TRACE("buffer=%s\n", buffer);
 end:
-    if( hSubKey!=NULL )
-        RegCloseKey( hSubKey );
+    if (hSubKey) RegCloseKey(hSubKey);
 
     return buffer;
-    
 }
 
-/*****************************************************************************
- * setConfigValue : Sets a configuration key in the registry. Section
- * will be created if it doesn't already exist
+/**
+ * setkey: convenience wrapper to set a key/value pair
  *
- * HKEY  hCurrent : the registry key that the configuration is rooted at
  * const char *subKey : the name of the config section
  * const char *valueName : the name of the config value
  * const char *value : the value to set the configuration key to
  *
  * Returns 0 on success, non-zero otherwise
- * 
- * If *valueName or *value is NULL, an empty section will be created
+ *
+ * If valueName or value is NULL, an empty section will be created
  */
-int setConfigValue (const char *subkey, const char *valueName, const char *value) {
+int setkey(const char *subkey, const char *name, const char *value) {
     DWORD res = 1;
     HKEY key = NULL;
 
-    WINE_TRACE("subkey=%s, valueName=%s, value=%s\n", subkey, valueName, value);
+    WINE_TRACE("subkey=%s: name=%s, value=%s\n", subkey, name, value);
 
     assert( subkey != NULL );
-    
-    res = RegCreateKey(configKey, subkey, &key);
+
+    res = RegCreateKey(config_key, subkey, &key);
     if (res != ERROR_SUCCESS) goto end;
-    if (value == NULL || valueName == NULL) goto end;
+    if (name == NULL || value == NULL) goto end;
 
-    res = RegSetValueEx(key, valueName, 0, REG_SZ, value, strlen(value) + 1);
+    res = RegSetValueEx(key, name, 0, REG_SZ, value, strlen(value) + 1);
     if (res != ERROR_SUCCESS) goto end;
 
     res = 0;
 end:
     if (key) RegCloseKey(key);
-    if (res != 0) WINE_ERR("Unable to set configuration key %s in section %s to %s, res=%ld\n", valueName, subkey, value, res);
+    if (res != 0) WINE_ERR("Unable to set configuration key %s in section %s to %s, res=%ld\n", name, subkey, value, res);
     return res;
 }
 
-/* returns 0 on success, an HRESULT from the registry funtions otherwise */
-HRESULT doesConfigValueExist(const char *subkey, const char *valueName) {
+/* removes the requested value from the registry, however, does not
+ * remove the section if empty. Returns S_OK (0) on success.
+ */
+static HRESULT remove_value(const char *subkey, const char *name)
+{
     HRESULT hr;
     HKEY key;
 
-    WINE_TRACE("subkey=%s, valueName=%s - ", subkey, valueName);
-    
-    hr = RegOpenKeyEx(configKey, subkey, 0, KEY_READ, &key);
-    if (hr != S_OK) {
-	WINE_TRACE("no: subkey does not exist\n");
-	return hr;
+    WINE_TRACE("subkey=%s, name=%s\n", subkey, name);
+
+    hr = RegOpenKeyEx(config_key, subkey, 0, KEY_READ, &key);
+    if (hr != S_OK) return hr;
+
+    hr = RegDeleteValue(key, name);
+    if (hr != ERROR_SUCCESS) return hr;
+
+    return S_OK;
+}
+
+/* removes the requested subkey from the registry, assuming it exists */
+static HRESULT remove_path(char *section) {
+    WINE_TRACE("section=%s\n", section);
+
+    return RegDeleteKey(config_key, section);
+}
+
+
+/* ========================================================================= */
+
+/* This code exists for the following reasons:
+ *
+ * - It makes working with the registry easier
+ * - By storing a mini cache of the registry, we can more easily implement
+ *   cancel/revert and apply. The 'settings list' is an overlay on top of
+ *   the actual registry data that we can write out at will.
+ *
+ * Rather than model a tree in memory, we simply store each absolute (rooted
+ * at the config key) path.
+ *
+ */
+
+struct setting
+{
+    struct list entry;
+    char *path;   /* path in the registry rooted at the config key  */
+    char *name;   /* name of the registry value  */
+    char *value;  /* contents of the registry value. if null, this means a deletion  */
+};
+
+struct list *settings;
+
+static void free_setting(struct setting *setting)
+{
+    assert( setting != NULL );
+
+    WINE_TRACE("destroying %p\n", setting);
+
+    assert( setting->path && setting->name );
+
+    HeapFree(GetProcessHeap(), 0, setting->path);
+    HeapFree(GetProcessHeap(), 0, setting->name);
+    if (setting->value) HeapFree(GetProcessHeap(), 0, setting->value);
+
+    list_remove(&setting->entry);
+
+    HeapFree(GetProcessHeap(), 0, setting);
+}
+
+/**
+ * Returns the contents of the value at path. If not in the settings
+ * list, it will be fetched from the registry - failing that, the
+ * default will be used.
+ *
+ * If already in the list, the contents as given there will be
+ * returned. You are expected to HeapFree the result.
+ */
+char *get(char *path, char *name, char *def)
+{
+    struct list *cursor;
+    struct setting *s;
+    char *val;
+
+    WINE_TRACE("path=%s, name=%s, def=%s\n", path, name, def);
+
+    /* check if it's in the list */
+    LIST_FOR_EACH( cursor, settings )
+    {
+        s = LIST_ENTRY(cursor, struct setting, entry);
+
+        if (strcasecmp(path, s->path) != 0) continue;
+        if (strcasecmp(name, s->name) != 0) continue;
+
+        WINE_TRACE("found %s:%s in settings list, returning %s\n", path, name, s->value);
+        return strdupA(s->value);
     }
 
-    hr = RegQueryValueEx(key, valueName, NULL, NULL, NULL, NULL);
-    if (hr != S_OK) {
-	WINE_TRACE("no: key does not exist\n");
-	return hr;
+    /* no, so get from the registry */
+    val = getkey(path, name, def);
+
+    WINE_TRACE("returning %s\n", val);
+
+    return val;
+}
+
+/**
+ * Used to set a registry key.
+ *
+ * path is rooted at the config key, ie use "Version" or
+ * "AppDefaults\\fooapp.exe\\Version". You can use keypath()
+ * to get such a string.
+ *
+ * name is the value name, it must not be null (you cannot create
+ * empty groups, sorry ...)
+ *
+ * value is what to set the value to, or NULL to delete it.
+ *
+ * These values will be copied when necessary.
+ */
+void set(char *path, char *name, char *value)
+{
+    struct list *cursor;
+    struct setting *s;
+
+    assert( path != NULL );
+    assert( name != NULL );
+
+    WINE_TRACE("path=%s, name=%s, value=%s\n", path, name, value);
+
+    /* firstly, see if we already set this setting  */
+    LIST_FOR_EACH( cursor, settings )
+    {
+        struct setting *s = LIST_ENTRY(cursor, struct setting, entry);
+
+        if (strcasecmp(s->path, path) != 0) continue;
+        if (strcasecmp(s->name, name) != 0) continue;
+
+        /* yes, we have already set it, so just replace the content and return  */
+        if (s->value) HeapFree(GetProcessHeap(), 0, s->value);
+        s->value = value ? strdupA(value) : NULL;
+
+        return;
     }
 
-    RegCloseKey(key);
-    WINE_TRACE("yes\n");
-    return S_OK;
+    /* otherwise add a new setting for it  */
+    s = HeapAlloc(GetProcessHeap(), 0, sizeof(struct setting));
+    s->path = strdupA(path);
+    s->name = strdupA(name);
+    s->value = value ? strdupA(value) : NULL;
+
+    list_add_tail(settings, &s->entry);
 }
 
-/* removes the requested value from the registry, however, does not remove the section if empty. Returns S_OK (0) on success. */
-HRESULT removeConfigValue(const char *subkey, const char *valueName) {
-    HRESULT hr;
+/**
+ * enumerates the value names at the given path, taking into account
+ * the changes in the settings list.
+ *
+ * you are expected to HeapFree each element of the array, which is null
+ * terminated, as well as the array itself.
+ */
+char **enumerate_values(char *path)
+{
     HKEY key;
-    WINE_TRACE("subkey=%s, valueName=%s\n", subkey, valueName);
-    
-    hr = RegOpenKeyEx(configKey, subkey, 0, KEY_READ, &key);
-    if (hr != S_OK) return hr;
+    DWORD res, i = 0;
+    char **values = NULL;
+    int valueslen = 0;
+    struct list *cursor;
 
-    hr = RegDeleteValue(key, valueName);
-    if (hr != ERROR_SUCCESS) return hr;
+    res = RegOpenKeyEx(config_key, path, 0, KEY_READ, &key);
+    if (res == ERROR_SUCCESS)
+    {
+        while (TRUE)
+        {
+            char name[1024];
+            DWORD namesize = sizeof(name);
+            BOOL removed = FALSE;
+
+            /* find out the needed size, allocate a buffer, read the value  */
+            if ((res = RegEnumValue(key, i, name, &namesize, NULL, NULL, NULL, NULL)) != ERROR_SUCCESS)
+                break;
+
+            WINE_TRACE("name=%s\n", name);
+
+            /* check if this value name has been removed in the settings list  */
+            LIST_FOR_EACH( cursor, settings )
+            {
+                struct setting *s = LIST_ENTRY(cursor, struct setting, entry);
+                if (strcasecmp(s->path, path) != 0) continue;
+                if (strcasecmp(s->name, name) != 0) continue;
+
+                if (!s->value)
+                {
+                    WINE_TRACE("this key has been removed, so skipping\n");
+                    removed = TRUE;
+                    break;
+                }
+            }
+
+            if (removed)            /* this value was deleted by the user, so don't include it */
+            {
+                HeapFree(GetProcessHeap(), 0, name);
+                i++;
+                continue;
+            }
+
+            /* grow the array if necessary, add buffer to it, iterate  */
+            if (values) values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1));
+            else values = HeapAlloc(GetProcessHeap(), 0, sizeof(char*));
+
+            values[valueslen++] = strdupA(name);
+            WINE_TRACE("valueslen is now %d\n", valueslen);
+            i++;
+        }
+    }
+    else
+    {
+        WINE_WARN("failed opening registry key %s, res=0x%lx\n", path, res);
+    }
 
-    return S_OK;
+    WINE_TRACE("adding settings in list but not registry\n");
+
+    /* now we have to add the values that aren't in the registry but are in the settings list */
+    LIST_FOR_EACH( cursor, settings )
+    {
+        struct setting *setting = LIST_ENTRY(cursor, struct setting, entry);
+        BOOL found = FALSE;
+
+        if (strcasecmp(setting->path, path) != 0) continue;
+
+        if (!setting->value) continue;
+
+        for (i = 0; i < valueslen; i++)
+        {
+            if (strcasecmp(setting->name, values[i]) == 0)
+            {
+                found = TRUE;
+                break;
+            }
+        }
+
+        if (found) continue;
+
+        WINE_TRACE("%s in list but not registry\n", setting->name);
+
+        /* otherwise it's been set by the user but isn't in the registry */
+        if (values) values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1));
+        else values = HeapAlloc(GetProcessHeap(), 0, sizeof(char*));
+
+        values[valueslen++] = strdupA(setting->name);
+    }
+
+    WINE_TRACE("adding null terminator\n");
+    if (values)
+    {
+        values = HeapReAlloc(GetProcessHeap(), 0, values, sizeof(char*) * (valueslen + 1));
+        values[valueslen] = NULL;
+    }
+
+    RegCloseKey(key);
+
+    return values;
 }
 
-/* removes the requested configuration section (subkey) from the registry, assuming it exists */
-/* this function might be slightly pointless, but in future we may wish to treat recursion specially etc, so we'll keep it for now */
-HRESULT removeConfigSection(char *section) {
-    HRESULT hr;
-    WINE_TRACE("section=%s\n", section);
+/**
+ * returns true if the given key/value pair exists in the registry or
+ * has been written to.
+ */
+BOOL exists(char *path, char *name)
+{
+    char *val = get(path, name, NULL);
+
+    if (val)
+    {
+        HeapFree(GetProcessHeap(), 0, val);
+        return TRUE;
+    }
 
-    return hr = RegDeleteKey(configKey, section);
+    return FALSE;
 }
 
+static void process_setting(struct setting *s)
+{
+    if (s->value)
+    {
+	WINE_TRACE("Setting %s:%s to '%s'\n", s->path, s->name, s->value);
+        setkey(s->path, s->name, s->value);
+    }
+    else
+    {
+        /* NULL name means remove that path/section entirely */
+	if (s->path && s->name) remove_value(s->path, s->name);
+        else if (s->path && !s->name) remove_path(s->path);
+    }
+}
 
-/* ========================================================================= */
-/* Transaction management code */
+void apply(void)
+{
+    if (list_empty(settings)) return; /* we will be called for each page when the user clicks OK */
 
-struct transaction *tqhead, *tqtail;
-int instantApply = 1;
+    WINE_TRACE("()\n");
 
-void destroyTransaction(struct transaction *trans) {
-    assert( trans != NULL );
-    
-    WINE_TRACE("destroying %p\n", trans);
-    
-    free(trans->section);
-    if (trans->key) free(trans->key);
-    if (trans->newValue) free(trans->newValue);
-    
-    if (trans->next) trans->next->prev = trans->prev;
-    if (trans->prev) trans->prev->next = trans->next;
-    if (trans == tqhead) tqhead = NULL;
-    if (trans == tqtail) tqtail = NULL;
-    
-    free(trans);
-}
-
-void addTransaction(const char *section, const char *key, enum transaction_action action, const char *newValue) {
-    struct transaction *trans = calloc(sizeof(struct transaction),1);
-    
-    assert( section != NULL );
-    if (action == ACTION_SET) assert( newValue != NULL );
-    if (action == ACTION_SET) assert( key != NULL );
-				     
-    trans->section = strdup(section);
-    if (key) trans->key = strdup(key);
-    if (newValue) trans->newValue = strdup(newValue);
-    trans->action = action;
-    
-    if (tqtail == NULL) {
-	tqtail = trans;
-	tqhead = tqtail;
-    } else {
-	tqhead->next = trans;
-	trans->prev = tqhead;
-	tqhead = trans;
-    }
-
-    if (instantApply) {
-	processTransaction(trans);
-	destroyTransaction(trans);
-    }
-}
-
-void processTransaction(struct transaction *trans) {
-    if (trans->action == ACTION_SET) {
-	WINE_TRACE("Setting %s\\%s to '%s'\n", trans->section, trans->key, trans->newValue);
-	setConfigValue(trans->section, trans->key, trans->newValue);
-    } else if (trans->action == ACTION_REMOVE) {
-	if (trans->key) {
-	    WINE_TRACE("Removing %s\\%s\n", trans->section, trans->key);
-	    removeConfigValue(trans->section, trans->key);
-	} else {
-	    /* NULL key means remove that section entirely */
-	    WINE_TRACE("Removing section %s\n", trans->section);
-	    removeConfigSection(trans->section);
-	}
-    }
-    /* TODO: implement notifications here */
-}
-
-void processTransQueue(void)
-{
-    WINE_TRACE("\n");
-    while (tqtail != NULL) {
-	struct transaction *next = tqtail->next;
-	processTransaction(tqtail);
-	destroyTransaction(tqtail);
-	tqtail = next;	
+    while (!list_empty(settings))
+    {
+        struct setting *s = (struct setting *) list_head(settings);
+        process_setting(s);
+        free_setting(s);
     }
 }
 
@@ -292,19 +471,19 @@
 char *keypath(char *section)
 {
     static char *result = NULL;
-    
-    if (result) release(result);
+
+    if (result) HeapFree(GetProcessHeap(), 0, result);
 
     if (currentApp)
     {
-        result = alloc(strlen("AppDefaults\\") + strlen(currentApp) + 2 /* \\ */ + strlen(section) + 1 /* terminator */);
+        result = HeapAlloc(GetProcessHeap(), 0, strlen("AppDefaults\\") + strlen(currentApp) + 2 /* \\ */ + strlen(section) + 1 /* terminator */);
         sprintf(result, "AppDefaults\\%s\\%s", currentApp, section);
     }
     else
     {
         result = strdupA(section);
     }
-    
+
     return result;
 }
 
@@ -326,3 +505,18 @@
                        (LPSTR)&msg, 0, NULL);
         WINE_TRACE("error: '%s'\n", msg);
 }
+
+int initialize(void) {
+    DWORD res = RegCreateKey(HKEY_LOCAL_MACHINE, WINE_KEY_ROOT, &config_key);
+
+    if (res != ERROR_SUCCESS) {
+	WINE_ERR("RegOpenKey failed on wine config key (%ld)\n", res);
+	return 1;
+    }
+
+    /* we could probably just have the list as static data  */
+    settings = HeapAlloc(GetProcessHeap(), 0, sizeof(struct list));
+    list_init(settings);
+
+    return 0;
+}
--- programs/winecfg.working/libraries.c	2004-08-23 17:57:18.000000000 +0100
+++ programs/winecfg/libraries.c	2004-09-20 21:42:43.492074552 +0100
@@ -2,6 +2,7 @@
  * WineCfg libraries tabsheet
  *
  * Copyright 2004 Robert van Herk
+ *           2004 Mike Hearn <mike at navi.cx>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,535 +25,324 @@
 #include <commdlg.h>
 #include <wine/debug.h>
 #include <stdio.h>
+#include <assert.h>
 #include "winecfg.h"
 #include "resource.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
 
-typedef enum _DLGMODE
+enum dllmode
 {
-	DLL,
-	APP,
-	GLOBAL,
-} DLGMODE;
-
-typedef enum _DLLMODE {
 	BUILTIN_NATIVE,
 	NATIVE_BUILTIN,
 	BUILTIN,
 	NATIVE,
 	DISABLE,
-	UNKNOWN /*Special value indicating an erronous DLL override mode*/
-} DLLMODE;
+	UNKNOWN /* Special value indicating an erronous DLL override mode */
+};
+
+struct dll
+{
+        char *name;
+        enum dllmode mode;
+};
 
-static void removeSpaces(char* in, char* out)
+static enum dllmode parse_override(char *in)
 {
-  int i,j;
-  j = 0;
-  for (i = 0; i < strlen(in); i++)
-  {
-    if (in[i] != ' ')
+    int i, j;
+    char *out;
+
+    out = HeapAlloc(GetProcessHeap(), 0, strlen(in));
+
+    /* remove the spaces */
+    j = 0;
+    for (i = 0; i < strlen(in); i++)
     {
-      out[j] = in[i];
-      j++;
+        if (in[i] != ' ')
+        {
+            out[j] = in[i];
+            j++;
+        }
     }
-  }
-  out[j] = 0;
-}
+    out[j] = 0;
+
+    /* parse the string */
+    if (strcmp(out, "builtin,native") == 0) return BUILTIN_NATIVE;
+    else if (strcmp(out, "native,builtin") == 0) return NATIVE_BUILTIN;
+    else if (strcmp(out, "native") == 0) return NATIVE;
+    else if (strcmp(out, "builtin") == 0) return BUILTIN;
+    else if (strcmp(out, "") == 0) return DISABLE;
 
-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)
+/* this is used to convert a dllmode to a human readable string. we should read from the translations here  */
+static char* mode_to_label(enum 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);
-}
+    char* res;
 
-typedef struct _DLLOVERRIDE
-{
-	char* lpcKey;    /*The actual dll name*/
-	DLLMODE mode;
-} DLLOVERRIDE, *LPDLLOVERRIDE;
+    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 = "disabled";
+            break;
+        default:
+            res = "unknown/invalid";
+            break;
+    }
 
-static LPDLLOVERRIDE CreateDLLOverride(char* lpcKey)
-{
-	LPDLLOVERRIDE out = HeapAlloc(GetProcessHeap(),0,sizeof(DLLOVERRIDE));
-	out->lpcKey = strdup (lpcKey);
-	return out;
+    return res;
 }
 
-static VOID FreeDLLOverride(LPDLLOVERRIDE ldo)
+static void set_controls_from_selection(HWND dialog)
 {
-	if (ldo->lpcKey)
-		free(ldo->lpcKey);
-	HeapFree(GetProcessHeap(),0,ldo);
-}
+    int index = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
+    struct dll *dll;
+    DWORD id;
+    int i;
+    
+    if (index == -1) /* no selection  */
+    {
+        for (i = IDC_RAD_BUILTIN; i <= IDC_RAD_DISABLE; i++)
+            disable(i);
 
-typedef struct _APPL
-{
-	BOOL isGlobal;
-	char* lpcApplication;
-	char* lpcSection; /*Registry section*/
-} APPL, *LPAPPL;
+        CheckRadioButton(dialog, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, -1);
+        
+        return;
+    }
 
-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;
-}
+    /* enable the controls  */
+    for (i = IDC_RAD_BUILTIN; i <= IDC_RAD_DISABLE; i++)
+        enable(i);
+
+    dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, index, 0);
+    
+    switch (dll->mode)
+    {
+        case NATIVE:
+            id = IDC_RAD_NATIVE;
+            break;
+        case BUILTIN:
+            id = IDC_RAD_BUILTIN;
+            break;
+        case NATIVE_BUILTIN:
+            id = IDC_RAD_NATIVE_BUILTIN;
+            break;
+        case BUILTIN_NATIVE:
+            id = IDC_RAD_BUILTIN_NATIVE;
+            break;
+        case DISABLE:
+            id = IDC_RAD_DISABLE;
+            break;
+
+        case UNKNOWN:
+        default:
+            id = -1;
+            break;
+    }
 
-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);
+    CheckRadioButton(dialog, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, id);
 }
 
-typedef struct _ITEMTAG
-{
-	LPAPPL lpAppl;
-	LPDLLOVERRIDE lpDo;
-} ITEMTAG, *LPITEMTAG;
 
-static LPITEMTAG CreateItemTag()
+static void clear_settings(HWND dialog)
 {
-	LPITEMTAG out;
-	out = HeapAlloc(GetProcessHeap(),0,sizeof(ITEMTAG));
-	out->lpAppl = 0;
-	out->lpDo = 0;
-	return out;
-}
+    int count = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0);
+    int i;
 
-static VOID FreeItemTag(LPITEMTAG lpit)
-{
-	if (lpit->lpAppl)
-		FreeAppl(lpit->lpAppl);
-	if (lpit->lpDo)
-		FreeDLLOverride(lpit->lpDo);
-	HeapFree(GetProcessHeap(),0,lpit);
+    WINE_TRACE("count=%d\n", count);
+    
+    for (i = 0; i < count; i++)
+    {
+        struct dll *dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, 0, 0);
+        
+        SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_DELETESTRING, 0, 0);
+        
+        HeapFree(GetProcessHeap(), 0, dll->name);
+        HeapFree(GetProcessHeap(), 0, dll);
+    }
 }
 
-static VOID UpdateDLLList(HWND hDlg, char* dll)
+static void load_library_settings(HWND dialog)
 {
-	/*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);
-}
+    char **overrides = enumerate_values(keypath("DllOverrides"));
+    char **p;
+    int sel, count = 0;
 
-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);
-	}
-}
+    sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
 
-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);
-	}
+    WINE_TRACE("sel=%d\n", sel);
 
-	if (dlgmode == APP) {
-		enable(IDC_DLLS_REMOVEAPP);
-	}
-	else {
-		disable(IDC_DLLS_REMOVEAPP);
-	}
-}
+    clear_settings(dialog);
+    
+    if (!overrides || *overrides == NULL)
+    {
+        set_controls_from_selection(dialog);
+        disable(IDC_DLLS_REMOVEDLL);
+        HeapFree(GetProcessHeap(), 0, overrides);
+        return;
+    }
 
-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);
-	}
+    enable(IDC_DLLS_REMOVEDLL);
+    
+    for (p = overrides; *p != NULL; p++)
+    {
+        int index;
+        char *str, *value, *label;
+        struct dll *dll;
+
+        value = get(keypath("DllOverrides"), *p, NULL);
+
+        label = mode_to_label(parse_override(value));
+        
+        str = HeapAlloc(GetProcessHeap(), 0, strlen(*p) + 2 + strlen(label) + 2);
+        strcpy(str, *p);
+        strcat(str, " (");
+        strcat(str, label);
+        strcat(str, ")");
+
+        dll = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dll));
+        dll->name = *p;
+        dll->mode = parse_override(value);
 
-	SetEnabledDLLControls(hDlg, GLOBAL);
-}
+        index = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_ADDSTRING, (WPARAM) -1, (LPARAM) str);
+        SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETITEMDATA, index, (LPARAM) dll);
 
-static VOID OnTreeViewChangeItem(HWND hDlg, HWND hTV)
-{
-	TVITEM ti;
-	LPITEMTAG lpit;
-	int buttonId;
+        HeapFree(GetProcessHeap(), 0, str);
 
-	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);
-			}
-		}
-	}
-}
+        count++;
+    }
 
-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);
-		}
-	}
-}
+    HeapFree(GetProcessHeap(), 0, overrides);
 
-static VOID OnBuiltinClick(HWND hDlg)
-{
-	SetDLLMode(hDlg, BUILTIN);
-}
+    /* restore the previous selection, if possible  */
+    if (sel >= count - 1) sel = count - 1;
+    else if (sel == -1) sel = 0;
+    
+    SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETCURSEL, sel, 0);
 
-static VOID OnNativeClick(HWND hDlg)
-{
-	SetDLLMode(hDlg, NATIVE);
+    set_controls_from_selection(dialog);
 }
 
-static VOID OnBuiltinNativeClick(HWND hDlg)
+/* Called when the application is initialized (cannot reinit!)  */
+static void init_libsheet(HWND dialog)
 {
-	SetDLLMode(hDlg, BUILTIN_NATIVE);
+    /* clear the add dll controls  */
+    SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_SETTEXT, 1, (LPARAM) "");
+    disable(IDC_DLLS_ADDDLL);
 }
 
-static VOID OnNativeBuiltinClick(HWND hDlg)
-{
-	SetDLLMode(hDlg, NATIVE_BUILTIN);
-}
 
-static VOID OnDisableClick(HWND hDlg)
+static void on_add_combo_change(HWND dialog)
 {
-	SetDLLMode(hDlg, DISABLE);
-}
+    char buffer[1024];
 
-static VOID OnTreeViewDeleteItem(NMTREEVIEW* nmt)
-{
-	FreeItemTag((LPITEMTAG)(nmt->itemOld.lParam));
+    SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_GETTEXT, sizeof(buffer), (LPARAM) buffer);
+
+    if (strlen(buffer))
+        enable(IDC_DLLS_ADDDLL)
+    else
+        disable(IDC_DLLS_ADDDLL);
 }
 
-static VOID OnAddDLLClick(HWND hDlg)
+static void set_dllmode(HWND dialog, DWORD id)
 {
-	HWND hTV;
-	TVITEM ti;
-	LPITEMTAG lpit;
-	LPITEMTAG lpitNew;
-	TVITEM childti;
-	char dll [255];
-	BOOL doAdd;
-	TVINSERTSTRUCT tis;
+    enum dllmode mode;
+    struct dll *dll;
+    int sel;
+    char *str;
 
-	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;
-}
+#define CONVERT(s) case IDC_RAD_##s: mode = s; break;
+    
+    switch (id)
+    {
+        CONVERT( BUILTIN );
+        CONVERT( NATIVE );
+        CONVERT( BUILTIN_NATIVE );
+        CONVERT( NATIVE_BUILTIN );
+        CONVERT( DISABLE );
 
-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);
-				}
-			}
-		}
-	}
+        default: assert( FALSE ); /* should not be reached  */
+    }
+
+#undef CONVERT
+
+    sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
+    if (sel == -1) return;
+    
+    dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0);
+
+    switch (mode)
+    {
+        case BUILTIN: str = "builtin"; break;
+        case NATIVE: str = "native"; break;
+        case BUILTIN_NATIVE: str = "builtin, native"; break;
+        case NATIVE_BUILTIN: str = "native, builtin"; break;
+        case DISABLE: str = ""; break;
+        default: assert( FALSE ); /* unreachable  */
+    }
+    WINE_TRACE("Setting %s to %s\n", dll->name, str);
+    
+    set(keypath("DllOverrides"), dll->name, str);
+
+    load_library_settings(dialog);  /* ... and refresh  */
 }
 
-static VOID OnAddApplicationClick(HWND hDlg)
+static void on_add_click(HWND dialog)
 {
-	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);
+    char buffer[1024];
 
-	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);
-	}
+    ZeroMemory(buffer, sizeof(buffer));
+
+    SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_GETTEXT, sizeof(buffer), (LPARAM) buffer);
+
+    SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_SETTEXT, 0, (LPARAM) "");
+    disable(IDC_DLLS_ADDDLL);
+    
+    WINE_TRACE("Adding %s as native, builtin", buffer);
+    
+    set(keypath("DllOverrides"), buffer, "native,builtin");
+
+    load_library_settings(dialog);
+
+    SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SELECTSTRING, (WPARAM) 0, (LPARAM) buffer);
+
+    set_controls_from_selection(dialog);
 }
 
-static VOID OnRemoveApplicationClick(HWND hDlg)
+static void on_remove_click(HWND dialog)
 {
-	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 sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
+    struct dll *dll;
+
+    if (sel == LB_ERR) return;
+    
+    dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0);
+    
+    SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_DELETESTRING, sel, 0);
+
+    set(keypath("DllOverrides"), dll->name, NULL);
+
+    HeapFree(GetProcessHeap(), 0, dll->name);
+    HeapFree(GetProcessHeap(), 0, dll);
+
+    if (SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0) > 0)
+        SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETCURSEL, max(sel - 1, 0), 0);
+    else
+        disable(IDC_DLLS_REMOVEDLL);
+
+    set_controls_from_selection(dialog);
 }
 
 INT_PTR CALLBACK
@@ -561,56 +351,53 @@
 	switch (uMsg)
 	{
 	case WM_INITDIALOG:
-		OnInitLibrariesDlg(hDlg);
-		break;  
+		init_libsheet(hDlg);
+		break;
+        case WM_SHOWWINDOW:
+                set_window_title(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;
+                case PSN_SETACTIVE:
+                    load_library_settings(hDlg);
+                    break;
 		}
 		break;
 	case WM_COMMAND:
 		switch(HIWORD(wParam)) {
+
+                    /* FIXME: when the user hits enter in the DLL combo box we should invoke the add
+                     * add button, rather than the propsheet OK button. But I don't know how to do that!
+                     */
+                    
+                case CBN_EDITCHANGE:
+                        if(LOWORD(wParam) == IDC_DLLCOMBO)
+                        {
+                            on_add_combo_change(hDlg);
+                            break;
+                        }
+                    
 		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;
+                            set_dllmode(hDlg, LOWORD(wParam));
+                            break;
+                            
 			case IDC_DLLS_ADDDLL:
-				OnAddDLLClick(hDlg);
-				break;
+                            on_add_click(hDlg);
+                            break;
 			case IDC_DLLS_REMOVEDLL:
-				OnRemoveDLLClick(hDlg);
-				break;
+                            on_remove_click(hDlg);
+                            break;
 			}
 			break;
+                case LBN_SELCHANGE:
+                        set_controls_from_selection(hDlg);
+                        break;
 		}
 		break;
 	}
--- programs/winecfg.working/winecfg.h	2004-08-25 20:46:30.000000000 +0100
+++ programs/winecfg/winecfg.h	2004-09-20 22:02:16.931684616 +0100
@@ -45,31 +45,22 @@
     }
 
 #define WRITEME(owner) MessageBox(owner, "Write me!", "", MB_OK | MB_ICONEXCLAMATION);
-  
-
-/* Transaction management */
-enum transaction_action {
-    ACTION_SET,
-    ACTION_REMOVE
-};
-
-struct transaction {
-    char *section;
-    char *key;
-    char *newValue;
-    enum transaction_action action;
-    struct transaction *next, *prev;
-};
-extern struct transaction *tqhead, *tqtail;
-
-extern int instantApply; /* non-zero means apply all changes instantly */
-
-#define EDITING_GLOBAL 0
-#define EDITING_APP    1
-extern int appSettings;  /* non-zero means we are editing appdefault settings */
 
 extern char *currentApp; /* NULL means editing global settings  */
 
+/* Use get and set to alter registry settings. The changes made through set
+   won't be committed to the registry until process_all_settings is called,
+   however get will still return accurate information.
+
+   You are expected to release the result of get. The parameters to set will
+   be copied, so release them too when necessary.
+ */
+void set(char *path, char *name, char *value);
+char *get(char *path, char *name, char *def);
+BOOL exists(char *path, char *name);
+void apply(void);
+char **enumerate_values(char *path);
+
 /* returns a string of the form "AppDefaults\\appname.exe\\section", or just "section" if
  * the user is editing the global settings.
  *
@@ -77,31 +68,11 @@
  */
 char *keypath(char *section); 
 
-/* Commits a transaction to the registry */
-void processTransaction(struct transaction *trans);
-
-/* Processes every pending transaction in the queue, removing them as it works from head to tail */
-void processTransQueue();
-
-/* Adds a transaction to the head of the queue. If we're using instant apply, this calls processTransaction
- * action can be either:
- *   ACTION_SET -> this transaction will change a registry key, newValue is the replacement value
- *   ACTION_REMOVE -> this transaction will remove a registry key. In this case, newValue is ignored.
- */
-void addTransaction(const char *section, const char *key, enum transaction_action action, const char *newValue);
-
-/* frees the transaction structure, all fields, and removes it from the queue if in it */
-void destroyTransaction(struct transaction *trans);
-
 /* Initializes the transaction system */
 int initialize(void);
-extern HKEY configKey;
+extern HKEY config_key;
 
-/* don't use these directly!  */
-int setConfigValue (const char *subkey, const char *valueName, const char *value);
-char *getConfigValue (const char *subkey, const char *valueName, const char *defaultResult);
-HRESULT doesConfigValueExist (const char *subkey, const char *valueName);
-HRESULT removeConfigValue (const char *subkey, const char *valueName);
+void set_window_title(HWND dialog);
 
 /* Graphics */
 
@@ -125,14 +96,12 @@
 char *getDialogItemText(HWND hDlg, WORD controlID);
 #define disable(id) EnableWindow(GetDlgItem(dialog, id), 0);
 #define enable(id) EnableWindow(GetDlgItem(dialog, id), 1);
-#define alloc(size) HeapAlloc(GetProcessHeap(), 0, size);
-#define release(ptr) HeapFree(GetProcessHeap(), 0, ptr);
 void PRINTERROR(void); /* WINE_TRACE() the plaintext error message from GetLastError() */
 
 /* returns a string in the win32 heap  */
 static inline char *strdupA(char *s)
 {
-    char *r = alloc(strlen(s));
+    char *r = HeapAlloc(GetProcessHeap(), 0, strlen(s));
     return strcpy(r, s);
 }
 
--- programs/winecfg.working/En.rc	2004-08-25 19:16:30.000000000 +0100
+++ programs/winecfg/En.rc	2004-09-20 21:45:51.203538072 +0100
@@ -84,20 +84,18 @@
 FONT 8, "MS Sans Serif"
 BEGIN
     GROUPBOX        "DLL Overrides",IDC_STATIC,8,4,244,240
-    LTEXT           "Libraries can be specified individually to be either builtin or native. A DLL entry specified as ""*"" pertains to all DLLs not specified explicitly."
+    LTEXT           "Dynamic Link Libraries can be specified individually to be either builtin (provided by Wine) or native (taken from Windows or provided by the application)."
                     ,  IDC_STATIC,15,17,228,32
-    CONTROL         "DLL Overrides", IDC_TREE_DLLS, "SysTreeView32", WS_BORDER | WS_TABSTOP | TVS_LINESATROOT | TVS_HASLINES | TVS_SHOWSELALWAYS | TVS_HASBUTTONS, 15,50,142,187
+    LISTBOX         IDC_DLLS_LIST,15,50,142,187,WS_BORDER | WS_TABSTOP | WS_VSCROLL
     LTEXT           "Load order:",IDC_STATIC,163,50,37,8
-    CONTROL         "Builtin (Wine)",IDC_RAD_BUILTIN,"Button", BS_AUTORADIOBUTTON | WS_GROUP,163,65,75,10
-    CONTROL         "Native (Windows)",IDC_RAD_NATIVE,"Button", BS_AUTORADIOBUTTON,163,80,75,10
-    CONTROL         "Builtin, Native",IDC_RAD_BUILTIN_NATIVE,"Button", BS_AUTORADIOBUTTON,163,95,75,10
-    CONTROL         "Native, Builtin",IDC_RAD_NATIVE_BUILTIN,"Button", BS_AUTORADIOBUTTON,163,110,75,10
-    CONTROL         "Disable",IDC_RAD_DISABLE,"Button", BS_AUTORADIOBUTTON,163,125,75,10
-    PUSHBUTTON	    "Add application...",IDC_DLLS_ADDAPP,163,144,82,14
-    PUSHBUTTON	    "Remove application",IDC_DLLS_REMOVEAPP, 163,164,82,14
-    PUSHBUTTON	    "Add DLL override for:",IDC_DLLS_ADDDLL, 163,184,82,14
-    COMBOBOX        IDC_DLLLIST,163,204,82,14,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP | CBS_SORT | CBS_LOWERCASE
-    PUSHBUTTON	    "Remove DLL override",IDC_DLLS_REMOVEDLL,163,224,82,14
+    CONTROL         "&Builtin (Wine)",IDC_RAD_BUILTIN,"Button", BS_AUTORADIOBUTTON | WS_GROUP,163,65,75,10
+    CONTROL         "&Native (Windows)",IDC_RAD_NATIVE,"Button", BS_AUTORADIOBUTTON,163,80,75,10
+    CONTROL         "Bui&ltin then Native",IDC_RAD_BUILTIN_NATIVE,"Button", BS_AUTORADIOBUTTON,163,95,75,10
+    CONTROL         "Nati&ve then Builtin",IDC_RAD_NATIVE_BUILTIN,"Button", BS_AUTORADIOBUTTON,163,110,75,10
+    CONTROL         "&Disable",IDC_RAD_DISABLE,"Button", BS_AUTORADIOBUTTON,163,125,75,10
+    PUSHBUTTON	    "&Add DLL override for:",IDC_DLLS_ADDDLL, 163,184,82,14
+    COMBOBOX        IDC_DLLCOMBO,163,204,82,14,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP | CBS_SORT | CBS_LOWERCASE
+    PUSHBUTTON	    "&Remove DLL override",IDC_DLLS_REMOVEDLL,163,224,82,14
 END
 
 IDD_SYSTEMCFG DIALOG DISCARDABLE  0, 0, 260, 250
--- programs/winecfg.working/appdefaults.c	2004-08-25 19:16:30.000000000 +0100
+++ programs/winecfg/appdefaults.c	2004-09-19 18:02:17.000000000 +0100
@@ -40,23 +40,21 @@
   char *winver, *dosver;
   
   /* retrieve the registry values */
-  winver = getConfigValue(keypath("Version"), "Windows", NULL);
-  dosver = getConfigValue(keypath("Version"), "DOS", NULL);
+  winver = get(keypath("Version"), "Windows", "");
+  dosver = get(keypath("Version"), "DOS", "");
 
-  /* NULL winver/dosver means use automatic mode (ie the builtin dll linkage heuristics)  */
+  /* empty winver/dosver means use automatic mode (ie the builtin dll linkage heuristics)  */
   
-  WINE_TRACE("winver is %s\n", winver ? winver : "null (automatic mode)");
-  WINE_TRACE("dosver is %s\n", dosver ? dosver : "null (automatic mode)");
+  WINE_TRACE("winver is %s\n", *winver != '\0' ? winver : "null (automatic mode)");
+  WINE_TRACE("dosver is %s\n", *dosver != '\0' ? dosver : "null (automatic mode)");
 
   /* normalize the version strings */
-  if (winver && strlen(winver))
+  if (*winver != '\0')
   {
     if ((pVer = getWinVersions ()))
     {
-      WINE_TRACE("Windows version\n");
       for (i = 0; *pVer->szVersion || *pVer->szDescription; i++, pVer++)
       {
-	WINE_TRACE("pVer->szVersion == %s\n", pVer->szVersion);
 	if (!strcasecmp (pVer->szVersion, winver))
 	{
 	  SendDlgItemMessage (dialog, IDC_WINVER, CB_SETCURSEL, (WPARAM) (i + 1), 0);
@@ -71,14 +69,12 @@
     SendDlgItemMessage (dialog, IDC_WINVER, CB_SETCURSEL, 0, 0);
   }
 
-  if (dosver && strlen(dosver))
+  if (*dosver != '\0')
   {
     if ((pVer = getDOSVersions ()))
     {
-      WINE_TRACE("DOS version\n");
       for (i = 0; *pVer->szVersion || *pVer->szDescription; i++, pVer++)
       {
-	WINE_TRACE("pVer->szVersion == %s\n", pVer->szVersion);
 	if (!strcasecmp (pVer->szVersion, dosver))
 	{
 	  SendDlgItemMessage (dialog, IDC_DOSVER, CB_SETCURSEL,
@@ -93,9 +89,9 @@
     WINE_TRACE("setting dosver combobox to automatic/default\n");
     SendDlgItemMessage (dialog, IDC_DOSVER, CB_SETCURSEL, 0, 0);
   }
-
-  if (winver) free(winver);
-  if (dosver) free(dosver);
+  
+  HeapFree(GetProcessHeap(), 0, winver);
+  HeapFree(GetProcessHeap(), 0, dosver);
 }
 
 void
@@ -153,6 +149,7 @@
   ListView_InsertItem(listview, &item);
 }
 
+/* Called when the application is initialized (cannot reinit!)  */
 static void init_appsheet(HWND dialog)
 {
   HWND listview;
@@ -160,22 +157,21 @@
   int i;
   DWORD size;
   char appname[1024];
-  FILETIME ft;
 
   WINE_TRACE("()\n");
-  
+
   listview = GetDlgItem(dialog, IDC_APP_LISTVIEW);
 
   /* we use the lparam field of the item so we can alter the presentation later and not change code
    * for instance, to use the tile view or to display the EXEs embedded 'display name' */
   add_listview_item(listview, "Default Settings", NULL);
-  
-  /* do the application specific stuff, then add the default item last */
-  if (RegOpenKey(configKey, "AppDefaults", &key) == ERROR_SUCCESS)
+
+  /* because this list is only populated once, it's safe to bypass the settings list here  */
+  if (RegOpenKey(config_key, "AppDefaults", &key) == ERROR_SUCCESS)
   {
       i = 0;
       size = sizeof(appname);
-      while (RegEnumKeyEx(key, i, appname, &size, NULL, NULL, NULL, &ft) == ERROR_SUCCESS)
+      while (RegEnumKeyEx(key, i, appname, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
       {
           add_listview_item(listview, appname, strdup(appname));
 
@@ -218,12 +214,13 @@
   return -1;
 }
 
+
 /* called when the user selects a different application */
 static void on_selection_change(HWND dialog, HWND listview)
 {
   LVITEM item;
   char *oldapp = currentApp;
-
+    
   WINE_TRACE("()\n");
   
   item.iItem = get_listview_selection(listview);
@@ -253,6 +250,8 @@
       init_comboboxes(dialog);
   
   update_comboboxes(dialog);
+
+  set_window_title(dialog);
 }
 
 static void on_add_app_click(HWND dialog)
@@ -295,14 +294,14 @@
 {
     HWND listview = GetDlgItem(dialog, IDC_APP_LISTVIEW);
     int selection = get_listview_selection(listview);
-    char *section = keypath("");
+    char *section = keypath(""); /* AppDefaults\\whatever.exe\\ */
 
     WINE_TRACE("selection=%d, section=%s\n", selection, section);
     
     assert( selection != 0 ); /* user cannot click this button when "default settings" is selected  */
 
     section[strlen(section)] = '\0'; /* remove last backslash  */
-    addTransaction(section, NULL, ACTION_REMOVE, NULL);
+    set(section, NULL, NULL); /* delete the section  */
     ListView_DeleteItem(listview, selection);
 
     SetFocus(listview);
@@ -316,13 +315,16 @@
     if (selection == 0)
     {
         WINE_TRACE("automatic/default selected so removing current setting\n");
-        addTransaction(keypath("Version"), "Windows", ACTION_REMOVE, NULL);
+        set(keypath("Version"), "Windows", NULL);
     }
     else
     {
         WINE_TRACE("setting Version\\Windows key to value '%s'\n", ver[selection - 1].szVersion);
-        addTransaction(keypath("Version"), "Windows", ACTION_SET,  ver[selection - 1].szVersion);
+        set(keypath("Version"), "Windows", ver[selection - 1].szVersion);
     }
+
+    /* enable the apply button  */
+    SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
 }
 
 static void on_dosver_change(HWND dialog)
@@ -333,13 +335,16 @@
     if (selection == 0)
     {
         WINE_TRACE("automatic/default selected so removing current setting\n");
-        addTransaction(keypath("Version"), "DOS", ACTION_REMOVE, NULL);
+        set(keypath("Version"), "DOS", NULL);
     }
     else
     {
         WINE_TRACE("setting Version\\DOS key to value '%s'\n", ver[selection - 1].szVersion);
-        addTransaction(keypath("Version"), "DOS", ACTION_SET,  ver[selection - 1].szVersion);
+        set(keypath("Version"), "DOS", ver[selection - 1].szVersion);
     }
+
+    /* enable the apply button  */
+    SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
 }
 
 INT_PTR CALLBACK
@@ -348,17 +353,25 @@
   switch (uMsg)
   {
     case WM_INITDIALOG:
-      init_appsheet(hDlg);
-      break;
+        init_appsheet(hDlg);
+        break;
+
+    case WM_SHOWWINDOW:
+        set_window_title(hDlg);
+        break;
 
     case WM_NOTIFY:
-    
       switch (((LPNMHDR)lParam)->code)
       {
         case LVN_ITEMCHANGED:
-          on_selection_change(hDlg, GetDlgItem(hDlg, IDC_APP_LISTVIEW));
-          break;
+            on_selection_change(hDlg, GetDlgItem(hDlg, IDC_APP_LISTVIEW));
+            break;
+        case PSN_APPLY:
+            apply();
+            SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
+            break;
       }
+      
       break;
     
     case WM_COMMAND:
@@ -383,6 +396,7 @@
           }
           break;
       }
+
       break;
   }
   
--- programs/winecfg.working/audio.c	2004-08-23 17:57:18.000000000 +0100
+++ programs/winecfg/audio.c	2004-08-26 20:49:26.000000000 +0100
@@ -55,7 +55,8 @@
     {
       if (!strcmp (pAudioDrv->szDriver, drivername))
       {
-	addTransaction("Winmm", "Drivers", ACTION_SET, pAudioDrv->szDriver);
+	set("Winmm", "Drivers", (char *) pAudioDrv->szDriver);
+        SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM) hDlg, 0); /* enable apply button */
 	SendDlgItemMessage(hDlg, IDC_AUDIO_DRIVER, CB_SETCURSEL,
 			   (WPARAM) i, 0);
       }
@@ -66,7 +67,7 @@
 void
 initAudioDlg (HWND hDlg)
 {
-  char *curAudioDriver = getConfigValue("Winmm", "Drivers", "winealsa.drv");
+  char *curAudioDriver = get("Winmm", "Drivers", "winealsa.drv");
   const AUDIO_DRIVER *pAudioDrv = NULL;
   int i;
 
@@ -175,13 +176,18 @@
 	     break;
 	}
 	break;
-	
+
+      case WM_SHOWWINDOW:
+        set_window_title(hDlg);
+        break;
+        
       case WM_NOTIFY:
 	switch(((LPNMHDR)lParam)->code) {
 	    case PSN_KILLACTIVE:
 	      SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
 	      break;
 	    case PSN_APPLY:
+              apply();
 	      SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
 	      break;
 	    case PSN_SETACTIVE:
--- programs/winecfg.working/drive.c	2004-08-23 17:57:19.000000000 +0100
+++ programs/winecfg/drive.c	2004-08-25 20:24:18.000000000 +0100
@@ -212,14 +212,13 @@
     ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);
   
   /* disable or enable controls depending on whether we are editing global vs app specific config */
-  if (appSettings == EDITING_GLOBAL) {
+  if (currentApp) {
     WINE_TRACE("enabling controls\n");
     enable(IDC_LIST_DRIVES);
     enable(IDC_BUTTON_ADD);
     enable(IDC_BUTTON_REMOVE);
     enable(IDC_BUTTON_EDIT);
     enable(IDC_BUTTON_AUTODETECT);
-    
   } else {
     WINE_TRACE("disabling controls\n");
     disable(IDC_LIST_DRIVES);
@@ -1015,6 +1014,11 @@
       case WM_INITDIALOG:
           onDriveInitDialog();
           break;
+
+      case WM_SHOWWINDOW:
+          set_window_title(hDlg);
+          break;
+          
       case WM_COMMAND:
 	switch (LOWORD(wParam)) {
 	    case IDC_LIST_DRIVES:
--- programs/winecfg.working/main.c	2004-08-25 19:09:50.000000000 +0100
+++ programs/winecfg/main.c	2004-08-26 20:05:14.000000000 +0100
@@ -217,10 +217,6 @@
 	WINE_ERR("initialization failed, aborting\n");
 	ExitProcess(1);
     }
-
-    /* is the user running as root? */
-    if(getuid() == 0)
-        MessageBox(NULL, "It is not advisable to run wine as root.  Doing so may compromise the security of your computer.  Please run wine as a normal user.", "", MB_OK);
     
     /*
      * The next 3 lines should be all that is needed
--- programs/winecfg.working/resource.h	2004-08-25 19:16:30.000000000 +0100
+++ programs/winecfg/resource.h	2004-08-25 20:33:25.000000000 +0100
@@ -53,26 +53,17 @@
 #define IDC_DESKTOP_BY                  1026
 #define IDC_XDGA                        1027
 #define IDC_XSHM                        1028
+
+/* dll editing  */
 #define IDC_RAD_BUILTIN                 1029
 #define IDC_RAD_NATIVE                  1030
 #define IDC_RAD_BUILTIN_NATIVE          1031
 #define IDC_RAD_NATIVE_BUILTIN          1032
 #define IDC_RAD_DISABLE                 1033
-#define IDC_TREE_DLLS                   1034
-#define IDC_DLLS_ADDAPP                 8000
+#define IDC_DLLS_LIST                   1034
 #define IDC_DLLS_ADDDLL                 8001
-#define IDC_DLLS_REMOVEAPP              8002
 #define IDC_DLLS_REMOVEDLL              8003
-#define IDC_DLLLIST                     8004
-#define IDC_RADIO_DEFAULT_BUILTIN       1033
-#define IDC_RADIO_DEFAULT_NATIVE        1034
-#define IDC_RADIO_VIRTUAL               1035
-#define IDC_EDIT_VIRTUAL                1036
-#define IDC_BUTTON_VIRTUAL              1037
-#define IDC_RADIO_REAL                  1038
-#define IDC_EDIT_REAL                   1039
-#define IDC_BUTTON_REAL                 1040
-#define IDC_BUTTON_FOLDERS              1041
+#define IDC_DLLCOMBO                    8004
 
 /* drive editing */
 #define IDC_LIST_DRIVES                 1042
--- programs/winecfg.working/x11drvdlg.c	2004-08-25 19:16:30.000000000 +0100
+++ programs/winecfg/x11drvdlg.c	2004-09-20 21:47:05.701212704 +0100
@@ -36,19 +36,18 @@
 
 #define RES_MAXLEN 5 /* the maximum number of characters in a screen dimension. 5 digits should be plenty, what kind of crazy person runs their screen >10,000 pixels across? */
 
-int updatingUI;
+int updating_ui;
 
-int appSettings = EDITING_GLOBAL; /* start by editing global */
-
-void updateGUIForDesktopMode(HWND dialog) {
+void update_gui_for_desktop_mode(HWND dialog) {
     WINE_TRACE("\n");
 
-    updatingUI = TRUE;
+    updating_ui = TRUE;
     
     /* do we have desktop mode enabled? */
-    if (doesConfigValueExist(keypath("x11drv"), "Desktop") == S_OK) {
+    if (exists(keypath("x11drv"), "Desktop"))
+    {
 	CheckDlgButton(dialog, IDC_ENABLE_DESKTOP, BST_CHECKED);
-	/* enable the controls */
+	
 	enable(IDC_DESKTOP_WIDTH);
 	enable(IDC_DESKTOP_HEIGHT);
 	enable(IDC_DESKTOP_SIZE);
@@ -57,9 +56,10 @@
 	SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_WIDTH), "640");
 	SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_HEIGHT), "480");	
     }
-    else {
+    else
+    {
 	CheckDlgButton(dialog, IDC_ENABLE_DESKTOP, BST_UNCHECKED);
-	/* disable the controls */
+	
 	disable(IDC_DESKTOP_WIDTH);
 	disable(IDC_DESKTOP_HEIGHT);
 	disable(IDC_DESKTOP_SIZE);
@@ -69,22 +69,22 @@
 	SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_HEIGHT), "");
     }
 
-    updatingUI = FALSE;
+    updating_ui = FALSE;
 }
 
 /* pokes the win32 api to setup the dialog from the config struct */
 void initGraphDlg (HWND hDlg)
 {
-    static const char default_desktop[] = "640x480";
+    static char *default_desktop = "640x480";
     char *buf;
     char *bufindex;
 
-    updateGUIForDesktopMode(hDlg);
+    update_gui_for_desktop_mode(hDlg);
 
-    updatingUI = TRUE;
+    updating_ui = TRUE;
     
     /* desktop size */
-    buf = getConfigValue(keypath("x11drv"), "Desktop", default_desktop);
+    buf = get(keypath("x11drv"), "Desktop", default_desktop);
     bufindex = strchr(buf, 'x');
     if(!bufindex) /* handle invalid "Desktop" values */
     {
@@ -96,7 +96,7 @@
     bufindex++;
     SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_WIDTH), buf);
     SetWindowText(GetDlgItem(hDlg, IDC_DESKTOP_HEIGHT), bufindex);
-    free(buf);
+    HeapFree(GetProcessHeap(), 0, buf);
 
     SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_RESETCONTENT, 0, 0);
     SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_ADDSTRING, 0, (LPARAM) "8 bit");
@@ -104,7 +104,7 @@
     SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_ADDSTRING, 0, (LPARAM) "24 bit");
     SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_ADDSTRING, 0, (LPARAM) "32 bit"); /* is this valid? */
 
-    buf = getConfigValue(keypath("x11drv"), "ScreenDepth", "24");
+    buf = get(keypath("x11drv"), "ScreenDepth", "24");
     if (strcmp(buf, "8") == 0)
 	SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_SETCURSEL, 0, 0);
     else if (strcmp(buf, "16") == 0)
@@ -115,36 +115,34 @@
 	SendDlgItemMessage(hDlg, IDC_SCREEN_DEPTH, CB_SETCURSEL, 3, 0);
     else
 	WINE_ERR("Invalid screen depth read from registry (%s)\n", buf);
-    free(buf);
+    HeapFree(GetProcessHeap(), 0, buf);
 
     SendDlgItemMessage(hDlg, IDC_DESKTOP_WIDTH, EM_LIMITTEXT, RES_MAXLEN, 0);
     SendDlgItemMessage(hDlg, IDC_DESKTOP_HEIGHT, EM_LIMITTEXT, RES_MAXLEN, 0);
 
-    buf = getConfigValue(keypath("x11drv"), "DXGrab", "Y");
+    buf = get(keypath("x11drv"), "DXGrab", "Y");
     if (IS_OPTION_TRUE(*buf))
 	CheckDlgButton(hDlg, IDC_DX_MOUSE_GRAB, BST_CHECKED);
     else
 	CheckDlgButton(hDlg, IDC_DX_MOUSE_GRAB, BST_UNCHECKED);
-    free(buf);
+    HeapFree(GetProcessHeap(), 0, buf);
 
-    buf = getConfigValue(keypath("x11drv"), "DesktopDoubleBuffered", "Y");
+    buf = get(keypath("x11drv"), "DesktopDoubleBuffered", "Y");
     if (IS_OPTION_TRUE(*buf))
 	CheckDlgButton(hDlg, IDC_DOUBLE_BUFFER, BST_CHECKED);
     else
 	CheckDlgButton(hDlg, IDC_DOUBLE_BUFFER, BST_UNCHECKED);
-    free(buf);
+    HeapFree(GetProcessHeap(), 0, buf);
     
-    updatingUI = FALSE;
+    updating_ui = FALSE;
 }
 
-
-
 void setFromDesktopSizeEdits(HWND hDlg) {
-    char *width = malloc(RES_MAXLEN+1);
-    char *height = malloc(RES_MAXLEN+1);
-    char *newStr = malloc((RES_MAXLEN*2) + 2);
+    char *width = HeapAlloc(GetProcessHeap(), 0, RES_MAXLEN+1);
+    char *height = HeapAlloc(GetProcessHeap(), 0, RES_MAXLEN+1);
+    char *new = HeapAlloc(GetProcessHeap(), 0, (RES_MAXLEN*2) + 2);
 
-    if (updatingUI) return;
+    if (updating_ui) goto end;
     
     WINE_TRACE("\n");
     
@@ -154,12 +152,13 @@
     if (strcmp(width, "") == 0) strcpy(width, "640");
     if (strcmp(height, "") == 0) strcpy(height, "480");
     
-    sprintf(newStr, "%sx%s", width, height);
-    addTransaction(keypath("x11drv"), "Desktop", ACTION_SET, newStr);
-
-    free(width);
-    free(height);
-    free(newStr);
+    sprintf(new, "%sx%s", width, height);
+    set(keypath("x11drv"), "Desktop", new);
+    
+end:
+    HeapFree(GetProcessHeap(), 0, width);
+    HeapFree(GetProcessHeap(), 0, height);
+    HeapFree(GetProcessHeap(), 0, new);
 }
 
 void onEnableDesktopClicked(HWND hDlg) {
@@ -169,9 +168,9 @@
 	setFromDesktopSizeEdits(hDlg);
     } else {
 	/* it was just checked, so remove the config values */
-	addTransaction(keypath("x11drv"), "Desktop", ACTION_REMOVE, NULL);
+	set(keypath("x11drv"), "Desktop", NULL);
     }
-    updateGUIForDesktopMode(hDlg);
+    update_gui_for_desktop_mode(hDlg);
 }
 
 void onScreenDepthChanged(HWND hDlg) {
@@ -179,26 +178,26 @@
     char *spaceIndex = strchr(newvalue, ' ');
     
     WINE_TRACE("newvalue=%s\n", newvalue);
-    if (updatingUI) return;
+    if (updating_ui) return;
 
     *spaceIndex = '\0';
-    addTransaction(keypath("x11drv"), "ScreenDepth", ACTION_SET, newvalue);
+    set(keypath("x11drv"), "ScreenDepth", newvalue);
     free(newvalue);
 }
 
 void onDXMouseGrabClicked(HWND hDlg) {
     if (IsDlgButtonChecked(hDlg, IDC_DX_MOUSE_GRAB) == BST_CHECKED)
-	addTransaction(keypath("x11drv"), "DXGrab", ACTION_SET, "Y");
+	set(keypath("x11drv"), "DXGrab", "Y");
     else
-	addTransaction(keypath("x11drv"), "DXGrab", ACTION_SET, "N");
+	set(keypath("x11drv"), "DXGrab", "N");
 }
 
 
 void onDoubleBufferClicked(HWND hDlg) {
     if (IsDlgButtonChecked(hDlg, IDC_DOUBLE_BUFFER) == BST_CHECKED)
-	addTransaction(keypath("x11drv"), "DesktopDoubleBuffered", ACTION_SET, "Y");
+	set(keypath("x11drv"), "DesktopDoubleBuffered", "Y");
     else
-	addTransaction(keypath("x11drv"), "DesktopDoubleBuffered", ACTION_SET, "N");
+	set(keypath("x11drv"), "DesktopDoubleBuffered", "N");
 }
 
 INT_PTR CALLBACK
@@ -207,17 +206,21 @@
     switch (uMsg) {
 	case WM_INITDIALOG:
 	    break;
-	    
+
+        case WM_SHOWWINDOW:
+            set_window_title(hDlg);
+            break;
+            
 	case WM_COMMAND:
 	    switch(HIWORD(wParam)) {
 		case EN_CHANGE: {
 		    SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0);
-		    if ( ((LOWORD(wParam) == IDC_DESKTOP_WIDTH) || (LOWORD(wParam) == IDC_DESKTOP_HEIGHT)) && !updatingUI )
+		    if ( ((LOWORD(wParam) == IDC_DESKTOP_WIDTH) || (LOWORD(wParam) == IDC_DESKTOP_HEIGHT)) && !updating_ui )
 			setFromDesktopSizeEdits(hDlg);
 		    break;
 		}
 		case BN_CLICKED: {
-		    if (updatingUI) break;
+		    if (updating_ui) break;
 		    switch(LOWORD(wParam)) {
 			case IDC_ENABLE_DESKTOP: onEnableDesktopClicked(hDlg); break;
 			case IDC_DX_MOUSE_GRAB:  onDXMouseGrabClicked(hDlg); break;
@@ -243,6 +246,7 @@
 		    break;
 		}
 		case PSN_APPLY: {
+                    apply();
 		    SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
 		    break;
 		}


More information about the wine-patches mailing list