Added support for path wildcards of the form "*dllname" in load order

specifications.
Only use wildcard entry for dlls that don't specify an explicit path.
Removed the old DllOverrides syntax support.
Misc cleanups and optimizations.
oldstable
Alexandre Julliard 2002-06-25 00:23:23 +00:00
parent ae4278ee59
commit 69622dbdcc
5 changed files with 202 additions and 224 deletions

View File

@ -7,7 +7,7 @@ wine.conf \- Wine configuration file
expects a configuration file (
.I $WINEPREFIX/config
(~/.wine/config)
), which should conform to the following rules.
), which should conform to the following rules.
A sample configuration file is available as
.I documentation/samples/config
in the Wine source distribution.
@ -33,7 +33,7 @@ are listed below.
.br
This section is used to specify the root directory and type of each emulated
.B DOS
drive, since most Windows applications require a DOS/MS-Windows based
drive, since most Windows applications require a DOS/MS-Windows based
disk drive & directory scheme, which is either provided by a real
DOS partition mounted somewhere or by some carefully crafted directory layout
on a Unix file system ("no-windows fake installation").
@ -43,10 +43,10 @@ There is one such section for every drive you want to configure.
.br
default: none
.br
If you mounted your dos partition as
If you mounted your dos partition as
.I /dos
and installed Microsoft Windows in
C:\\WINDOWS (thus it shows up as /dos/WINDOWS), then you should specify
and installed Microsoft Windows in
C:\\WINDOWS (thus it shows up as /dos/WINDOWS), then you should specify
.I """Path""=""/dos"""
in the
.I [Drive C]
@ -125,7 +125,7 @@ directory would be used for this.
.br
default: "C:\\\\TEMP"
.br
Used to specify a directory where Windows applications can store
Used to specify a directory where Windows applications can store
temporary files. E.g. with a C: drive at /home/user/wine_c, this would be
the /home/user/wine_c/TEMP directory.
.PP
@ -178,11 +178,12 @@ Also valid as an AppDefaults setting (recommended/preferred use).
.I format: """modulename""=""native,so,builtin"""
.br
.I modulename
can be any valid DLL module name, without extension. The specified value
is a comma separated list of module-types to try to load in that
specific order. Case is not important and only the first letter of
each type is enough to identify the type n[ative], s[o],
b[uiltin]. Also whitespace is ignored. See also commandline option
can be any valid DLL module name. If no extension is specified .dll is
assumed. The specified value is a comma separated list of module-types
to try to load in that specific order. Case is not important and only
the first letter of each type is enough to identify the type n[ative],
s[o], b[uiltin]. Also whitespace is ignored. See also commandline
option
.I --dll
for details about the allowable types.
.br
@ -202,9 +203,24 @@ Examples:
.br
.I """*""=""builtin,native"""
.br
Changing the load order of kernel/kernel32 and gdi/gdi32 to
anything other than builtin will cause wine to fail because wine cannot
use native versions for these libraries.
When the specified module name does not contain a path, it matches
only dlls loaded from the Windows system directory. If the application
explicitly loads a dll from a different directory, it has to be
configured separately. This can be done either by specifying the full
path in the module name, or by using a path wildcard of the form
.I """*modulename""".
.br
For instance, the following will load the native shell32 when loaded
from C:\\Program Files, and the builtin when loaded from any other
directory:
.br
.I """C:\\\\\\\\Program Files\\\\\\\\shell32"" = ""native"""
.br
.I """*shell32"" = ""builtin"""
.br
Changing the load order of low-level dlls like kernel32, gdi32 or
user32 to anything other than builtin will cause wine to fail because
wine cannot use native versions for these libraries.
.br
Always make sure that you have some kind of strategy in mind when you start
fiddling with the current defaults and needless to say that you must know
@ -245,7 +261,7 @@ default: none
.I format: """WineLook""=""<Win31|Win95|Win98>"""
.br
default: "Win31"
.br
.br
Use Win95-like window displays or Win3.1-like window displays.
.PP
.B [Registry]
@ -264,7 +280,7 @@ TRY to write all changes to the home registry files
.PP
.I format: """LoadWindowsRegistryFiles""=""<boolean>"""
.br
Load Windows registry from the current Windows directory.
Load Windows registry from the current Windows directory.
.PP
booleans: Y/y/T/t/1 are true, N/n/F/f/0 are false.
.br
@ -293,8 +309,8 @@ section.
.br
The only sections that support application-specific information at the
moment are
.I DllOverrides
and
.I DllOverrides
and
.I x11drv.
.br
Make sure to use double backslashes in the section name.
@ -308,7 +324,7 @@ in the Wine source distribution.
.I ~/.wine/config
User-specific configuration file
.SH ENVIRONMENT VARIABLES
.TP
.TP
.I WINEPREFIX
Specifies the directory that contains the per-user
.I config

View File

@ -265,7 +265,6 @@ extern BOOL PE_InitDLL( HMODULE module, DWORD type, LPVOID lpReserved );
extern DWORD PE_fixup_imports(WINE_MODREF *wm);
/* loader/loadorder.c */
extern void MODULE_InitLoadOrder(void);
extern void MODULE_GetLoadOrder( enum loadorder_type plo[], const char *path, BOOL win32 );
extern void MODULE_AddLoadOrderOption( const char *option );

View File

@ -94,6 +94,12 @@ static const struct loadorder_list default_list =
default_order_list
};
/* default if nothing else specified */
static const enum loadorder_type default_loadorder[LOADORDER_NTYPES] =
{
LOADORDER_DLL, LOADORDER_BI, 0, 0
};
static struct loadorder_list cmdline_list;
@ -150,6 +156,49 @@ static char *get_tok(const char *str, const char *delim)
}
/***************************************************************************
* get_basename
*
* Return the base name of a file name (i.e. remove the path components).
*/
static const char *get_basename( const char *name )
{
const char *ptr;
if (name[0] && name[1] == ':') name += 2; /* strip drive specification */
if ((ptr = strrchr( name, '\\' ))) name = ptr + 1;
if ((ptr = strrchr( name, '/' ))) name = ptr + 1;
return name;
}
/***************************************************************************
* debugstr_loadorder
*
* Return a loadorder in printable form.
*/
static const char *debugstr_loadorder( enum loadorder_type lo[] )
{
int i;
char buffer[LOADORDER_NTYPES*3+1];
buffer[0] = 0;
for(i = 0; i < LOADORDER_NTYPES; i++)
{
if (lo[i] == LOADORDER_INVALID) break;
switch(lo[i])
{
case LOADORDER_DLL: strcat( buffer, "n," ); break;
case LOADORDER_SO: strcat( buffer, "s," ); break;
case LOADORDER_BI: strcat( buffer, "b," ); break;
default: strcat( buffer, "?," ); break;
}
}
if (buffer[0]) buffer[strlen(buffer)-1] = 0;
return debugstr_a(buffer);
}
/***************************************************************************
* ParseLoadOrder (internal, static)
*
@ -303,74 +352,6 @@ void MODULE_AddLoadOrderOption( const char *option )
}
/***************************************************************************
* set_registry_keys
*
* Set individual registry keys for a multiple dll specification
* Helper for MODULE_InitLoadOrder().
*/
inline static void set_registry_keys( HKEY hkey, char *module, const char *buffer )
{
static int warn;
char *p = get_tok( module, ", \t" );
TRACE( "converting \"%s\" = \"%s\"\n", module, buffer );
if (!warn)
MESSAGE( "Warning: setting multiple modules in a single DllOverrides entry is no longer\n"
"recommended. It is suggested that you rewrite the configuration file entry:\n\n"
"\"%s\" = \"%s\"\n\n"
"into something like:\n\n", module, buffer );
while (p)
{
if (!warn) MESSAGE( "\"%s\" = \"%s\"\n", p, buffer );
/* only set it if not existing already */
if (RegQueryValueExA( hkey, p, 0, NULL, NULL, NULL ) == ERROR_FILE_NOT_FOUND)
RegSetValueExA( hkey, p, 0, REG_SZ, buffer, strlen(buffer)+1 );
p = get_tok( NULL, ", \t" );
}
if (!warn) MESSAGE( "\n" );
warn = 1;
}
/***************************************************************************
* MODULE_InitLoadOrder
*
* Convert entries containing multiple dll names (old syntax) to the
* new one dll module per entry syntax
*/
void MODULE_InitLoadOrder(void)
{
char module[80];
char buffer[1024];
char *p;
HKEY hkey;
DWORD index = 0;
if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\DllOverrides", &hkey ))
return;
for (;;)
{
DWORD type, count = sizeof(buffer), name_len = sizeof(module);
if (RegEnumValueA( hkey, index, module, &name_len, NULL, &type, buffer, &count )) break;
p = module;
while (isspace(*p)) p++;
p += strcspn( p, ", \t" );
while (isspace(*p)) p++;
if (*p)
{
RegDeleteValueA( hkey, module );
set_registry_keys( hkey, module, buffer );
}
else index++;
}
RegCloseKey( hkey );
}
/***************************************************************************
* get_list_load_order
*
@ -391,113 +372,52 @@ static BOOL get_list_load_order( const char *module, const struct loadorder_list
/***************************************************************************
* get_app_load_order
* open_app_key
*
* Get the load order for a given module from the app-specific DllOverrides list.
* Also look for default '*' key if no module key found.
* Open the registry key to the app-specific DllOverrides list.
*/
static BOOL get_app_load_order( const char *module, enum loadorder_type lo[], BOOL *got_default )
static HKEY open_app_key( const char *module )
{
HKEY hkey, appkey;
DWORD count, type, res;
char buffer[MAX_PATH+16], *appname, *p;
char buffer[MAX_PATH+16], *appname;
if (!GetModuleFileName16( GetCurrentTask(), buffer, MAX_PATH ) &&
!GetModuleFileNameA( 0, buffer, MAX_PATH ))
{
WARN( "could not get module file name loading %s\n", module );
return FALSE;
return 0;
}
appname = buffer;
if ((p = strrchr( appname, '/' ))) appname = p + 1;
if ((p = strrchr( appname, '\\' ))) appname = p + 1;
appname = (char *)get_basename( buffer );
TRACE( "searching '%s' in AppDefaults\\%s\\DllOverrides\n", module, appname );
if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &hkey ))
return FALSE;
return 0;
/* open AppDefaults\\appname\\DllOverrides key */
strcat( appname, "\\DllOverrides" );
res = RegOpenKeyA( hkey, appname, &appkey );
if (RegOpenKeyA( hkey, appname, &appkey )) appkey = 0;
RegCloseKey( hkey );
if (res) return FALSE;
count = sizeof(buffer);
if ((res = RegQueryValueExA( appkey, module, NULL, &type, buffer, &count )))
{
if (!(res = RegQueryValueExA( appkey, "*", NULL, &type, buffer, &count )))
*got_default = TRUE;
}
else TRACE( "got app loadorder '%s' for '%s'\n", buffer, module );
RegCloseKey( appkey );
if (res) return FALSE;
return ParseLoadOrder( buffer, lo );
return appkey;
}
/***************************************************************************
* get_standard_load_order
* get_registry_value
*
* Get the load order for a given module from the main DllOverrides list
* Also look for default '*' key if no module key found.
* Load the registry loadorder value for a given module.
*/
static BOOL get_standard_load_order( const char *module, enum loadorder_type lo[],
BOOL *got_default )
static BOOL get_registry_value( HKEY hkey, const char *module, enum loadorder_type lo[] )
{
HKEY hkey;
DWORD count, type, res;
char buffer[80];
if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\DllOverrides", &hkey ))
return FALSE;
DWORD count, type;
count = sizeof(buffer);
if ((res = RegQueryValueExA( hkey, module, NULL, &type, buffer, &count )))
{
if (!(res = RegQueryValueExA( hkey, "*", NULL, &type, buffer, &count )))
*got_default = TRUE;
}
else TRACE( "got standard loadorder '%s' for '%s'\n", buffer, module );
RegCloseKey( hkey );
if (res) return FALSE;
if (RegQueryValueExA( hkey, module, NULL, &type, buffer, &count )) return FALSE;
return ParseLoadOrder( buffer, lo );
}
/***************************************************************************
* get_default_load_order
*
* Get the default load order if nothing specified for a given dll.
*/
static void get_default_load_order( enum loadorder_type lo[] )
{
DWORD res;
static enum loadorder_type default_loadorder[LOADORDER_NTYPES];
static int loaded;
if (!loaded)
{
char buffer[80];
HKEY hkey;
if (!(res = RegOpenKeyA( HKEY_LOCAL_MACHINE,
"Software\\Wine\\Wine\\Config\\DllDefaults", &hkey )))
{
DWORD type, count = sizeof(buffer);
res = RegQueryValueExA( hkey, "DefaultLoadOrder", NULL, &type, buffer, &count );
RegCloseKey( hkey );
}
if (res) strcpy( buffer, "n,b,s" );
ParseLoadOrder( buffer, default_loadorder );
loaded = 1;
TRACE( "got default loadorder '%s'\n", buffer );
}
memcpy( lo, default_loadorder, sizeof(default_loadorder) );
}
/***************************************************************************
* MODULE_GetLoadOrder (internal)
*
@ -508,76 +428,119 @@ static void get_default_load_order( enum loadorder_type lo[] )
*/
void MODULE_GetLoadOrder( enum loadorder_type loadorder[], const char *path, BOOL win32 )
{
char fname[256];
char sysdir[MAX_PATH+1];
char *cptr;
char *name;
int len;
BOOL got_app_default = FALSE, got_std_default = FALSE;
enum loadorder_type lo_default[LOADORDER_NTYPES];
static HKEY std_key = (HKEY)-1; /* key to standard section, cached */
HKEY app_key = 0;
char *module, *basename;
int len;
TRACE("looking for %s\n", path);
TRACE("looking for %s\n", path);
if ( ! GetSystemDirectoryA ( sysdir, MAX_PATH ) ) goto done;
loadorder[0] = LOADORDER_INVALID; /* in case something bad happens below */
/* Strip path information for 16 bit modules or if the module
resides in the system directory */
if ( !win32 || !FILE_strncasecmp ( sysdir, path, strlen (sysdir) ) )
{
/* Strip path information for 16 bit modules or if the module
* resides in the system directory */
if (!win32) path = get_basename( path );
else
{
char sysdir[MAX_PATH+1];
if (!GetSystemDirectoryA( sysdir, MAX_PATH )) return;
if (!FILE_strncasecmp( sysdir, path, strlen (sysdir) ))
{
path += strlen(sysdir);
while (*path == '\\' || *path == '/') path++;
}
}
cptr = strrchr(path, '\\');
if(!cptr)
name = strrchr(path, '/');
else
name = strrchr(cptr, '/');
if (!(len = strlen(path))) return;
if (!(module = HeapAlloc( GetProcessHeap(), 0, len + 2 ))) return;
strcpy( module+1, path ); /* reserve module[0] for the wildcard char */
if(!name)
name = cptr ? cptr+1 : (char *)path;
else
name++;
if (len >= 4)
{
char *ext = module + 1 + len - 4;
if (!FILE_strcasecmp( ext, ".dll" )) *ext = 0;
}
if((cptr = strchr(name, ':')) != NULL) /* Also strip drive if in format 'C:MODULE.DLL' */
name = cptr+1;
}
else
name = (char *)path;
/* check command-line first */
if (get_list_load_order( module+1, &cmdline_list, loadorder ))
{
TRACE( "got cmdline %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
goto done;
}
len = strlen(name);
if(len >= sizeof(fname) || len <= 0)
{
WARN("Path '%s' -> '%s' reduces to zilch or just too large...\n", path, name);
/* then explicit module name in AppDefaults */
app_key = open_app_key( module+1 );
if (app_key && get_registry_value( app_key, module+1, loadorder ))
{
TRACE( "got app defaults %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
goto done;
}
/* then explicit module name in standard section */
if (std_key == (HKEY)-1)
RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\DllOverrides", &std_key );
if (std_key && get_registry_value( std_key, module+1, loadorder ))
{
TRACE( "got standard entry %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
goto done;
}
/* then module basename preceded by '*' in AppDefaults */
basename = (char *)get_basename( module+1 );
basename[-1] = '*';
if (app_key && get_registry_value( app_key, basename-1, loadorder ))
{
TRACE( "got app defaults basename %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
goto done;
}
/* then module name preceded by '*' in standard section */
if (std_key && get_registry_value( std_key, basename-1, loadorder ))
{
TRACE( "got standard base name %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
goto done;
}
/* then base name matching compiled-in defaults */
if (get_list_load_order( basename, &default_list, loadorder ))
{
TRACE( "got compiled-in default %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
goto done;
}
if (basename == module+1)
{
/* then wildcard entry in AppDefaults (only if no explicit path) */
if (app_key && get_registry_value( app_key, "*", loadorder ))
{
TRACE( "got app defaults wildcard %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
goto done;
}
strcpy(fname, name);
if(len >= 4 && !FILE_strcasecmp(fname+len-4, ".dll")) fname[len-4] = '\0';
/* check command-line first */
if (get_list_load_order( fname, &cmdline_list, loadorder )) return;
/* then app-specific config */
if (get_app_load_order( fname, loadorder, &got_app_default ))
{
if (!got_app_default) return;
/* save the default value for later on */
memcpy( lo_default, loadorder, sizeof(lo_default) );
}
/* then standard config */
if (get_standard_load_order( fname, loadorder, &got_std_default ))
/* then wildcard entry in standard section (only if no explicit path) */
if (std_key && get_registry_value( std_key, "*", loadorder ))
{
if (!got_std_default) return;
/* save the default value for later on */
if (!got_app_default) memcpy( lo_default, loadorder, sizeof(lo_default) );
TRACE( "got standard wildcard %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
goto done;
}
}
/* and last the hard-coded default */
memcpy( loadorder, default_loadorder, sizeof(default_loadorder) );
TRACE( "got hardcoded default %s for %s\n",
debugstr_loadorder(loadorder), debugstr_a(path) );
/* then compiled-in defaults */
if (get_list_load_order( fname, &default_list, loadorder )) return;
done:
/* last, return the default */
if (got_app_default || got_std_default)
memcpy( loadorder, lo_default, sizeof(lo_default) );
else
get_default_load_order( loadorder );
if (app_key) RegCloseKey( app_key );
HeapFree( GetProcessHeap(), 0, module );
}

View File

@ -34,7 +34,6 @@
#include "drive.h"
#include "file.h"
#include "options.h"
#include "module.h"
#include "wine/debug.h"
#include "wine/server.h"
@ -75,9 +74,6 @@ BOOL MAIN_MainInit(void)
/* Registry initialisation */
SHELL_LoadRegistry();
/* Initialize module loadorder */
if (CLIENT_IsBootThread()) MODULE_InitLoadOrder();
/* Global boot finished, the rest is process-local */
CLIENT_BootDone( TRACE_ON(server) );

View File

@ -1425,6 +1425,10 @@ static void MODULE_FlushModrefs(void)
MODULE_modref_list = wm->next;
TRACE(" unloading %s\n", wm->filename);
if (!TRACE_ON(module))
TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
wm->dlhandle ? "builtin" : "native" );
if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
else UnmapViewOfFile( (LPVOID)wm->module );
FreeLibrary16(wm->hDummyMod);