- fixed a couple of bugs in ntdll environment functions (one in trace,

the other one in environment variable expansion)
- the process parameters, when passed thru wineserver, are now fully
  handled in ntdll, they are stored in the RTL_USER_PROCESS_PARAMETERS
  structure.
- later on in kernel32 loading sequence, those parameters are copied
  into STARTUPINFO shadow structures
- later modification to those paramters are now reflected to the
  RTL_USER_PROCESS_PARAMETERS structure (and STARTUPINFO is kept
  untouched) (for example, StdHandle setting) (Win 2k behaves like this)
- ENVDB has been removed
- command line inheritance (from unix command line) is now purely in ntdll
- all kernel32 environment functions now rely on their ntdll counterparts
- goodies: input/output handle inheritance while asking for a detached
  console is better handled; a few more kernel32 environment tests now
  pass ; silenced a valgrind warning in process creation
This commit is contained in:
Eric Pouech 2003-06-18 03:23:22 +00:00 committed by Alexandre Julliard
parent d478261f30
commit b53b5bcb50
6 changed files with 618 additions and 646 deletions

View File

@ -48,6 +48,8 @@ extern BOOL RELAY_Init(void);
extern void COMPUTERNAME_Init(void);
extern int __wine_set_signal_handler(unsigned, int (*)(unsigned));
/* memory/environ.c */
extern void ENV_CopyStartupInformation(void);
extern int main_create_flags;
@ -113,6 +115,9 @@ static BOOL process_attach(void)
/* Setup computer name */
COMPUTERNAME_Init();
/* copy process information from ntdll */
ENV_CopyStartupInformation();
if ((hModule = LoadLibrary16( "krnl386.exe" )) >= 32)
{
@ -168,6 +173,14 @@ static BOOL process_attach(void)
if (RtlImageNtHeader(mod)->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
AllocConsole();
}
else if (!(main_create_flags & DETACHED_PROCESS))
{
/* 1/ shall inherit console + handles
* 2/ shall create std handles, if handles are not inherited
* TBD when not using wineserver handles for console handles
*/
}
if (main_create_flags & CREATE_NEW_PROCESS_GROUP)
SetConsoleCtrlHandler(NULL, TRUE);

View File

@ -130,6 +130,7 @@ NTSTATUS WINAPI RtlQueryEnvironmentVariable_U(PWSTR env,
if (var != NULL)
{
value->Length = strlenW(var) * sizeof(WCHAR);
if (value->Length <= value->MaximumLength)
{
memmove(value->Buffer, var, min(value->Length + sizeof(WCHAR), value->MaximumLength));
@ -171,7 +172,9 @@ NTSTATUS WINAPI RtlSetEnvironmentVariable(PWSTR* penv, PUNICODE_STRING name,
NTSTATUS nts = STATUS_VARIABLE_NOT_FOUND;
MEMORY_BASIC_INFORMATION mbi;
TRACE("(%p,%s,%s): stub!\n", penv, debugstr_w(name->Buffer), debugstr_w(value->Buffer));
TRACE("(%p,%s,%s)\n",
penv, debugstr_w(name->Buffer),
value ? debugstr_w(value->Buffer) : "--nil--");
if (!name || !name->Buffer || !name->Buffer[0])
return STATUS_INVALID_PARAMETER_1;
@ -245,7 +248,6 @@ NTSTATUS WINAPI RtlSetEnvironmentVariable(PWSTR* penv, PUNICODE_STRING name,
strcatW(p, equalW);
strcatW(p, value->Buffer);
}
done:
if (!penv) RtlReleasePebLock();
@ -256,18 +258,23 @@ done:
* RtlExpandEnvironmentStrings_U (NTDLL.@)
*
*/
NTSTATUS WINAPI RtlExpandEnvironmentStrings_U(PWSTR env, const UNICODE_STRING* us_src,
NTSTATUS WINAPI RtlExpandEnvironmentStrings_U(PWSTR renv, const UNICODE_STRING* us_src,
PUNICODE_STRING us_dst, PULONG plen)
{
DWORD len, count, total_size = 1; /* 1 for terminating '\0' */
LPCWSTR src, p, var;
LPCWSTR env, src, p, var;
LPWSTR dst;
src = us_src->Buffer;
count = us_dst->MaximumLength / sizeof(WCHAR);
dst = count ? us_dst->Buffer : NULL;
RtlAcquirePebLock();
if (!renv)
{
RtlAcquirePebLock();
env = ntdll_get_process_pmts()->Environment;
}
else env = renv;
while (*src)
{
@ -312,12 +319,12 @@ NTSTATUS WINAPI RtlExpandEnvironmentStrings_U(PWSTR env, const UNICODE_STRING* u
}
}
RtlReleasePebLock();
if (!renv) RtlReleasePebLock();
/* Null-terminate the string */
if (dst && count) *dst = '\0';
us_dst->Length = (dst) ? (dst - us_dst->Buffer) * sizeof(WCHAR): 0;
us_dst->Length = (dst) ? (dst - us_dst->Buffer) * sizeof(WCHAR) : 0;
if (plen) *plen = total_size * sizeof(WCHAR);
return (count) ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
@ -328,7 +335,7 @@ NTSTATUS WINAPI RtlExpandEnvironmentStrings_U(PWSTR env, const UNICODE_STRING* u
*
* Build the Win32 environment from the Unix environment
*/
BOOL build_initial_environment(void)
static NTSTATUS build_initial_environment(void)
{
extern char **environ;
LPSTR* e, te;
@ -349,9 +356,10 @@ BOOL build_initial_environment(void)
/* Now allocate the environment */
nts = NtAllocateVirtualMemory(NtCurrentProcess(), (void**)&p, 0, &size,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (nts != STATUS_SUCCESS) return FALSE;
if (nts != STATUS_SUCCESS) return nts;
ntdll_get_process_pmts()->Environment = p;
/* And fill it with the Unix environment */
for (e = environ; *e; e++)
{
@ -365,5 +373,258 @@ BOOL build_initial_environment(void)
}
*p = 0;
return STATUS_SUCCESS;
}
static void init_unicode( UNICODE_STRING* us, const char** src, size_t len)
{
if (len)
{
STRING ansi;
ansi.Buffer = (char*)*src;
ansi.Length = len;
ansi.MaximumLength = len;
/* FIXME: should check value returned */
RtlAnsiStringToUnicodeString( us, &ansi, TRUE );
*src += len;
}
}
/***********************************************************************
* init_user_process_pmts
*
* Fill the RTL_USER_PROCESS_PARAMETERS structure from the server.
*/
BOOL init_user_process_pmts( size_t info_size, char *main_exe_name, size_t main_exe_size )
{
startup_info_t info;
void *data;
const char *src;
size_t len;
RTL_USER_PROCESS_PARAMETERS *rupp;
if (build_initial_environment() != STATUS_SUCCESS) return FALSE;
if (!info_size) return TRUE;
if (!(data = RtlAllocateHeap( ntdll_get_process_heap(), 0, info_size )))
return FALSE;
SERVER_START_REQ( get_startup_info )
{
wine_server_set_reply( req, data, info_size );
wine_server_call( req );
info_size = wine_server_reply_size( reply );
}
SERVER_END_REQ;
if (info_size < sizeof(info.size)) goto done;
len = min( info_size, ((startup_info_t *)data)->size );
memset( &info, 0, sizeof(info) );
memcpy( &info, data, len );
src = (char *)data + len;
info_size -= len;
/* fixup the lengths */
if (info.filename_len > info_size) info.filename_len = info_size;
info_size -= info.filename_len;
if (info.cmdline_len > info_size) info.cmdline_len = info_size;
info_size -= info.cmdline_len;
if (info.desktop_len > info_size) info.desktop_len = info_size;
info_size -= info.desktop_len;
if (info.title_len > info_size) info.title_len = info_size;
/* store the filename */
len = min( info.filename_len, main_exe_size-1 );
memcpy( main_exe_name, src, len );
main_exe_name[len] = 0;
rupp = NtCurrentTeb()->Peb->ProcessParameters;
init_unicode( &rupp->ImagePathName, &src, info.filename_len );
init_unicode( &rupp->CommandLine, &src, info.cmdline_len );
init_unicode( &rupp->Desktop, &src, info.desktop_len );
init_unicode( &rupp->WindowTitle, &src, info.title_len );
rupp->dwX = info.x;
rupp->dwY = info.y;
rupp->dwXSize = info.cx;
rupp->dwYSize = info.cy;
rupp->dwXCountChars = info.x_chars;
rupp->dwYCountChars = info.y_chars;
rupp->dwFillAttribute = info.attribute;
rupp->wShowWindow = info.cmd_show;
rupp->dwFlags = info.flags;
done:
RtlFreeHeap( ntdll_get_process_heap(), 0, data );
return TRUE;
}
/***********************************************************************
* set_library_argv
*
* Set the Wine library argc/argv global variables.
*/
static void set_library_argv( char **argv )
{
int argc;
WCHAR *p;
WCHAR **wargv;
DWORD total = 0, len, reslen;
for (argc = 0; argv[argc]; argc++)
{
len = strlen(argv[argc]) + 1;
RtlMultiByteToUnicodeN(NULL, 0, &reslen, argv[argc], len);
total += reslen;
}
wargv = RtlAllocateHeap( ntdll_get_process_heap(), 0,
total + (argc + 1) * sizeof(*wargv) );
p = (WCHAR *)(wargv + argc + 1);
for (argc = 0; argv[argc]; argc++)
{
len = strlen(argv[argc]) + 1;
RtlMultiByteToUnicodeN(p, total, &reslen, argv[argc], len);
wargv[argc] = p;
p += reslen / sizeof(WCHAR);
total -= reslen;
}
wargv[argc] = NULL;
__wine_main_argc = argc;
__wine_main_argv = argv;
__wine_main_wargv = wargv;
}
/***********************************************************************
* build_command_line
*
* Build the command line of a process from the argv array.
*
* Note that it does NOT necessarily include the file name.
* Sometimes we don't even have any command line options at all.
*
* We must quote and escape characters so that the argv array can be rebuilt
* from the command line:
* - spaces and tabs must be quoted
* 'a b' -> '"a b"'
* - quotes must be escaped
* '"' -> '\"'
* - if '\'s are followed by a '"', they must be doubled and followed by '\"',
* resulting in an odd number of '\' followed by a '"'
* '\"' -> '\\\"'
* '\\"' -> '\\\\\"'
* - '\'s that are not followed by a '"' can be left as is
* 'a\b' == 'a\b'
* 'a\\b' == 'a\\b'
*/
BOOL build_command_line( char **argv )
{
int len;
char **arg;
LPWSTR p;
RTL_USER_PROCESS_PARAMETERS* rupp;
set_library_argv( argv );
rupp = ntdll_get_process_pmts();
if (rupp->CommandLine.Buffer) return TRUE; /* already got it from the server */
len = 0;
for (arg = argv; *arg; arg++)
{
int has_space,bcount;
char* a;
has_space=0;
bcount=0;
a=*arg;
while (*a!='\0') {
if (*a=='\\') {
bcount++;
} else {
if (*a==' ' || *a=='\t') {
has_space=1;
} else if (*a=='"') {
/* doubling of '\' preceeding a '"',
* plus escaping of said '"'
*/
len+=2*bcount+1;
}
bcount=0;
}
a++;
}
len+=(a-*arg)+1 /* for the separating space */;
if (has_space)
len+=2; /* for the quotes */
}
if (!(rupp->CommandLine.Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len * sizeof(WCHAR))))
return FALSE;
p = rupp->CommandLine.Buffer;
rupp->CommandLine.Length = (len - 1) * sizeof(WCHAR);
rupp->CommandLine.MaximumLength = len * sizeof(WCHAR);
for (arg = argv; *arg; arg++)
{
int has_space,has_quote;
char* a;
/* Check for quotes and spaces in this argument */
has_space=has_quote=0;
a=*arg;
while (*a!='\0') {
if (*a==' ' || *a=='\t') {
has_space=1;
if (has_quote)
break;
} else if (*a=='"') {
has_quote=1;
if (has_space)
break;
}
a++;
}
/* Now transfer it to the command line */
if (has_space)
*p++='"';
if (has_quote) {
int bcount;
char* a;
bcount=0;
a=*arg;
while (*a!='\0') {
if (*a=='\\') {
*p++=*a;
bcount++;
} else {
if (*a=='"') {
int i;
/* Double all the '\\' preceeding this '"', plus one */
for (i=0;i<=bcount;i++)
*p++='\\';
*p++='"';
} else {
*p++=*a;
}
bcount=0;
}
a++;
}
} else {
char* x = *arg;
while ((*p=*x++)) p++;
}
if (has_space)
*p++='"';
*p++=' ';
}
if (p > rupp->CommandLine.Buffer)
p--; /* remove last space */
*p = '\0';
return TRUE;
}

View File

@ -45,12 +45,8 @@ static inline HANDLE ntdll_get_process_heap(void)
return NtCurrentTeb()->Peb->ProcessHeap;
}
/* FIXME: this should be part of PEB, once it's defined */
extern RTL_USER_PROCESS_PARAMETERS process_pmts;
BOOL build_initial_environment(void);
static inline RTL_USER_PROCESS_PARAMETERS* ntdll_get_process_pmts(void)
{
return &process_pmts;
return NtCurrentTeb()->Peb->ProcessParameters;
}
#endif

View File

@ -126,7 +126,7 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS
ULONG dwFlags;
ULONG wShowWindow;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING Desktop;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeInfo;
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,6 @@
#include "wine/server.h"
#include "options.h"
#include "wine/debug.h"
#include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(process);
WINE_DECLARE_DEBUG_CHANNEL(server);
@ -55,15 +54,13 @@ WINE_DECLARE_DEBUG_CHANNEL(relay);
WINE_DECLARE_DEBUG_CHANNEL(snoop);
WINE_DECLARE_DEBUG_CHANNEL(win32);
struct _ENVDB;
/* Win32 process database */
typedef struct _PDB
{
LONG header[2]; /* 00 Kernel object header */
HMODULE module; /* 08 Main exe module (NT) */
void *event; /* 0c Pointer to an event object (unused) */
DWORD exit_code; /* 10 Process exit code */
RTL_USER_PROCESS_PARAMETERS *ProcessParameters; /* 10 Process parameters*/
DWORD unknown2; /* 14 Unknown */
HANDLE heap; /* 18 Default process heap */
HANDLE mem_context; /* 1c Process memory context */
@ -109,7 +106,7 @@ typedef struct _PDB
PDB current_process;
RTL_USER_PROCESS_PARAMETERS process_pmts;
static RTL_USER_PROCESS_PARAMETERS process_pmts;
/* Process flags */
#define PDB32_DEBUGGED 0x0001 /* Process is being debugged */
@ -126,15 +123,13 @@ static unsigned int server_startticks;
int main_create_flags = 0;
/* memory/environ.c */
extern struct _ENVDB *ENV_InitStartupInfo( size_t info_size, char *main_exe_name,
size_t main_exe_size );
extern BOOL ENV_BuildCommandLine( char **argv );
extern STARTUPINFOA current_startupinfo;
/* scheduler/pthread.c */
extern void PTHREAD_init_done(void);
/* dlls/ntdll/env.c */
extern BOOL init_user_process_pmts( size_t, char*, size_t );
extern BOOL build_command_line( char **argv );
extern void RELAY_InitDebugLists(void);
extern void SHELL_LoadRegistry(void);
extern void VERSION_Init( const char *appname );
@ -302,12 +297,12 @@ static BOOL process_init( char *argv[] )
argv0 = argv[0];
/* Fill the initial process structure */
current_process.exit_code = STILL_ACTIVE;
current_process.threads = 1;
current_process.running_threads = 1;
current_process.ring0_threads = 1;
current_process.group = &current_process;
current_process.priority = 8; /* Normal */
current_process.ProcessParameters = &process_pmts;
/* Setup the server connection */
CLIENT_InitServer();
@ -322,9 +317,9 @@ static BOOL process_init( char *argv[] )
main_create_flags = reply->create_flags;
info_size = reply->info_size;
server_startticks = reply->server_start;
current_startupinfo.hStdInput = reply->hstdin;
current_startupinfo.hStdOutput = reply->hstdout;
current_startupinfo.hStdError = reply->hstderr;
process_pmts.hStdInput = reply->hstdin;
process_pmts.hStdOutput = reply->hstdout;
process_pmts.hStdError = reply->hstderr;
}
}
SERVER_END_REQ;
@ -334,44 +329,33 @@ static BOOL process_init( char *argv[] )
current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
if (main_create_flags == 0 &&
current_startupinfo.hStdInput == 0 &&
current_startupinfo.hStdOutput == 0 &&
current_startupinfo.hStdError == 0)
process_pmts.hStdInput == 0 &&
process_pmts.hStdOutput == 0 &&
process_pmts.hStdError == 0)
{
/* no parent, and no new console requested, create a simple console with bare handles to
/* This is wine specific:
* no parent, and no new console requested, create a simple console with bare handles to
* unix stdio input & output streams (aka simple console)
*/
HANDLE handle;
wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, TRUE, &handle );
SetStdHandle( STD_INPUT_HANDLE, handle );
wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, TRUE, &handle );
SetStdHandle( STD_OUTPUT_HANDLE, handle );
wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, TRUE, &handle );
SetStdHandle( STD_ERROR_HANDLE, handle );
}
else if (!(main_create_flags & (DETACHED_PROCESS|CREATE_NEW_CONSOLE)))
{
SetStdHandle( STD_INPUT_HANDLE, current_startupinfo.hStdInput );
SetStdHandle( STD_OUTPUT_HANDLE, current_startupinfo.hStdOutput );
SetStdHandle( STD_ERROR_HANDLE, current_startupinfo.hStdError );
wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, TRUE, &process_pmts.hStdInput );
wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, TRUE, &process_pmts.hStdOutput );
wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, TRUE, &process_pmts.hStdError );
}
/* Now we can use the pthreads routines */
PTHREAD_init_done();
/* Copy the parent environment */
if (!(current_process.env_db = ENV_InitStartupInfo( info_size, main_exe_name,
sizeof(main_exe_name) )))
if (!init_user_process_pmts( info_size, main_exe_name, sizeof(main_exe_name) ))
return FALSE;
/* Parse command line arguments */
OPTIONS_ParseOptions( !info_size ? argv : NULL );
/* <hack: to be changed later on> */
build_initial_environment();
process_pmts.CurrentDirectoryName.Length = 3 * sizeof(WCHAR);
process_pmts.CurrentDirectoryName.MaximumLength = RtlGetLongestNtPathLength() * sizeof(WCHAR);
process_pmts.CurrentDirectoryName.Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, process_pmts.CurrentDirectoryName.MaximumLength);
process_pmts.CurrentDirectoryName.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, process_pmts.CurrentDirectoryName.MaximumLength);
process_pmts.CurrentDirectoryName.Buffer[0] = 'C';
process_pmts.CurrentDirectoryName.Buffer[1] = ':';
process_pmts.CurrentDirectoryName.Buffer[2] = '\\';
@ -579,7 +563,7 @@ void __wine_process_init( int argc, char *argv[] )
found:
/* build command line */
if (!ENV_BuildCommandLine( argv )) goto error;
if (!build_command_line( argv )) goto error;
/* create 32-bit module for main exe */
if (!(current_process.module = BUILTIN32_LoadExeModule( current_process.module ))) goto error;
@ -861,7 +845,7 @@ static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCST
int execfd[2];
pid_t pid;
int err;
char dummy;
char dummy = 0;
if (!env)
{
@ -1404,7 +1388,8 @@ BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
*/
DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
{
DWORD x, y;
DWORD x, y;
STARTUPINFOW siw;
TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
@ -1435,30 +1420,36 @@ DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
return (DWORD)&current_process;
case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
return (DWORD)current_startupinfo.hStdOutput;
GetStartupInfoW(&siw);
return (DWORD)siw.hStdOutput;
case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
return (DWORD)current_startupinfo.hStdInput;
GetStartupInfoW(&siw);
return (DWORD)siw.hStdInput;
case GPD_STARTF_SHOWWINDOW:
return current_startupinfo.wShowWindow;
GetStartupInfoW(&siw);
return siw.wShowWindow;
case GPD_STARTF_SIZE:
x = current_startupinfo.dwXSize;
GetStartupInfoW(&siw);
x = siw.dwXSize;
if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
y = current_startupinfo.dwYSize;
y = siw.dwYSize;
if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
return MAKELONG( x, y );
case GPD_STARTF_POSITION:
x = current_startupinfo.dwX;
GetStartupInfoW(&siw);
x = siw.dwX;
if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
y = current_startupinfo.dwY;
y = siw.dwY;
if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
return MAKELONG( x, y );
case GPD_STARTF_FLAGS:
return current_startupinfo.dwFlags;
GetStartupInfoW(&siw);
return process_pmts.dwFlags;
case GPD_PARENT:
return 0;