diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 207b4093b85776c6527e94f30c3e952766cc98e5..6369ffeb7b4f3b5908d9cae200f3f9ef52d3f051 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -38,6 +38,7 @@
 #include "resource.h"
 #include "wine/exception.h"
 #include "wine/heap.h"
+#include "wine/rbtree.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
 
@@ -3583,42 +3584,6 @@ static void init_font_options(void)
     }
 }
 
-/***********************************************************************
- *              font_init
- */
-void font_init(void)
-{
-    static const WCHAR mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_',0};
-    HANDLE mutex;
-    DWORD disposition;
-
-    if (RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0,
-                         KEY_ALL_ACCESS, NULL, &wine_fonts_key, NULL ))
-        return;
-
-    init_font_options();
-    update_codepage();
-    if (!WineEngInit( &font_funcs )) return;
-
-    if (!(mutex = CreateMutexW( NULL, FALSE, mutex_nameW ))) return;
-    WaitForSingleObject( mutex, INFINITE );
-
-    RegCreateKeyExA( wine_fonts_key, "Cache", 0, NULL, REG_OPTION_VOLATILE,
-                     KEY_ALL_ACCESS, NULL, &wine_fonts_cache_key, &disposition );
-
-    if (disposition == REG_CREATED_NEW_KEY) font_funcs->load_fonts();
-    else load_font_list_from_cache();
-
-    ReleaseMutex( mutex );
-
-    reorder_font_list();
-    load_gdi_font_subst();
-    load_gdi_font_replacements();
-    load_system_links();
-    dump_gdi_font_list();
-    dump_gdi_font_subst();
-}
-
 
 static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
 {
@@ -7441,7 +7406,7 @@ static BOOL remove_font_resource( LPCWSTR file, DWORD flags )
     return ret;
 }
 
-void load_system_bitmap_fonts(void)
+static void load_system_bitmap_fonts(void)
 {
     static const WCHAR keyW[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s',0};
     static const WCHAR fontsW[] = {'F','O','N','T','S','.','F','O','N',0};
@@ -7482,7 +7447,7 @@ static void load_directory_fonts( WCHAR *path, UINT flags )
     FindClose( handle );
 }
 
-void load_file_system_fonts(void)
+static void load_file_system_fonts(void)
 {
     static const WCHAR pathW[] = {'P','a','t','h',0};
     static const WCHAR slashstarW[] = {'\\','*',0};
@@ -7513,7 +7478,121 @@ void load_file_system_fonts(void)
     }
 }
 
-void load_registry_fonts(void)
+struct external_key
+{
+    struct wine_rb_entry entry;
+    BOOL                 found;
+    WCHAR                value[LF_FULLFACESIZE + 12];
+    WCHAR                path[1];
+};
+
+static int compare_external_key( const void *key, const struct wine_rb_entry *entry )
+{
+    return strcmpiW( key, WINE_RB_ENTRY_VALUE( entry, struct external_key, entry )->value );
+}
+
+static struct wine_rb_tree external_keys = { compare_external_key };
+
+static HKEY load_external_font_keys(void)
+{
+    static const WCHAR externalW[] = {'E','x','t','e','r','n','a','l',' ','F','o','n','t','s',0};
+    WCHAR value[LF_FULLFACESIZE + 12], path[MAX_PATH];
+    DWORD i = 0, type, dlen, vlen;
+    struct external_key *key;
+    HKEY hkey;
+
+    if (RegCreateKeyW( wine_fonts_key, externalW, &hkey )) return 0;
+
+    vlen = ARRAY_SIZE(value);
+    dlen = sizeof(path);
+    while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (BYTE *)path, &dlen ))
+    {
+        if (type != REG_SZ) goto next;
+        dlen /= sizeof(WCHAR);
+        if (!(key = HeapAlloc( GetProcessHeap(), 0, offsetof(struct external_key, path[dlen]) ))) break;
+        key->found = FALSE;
+        strcpyW( key->value, value );
+        strcpyW( key->path, path );
+        wine_rb_put( &external_keys, value, &key->entry );
+    next:
+        vlen = ARRAY_SIZE(value);
+        dlen = sizeof(path);
+    }
+    return hkey;
+}
+
+static void update_external_font_keys( HKEY hkey )
+{
+    static const WCHAR win9x_keyW[] = {'S','o','f','t','w','a','r','e','\\',
+                                       'M','i','c','r','o','s','o','f','t','\\',
+                                       'W','i','n','d','o','w','s','\\',
+                                       'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+                                       'F','o','n','t','s',0};
+    static const WCHAR winnt_keyW[] = {'S','o','f','t','w','a','r','e','\\',
+                                       'M','i','c','r','o','s','o','f','t','\\',
+                                       'W','i','n','d','o','w','s',' ','N','T','\\',
+                                       'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+                                       'F','o','n','t','s',0};
+    static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')',0};
+    HKEY winnt_key = 0, win9x_key = 0;
+    struct gdi_font_family *family;
+    struct gdi_font_face *face;
+    struct wine_rb_entry *entry;
+    struct external_key *key, *next;
+    DWORD len;
+    BOOL skip;
+    WCHAR value[LF_FULLFACESIZE + 12], path[MAX_PATH];
+    WCHAR *file;
+
+    RegCreateKeyExW( HKEY_LOCAL_MACHINE, winnt_keyW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL );
+    RegCreateKeyExW( HKEY_LOCAL_MACHINE, win9x_keyW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL );
+
+    /* enumerate the fonts and add external ones to the two keys */
+
+    LIST_FOR_EACH_ENTRY( family, &font_list, struct gdi_font_family, entry )
+    {
+        LIST_FOR_EACH_ENTRY( face, &family->faces, struct gdi_font_face, entry )
+        {
+            if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
+
+            strcpyW( value, face->full_name );
+            if (face->scalable) strcatW( value, TrueType );
+
+            if (GetFullPathNameW( face->file, MAX_PATH, path, NULL ))
+                file = path;
+            else if ((file = strrchrW( face->file, '\\' )))
+                file++;
+            else
+                file = face->file;
+
+            skip = FALSE;
+            if ((entry = wine_rb_get( &external_keys, value )))
+            {
+                struct external_key *key = WINE_RB_ENTRY_VALUE( entry, struct external_key, entry );
+                skip = key->found && !strcmpiW( key->path, file );
+                wine_rb_remove_key( &external_keys, value );
+                HeapFree( GetProcessHeap(), 0, key );
+            }
+            if (skip) continue;
+            len = (strlenW(file) + 1) * sizeof(WCHAR);
+            RegSetValueExW( winnt_key, value, 0, REG_SZ, (BYTE *)file, len );
+            RegSetValueExW( win9x_key, value, 0, REG_SZ, (BYTE *)file, len );
+            RegSetValueExW( hkey, value, 0, REG_SZ, (BYTE *)file, len );
+        }
+    }
+    WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( key, next, &external_keys, struct external_key, entry )
+    {
+        RegDeleteValueW( win9x_key, key->value );
+        RegDeleteValueW( winnt_key, key->value );
+        RegDeleteValueW( hkey, key->value );
+        wine_rb_remove_key( &external_keys, key->value );
+        HeapFree( GetProcessHeap(), 0, key );
+    }
+    RegCloseKey( win9x_key );
+    RegCloseKey( winnt_key );
+}
+
+static void load_registry_fonts(void)
 {
     static const WCHAR dot_fonW[] = {'.','f','o','n',0};
     static const WCHAR win9x_key[] = {'S','o','f','t','w','a','r','e','\\',
@@ -7526,8 +7605,9 @@ void load_registry_fonts(void)
                                       'W','i','n','d','o','w','s',' ','N','T','\\',
                                       'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
                                       'F','o','n','t','s',0};
-    WCHAR value[MAX_PATH], data[MAX_PATH];
+    WCHAR value[LF_FULLFACESIZE + 12], data[MAX_PATH];
     DWORD i = 0, type, dlen, vlen;
+    struct wine_rb_entry *entry;
     HKEY hkey;
 
     /* Look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
@@ -7541,18 +7621,73 @@ void load_registry_fonts(void)
     dlen = sizeof(data);
     while (!RegEnumValueW( hkey, i++, value, &vlen, NULL, &type, (LPBYTE)data, &dlen ))
     {
+        if (type != REG_SZ) goto next;
         dlen /= sizeof(WCHAR);
+        if ((entry = wine_rb_get( &external_keys, value )))
+        {
+            struct external_key *key = WINE_RB_ENTRY_VALUE( entry, struct external_key, entry );
+            if (!strcmpiW( key->path, data ))
+            {
+                key->found = TRUE;
+                goto next;
+            }
+        }
         if (data[0] && data[1] == ':')
             add_font_resource( data, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE );
         else if (dlen >= 6 && !strcmpiW( data + dlen - 5, dot_fonW ))
             add_system_font_resource( data, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE );
-
+    next:
         vlen = ARRAY_SIZE(value);
         dlen = sizeof(data);
     }
     RegCloseKey( hkey );
 }
 
+/***********************************************************************
+ *              font_init
+ */
+void font_init(void)
+{
+    static const WCHAR mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_',0};
+    HANDLE mutex;
+    DWORD disposition;
+
+    if (RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0,
+                         KEY_ALL_ACCESS, NULL, &wine_fonts_key, NULL ))
+        return;
+
+    init_font_options();
+    update_codepage();
+    if (!WineEngInit( &font_funcs )) return;
+
+    if (!(mutex = CreateMutexW( NULL, FALSE, mutex_nameW ))) return;
+    WaitForSingleObject( mutex, INFINITE );
+
+    RegCreateKeyExA( wine_fonts_key, "Cache", 0, NULL, REG_OPTION_VOLATILE,
+                     KEY_ALL_ACCESS, NULL, &wine_fonts_cache_key, &disposition );
+
+    if (disposition == REG_CREATED_NEW_KEY)
+    {
+        HKEY key = load_external_font_keys();
+        load_system_bitmap_fonts();
+        load_file_system_fonts();
+        load_registry_fonts();
+        font_funcs->load_fonts();
+        update_external_font_keys( key );
+        RegCloseKey( key );
+    }
+    else load_font_list_from_cache();
+
+    ReleaseMutex( mutex );
+
+    reorder_font_list();
+    load_gdi_font_subst();
+    load_gdi_font_replacements();
+    load_system_links();
+    dump_gdi_font_list();
+    dump_gdi_font_subst();
+}
+
 /***********************************************************************
  *           AddFontResourceExW    (GDI32.@)
  */
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 448531a652d9991e24aa076bf9ce4a8b961ac68e..755f1286edaac56c98ab9cc9a1d76910e8647652 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -250,19 +250,6 @@ static inline FT_Face get_ft_face( struct gdi_font *font )
 
 static const struct font_backend_funcs font_funcs;
 
-static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
-                                           'W','i','n','d','o','w','s','\\',
-                                           'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
-                                           'F','o','n','t','s','\0'};
-
-static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
-                                           'W','i','n','d','o','w','s',' ','N','T','\\',
-                                           'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
-                                           'F','o','n','t','s','\0'};
-
-static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
-                                               'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
-
 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
 
 struct font_mapping
@@ -1511,177 +1498,6 @@ static void load_mac_fonts(void)
 
 #endif
 
-static WCHAR *get_full_path_name(const WCHAR *name)
-{
-    WCHAR *full_path;
-    DWORD len;
-
-    if (!(len = GetFullPathNameW(name, 0, NULL, NULL)))
-    {
-        ERR("GetFullPathNameW() failed, name %s.\n", debugstr_w(name));
-        return NULL;
-    }
-
-    if (!(full_path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*full_path))))
-    {
-        ERR("Could not get memory.\n");
-        return NULL;
-    }
-
-    if (GetFullPathNameW(name, len, full_path, NULL) != len - 1)
-    {
-        ERR("Unexpected GetFullPathNameW() result, name %s.\n", debugstr_w(name));
-        HeapFree(GetProcessHeap(), 0, full_path);
-        return NULL;
-    }
-
-    return full_path;
-}
-
-/*************************************************************
- *
- * This adds registry entries for any externally loaded fonts
- * (fonts from fontconfig or FontDirs).  It also deletes entries
- * of no longer existing fonts.
- *
- */
-static void update_reg_entries(void)
-{
-    HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
-    LPWSTR valueW;
-    DWORD len;
-    Family *family;
-    Face *face;
-    WCHAR *file, *path;
-    static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
-
-    if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
-                       0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
-        ERR("Can't create Windows font reg key\n");
-        goto end;
-    }
-
-    if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
-                       0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
-        ERR("Can't create Windows font reg key\n");
-        goto end;
-    }
-
-    if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
-                       0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
-        ERR("Can't create external font reg key\n");
-        goto end;
-    }
-
-    /* enumerate the fonts and add external ones to the two keys */
-
-    LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
-        LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
-            if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
-
-            len = strlenW( face->full_name ) + 1;
-            if (face->scalable)
-                len += ARRAY_SIZE(TrueType);
-
-            valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-            strcpyW( valueW, face->full_name );
-
-            if (face->scalable)
-                strcatW(valueW, TrueType);
-
-            if ((path = get_full_path_name(face->file)))
-            {
-                file = path;
-            }
-            else if ((file = strrchrW(face->file, '\\')))
-            {
-                file++;
-            }
-            else
-            {
-                file = face->file;
-            }
-
-            len = strlenW(file) + 1;
-            RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
-            RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
-            RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
-
-            HeapFree(GetProcessHeap(), 0, path);
-            HeapFree(GetProcessHeap(), 0, valueW);
-        }
-    }
- end:
-    if(external_key) RegCloseKey(external_key);
-    if(win9x_key) RegCloseKey(win9x_key);
-    if(winnt_key) RegCloseKey(winnt_key);
-}
-
-static void delete_external_font_keys(void)
-{
-    HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
-    DWORD dlen, plen, vlen, datalen, valuelen, i, type, path_type;
-    LPWSTR valueW;
-    LPVOID data;
-    BYTE *path;
-
-    if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
-                       0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
-        ERR("Can't create Windows font reg key\n");
-        goto end;
-    }
-
-    if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
-                       0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
-        ERR("Can't create Windows font reg key\n");
-        goto end;
-    }
-
-    if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
-        ERR("Can't create external font reg key\n");
-        goto end;
-    }
-
-    /* Delete all external fonts added last time */
-
-    RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                     &valuelen, &datalen, NULL, NULL);
-    valuelen++; /* returned value doesn't include room for '\0' */
-    valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
-    data = HeapAlloc(GetProcessHeap(), 0, datalen);
-    path = HeapAlloc(GetProcessHeap(), 0, datalen);
-
-    dlen = datalen;
-    vlen = valuelen;
-    i = 0;
-    while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
-                        &dlen) == ERROR_SUCCESS) {
-        plen = dlen;
-        if (RegQueryValueExW(winnt_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
-            type == path_type && dlen == plen && !memcmp(data, path, plen))
-            RegDeleteValueW(winnt_key, valueW);
-
-        plen = dlen;
-        if (RegQueryValueExW(win9x_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
-            type == path_type && dlen == plen && !memcmp(data, path, plen))
-            RegDeleteValueW(win9x_key, valueW);
-
-        /* reset dlen and vlen */
-        dlen = datalen;
-        vlen = valuelen;
-    }
-    HeapFree(GetProcessHeap(), 0, path);
-    HeapFree(GetProcessHeap(), 0, data);
-    HeapFree(GetProcessHeap(), 0, valueW);
-
-    /* Delete the old external fonts key */
-    RegCloseKey(external_key);
-    RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
-
- end:
-    if(win9x_key) RegCloseKey(win9x_key);
-    if(winnt_key) RegCloseKey(winnt_key);
-}
 
 static BOOL init_freetype(void)
 {
@@ -1772,11 +1588,6 @@ sym_not_found:
  */
 static void CDECL freetype_load_fonts(void)
 {
-    delete_external_font_keys();
-    load_system_bitmap_fonts();
-    load_file_system_fonts();
-    load_registry_fonts();
-
 #ifdef SONAME_LIBFONTCONFIG
     load_fontconfig_fonts();
 #elif defined(HAVE_CARBON_CARBON_H)
@@ -1784,8 +1595,6 @@ static void CDECL freetype_load_fonts(void)
 #elif defined(__ANDROID__)
     ReadFontDir("/system/fonts", TRUE);
 #endif
-
-    update_reg_entries();
 }
 
 /*************************************************************
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index ad321c829f27c80d069cee70f74243901aa838e6..1afbddf603afe74f14af86195f96aa6e2cad114d 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -449,10 +449,6 @@ struct font_backend_funcs
     void  (CDECL *destroy_font)( struct gdi_font *font );
 };
 
-extern void load_system_bitmap_fonts(void) DECLSPEC_HIDDEN;
-extern void load_file_system_fonts(void) DECLSPEC_HIDDEN;
-extern void load_registry_fonts(void) DECLSPEC_HIDDEN;
-
 extern const WCHAR *get_gdi_font_subst( const WCHAR *from_name, int from_charset, int *to_charset ) DECLSPEC_HIDDEN;
 
 extern struct list font_list DECLSPEC_HIDDEN;