diff --git a/README.md b/README.md index 6032a494..986647cf 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Wine. All those differences are also documented on the Included bug fixes and improvements =================================== -**Bugfixes and features included in the next upcoming release [12]:** +**Bugfixes and features included in the next upcoming release [13]:** * Add support for GetPropValue to PulseAudio backend * Fix condition mask handling in RtlVerifyVersionInfo ([Wine Bug #36143](https://bugs.winehq.org/show_bug.cgi?id=36143)) @@ -50,6 +50,7 @@ Included bug fixes and improvements * Set last error when GetRawInputDeviceList fails ([Wine Bug #37667](https://bugs.winehq.org/show_bug.cgi?id=37667)) * Support for StrCatChainW * Support for combase HSTRING objects +* Support for loader dll redirections * wininet should allow Accept-Encoding header for HTTP/1.0 ([Wine Bug #37046](https://bugs.winehq.org/show_bug.cgi?id=37046)) diff --git a/debian/changelog b/debian/changelog index 160ca42d..d9c551aa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,7 @@ wine-compholio (1.7.33) UNRELEASED; urgency=low * Added patch to ignore unsupported flags for CoInternetSetFeatureEnabled. * Added patch to provide named entry point shell32.SHILCreateFromPath for vista apps. * Added patch to reallocate buffer when adding records to AVI files. + * Added patch to implement support for loader dll redirections. * Removed patch to fix copy and paste errors in ws2_32 tests (accepted upstream). * Removed patch to fix ordering of IP addresses by metric if two addresses have the same metric (accepted upstream). * Removed patch to reset data->pWintrustData->u.pFile->hFile after closing handle (accepted upstream). diff --git a/patches/Makefile b/patches/Makefile index 1b18ad12..e027e184 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -60,6 +60,7 @@ PATCHLIST := \ msvcp90-basic_string_wchar_dtor.ok \ msvcrt-atof_strtod.ok \ ntdll-DOS_Attributes.ok \ + ntdll-DllRedirects.ok \ ntdll-Dynamic_DST.ok \ ntdll-Exception.ok \ ntdll-FD_Cache.ok \ @@ -881,6 +882,26 @@ ntdll-DOS_Attributes.ok: echo '+ { "Erich E. Hoover", "ntdll: Perform the Unix-style hidden file check within the unified file info grabbing routine.", 1 },'; \ ) > ntdll-DOS_Attributes.ok +# Patchset ntdll-DllRedirects +# | +# | Modified files: +# | * dlls/ntdll/loader.c, dlls/ntdll/loadorder.c, dlls/ntdll/ntdll_misc.h +# | +.INTERMEDIATE: ntdll-DllRedirects.ok +ntdll-DllRedirects.ok: + $(call APPLY_FILE,ntdll-DllRedirects/0001-ntdll-Move-logic-to-determine-loadorder-HKCU-app-key.patch) + $(call APPLY_FILE,ntdll-DllRedirects/0002-ntdll-Move-logic-to-read-loadorder-registry-values-i.patch) + $(call APPLY_FILE,ntdll-DllRedirects/0003-ntdll-Move-code-to-determine-module-basename-into-se.patch) + $(call APPLY_FILE,ntdll-DllRedirects/0004-ntdll-Implement-get_redirect-function.patch) + $(call APPLY_FILE,ntdll-DllRedirects/0005-ntdll-Implement-loader-redirection-scheme.patch) + @( \ + echo '+ { "Michael Müller", "ntdll: Move logic to determine loadorder HKCU/app key into separate functions.", 1 },'; \ + echo '+ { "Michael Müller", "ntdll: Move logic to read loadorder registry values into separate function.", 1 },'; \ + echo '+ { "Michael Müller", "ntdll: Move code to determine module basename into separate function.", 1 },'; \ + echo '+ { "Michael Müller", "ntdll: Implement get_redirect function.", 1 },'; \ + echo '+ { "Michael Müller", "ntdll: Implement loader redirection scheme.", 1 },'; \ + ) > ntdll-DllRedirects.ok + # Patchset ntdll-Dynamic_DST # | # | This patchset fixes the following Wine bugs: diff --git a/patches/ntdll-DllRedirects/0001-ntdll-Move-logic-to-determine-loadorder-HKCU-app-key.patch b/patches/ntdll-DllRedirects/0001-ntdll-Move-logic-to-determine-loadorder-HKCU-app-key.patch new file mode 100644 index 00000000..18bfd9d0 --- /dev/null +++ b/patches/ntdll-DllRedirects/0001-ntdll-Move-logic-to-determine-loadorder-HKCU-app-key.patch @@ -0,0 +1,146 @@ +From 13b6ccee7fb76c5eb81b7e02afe25b58553cfebf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sat, 13 Dec 2014 02:14:30 +0100 +Subject: ntdll: Move logic to determine loadorder HKCU/app key into separate + functions. + +--- + dlls/ntdll/loadorder.c | 104 +++++++++++++++++++++++++++---------------------- + 1 file changed, 58 insertions(+), 46 deletions(-) + +diff --git a/dlls/ntdll/loadorder.c b/dlls/ntdll/loadorder.c +index 401d256..d45a85f 100644 +--- a/dlls/ntdll/loadorder.c ++++ b/dlls/ntdll/loadorder.c +@@ -290,6 +290,60 @@ static inline enum loadorder get_env_load_order( const WCHAR *module ) + + + /*************************************************************************** ++ * open_user_reg_key ++ * ++ * Return a handle to a registry key under HKCU. ++ */ ++static HANDLE open_user_reg_key(const WCHAR *key_name) ++{ ++ HANDLE hkey, root; ++ OBJECT_ATTRIBUTES attr; ++ UNICODE_STRING nameW; ++ ++ RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); ++ attr.Length = sizeof(attr); ++ attr.RootDirectory = root; ++ attr.ObjectName = &nameW; ++ attr.Attributes = 0; ++ attr.SecurityDescriptor = NULL; ++ attr.SecurityQualityOfService = NULL; ++ RtlInitUnicodeString( &nameW, key_name ); ++ ++ if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) hkey = 0; ++ NtClose( root ); ++ ++ return hkey; ++} ++ ++ ++/*************************************************************************** ++ * open_app_reg_key ++ * ++ * Return a handle to an app-specific registry key. ++ */ ++static HANDLE open_app_reg_key( const WCHAR *sub_key, const WCHAR *app_name ) ++{ ++ static const WCHAR AppDefaultsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', ++ 'A','p','p','D','e','f','a','u','l','t','s','\\',0}; ++ WCHAR *str; ++ HANDLE hkey; ++ ++ str = RtlAllocateHeap( GetProcessHeap(), 0, ++ sizeof(AppDefaultsW) + ++ strlenW(sub_key) * sizeof(WCHAR) + ++ strlenW(app_name) * sizeof(WCHAR) ); ++ if (!str) return 0; ++ strcpyW( str, AppDefaultsW ); ++ strcatW( str, app_name ); ++ strcatW( str, sub_key ); ++ ++ hkey = open_user_reg_key( str ); ++ RtlFreeHeap( GetProcessHeap(), 0, str ); ++ return hkey; ++} ++ ++ ++/*************************************************************************** + * get_standard_key + * + * Return a handle to the standard DllOverrides registry section. +@@ -301,24 +355,8 @@ static HANDLE get_standard_key(void) + static HANDLE std_key = (HANDLE)-1; + + if (std_key == (HANDLE)-1) +- { +- OBJECT_ATTRIBUTES attr; +- UNICODE_STRING nameW; +- HANDLE root; +- +- RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); +- attr.Length = sizeof(attr); +- attr.RootDirectory = root; +- attr.ObjectName = &nameW; +- attr.Attributes = 0; +- attr.SecurityDescriptor = NULL; +- attr.SecurityQualityOfService = NULL; +- RtlInitUnicodeString( &nameW, DllOverridesW ); +- +- /* @@ Wine registry key: HKCU\Software\Wine\DllOverrides */ +- if (NtOpenKey( &std_key, KEY_ALL_ACCESS, &attr )) std_key = 0; +- NtClose( root ); +- } ++ std_key = open_user_reg_key( DllOverridesW ); ++ + return std_key; + } + +@@ -330,38 +368,12 @@ static HANDLE get_standard_key(void) + */ + static HANDLE get_app_key( const WCHAR *app_name ) + { +- OBJECT_ATTRIBUTES attr; +- UNICODE_STRING nameW; +- HANDLE root; +- WCHAR *str; +- static const WCHAR AppDefaultsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', +- 'A','p','p','D','e','f','a','u','l','t','s','\\',0}; + static const WCHAR DllOverridesW[] = {'\\','D','l','l','O','v','e','r','r','i','d','e','s',0}; + static HANDLE app_key = (HANDLE)-1; + +- if (app_key != (HANDLE)-1) return app_key; ++ if (app_key == (HANDLE)-1) ++ app_key = open_app_reg_key( DllOverridesW, app_name ); + +- str = RtlAllocateHeap( GetProcessHeap(), 0, +- sizeof(AppDefaultsW) + sizeof(DllOverridesW) + +- strlenW(app_name) * sizeof(WCHAR) ); +- if (!str) return 0; +- strcpyW( str, AppDefaultsW ); +- strcatW( str, app_name ); +- strcatW( str, DllOverridesW ); +- +- RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); +- attr.Length = sizeof(attr); +- attr.RootDirectory = root; +- attr.ObjectName = &nameW; +- attr.Attributes = 0; +- attr.SecurityDescriptor = NULL; +- attr.SecurityQualityOfService = NULL; +- RtlInitUnicodeString( &nameW, str ); +- +- /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DllOverrides */ +- if (NtOpenKey( &app_key, KEY_ALL_ACCESS, &attr )) app_key = 0; +- NtClose( root ); +- RtlFreeHeap( GetProcessHeap(), 0, str ); + return app_key; + } + +-- +1.9.1 + diff --git a/patches/ntdll-DllRedirects/0002-ntdll-Move-logic-to-read-loadorder-registry-values-i.patch b/patches/ntdll-DllRedirects/0002-ntdll-Move-logic-to-read-loadorder-registry-values-i.patch new file mode 100644 index 00000000..12002b02 --- /dev/null +++ b/patches/ntdll-DllRedirects/0002-ntdll-Move-logic-to-read-loadorder-registry-values-i.patch @@ -0,0 +1,85 @@ +From 659b7d1dce76b50a488472fd8fc53b1f4e9b48ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sat, 13 Dec 2014 02:32:51 +0100 +Subject: ntdll: Move logic to read loadorder registry values into separate + function. + +--- + dlls/ntdll/loadorder.c | 40 ++++++++++++++++++++++++++++------------ + 1 file changed, 28 insertions(+), 12 deletions(-) + +diff --git a/dlls/ntdll/loadorder.c b/dlls/ntdll/loadorder.c +index d45a85f..8250692 100644 +--- a/dlls/ntdll/loadorder.c ++++ b/dlls/ntdll/loadorder.c +@@ -379,25 +379,41 @@ static HANDLE get_app_key( const WCHAR *app_name ) + + + /*************************************************************************** +- * get_registry_value ++ * get_registry_string + * +- * Load the registry loadorder value for a given module. ++ * Load a registry string for a given module. + */ +-static enum loadorder get_registry_value( HANDLE hkey, const WCHAR *module ) ++static WCHAR* get_registry_string( HANDLE hkey, const WCHAR *module, BYTE *buffer, ++ ULONG size ) + { + UNICODE_STRING valueW; +- char buffer[80]; + DWORD count; ++ WCHAR *ret = NULL; + + RtlInitUnicodeString( &valueW, module ); +- +- if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, +- buffer, sizeof(buffer), &count )) ++ if (size >= sizeof(WCHAR) && ++ !NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, ++ buffer, size - sizeof(WCHAR), &count )) + { +- WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data; +- return parse_load_order( str ); ++ KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buffer; ++ ret = (WCHAR *)info->Data; ++ ret[info->DataLength / sizeof(WCHAR)] = 0; + } +- return LO_INVALID; ++ ++ return ret; ++} ++ ++ ++/*************************************************************************** ++ * get_registry_load_order ++ * ++ * Load the registry loadorder value for a given module. ++ */ ++static enum loadorder get_registry_load_order( HANDLE hkey, const WCHAR *module ) ++{ ++ BYTE buffer[81]; ++ WCHAR *str = get_registry_string( hkey, module, buffer, sizeof(buffer) ); ++ return str ? parse_load_order( str ) : LO_INVALID; + } + + +@@ -419,13 +435,13 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, cons + return ret; + } + +- if (app_key && ((ret = get_registry_value( app_key, module )) != LO_INVALID)) ++ if (app_key && ((ret = get_registry_load_order( app_key, module )) != LO_INVALID)) + { + TRACE( "got app defaults %s for %s\n", debugstr_loadorder(ret), debugstr_w(module) ); + return ret; + } + +- if (std_key && ((ret = get_registry_value( std_key, module )) != LO_INVALID)) ++ if (std_key && ((ret = get_registry_load_order( std_key, module )) != LO_INVALID)) + { + TRACE( "got standard key %s for %s\n", debugstr_loadorder(ret), debugstr_w(module) ); + return ret; +-- +1.9.1 + diff --git a/patches/ntdll-DllRedirects/0003-ntdll-Move-code-to-determine-module-basename-into-se.patch b/patches/ntdll-DllRedirects/0003-ntdll-Move-code-to-determine-module-basename-into-se.patch new file mode 100644 index 00000000..f7baa09a --- /dev/null +++ b/patches/ntdll-DllRedirects/0003-ntdll-Move-code-to-determine-module-basename-into-se.patch @@ -0,0 +1,87 @@ +From 219c4257ae314f8e2abe1e1567232336cdbbbdb4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sat, 13 Dec 2014 02:57:41 +0100 +Subject: ntdll: Move code to determine module basename into separate function. + +--- + dlls/ntdll/loadorder.c | 48 ++++++++++++++++++++++++++++++++---------------- + 1 file changed, 32 insertions(+), 16 deletions(-) + +diff --git a/dlls/ntdll/loadorder.c b/dlls/ntdll/loadorder.c +index 8250692..fbaa2d6 100644 +--- a/dlls/ntdll/loadorder.c ++++ b/dlls/ntdll/loadorder.c +@@ -452,25 +452,17 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, cons + + + /*************************************************************************** +- * get_load_order (internal) ++ * get_module_basename + * +- * Return the loadorder of a module. +- * The system directory and '.dll' extension is stripped from the path. ++ * Determine the module basename. The caller is responsible for releasing ++ * the memory. + */ +-enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) ++static WCHAR* get_module_basename( const WCHAR *path, WCHAR **basename ) + { +- enum loadorder ret = LO_INVALID; +- HANDLE std_key, app_key = 0; +- WCHAR *module, *basename; + UNICODE_STRING path_str; ++ WCHAR *module; + int len; + +- if (!init_done) init_load_order(); +- std_key = get_standard_key(); +- if (app_name) app_key = get_app_key( app_name ); +- +- TRACE("looking for %s\n", debugstr_w(path)); +- + /* Strip path information if the module resides in the system directory + */ + RtlInitUnicodeString( &path_str, path ); +@@ -481,12 +473,36 @@ enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) + if (!strchrW( p, '\\' ) && !strchrW( p, '/' )) path = p; + } + +- if (!(len = strlenW(path))) return ret; +- if (!(module = RtlAllocateHeap( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) return ret; ++ if (!(len = strlenW(path))) return NULL; ++ if (!(module = RtlAllocateHeap( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) return NULL; + strcpyW( module+1, path ); /* reserve module[0] for the wildcard char */ +- basename = (WCHAR *)get_basename( module+1 ); ++ *basename = (WCHAR *)get_basename( module+1 ); + + if (len >= 4) remove_dll_ext( module + 1 + len - 4 ); ++ return module; ++} ++ ++ ++/*************************************************************************** ++ * get_load_order (internal) ++ * ++ * Return the loadorder of a module. ++ * The system directory and '.dll' extension is stripped from the path. ++ */ ++enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) ++{ ++ enum loadorder ret = LO_INVALID; ++ HANDLE std_key, app_key = 0; ++ WCHAR *module, *basename; ++ ++ if (!init_done) init_load_order(); ++ std_key = get_standard_key(); ++ if (app_name) app_key = get_app_key( app_name ); ++ ++ TRACE("looking for %s\n", debugstr_w(path)); ++ ++ if (!(module = get_module_basename(path, &basename))) ++ return ret; + + /* first explicit module name */ + if ((ret = get_load_order_value( std_key, app_key, module+1 )) != LO_INVALID) +-- +1.9.1 + diff --git a/patches/ntdll-DllRedirects/0004-ntdll-Implement-get_redirect-function.patch b/patches/ntdll-DllRedirects/0004-ntdll-Implement-get_redirect-function.patch new file mode 100644 index 00000000..9ee36d39 --- /dev/null +++ b/patches/ntdll-DllRedirects/0004-ntdll-Implement-get_redirect-function.patch @@ -0,0 +1,195 @@ +From 61fb04be5f07b22582095cbf7ed0f16408eeac53 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sat, 13 Dec 2014 03:18:35 +0100 +Subject: ntdll: Implement get_redirect function. + +--- + dlls/ntdll/loadorder.c | 120 +++++++++++++++++++++++++++++++++++++++++++++--- + dlls/ntdll/ntdll_misc.h | 1 + + 2 files changed, 114 insertions(+), 7 deletions(-) + +diff --git a/dlls/ntdll/loadorder.c b/dlls/ntdll/loadorder.c +index fbaa2d6..c7c4592 100644 +--- a/dlls/ntdll/loadorder.c ++++ b/dlls/ntdll/loadorder.c +@@ -344,11 +344,11 @@ static HANDLE open_app_reg_key( const WCHAR *sub_key, const WCHAR *app_name ) + + + /*************************************************************************** +- * get_standard_key ++ * get_override_standard_key + * + * Return a handle to the standard DllOverrides registry section. + */ +-static HANDLE get_standard_key(void) ++static HANDLE get_override_standard_key(void) + { + static const WCHAR DllOverridesW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', + 'D','l','l','O','v','e','r','r','i','d','e','s',0}; +@@ -362,11 +362,11 @@ static HANDLE get_standard_key(void) + + + /*************************************************************************** +- * get_app_key ++ * get_override_app_key + * + * Get the registry key for the app-specific DllOverrides list. + */ +-static HANDLE get_app_key( const WCHAR *app_name ) ++static HANDLE get_override_app_key( const WCHAR *app_name ) + { + static const WCHAR DllOverridesW[] = {'\\','D','l','l','O','v','e','r','r','i','d','e','s',0}; + static HANDLE app_key = (HANDLE)-1; +@@ -379,6 +379,41 @@ static HANDLE get_app_key( const WCHAR *app_name ) + + + /*************************************************************************** ++ * get_redirect_standard_key ++ * ++ * Return a handle to the standard DllRedirects registry section. ++ */ ++static HANDLE get_redirect_standard_key(void) ++{ ++ static const WCHAR DllRedirectsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', ++ 'D','l','l','R','e','d','i','r','e','c','t','s',0}; ++ static HANDLE std_key = (HANDLE)-1; ++ ++ if (std_key == (HANDLE)-1) ++ std_key = open_user_reg_key( DllRedirectsW ); ++ ++ return std_key; ++} ++ ++ ++/*************************************************************************** ++ * get_redirect_app_key ++ * ++ * Get the registry key for the app-specific DllRedirects list. ++ */ ++static HANDLE get_redirect_app_key( const WCHAR *app_name ) ++{ ++ static const WCHAR DllRedirectsW[] = {'\\','D','l','l','R','e','d','i','r','e','c','t','s',0}; ++ static HANDLE app_key = (HANDLE)-1; ++ ++ if (app_key == (HANDLE)-1) ++ app_key = open_app_reg_key( DllRedirectsW, app_name ); ++ ++ return app_key; ++} ++ ++ ++/*************************************************************************** + * get_registry_string + * + * Load a registry string for a given module. +@@ -452,6 +487,34 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, cons + + + /*************************************************************************** ++ * get_redirect_value ++ * ++ * Get the redirect value for the exact specified module string, looking in: ++ * 1. The per-application DllRedirects key ++ * 2. The standard DllRedirects key ++ */ ++static WCHAR* get_redirect_value( HANDLE std_key, HANDLE app_key, const WCHAR *module, ++ BYTE *buffer, ULONG size ) ++{ ++ WCHAR *ret = NULL; ++ ++ if (app_key && (ret = get_registry_string( app_key, module, buffer, size ))) ++ { ++ TRACE( "got app defaults %s for %s\n", debugstr_w(ret), debugstr_w(module) ); ++ return ret; ++ } ++ ++ if (std_key && (ret = get_registry_string( std_key, module, buffer, size ))) ++ { ++ TRACE( "got standard key %s for %s\n", debugstr_w(ret), debugstr_w(module) ); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++ ++/*************************************************************************** + * get_module_basename + * + * Determine the module basename. The caller is responsible for releasing +@@ -496,10 +559,10 @@ enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) + WCHAR *module, *basename; + + if (!init_done) init_load_order(); +- std_key = get_standard_key(); +- if (app_name) app_key = get_app_key( app_name ); ++ std_key = get_override_standard_key(); ++ if (app_name) app_key = get_override_app_key( app_name ); + +- TRACE("looking for %s\n", debugstr_w(path)); ++ TRACE("looking up loadorder for %s\n", debugstr_w(path)); + + if (!(module = get_module_basename(path, &basename))) + return ret; +@@ -533,3 +596,46 @@ enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) + RtlFreeHeap( GetProcessHeap(), 0, module ); + return ret; + } ++ ++ ++/*************************************************************************** ++ * get_redirect (internal) ++ * ++ * Return the redirect value of a module. ++ * The system directory and '.dll' extension is stripped from the path. ++ */ ++WCHAR* get_redirect( const WCHAR *app_name, const WCHAR *path, BYTE *buffer, ULONG size ) ++{ ++ WCHAR *ret = NULL; ++ HANDLE std_key, app_key = 0; ++ WCHAR *module, *basename; ++ ++ std_key = get_redirect_standard_key(); ++ if (app_name) app_key = get_redirect_app_key( app_name ); ++ ++ TRACE("looking up redirection for %s\n", debugstr_w(path)); ++ ++ if (!(module = get_module_basename(path, &basename))) ++ return ret; ++ ++ /* first explicit module name */ ++ if ((ret = get_redirect_value( std_key, app_key, module+1, buffer, size ))) ++ goto done; ++ ++ /* then module basename preceded by '*' */ ++ basename[-1] = '*'; ++ if ((ret = get_redirect_value( std_key, app_key, basename-1, buffer, size ))) ++ goto done; ++ ++ /* then module basename without '*' (only if explicit path) */ ++ if (basename != module+1 && (ret = get_redirect_value( std_key, app_key, basename, buffer, size ))) ++ goto done; ++ ++ /* and last the hard-coded default */ ++ ret = NULL; ++ TRACE( "no redirection found for %s\n", debugstr_w(path) ); ++ ++ done: ++ RtlFreeHeap( GetProcessHeap(), 0, module ); ++ return ret; ++} +diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h +index aac9320..aa2e660 100644 +--- a/dlls/ntdll/ntdll_misc.h ++++ b/dlls/ntdll/ntdll_misc.h +@@ -202,6 +202,7 @@ enum loadorder + }; + + extern enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) DECLSPEC_HIDDEN; ++extern WCHAR* get_redirect( const WCHAR *app_name, const WCHAR *path, BYTE *buffer, ULONG size ) DECLSPEC_HIDDEN; + + struct debug_info + { +-- +1.9.1 + diff --git a/patches/ntdll-DllRedirects/0005-ntdll-Implement-loader-redirection-scheme.patch b/patches/ntdll-DllRedirects/0005-ntdll-Implement-loader-redirection-scheme.patch new file mode 100644 index 00000000..58023da5 --- /dev/null +++ b/patches/ntdll-DllRedirects/0005-ntdll-Implement-loader-redirection-scheme.patch @@ -0,0 +1,225 @@ +From ea4f613ec5b7e4cdc5cb9d850f66c194af9eb5e6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sat, 13 Dec 2014 05:34:48 +0100 +Subject: ntdll: Implement loader redirection scheme. + +--- + dlls/ntdll/loader.c | 66 +++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 44 insertions(+), 22 deletions(-) + +diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c +index e1444d2..c392f72 100644 +--- a/dlls/ntdll/loader.c ++++ b/dlls/ntdll/loader.c +@@ -87,6 +87,7 @@ struct builtin_load_info + { + const WCHAR *load_path; + const WCHAR *filename; ++ const WCHAR *fakemodule; + NTSTATUS status; + WINE_MODREF *wm; + }; +@@ -112,7 +113,8 @@ static WINE_MODREF *cached_modref; + static WINE_MODREF *current_modref; + static WINE_MODREF *last_failed_modref; + +-static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm ); ++static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, LPCWSTR fakemodule, ++ DWORD flags, WINE_MODREF** pwm ); + static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved ); + static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, + DWORD exp_size, DWORD ordinal, LPCWSTR load_path ); +@@ -438,7 +440,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS + if (!(wm = find_basename_module( mod_name ))) + { + TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward ); +- if (load_dll( load_path, mod_name, 0, &wm ) == STATUS_SUCCESS && ++ if (load_dll( load_path, mod_name, NULL, 0, &wm ) == STATUS_SUCCESS && + !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) + { + if (process_attach( wm, NULL ) != STATUS_SUCCESS) +@@ -587,7 +589,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d + { + ascii_to_unicode( buffer, name, len ); + buffer[len] = 0; +- status = load_dll( load_path, buffer, 0, &wmImp ); ++ status = load_dll( load_path, buffer, NULL, 0, &wmImp ); + } + else /* need to allocate a larger buffer */ + { +@@ -595,7 +597,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d + if (!ptr) return NULL; + ascii_to_unicode( ptr, name, len ); + ptr[len] = 0; +- status = load_dll( load_path, ptr, 0, &wmImp ); ++ status = load_dll( load_path, ptr, NULL, 0, &wmImp ); + RtlFreeHeap( GetProcessHeap(), 0, ptr ); + } + +@@ -906,7 +908,7 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path ) + * Allocate a WINE_MODREF structure and add it to the process list + * The loader_section must be locked while calling this function. + */ +-static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename ) ++static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename, LPCWSTR fakemodule ) + { + WINE_MODREF *wm; + const WCHAR *p; +@@ -929,7 +931,7 @@ static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename ) + wm->ldr.TimeDateStamp = 0; + wm->ldr.ActivationContext = 0; + +- RtlCreateUnicodeString( &wm->ldr.FullDllName, filename ); ++ RtlCreateUnicodeString( &wm->ldr.FullDllName, fakemodule ? fakemodule : filename ); + if ((p = strrchrW( wm->ldr.FullDllName.Buffer, '\\' ))) p++; + else p = wm->ldr.FullDllName.Buffer; + RtlInitUnicodeString( &wm->ldr.BaseDllName, p ); +@@ -1546,7 +1548,7 @@ static void load_builtin_callback( void *module, const char *filename ) + return; + } + +- wm = alloc_module( module, fullname ); ++ wm = alloc_module( module, fullname, builtin_load_info->fakemodule ); + RtlFreeHeap( GetProcessHeap(), 0, fullname ); + if (!wm) + { +@@ -1602,8 +1604,8 @@ static void load_builtin_callback( void *module, const char *filename ) + /****************************************************************************** + * load_native_dll (internal) + */ +-static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file, +- DWORD flags, WINE_MODREF** pwm ) ++static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, LPCWSTR fakemodule, ++ HANDLE file, DWORD flags, WINE_MODREF** pwm ) + { + void *module; + HANDLE mapping; +@@ -1627,7 +1629,7 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file, + + /* create the MODREF */ + +- if (!(wm = alloc_module( module, name ))) ++ if (!(wm = alloc_module( module, name, fakemodule ))) + { + status = STATUS_NO_MEMORY; + goto done; +@@ -1689,8 +1691,8 @@ done: + /*********************************************************************** + * load_builtin_dll + */ +-static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file, +- DWORD flags, WINE_MODREF** pwm ) ++static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, LPCWSTR fakemodule, ++ HANDLE file, DWORD flags, WINE_MODREF** pwm ) + { + char error[256], dllname[MAX_PATH]; + const WCHAR *name, *p; +@@ -1710,6 +1712,7 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file, + */ + info.load_path = load_path; + info.filename = NULL; ++ info.fakemodule = fakemodule; + info.status = STATUS_SUCCESS; + info.wm = NULL; + +@@ -2028,14 +2031,14 @@ overflow: + return STATUS_BUFFER_TOO_SMALL; + } + +- + /*********************************************************************** + * load_dll (internal) + * + * Load a PE style module according to the load order. + * The loader_section must be locked while calling this function. + */ +-static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm ) ++static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, LPCWSTR fakemodule, ++ DWORD flags, WINE_MODREF** pwm ) + { + enum loadorder loadorder; + WCHAR buffer[32]; +@@ -2072,6 +2075,25 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_ + } + + main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress ); ++ ++ /* handle dll redirection */ ++ if (!fakemodule) ++ { ++ BYTE buffer2[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR)]; ++ WCHAR *redirect = get_redirect( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, ++ filename, buffer2, sizeof(buffer2) ); ++ if (redirect) ++ { ++ FIXME("Loader redirect from %s to %s\n", debugstr_w(libname), debugstr_w(redirect)); ++ ++ nts = load_dll( load_path, redirect, filename, flags, pwm ); ++ ++ if (handle) NtClose( handle ); ++ if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename ); ++ return nts; ++ } ++ } ++ + loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, filename ); + + if (handle && is_fake_dll( handle )) +@@ -2094,22 +2116,22 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_ + if (!handle) nts = STATUS_DLL_NOT_FOUND; + else + { +- nts = load_native_dll( load_path, filename, handle, flags, pwm ); ++ nts = load_native_dll( load_path, filename, fakemodule, handle, flags, pwm ); + if (nts == STATUS_INVALID_IMAGE_NOT_MZ) + /* not in PE format, maybe it's a builtin */ +- nts = load_builtin_dll( load_path, filename, handle, flags, pwm ); ++ nts = load_builtin_dll( load_path, filename, fakemodule, handle, flags, pwm ); + } + if (nts == STATUS_DLL_NOT_FOUND && loadorder == LO_NATIVE_BUILTIN) +- nts = load_builtin_dll( load_path, filename, 0, flags, pwm ); ++ nts = load_builtin_dll( load_path, filename, fakemodule, 0, flags, pwm ); + break; + case LO_BUILTIN: + case LO_BUILTIN_NATIVE: + case LO_DEFAULT: /* default is builtin,native */ +- nts = load_builtin_dll( load_path, filename, handle, flags, pwm ); ++ nts = load_builtin_dll( load_path, filename, fakemodule, handle, flags, pwm ); + if (!handle) break; /* nothing else we can try */ + /* file is not a builtin library, try without using the specified file */ + if (nts != STATUS_SUCCESS) +- nts = load_builtin_dll( load_path, filename, 0, flags, pwm ); ++ nts = load_builtin_dll( load_path, filename, fakemodule, 0, flags, pwm ); + if (nts == STATUS_SUCCESS && loadorder == LO_DEFAULT && + (MODULE_InitDLL( *pwm, DLL_WINE_PREATTACH, NULL ) != STATUS_SUCCESS)) + { +@@ -2119,7 +2141,7 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_ + nts = STATUS_DLL_NOT_FOUND; + } + if (nts == STATUS_DLL_NOT_FOUND && loadorder != LO_BUILTIN) +- nts = load_native_dll( load_path, filename, handle, flags, pwm ); ++ nts = load_native_dll( load_path, filename, fakemodule, handle, flags, pwm ); + break; + } + +@@ -2152,7 +2174,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags, + RtlEnterCriticalSection( &loader_section ); + + if (!path_name) path_name = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer; +- nts = load_dll( path_name, libname->Buffer, flags, &wm ); ++ nts = load_dll( path_name, libname->Buffer, NULL, flags, &wm ); + + if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) + { +@@ -3115,7 +3137,7 @@ void __wine_process_init(void) + /* setup the load callback and create ntdll modref */ + wine_dll_set_callback( load_builtin_callback ); + +- if ((status = load_builtin_dll( NULL, kernel32W, 0, 0, &wm )) != STATUS_SUCCESS) ++ if ((status = load_builtin_dll( NULL, kernel32W, NULL, 0, 0, &wm )) != STATUS_SUCCESS) + { + MESSAGE( "wine: could not load kernel32.dll, status %x\n", status ); + exit(1); +-- +1.9.1 + diff --git a/patches/ntdll-DllRedirects/definition b/patches/ntdll-DllRedirects/definition new file mode 100644 index 00000000..d85f2449 --- /dev/null +++ b/patches/ntdll-DllRedirects/definition @@ -0,0 +1 @@ +Fixes: Support for loader dll redirections