Module: wine Branch: master Commit: b9b5117fe7841bff2ab2cbe2295ff6ab4e3e9844 URL: https://source.winehq.org/git/wine.git/?a=commit;h=b9b5117fe7841bff2ab2cbe22...
Author: Akihiro Sagawa sagawa.aki@gmail.com Date: Sun May 26 21:15:11 2019 +0900
advapi32: Cache result of LoadString.
Signed-off-by: Akihiro Sagawa sagawa.aki@gmail.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/advapi32/registry.c | 144 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 135 insertions(+), 9 deletions(-)
diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c index 8596aea..c9b207d 100644 --- a/dlls/advapi32/registry.c +++ b/dlls/advapi32/registry.c @@ -44,6 +44,7 @@
#include "wine/unicode.h" #include "wine/debug.h" +#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(reg);
@@ -89,6 +90,26 @@ static const WCHAR * const root_key_names[] = static HKEY special_root_keys[ARRAY_SIZE(root_key_names)]; static BOOL hkcu_cache_disabled;
+static CRITICAL_SECTION reg_mui_cs; +static CRITICAL_SECTION_DEBUG reg_mui_cs_debug = +{ + 0, 0, ®_mui_cs, + { ®_mui_cs_debug.ProcessLocksList, + ®_mui_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": reg_mui_cs") } +}; +static CRITICAL_SECTION reg_mui_cs = { ®_mui_cs_debug, -1, 0, 0, 0, 0 }; +struct mui_cache_entry { + struct list entry; + WCHAR *file_name; /* full path name */ + DWORD index; + LCID locale; + WCHAR *text; +}; +static struct list reg_mui_cache = LIST_INIT(reg_mui_cache); /* MRU */ +static unsigned int reg_mui_cache_count; +#define REG_MUI_CACHE_SIZE 8 + static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
/* check if value type needs string conversion (Ansi<->Unicode) */ @@ -3142,10 +3163,95 @@ static INT load_string(HINSTANCE hModule, UINT resId, LPWSTR *pResString) return *pString; }
+static void dump_mui_cache(void) +{ + struct mui_cache_entry *ent; + + TRACE("---------- MUI Cache ----------\n"); + LIST_FOR_EACH_ENTRY( ent, ®_mui_cache, struct mui_cache_entry, entry ) + TRACE("entry=%p, %s,-%u [%#x] => %s\n", + ent, wine_dbgstr_w(ent->file_name), ent->index, ent->locale, wine_dbgstr_w(ent->text)); +} + +static inline void free_mui_cache_entry(struct mui_cache_entry *ent) +{ + heap_free(ent->file_name); + heap_free(ent->text); + heap_free(ent); +} + +/* critical section must be held */ +static int reg_mui_cache_get(const WCHAR *file_name, UINT index, WCHAR **buffer) +{ + struct mui_cache_entry *ent; + + TRACE("(%s %u %p)\n", wine_dbgstr_w(file_name), index, buffer); + + LIST_FOR_EACH_ENTRY(ent, ®_mui_cache, struct mui_cache_entry, entry) + { + if (ent->index == index && ent->locale == GetThreadLocale() && + !strcmpiW(ent->file_name, file_name)) + goto found; + } + return 0; + +found: + /* move to the list head */ + if (list_prev(®_mui_cache, &ent->entry)) { + list_remove(&ent->entry); + list_add_head(®_mui_cache, &ent->entry); + } + + TRACE("=> %s\n", wine_dbgstr_w(ent->text)); + *buffer = ent->text; + return strlenW(ent->text); +} + +/* critical section must be held */ +static void reg_mui_cache_put(const WCHAR *file_name, UINT index, const WCHAR *buffer, INT size) +{ + struct mui_cache_entry *ent; + TRACE("(%s %u %s %d)\n", wine_dbgstr_w(file_name), index, wine_dbgstr_wn(buffer, size), size); + + ent = heap_calloc(sizeof(*ent), 1); + if (!ent) + return; + ent->file_name = heap_alloc((strlenW(file_name) + 1) * sizeof(WCHAR)); + if (!ent->file_name) { + free_mui_cache_entry(ent); + return; + } + strcpyW(ent->file_name, file_name); + ent->index = index; + ent->locale = GetThreadLocale(); + ent->text = heap_alloc((size + 1) * sizeof(WCHAR)); + if (!ent->text) { + free_mui_cache_entry(ent); + return; + } + memcpy(ent->text, buffer, size * sizeof(WCHAR)); + ent->text[size] = '\0'; + + TRACE("add %p\n", ent); + list_add_head(®_mui_cache, &ent->entry); + if (reg_mui_cache_count > REG_MUI_CACHE_SIZE) { + ent = LIST_ENTRY( list_tail( ®_mui_cache ), struct mui_cache_entry, entry ); + TRACE("freeing %p\n", ent); + list_remove(&ent->entry); + free_mui_cache_entry(ent); + } + else + reg_mui_cache_count++; + + if (TRACE_ON(reg)) + dump_mui_cache(); + return; +} + static LONG load_mui_string(const WCHAR *file_name, UINT res_id, WCHAR *buffer, INT max_chars, INT *req_chars, DWORD flags) { HMODULE hModule = NULL; - WCHAR *string; + WCHAR *string, *full_name; int size; LONG result;
@@ -3153,16 +3259,32 @@ static LONG load_mui_string(const WCHAR *file_name, UINT res_id, WCHAR *buffer, if (GetFileAttributesW(file_name) == INVALID_FILE_ATTRIBUTES) return ERROR_FILE_NOT_FOUND;
- /* Load the file */ - hModule = LoadLibraryExW(file_name, NULL, - LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); - if (!hModule) + size = GetFullPathNameW(file_name, 0, NULL, NULL); + full_name = heap_alloc(size * sizeof(WCHAR)); + if (!size) return GetLastError(); + GetFullPathNameW(file_name, size, full_name, NULL);
- size = load_string(hModule, res_id, &string); + EnterCriticalSection(®_mui_cs); + size = reg_mui_cache_get(full_name, res_id, &string); if (!size) { - result = GetLastError(); - goto cleanup; + LeaveCriticalSection(®_mui_cs); + + /* Load the file */ + hModule = LoadLibraryExW(full_name, NULL, + LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + if (!hModule) + return GetLastError(); + + size = load_string(hModule, res_id, &string); + if (!size) { + result = GetLastError(); + goto cleanup; + } + + EnterCriticalSection(®_mui_cs); + reg_mui_cache_put(full_name, res_id, string, size); + LeaveCriticalSection(®_mui_cs); } *req_chars = size + 1;
@@ -3191,7 +3313,11 @@ static LONG load_mui_string(const WCHAR *file_name, UINT res_id, WCHAR *buffer, result = ERROR_SUCCESS;
cleanup: - if (hModule) FreeLibrary(hModule); + if (hModule) + FreeLibrary(hModule); + else + LeaveCriticalSection(®_mui_cs); + heap_free(full_name); return result; }