LoadLibraryEx handles LOAD_WITH_ALTERED_SEARCH_PATH

Medland, Bill Bill.Medland at accpac.com
Tue Aug 14 14:53:14 CDT 2001


 <<diff14.txt>> 
-------------- next part --------------
Bill Medland (medbi01 at accpac.com)
Add handling of the LOAD_WITH_ALTERED_SEARCH_PATH to LoadLibraryEx
This implementation will not yet handle Windows DLLs loaded by a builtin DLL.

Index: wine/dlls/kernel/wowthunk.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/wowthunk.c,v
retrieving revision 1.16
diff -u -r1.16 wowthunk.c
--- wine/dlls/kernel/wowthunk.c	2001/07/25 00:43:30	1.16
+++ wine/dlls/kernel/wowthunk.c	2001/08/14 18:48:55
@@ -309,7 +309,7 @@
     /* if the file can not be found, call LoadLibraryExA anyway, since it might be
        a buildin module. This case is handled in MODULE_LoadLibraryExA */
 
-    if ( ! DIR_SearchPath ( NULL, lpszLibFile, ".DLL", &full_name, FALSE ) ) {
+    if ( ! DIR_SearchPath ( NULL, lpszLibFile, ".DLL", &full_name, 0 ) ) {
       strcpy ( full_name.short_name, lpszLibFile );
     }
 
Index: wine/files/directory.c
===================================================================
RCS file: /home/wine/wine/files/directory.c,v
retrieving revision 1.40
diff -u -r1.40 directory.c
--- wine/files/directory.c	2001/07/02 19:59:48	1.40
+++ wine/files/directory.c	2001/08/14 18:48:55
@@ -565,17 +565,25 @@
 /***********************************************************************
  *           DIR_SearchPath
  *
- * Implementation of SearchPathA. 'win32' specifies whether the search
- * order is Win16 (module path last) or Win32 (module path first).
+ * Implementation of SearchPathA and similar functions.
+ *   flags controls how the search is done.
+ *    bit 0. specifies whether the search order is Win16 (module path last) or
+ *           Win32 (module path first).  (Win32 when set, Win16 when reset)
+ *    bit 1. specifies whether the module path is the path of the application
+ *           (as used in e.g. SearchPath) or the location of a DLL being
+ *           loaded with LoadLibraryEx (..LOAD_WITH_ALTERED_SEARCH_PATH).
+ *           When reset the application is used.  When set the DLL location
+ *           (passed in via the path) is used.
  *
  * FIXME: should return long path names.
  */
 DWORD DIR_SearchPath( LPCSTR path, LPCSTR name, LPCSTR ext,
-                      DOS_FULL_NAME *full_name, BOOL win32 )
+                      DOS_FULL_NAME *full_name, int flags )
 {
     LPCSTR p;
     LPSTR tmp = NULL;
     BOOL ret = TRUE;
+    BOOL win32 = flags & 0x01;
 
     /* First check the supplied parameters */
 
@@ -615,12 +623,14 @@
     if (path)
     {
         ret = DIR_TryEnvironmentPath( name, full_name, path );
-        goto done;
+        if (!(flags & 0x02) || ret)
+            goto done;
     }
 
     /* Try the path of the current executable (for Win32 search order) */
 
-    if (win32 && DIR_TryModulePath( name, full_name, win32 )) goto done;
+    if (win32 && !(flags & 0x02)  &&
+        DIR_TryModulePath( name, full_name, win32 )) goto done;
 
     /* Try the current directory */
 
@@ -649,6 +659,46 @@
     return ret;
 }
 
+/***********************************************************************
+ * 	SearchEitherPathA
+ *
+ * SearchPathA extended to allow searching by the alternate search path.
+ *
+ * Arguments are as for SearchPath except for the following:
+ *
+ * flags controls the order in which the directories are searched.
+ *       If flags is 1 then the directories are searched as for SearchPath
+ *       If flags is 3 then the directories are searched as for LoadLibraryEx
+ *       with the LOAD_WITH_ALTERED_SEARCH_PATH, with the name of the DLL's 
+ *       directory being passed in through the path argument.
+ *       For all other values the behaviour is undefined.
+ */
+
+DWORD WINAPI SearchEitherPathA( LPCSTR path, LPCSTR name, LPCSTR ext,
+                                DWORD buflen, LPSTR buffer,
+                                LPSTR *lastpart, int flags )
+{
+    LPSTR p, res;
+    DOS_FULL_NAME full_name;
+
+    if (!DIR_SearchPath( path, name, ext, &full_name, flags ))
+    {
+	SetLastError(ERROR_FILE_NOT_FOUND);
+	return 0;
+    }
+    lstrcpynA( buffer, full_name.short_name, buflen );
+    res = full_name.long_name +
+              strlen(DRIVE_GetRoot( full_name.short_name[0] - 'A' ));
+    while (*res == '/') res++;
+    if (buflen)
+    {
+        if (buflen > 3) lstrcpynA( buffer + 3, res, buflen - 3 );
+        for (p = buffer; *p; p++) if (*p == '/') *p = '\\';
+        if (lastpart) *lastpart = strrchr( buffer, '\\' ) + 1;
+    }
+    TRACE("Returning %d\n", strlen(res) + 3 );
+    return strlen(res) + 3;
+}
 
 /***********************************************************************
  * SearchPathA [KERNEL32.@]
@@ -679,31 +729,11 @@
  *    (tested on NT 4.0)
  */
 DWORD WINAPI SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext, DWORD buflen,
-                            LPSTR buffer, LPSTR *lastpart )
+                          LPSTR buffer, LPSTR *lastpart )
 {
-    LPSTR p, res;
-    DOS_FULL_NAME full_name;
-
-    if (!DIR_SearchPath( path, name, ext, &full_name, TRUE ))
-    {
-	SetLastError(ERROR_FILE_NOT_FOUND);
-	return 0;
-    }
-    lstrcpynA( buffer, full_name.short_name, buflen );
-    res = full_name.long_name +
-              strlen(DRIVE_GetRoot( full_name.short_name[0] - 'A' ));
-    while (*res == '/') res++;
-    if (buflen)
-    {
-        if (buflen > 3) lstrcpynA( buffer + 3, res, buflen - 3 );
-        for (p = buffer; *p; p++) if (*p == '/') *p = '\\';
-        if (lastpart) *lastpart = strrchr( buffer, '\\' ) + 1;
-    }
-    TRACE("Returning %d\n", strlen(res) + 3 );
-    return strlen(res) + 3;
+    return SearchEitherPathA (path, name, ext, buflen, buffer, lastpart, 0x01);
 }
 
-
 /***********************************************************************
  *           SearchPathW   (KERNEL32.@)
  */
@@ -717,7 +747,7 @@
     LPSTR pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
     LPSTR extA  = HEAP_strdupWtoA( GetProcessHeap(), 0, ext );
-    DWORD ret = DIR_SearchPath( pathA, nameA, extA, &full_name, TRUE );
+    DWORD ret = DIR_SearchPath( pathA, nameA, extA, &full_name, 0x01 );
     HeapFree( GetProcessHeap(), 0, extA );
     HeapFree( GetProcessHeap(), 0, nameA );
     HeapFree( GetProcessHeap(), 0, pathA );
Index: wine/files/file.c
===================================================================
RCS file: /home/wine/wine/files/file.c,v
retrieving revision 1.106
diff -u -r1.106 file.c
--- wine/files/file.c	2001/07/23 18:09:41	1.106
+++ wine/files/file.c	2001/08/14 18:48:55
@@ -923,7 +923,7 @@
 
     /* Now look for the file */
 
-    if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
+    if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 ? 1 : 0 )) goto not_found;
 
 found:
     TRACE("found %s = %s\n",
Index: wine/include/file.h
===================================================================
RCS file: /home/wine/wine/include/file.h,v
retrieving revision 1.28
diff -u -r1.28 file.h
--- wine/include/file.h	2001/07/12 22:29:42	1.28
+++ wine/include/file.h	2001/08/14 18:48:55
@@ -80,6 +80,9 @@
 extern int DIR_Init(void);
 extern UINT DIR_GetWindowsUnixDir( LPSTR path, UINT count );
 extern UINT DIR_GetSystemUnixDir( LPSTR path, UINT count );
+DWORD WINAPI SearchEitherPathA( LPCSTR path, LPCSTR name, LPCSTR ext,
+                                DWORD buflen, LPSTR buffer,
+                                LPSTR *lastpart, int flags );
 extern DWORD DIR_SearchPath( LPCSTR path, LPCSTR name, LPCSTR ext,
                              DOS_FULL_NAME *full_name, BOOL win32 );
 
Index: wine/include/module.h
===================================================================
RCS file: /home/wine/wine/include/module.h,v
retrieving revision 1.59
diff -u -r1.59 module.h
--- wine/include/module.h	2001/07/24 21:45:24	1.59
+++ wine/include/module.h	2001/08/14 18:48:55
@@ -179,7 +179,7 @@
 extern void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved );
 extern void MODULE_DllThreadAttach( LPVOID lpReserved );
 extern void MODULE_DllThreadDetach( LPVOID lpReserved );
-extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags );
+extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags, LPCSTR libdir );
 extern BOOL MODULE_FreeLibrary( WINE_MODREF *wm );
 extern WINE_MODREF *MODULE_FindModule( LPCSTR path );
 extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 );
@@ -228,12 +228,14 @@
 extern HGLOBAL PE_LoadResource(HMODULE,HRSRC);
 
 /* loader/pe_image.c */
-extern WINE_MODREF *PE_LoadLibraryExA(LPCSTR, DWORD);
+extern WINE_MODREF *PE_LoadLibraryExA(LPCSTR, DWORD, LPCSTR);
 extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags );
 extern WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename,
-                                     DWORD flags, HANDLE hFile, BOOL builtin );
+                                     DWORD flags, HANDLE hFile, BOOL builtin,
+                                     LPCSTR libdir);
 extern void PE_InitTls(void);
 extern BOOL PE_InitDLL( HMODULE module, DWORD type, LPVOID lpReserved );
+extern DWORD PE_fixup_imports(WINE_MODREF *wm, LPCSTR libdir);
 
 /* loader/loadorder.c */
 extern void MODULE_InitLoadOrder(void);
@@ -241,7 +243,7 @@
 extern void MODULE_AddLoadOrderOption( const char *option );
 
 /* loader/elf.c */
-extern WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags);
+extern WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, LPCSTR libdir);
 
 /* relay32/builtin.c */
 extern WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags);
Index: wine/loader/elf.c
===================================================================
RCS file: /home/wine/wine/loader/elf.c,v
retrieving revision 1.33
diff -u -r1.33 elf.c
--- wine/loader/elf.c	2001/07/24 21:45:24	1.33
+++ wine/loader/elf.c	2001/08/14 18:48:55
@@ -99,7 +99,12 @@
         return hmod;
 }
 
-WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags)
+/*****************************************************************
+ *	ELF_LoadLibraryExA
+ *
+ * libdir is carried around the recursion loop for MODULE_LoadLibraryExA
+ */
+WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, LPCSTR libdir)
 {
 	WINE_MODREF	*wm;
         HMODULE		hmod;
@@ -161,7 +166,7 @@
 
 	SNOOP_RegisterDLL(hmod,libname,0,STUBSIZE/sizeof(ELF_STDCALL_STUB));
 
-        wm = PE_CreateModule( hmod, libname, 0, 0, FALSE );
+        wm = PE_CreateModule( hmod, libname, 0, 0, FALSE, libdir );
         wm->find_export = ELF_FindExportedFunction;
 	wm->dlhandle = dlhandle;
 	return wm;
Index: wine/loader/module.c
===================================================================
RCS file: /home/wine/wine/loader/module.c,v
retrieving revision 1.137
diff -u -r1.137 module.c
--- wine/loader/module.c	2001/07/26 20:12:55	1.137
+++ wine/loader/module.c	2001/08/14 18:48:56
@@ -1299,7 +1299,7 @@
 
         RtlAcquirePebLock();
 
-	wm = MODULE_LoadLibraryExA( libname, hfile, flags );
+	wm = MODULE_LoadLibraryExA( libname, hfile, flags, NULL );
 	if ( wm )
 	{
 		if ( !MODULE_DllProcessAttach( wm, NULL ) )
@@ -1316,6 +1316,43 @@
 }
 
 /***********************************************************************
+ *      AllocateLibdir
+ *
+ * helper for MODULE_LoadLibraryExA.  Allocate space to hold the directory
+ * portion of the provided name and put the name in it.
+ * 
+ */
+static LPCSTR AllocateLibdir (LPCSTR libname)
+{
+    LPCSTR p1, p2, p3, pmax;
+    LPSTR result;
+    int length;
+
+    p1 = strrchr (libname, '\\');
+    p2 = strrchr (libname, '/'); /* Naughty.  MSDN says don't */
+    p3 = strrchr (libname, ':'); /* assert null or libname+1 */
+    /* assert (p1 || p2 || p3) */
+
+    /* assert null is less than all pointers */
+    pmax = p1;
+    if (p2 > pmax) pmax = p2;
+    if (p3 > pmax) pmax = p3;
+    /* assert pmax */
+    
+    length = (pmax - libname)+1;
+
+    result = HeapAlloc (GetProcessHeap(), 0, length+1);
+
+    if (result)
+    {
+        strncpy (result, libname, length);
+        result [length] = '\0';
+    }
+
+    return result;
+}
+
+/***********************************************************************
  *	MODULE_LoadLibraryExA	(internal)
  *
  * Load a PE style module according to the load order.
@@ -1325,8 +1362,12 @@
  * ignore the parameter because it would be extremely difficult to
  * integrate this with different types of module represenations.
  *
+ * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion
+ *        on this function.  When called from LoadLibraryExA it will be NULL
+ *        but thereafter it may point to a buffer containing the path portion
+ *        of the library name.
  */
-WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags )
+WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags, LPCSTR libdir )
 {
 	DWORD err = GetLastError();
 	WINE_MODREF *pwm;
@@ -1334,14 +1375,24 @@
 	enum loadorder_type loadorder[LOADORDER_NTYPES];
 	LPSTR filename, p;
         const char *filetype = "";
+        BOOL allocated_libdir = FALSE;
 
 	if ( !libname ) return NULL;
 
 	filename = HeapAlloc ( GetProcessHeap(), 0, MAX_PATH + 1 );
 	if ( !filename ) return NULL;
 
+        if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) &&
+	    ( strchr ( libname, '\\' ) || strchr ( libname, ':') ||
+              strchr ( libname, '/' ) ))
+        {
+            if (!(libdir = AllocateLibdir (libname))) goto error;
+            allocated_libdir = TRUE;
+        }
+
 	/* build the modules filename */
-	if (!SearchPathA( NULL, libname, ".dll", MAX_PATH, filename, NULL ))
+	if (!SearchEitherPathA( libdir, libname, ".dll", MAX_PATH, filename,
+                                NULL, libdir ? 0x03 : 0x01 ))
 	{
 	    if ( ! GetSystemDirectoryA ( filename, MAX_PATH ) ) 
   	        goto error;
@@ -1404,13 +1455,14 @@
                 if ((pwm->flags & WINE_MODREF_DONT_RESOLVE_REFS) &&
 		    !(flags & DONT_RESOLVE_DLL_REFERENCES))
                 {
-                    extern DWORD fixup_imports(WINE_MODREF *wm); /*FIXME*/
                     pwm->flags &= ~WINE_MODREF_DONT_RESOLVE_REFS;
-                    fixup_imports( pwm );
+                    PE_fixup_imports( pwm, libdir );
 		}
 		TRACE("Already loaded module '%s' at 0x%08x, count=%d, \n", filename, pwm->module, pwm->refCount);
                 RtlReleasePebLock();
 		HeapFree ( GetProcessHeap(), 0, filename );
+                if (allocated_libdir)
+                    HeapFree ( GetProcessHeap(), 0, (LPSTR)libdir );
 		return pwm;
 	}
 
@@ -1425,13 +1477,13 @@
 		{
 		case LOADORDER_DLL:
 			TRACE("Trying native dll '%s'\n", filename);
-			pwm = PE_LoadLibraryExA(filename, flags);
+			pwm = PE_LoadLibraryExA(filename, flags, libdir);
                         filetype = "native";
 			break;
 
 		case LOADORDER_SO:
 			TRACE("Trying so-library '%s'\n", filename);
-                        pwm = ELF_LoadLibraryExA(filename, flags);
+                        pwm = ELF_LoadLibraryExA(filename, flags, libdir);
                         filetype = "so";
 			break;
 
@@ -1459,6 +1511,8 @@
                         RtlReleasePebLock();
                         SetLastError( err );  /* restore last error */
 			HeapFree ( GetProcessHeap(), 0, filename );
+                        if (allocated_libdir)
+                            HeapFree ( GetProcessHeap(), 0, (LPSTR)libdir );
 			return pwm;
 		}
 
@@ -1470,6 +1524,8 @@
  error:
 	WARN("Failed to load module '%s'; error=0x%08lx, \n", filename, GetLastError());
 	HeapFree ( GetProcessHeap(), 0, filename );
+        if (allocated_libdir)
+            HeapFree ( GetProcessHeap(), 0, (LPSTR)libdir );
 	return NULL;
 }
 
Index: wine/loader/pe_image.c
===================================================================
RCS file: /home/wine/wine/loader/pe_image.c,v
retrieving revision 1.97
diff -u -r1.97 pe_image.c
--- wine/loader/pe_image.c	2001/08/09 21:16:55	1.97
+++ wine/loader/pe_image.c	2001/08/14 18:48:56
@@ -17,7 +17,7 @@
  * - If you want to enhance, speed up or clean up something in here, think
  *   twice WHY it is implemented in that strange way. There is usually a reason.
  *   Though sometimes it might just be lazyness ;)
- * - In PE_MapImage, right before fixup_imports() all external and internal 
+ * - In PE_MapImage, right before PE_fixup_imports() all external and internal 
  *   state MUST be correct since this function can be called with the SAME image
  *   AGAIN. (Thats recursion for you.) That means MODREF.module and
  *   NE_MODULE.module32.
@@ -242,7 +242,12 @@
 	}
 }
 
-DWORD fixup_imports( WINE_MODREF *wm )
+/****************************************************************
+ * 	PE_fixup_imports
+ *
+ * libdir is carried around the recursion loop for MODULE_LoadLibraryExA
+ */
+DWORD PE_fixup_imports( WINE_MODREF *wm, LPCSTR libdir )
 {
     IMAGE_IMPORT_DESCRIPTOR	*pe_imp;
     unsigned int load_addr	= wm->module;
@@ -286,7 +291,7 @@
 	if (characteristics_detection && !pe_imp->u.Characteristics)
 		break;
 
-	wmImp = MODULE_LoadLibraryExA( name, 0, 0 );
+	wmImp = MODULE_LoadLibraryExA( name, 0, 0, libdir );
 	if (!wmImp) {
 	    ERR_(module)("Module (file) %s needed by %s not found\n", name, wm->filename);
 	    return 1;
@@ -525,9 +530,11 @@
  *       process that is to own the module to be created.
  *
  * Note: Assumes that the process critical section is held
+ *
+ * libdir is carried around the recursion loop for MODULE_LoadLibraryExA
  */
 WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags,
-                              HANDLE hFile, BOOL builtin )
+                              HANDLE hFile, BOOL builtin, LPCSTR libdir )
 {
     DWORD load_addr = (DWORD)hModule;  /* for RVA */
     IMAGE_NT_HEADERS *nt = PE_HEADER(hModule);
@@ -633,7 +640,8 @@
 
     /* Fixup Imports */
 
-    if (!(wm->flags & WINE_MODREF_DONT_RESOLVE_REFS) && fixup_imports( wm ))
+    if (!(wm->flags & WINE_MODREF_DONT_RESOLVE_REFS) &&
+        PE_fixup_imports( wm, libdir ))
     {
         /* remove entry from modref chain */
 
@@ -681,8 +689,9 @@
 /******************************************************************************
  * The PE Library Loader frontend. 
  * FIXME: handle the flags.
+ * libdir is carried around the recursion loop for MODULE_LoadLibraryExA
  */
-WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags)
+WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags, LPCSTR libdir)
 {
 	HMODULE		hModule32;
 	WINE_MODREF	*wm;
@@ -701,7 +710,7 @@
 	}
 
 	/* Create 32-bit MODREF */
-	if ( !(wm = PE_CreateModule( hModule32, name, flags, hFile, FALSE )) )
+	if ( !(wm = PE_CreateModule( hModule32, name, flags, hFile, FALSE, libdir )) )
 	{
 		ERR( "can't load %s\n", name );
                 CloseHandle( hFile );
Index: wine/relay32/builtin32.c
===================================================================
RCS file: /home/wine/wine/relay32/builtin32.c,v
retrieving revision 1.81
diff -u -r1.81 builtin32.c
--- wine/relay32/builtin32.c	2001/07/25 00:43:36	1.81
+++ wine/relay32/builtin32.c	2001/08/14 18:48:56
@@ -87,7 +87,7 @@
         MESSAGE( "Warning: loading builtin %s, but native version already present. Expect trouble.\n", filename );
 
     /* Create 32-bit MODREF */
-    if (!(wm = PE_CreateModule( module, filename, 0, 0, TRUE )))
+    if (!(wm = PE_CreateModule( module, filename, 0, 0, TRUE, NULL )))
     {
         ERR( "can't load %s\n", filename );
         SetLastError( ERROR_OUTOFMEMORY );
Index: wine/scheduler/process.c
===================================================================
RCS file: /home/wine/wine/scheduler/process.c,v
retrieving revision 1.160
diff -u -r1.160 process.c
--- wine/scheduler/process.c	2001/08/06 17:48:17	1.160
+++ wine/scheduler/process.c	2001/08/14 18:48:56
@@ -353,7 +353,7 @@
     if (!SIGNAL_Init()) goto error;
 
     /* create the main modref and load dependencies */
-    if (!(wm = PE_CreateModule( current_process.module, main_exe_name, 0, 0, FALSE )))
+    if (!(wm = PE_CreateModule( current_process.module, main_exe_name, 0, 0, FALSE, NULL )))
         goto error;
     wm->refCount++;
 


More information about the wine-patches mailing list