mainly:
- it fixes 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 PROCESS_PARAMETERS structure.
- later on in process creation, those parameters are copied into STARTUPINFO shadow structure
- later modification to those paramters are now reflected to the PROCESS_PARAMETER structure (and STARTUPINFO is kept untouched) (for example, StdHandle setting) (Win 2k behaves like this)
- ENVDB handling has been moved to scheduler/process.c (it had merely nothing to do with environment)
- command line inheritance (from unix command line) is now purely in ntdll
- renamed RTL_USER_PROCESS_PARAMETERS into PROCESS_PARAMETERS (most of internet sources of information use the later form)
bad side effects & open question:
- we somehow no longer really use the ENVDB structure, so I really wonder if we should keep it around (are there really win32 programs relying on it ??)
- access to PROCESS_PARAMETERS from kernel32: currently this is done by exporting a function pointer from ntdll, but this is not a good solution IMO. Should we better: 1/ create a real PEB and store it at its real offset. 2/ store the pointer to PROCESS_PARAMETER in the PDB (even if it doesn't exist in PDB but in PEB) at an unused offset (I don't think it's really doable to merge PDB and PEB, or we'll have to trash PDB.exit_code)
- we no longer can provide a decent access to 16 bit environment block: mainly because the environment reference block is stored as unicode. Current code recreates a new 16 bit environment each time the environment is modified. However, this suffers from several issues: 1/ it's rather costly, 2/ it won't work when environment is modified thru ntdll APIs 3/ it won't work if the app modifies its own 16 bit environment. I wonder if current code is sufficient or not.
good side effects:
- fixed a bug in process creation when passing handles to the child, but asking the child to be detached from the console. in this case the handles weren't correctly passed. this is now fixed
- silenced a valgrind warning in process creation
- a few more kernel32 environment tests now pass
the patch also includes some modification to the environment tests (ntdll & kernel)
A+ -- Eric Pouech
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel24/kernel_main.c dlls/kernel/kernel_main.c --- dlls/kernel24/kernel_main.c 2003-05-13 19:29:57.000000000 +0200 +++ dlls/kernel/kernel_main.c 2003-05-18 15:35:19.000000000 +0200 @@ -168,6 +168,14 @@ 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); diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel24/tests/environ.c dlls/kernel/tests/environ.c --- dlls/kernel24/tests/environ.c 2002-12-19 22:06:52.000000000 +0100 +++ dlls/kernel/tests/environ.c 2003-05-16 22:41:03.000000000 +0200 @@ -141,9 +141,8 @@ lstrcpyW(buf, fooW); ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value)); - todo_wine { - ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer"); - }; + ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer"); + ok(ret_size == lstrlenW(value) + 1, "should return length with terminating 0 ret_size=%ld", ret_size); @@ -190,10 +189,7 @@ ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND, "should not find variable but ret_size=%ld GetLastError=%ld", ret_size, GetLastError()); - - todo_wine { - ok(lstrcmpW(buf, empty_strW) == 0, "should copy an empty string"); - }; + ok(lstrcmpW(buf, empty_strW) == 0, "should copy an empty string"); /* Test the limits */ ret_size = GetEnvironmentVariableW(NULL, NULL, 0); diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll24/env.c dlls/ntdll/env.c --- dlls/ntdll24/env.c 2003-05-13 19:30:01.000000000 +0200 +++ dlls/ntdll/env.c 2003-05-18 18:37:01.000000000 +0200 @@ -130,6 +130,7 @@ 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 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 @@ strcatW(p, equalW); strcatW(p, value->Buffer); } - done: if (!penv) RtlReleasePebLock(); @@ -256,18 +258,23 @@ * 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 @@ } } - 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 @@ * * 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 @@ /* 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,264 @@ } *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_ARAMETERS 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; + 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; + + RtlAcquirePebLock(); + + rupp = ntdll_get_process_pmts(); + + /* store the filename */ + len = min( info.filename_len, main_exe_size-1 ); + memcpy( main_exe_name, src, len ); + main_exe_name[len] = 0; + + 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; + + RtlReleasePebLock(); + + 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; + 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; +} + + diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll24/ntdll_misc.h dlls/ntdll/ntdll_misc.h --- dlls/ntdll24/ntdll_misc.h 2003-05-08 10:25:00.000000000 +0200 +++ dlls/ntdll/ntdll_misc.h 2003-05-18 11:09:07.000000000 +0200 @@ -40,59 +40,9 @@ FARPROC origfun, DWORD ordinal ); extern void RELAY_SetupDLL( const char *module ); -typedef struct RTL_DRIVE_LETTER_CURDIR -{ - USHORT Flags; - USHORT Length; - ULONG TimeStamp; - UNICODE_STRING DosPath; -} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; - -typedef struct _RTL_USER_PROCESS_PARAMETERS -{ - ULONG AllocationSize; - ULONG Size; - ULONG Flags; - ULONG DebugFlags; - HANDLE hConsole; - ULONG ProcessGroup; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - UNICODE_STRING CurrentDirectoryName; - HANDLE CurrentDirectoryHandle; - UNICODE_STRING DllPath; - UNICODE_STRING ImagePathName; - UNICODE_STRING CommandLine; - PWSTR Environment; - ULONG dwX; - ULONG dwY; - ULONG dwXSize; - ULONG dwYSize; - ULONG dwXCountChars; - ULONG dwYCountChars; - ULONG dwFillAttribute; - ULONG dwFlags; - ULONG wShowWindow; - UNICODE_STRING WindowTitle; - UNICODE_STRING DesktopInfo; - UNICODE_STRING ShellInfo; - UNICODE_STRING RuntimeInfo; - RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; -} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; - static inline HANDLE ntdll_get_process_heap(void) { HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process; return pdb[0x18 / sizeof(HANDLE)]; /* get dword at offset 0x18 in pdb */ } - -/* 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; -} #endif diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll24/ntdll.spec dlls/ntdll/ntdll.spec --- dlls/ntdll24/ntdll.spec 2003-05-15 19:32:26.000000000 +0200 +++ dlls/ntdll/ntdll.spec 2003-05-18 11:22:14.000000000 +0200 @@ -1073,3 +1073,4 @@ # Wine dll separation hacks, these will go away, don't use them # @ cdecl VIRTUAL_SetFaultHandler(ptr ptr ptr) +@ cdecl ntdll_get_process_pmts() diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll24/tests/env.c dlls/ntdll/tests/env.c --- dlls/ntdll24/tests/env.c 2003-05-13 19:30:02.000000000 +0200 +++ dlls/ntdll/tests/env.c 2003-05-16 21:57:37.000000000 +0200 @@ -48,6 +48,7 @@ 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',0, '=','o','O','H','=','I','I','I',0, + 'n','u','l','=',0, 0}; static void testQuery(void) @@ -77,6 +78,7 @@ {"sr", 256, STATUS_SUCCESS, "an=ouo"}, {"=oOH", 256, STATUS_SUCCESS, "III"}, {"", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, + {"nul", 256, STATUS_SUCCESS, ""}, {NULL, 0, 0, NULL} }; diff -u -N -r -x '*~' -x '.#*' -x CVS include24/winternl.h include/winternl.h --- include24/winternl.h 2003-05-15 19:34:06.000000000 +0200 +++ include/winternl.h 2003-05-18 14:34:13.000000000 +0200 @@ -588,6 +588,47 @@ PVOID pDebugInfo; } RTL_RWLOCK, *LPRTL_RWLOCK; +typedef struct RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct _PROCESS_PARAMETERS +{ + ULONG AllocationSize; + ULONG Size; + ULONG Flags; + ULONG DebugFlags; + HANDLE hConsole; + ULONG ProcessGroup; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + UNICODE_STRING CurrentDirectoryName; + HANDLE CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PWSTR Environment; + ULONG dwX; + ULONG dwY; + ULONG dwXSize; + ULONG dwYSize; + ULONG dwXCountChars; + ULONG dwYCountChars; + ULONG dwFillAttribute; + ULONG dwFlags; + ULONG wShowWindow; + UNICODE_STRING WindowTitle; + UNICODE_STRING Desktop; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeInfo; + RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; +} PROCESS_PARAMETERS, *PPROCESS_PARAMETERS; + /* System Information Class 0x00 */ typedef struct _SYSTEM_BASIC_INFORMATION { #ifdef __WINESRC__ @@ -1309,6 +1350,9 @@ NTSTATUS WINAPI LdrUnloadDll(HMODULE); NTSTATUS WINAPI LdrUnlockLoaderLock(ULONG,ULONG); +/* tempory hack until we come up with a real PEB */ +PROCESS_PARAMETERS* ntdll_get_process_pmts(void); + #ifdef __cplusplus } /* extern "C" */ #endif /* defined(__cplusplus) */ diff -u -N -r -x '*~' -x '.#*' -x CVS memory24/environ.c memory/environ.c --- memory24/environ.c 2003-05-15 20:26:54.000000000 +0200 +++ memory/environ.c 2003-05-18 18:46:43.000000000 +0200 @@ -23,6 +23,7 @@ #include <stdlib.h> #include <string.h> +#include <assert.h> #include "windef.h" #include "winerror.h" @@ -33,27 +34,13 @@ #include "heap.h" #include "winternl.h" #include "selectors.h" +#include "wine/debug.h" -/* Win32 process environment database */ -typedef struct _ENVDB -{ - LPSTR env; /* 00 Process environment strings */ - DWORD unknown1; /* 04 Unknown */ - LPSTR cmd_line; /* 08 Command line */ - LPSTR cur_dir; /* 0c Current directory */ - STARTUPINFOA *startup_info; /* 10 Startup information */ - HANDLE hStdin; /* 14 Handle for standard input */ - HANDLE hStdout; /* 18 Handle for standard output */ - HANDLE hStderr; /* 1c Handle for standard error */ - DWORD unknown2; /* 20 Unknown */ - DWORD inherit_console; /* 24 Inherit console flag */ - DWORD break_type; /* 28 Console events flag */ - void *break_sem; /* 2c SetConsoleCtrlHandler semaphore */ - void *break_event; /* 30 SetConsoleCtrlHandler event */ - void *break_thread; /* 34 SetConsoleCtrlHandler thread */ - void *break_handlers; /* 38 List of console handlers */ -} ENVDB; +WINE_DEFAULT_DEBUG_CHANNEL(environ); +/* TODO: + * - 16 bit environment ??? (see generate_env_block16 for the details) + */ /* Format of an environment block: * ASCIIZ string 1 (xx=yy format) @@ -67,386 +54,61 @@ * - contrary to Microsoft docs, the environment strings do not appear * to be sorted on Win95 (although they are on NT); so we don't bother * to sort them either. + * - on Win2K (and likely most of NT versions) the last part (WORD 1 and + * program name no longer appear in the environment block (from the 32 + * bit interface) */ static const char ENV_program_name[] = "C:\\WINDOWS\\SYSTEM\\KRNL386.EXE"; +static STARTUPINFOW startup_infoW; +static STARTUPINFOA startup_infoA; + /* Maximum length of a Win16 environment string (including NULL) */ #define MAX_WIN16_LEN 128 -STARTUPINFOA current_startupinfo = -{ - sizeof(STARTUPINFOA), /* cb */ - 0, /* lpReserved */ - 0, /* lpDesktop */ - 0, /* lpTitle */ - 0, /* dwX */ - 0, /* dwY */ - 0, /* dwXSize */ - 0, /* dwYSize */ - 0, /* dwXCountChars */ - 0, /* dwYCountChars */ - 0, /* dwFillAttribute */ - 0, /* dwFlags */ - 0, /* wShowWindow */ - 0, /* cbReserved2 */ - 0, /* lpReserved2 */ - 0, /* hStdInput */ - 0, /* hStdOutput */ - 0 /* hStdError */ -}; - -ENVDB current_envdb = -{ - 0, /* environ */ - 0, /* unknown1 */ - 0, /* cmd_line */ - 0, /* cur_dir */ - ¤t_startupinfo, /* startup_info */ - 0, /* hStdin */ - 0, /* hStdout */ - 0, /* hStderr */ - 0, /* unknown2 */ - 0, /* inherit_console */ - 0, /* break_type */ - 0, /* break_sem */ - 0, /* break_event */ - 0, /* break_thread */ - 0 /* break_handlers */ -}; - - -static WCHAR *cmdlineW; /* Unicode command line */ -static WORD env_sel; /* selector to the environment */ - -/*********************************************************************** - * ENV_FindVariable - * - * Find a variable in the environment and return a pointer to the value. - * Helper function for GetEnvironmentVariable and ExpandEnvironmentStrings. - */ -static LPCSTR ENV_FindVariable( LPCSTR env, LPCSTR name, INT len ) -{ - while (*env) - { - if (!strncasecmp( name, env, len ) && (env[len] == '=')) - return env + len + 1; - env += strlen(env) + 1; - } - return NULL; -} - - -/*********************************************************************** - * build_environment - * - * Build the environment for the initial process - */ -static BOOL build_environment(void) -{ - extern char **environ; - static const WORD one = 1; - LPSTR p, *e; - int size; - - /* Compute the total size of the Unix environment */ - - size = sizeof(BYTE) + sizeof(WORD) + sizeof(ENV_program_name); - for (e = environ; *e; e++) - { - if (!memcmp( *e, "PATH=", 5 )) continue; - size += strlen(*e) + 1; - } - - /* Now allocate the environment */ - - if (!(p = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; - current_envdb.env = p; - env_sel = SELECTOR_AllocBlock( p, 0x10000, WINE_LDT_FLAGS_DATA ); - - /* And fill it with the Unix environment */ - - for (e = environ; *e; e++) - { - /* skip Unix PATH and store WINEPATH as PATH */ - if (!memcmp( *e, "PATH=", 5 )) continue; - if (!memcmp( *e, "WINEPATH=", 9 )) strcpy( p, *e + 4 ); - else strcpy( p, *e ); - p += strlen(p) + 1; - } - - /* Now add the program name */ - - *p++ = 0; - memcpy( p, &one, sizeof(WORD) ); - strcpy( p + sizeof(WORD), ENV_program_name ); - return TRUE; -} - - -/*********************************************************************** - * copy_str - * - * Small helper for ENV_InitStartupInfo. - */ -inline static char *copy_str( char **dst, const char **src, size_t len ) -{ - char *ret; - - if (!len) return NULL; - ret = *dst; - memcpy( ret, *src, len ); - ret[len] = 0; - *dst += len + 1; - *src += len; - return ret; -} - - -/*********************************************************************** - * ENV_InitStartupInfo - * - * Fill the startup info structure from the server. - */ -ENVDB *ENV_InitStartupInfo( size_t info_size, char *main_exe_name, size_t main_exe_size ) -{ - startup_info_t info; - void *data; - char *dst; - const char *src; - size_t len; - - if (!build_environment()) return NULL; - if (!info_size) return ¤t_envdb; /* nothing to retrieve */ +static WORD env_sel; /* selector to the 16 bit environment */ - if (!(data = HeapAlloc( GetProcessHeap(), 0, info_size ))) return NULL; - - 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 */ - if (info.filename_len) - { - len = min( info.filename_len, main_exe_size-1 ); - memcpy( main_exe_name, src, len ); - main_exe_name[len] = 0; - src += info.filename_len; - } - - /* copy the other strings */ - len = info.cmdline_len + info.desktop_len + info.title_len; - if (len && (dst = HeapAlloc( GetProcessHeap(), 0, len + 3 ))) - { - current_envdb.cmd_line = copy_str( &dst, &src, info.cmdline_len ); - current_startupinfo.lpDesktop = copy_str( &dst, &src, info.desktop_len ); - current_startupinfo.lpTitle = copy_str( &dst, &src, info.title_len ); - } - - current_startupinfo.dwX = info.x; - current_startupinfo.dwY = info.y; - current_startupinfo.dwXSize = info.cx; - current_startupinfo.dwYSize = info.cy; - current_startupinfo.dwXCountChars = info.x_chars; - current_startupinfo.dwYCountChars = info.y_chars; - current_startupinfo.dwFillAttribute = info.attribute; - current_startupinfo.wShowWindow = info.cmd_show; - current_startupinfo.dwFlags = info.flags; - done: - HeapFree( GetProcessHeap(), 0, data ); - return ¤t_envdb; -} - - - -/*********************************************************************** - * 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; - - for (argc = 0; argv[argc]; argc++) - total += MultiByteToWideChar( CP_ACP, 0, argv[argc], -1, NULL, 0 ); - - wargv = HeapAlloc( GetProcessHeap(), 0, - total * sizeof(WCHAR) + (argc + 1) * sizeof(*wargv) ); - p = (WCHAR *)(wargv + argc + 1); - for (argc = 0; argv[argc]; argc++) - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, argv[argc], -1, p, total ); - wargv[argc] = p; - p += len; - total -= len; - } - wargv[argc] = NULL; - - __wine_main_argc = argc; - __wine_main_argv = argv; - __wine_main_wargv = wargv; -} - - -/*********************************************************************** - * ENV_BuildCommandLine - * - * Build the command line of a process from the argv array. +/****************************************************************** + * generate_env_block16 * - * Note that it does NOT necessarily include the file name. - * Sometimes we don't even have any command line options at all. + * This internal function generates a suitable environment for the 16 bit + * subsystem and returns the value as a segmented pointer. * - * 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 ENV_BuildCommandLine( char **argv ) -{ - int len; - char *p, **arg; - - set_library_argv( argv ); - - if (current_envdb.cmd_line) goto done; /* 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 */ - } + * FIXME: current implementation will allocate a private copy of the + * environment strings, but will not follow the modifications (if any) + * from the unicode env block stored in the PEB + * => how should this be updated from the ntdll modifications ? + * should we use the peb->EnvironmentUpdateCount field to + * know when environment has changed ??? + * we currently regenerate this block each time an environment + * variable is modified from a Win32 API call, but we'll miss all + * direct access to the NTDLL APIs + */ +static SEGPTR generate_env_block16(void) +{ + static LPSTR env16; + + DWORD size, new_size; + WORD one = 1; + + if (env16) FreeEnvironmentStringsA( env16 ); + + env16 = GetEnvironmentStringsA(); + size = HeapSize(GetProcessHeap(), 0, env16); + new_size = size + sizeof(WORD) + sizeof(ENV_program_name); + if (!(env16 = HeapReAlloc( GetProcessHeap(), 0, env16, new_size ))) return 0; + + memcpy(env16 + size, &one, sizeof(one)); + memcpy(env16 + size + sizeof(WORD), ENV_program_name, sizeof(ENV_program_name)); + if (env_sel) + env_sel = SELECTOR_ReallocBlock( env_sel, env16, new_size ); + else + env_sel = SELECTOR_AllocBlock( env16, 0x10000, WINE_LDT_FLAGS_DATA ); - if (!(current_envdb.cmd_line = HeapAlloc( GetProcessHeap(), 0, len ))) - return FALSE; - - p = current_envdb.cmd_line; - 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 { - strcpy(p,*arg); - p+=strlen(*arg); - } - if (has_space) - *p++='"'; - *p++=' '; - } - if (p > current_envdb.cmd_line) - p--; /* remove last space */ - *p = '\0'; - - /* now allocate the Unicode version */ - done: - len = MultiByteToWideChar( CP_ACP, 0, current_envdb.cmd_line, -1, NULL, 0 ); - if (!(cmdlineW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) - return FALSE; - MultiByteToWideChar( CP_ACP, 0, current_envdb.cmd_line, -1, cmdlineW, len ); - return TRUE; + return MAKESEGPTR( env_sel, 0 ); } - /*********************************************************************** * GetCommandLineA (KERNEL32.@) * @@ -467,7 +129,18 @@ */ LPSTR WINAPI GetCommandLineA(void) { - return current_envdb.cmd_line; + static char *cmdlineA; /* ASCII command line */ + + if (!cmdlineA) /* make an ansi version if we don't have it */ + { + ANSI_STRING ansi; + RtlAcquirePebLock(); + + cmdlineA = (RtlUnicodeStringToAnsiString( &ansi, &ntdll_get_process_pmts()->CommandLine, TRUE) == STATUS_SUCCESS) ? + ansi.Buffer : NULL; + RtlReleasePebLock(); + } + return cmdlineA; } /*********************************************************************** @@ -475,7 +148,7 @@ */ LPWSTR WINAPI GetCommandLineW(void) { - return cmdlineW; + return ntdll_get_process_pmts()->CommandLine.Buffer; } @@ -485,7 +158,38 @@ */ LPSTR WINAPI GetEnvironmentStringsA(void) { - return current_envdb.env; + LPWSTR ptrW; + unsigned len, slen; + LPSTR ret, ptrA; + + RtlAcquirePebLock(); + + len = 1; + + ptrW = ntdll_get_process_pmts()->Environment; + while (*ptrW) + { + slen = lstrlenW(ptrW) + 1; + len += WideCharToMultiByte( CP_ACP, 0, ptrW, slen, NULL, 0, NULL, NULL ); + ptrW += slen; + } + + if ((ret = HeapAlloc( GetProcessHeap(), 0, len )) != NULL) + { + ptrW = ntdll_get_process_pmts()->Environment; + ptrA = ret; + while (*ptrW) + { + slen = lstrlenW(ptrW) + 1; + WideCharToMultiByte( CP_ACP, 0, ptrW, slen, ptrA, len, NULL, NULL ); + ptrW += slen; + ptrA += strlen(ptrA) + 1; + } + *ptrA = 0; + } + + RtlReleasePebLock(); + return ret; } @@ -494,19 +198,7 @@ */ LPWSTR WINAPI GetEnvironmentStringsW(void) { - INT size; - LPWSTR ret; - - RtlAcquirePebLock(); - size = HeapSize( GetProcessHeap(), 0, current_envdb.env ); - if ((ret = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) )) != NULL) - { - LPSTR pA = current_envdb.env; - LPWSTR pW = ret; - while (size--) *pW++ = (WCHAR)(BYTE)*pA++; - } - RtlReleasePebLock(); - return ret; + return ntdll_get_process_pmts()->Environment; } @@ -515,12 +207,7 @@ */ BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr ) { - if (ptr != current_envdb.env) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - return TRUE; + return HeapFree( GetProcessHeap(), 0, ptr ); } @@ -529,7 +216,7 @@ */ BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr ) { - return HeapFree( GetProcessHeap(), 0, ptr ); + return TRUE; } @@ -538,30 +225,36 @@ */ DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size ) { - LPCSTR p; - INT ret = 0; + UNICODE_STRING us_name; + PWSTR valueW; + DWORD ret; if (!name || !*name) { - SetLastError( ERROR_ENVVAR_NOT_FOUND ); + SetLastError(ERROR_ENVVAR_NOT_FOUND); return 0; } - RtlAcquirePebLock(); - if ((p = ENV_FindVariable( current_envdb.env, name, strlen(name) ))) - { - ret = strlen(p); - if (size <= ret) - { - /* If not enough room, include the terminating null - * in the returned size */ - ret++; - } - else if (value) strcpy( value, p ); - } - RtlReleasePebLock(); - if (!ret) - SetLastError( ERROR_ENVVAR_NOT_FOUND ); + if (!(valueW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)))) + return 0; + + RtlCreateUnicodeStringFromAsciiz( &us_name, name ); + SetLastError(0); + ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size); + if (ret && ret < size) + { + WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL ); + } + /* this is needed to tell, with 0 as a return value, the difference between: + * - an error (GetLastError() != 0) + * - returning an empty string (in this case, we need to update the buffer) + */ + if (ret == 0 && size && GetLastError() == 0) + value[0] = '\0'; + + RtlFreeUnicodeString( &us_name ); + HeapFree(GetProcessHeap(), 0, valueW); + return ret; } @@ -569,28 +262,36 @@ /*********************************************************************** * GetEnvironmentVariableW (KERNEL32.@) */ -DWORD WINAPI GetEnvironmentVariableW( LPCWSTR nameW, LPWSTR valW, DWORD size) +DWORD WINAPI GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size ) { - LPSTR name, val; - DWORD ret; + UNICODE_STRING us_name; + UNICODE_STRING us_value; + NTSTATUS status; + unsigned len; + + TRACE("(%s %p %lu)\n", debugstr_w(name), val, size); - if (!nameW || !*nameW) + if (!name || !*name) { - SetLastError( ERROR_ENVVAR_NOT_FOUND ); + SetLastError(ERROR_ENVVAR_NOT_FOUND); return 0; } - name = HEAP_strdupWtoA( GetProcessHeap(), 0, nameW ); - val = valW ? HeapAlloc( GetProcessHeap(), 0, size ) : NULL; - ret = GetEnvironmentVariableA( name, val, size ); - if (ret && val) + RtlInitUnicodeString(&us_name, name); + us_value.Length = 0; + us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR); + us_value.Buffer = val; + + status = RtlQueryEnvironmentVariable_U(NULL, &us_name, &us_value); + len = us_value.Length / sizeof(WCHAR); + if (status != STATUS_SUCCESS) { - if (size && !MultiByteToWideChar( CP_ACP, 0, val, -1, valW, size )) - valW[size-1] = 0; + SetLastError( RtlNtStatusToDosError(status) ); + return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0; } - HeapFree( GetProcessHeap(), 0, name ); - if (val) HeapFree( GetProcessHeap(), 0, val ); - return ret; + if (size) val[len] = '\0'; + + return us_value.Length / sizeof(WCHAR); } @@ -599,59 +300,28 @@ */ BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value ) { - INT old_size, len, res; - LPSTR p, env, new_env; - BOOL ret = FALSE; + UNICODE_STRING us_name; + BOOL ret; - if (!name || !*name) + if (!name) { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; + SetLastError(ERROR_ENVVAR_NOT_FOUND); + return 0; } - RtlAcquirePebLock(); - env = p = current_envdb.env; - - /* Find a place to insert the string */ - - res = -1; - len = strlen(name); - while (*p) + RtlCreateUnicodeStringFromAsciiz( &us_name, name ); + if (value) { - if (!strncasecmp( name, p, len ) && (p[len] == '=')) break; - p += strlen(p) + 1; - } - if (!value && !*p) goto done; /* Value to remove doesn't exist */ - - /* Realloc the buffer */ + UNICODE_STRING us_value; - len = value ? strlen(name) + strlen(value) + 2 : 0; - if (*p) len -= strlen(p) + 1; /* The name already exists */ - old_size = HeapSize( GetProcessHeap(), 0, env ); - if (len < 0) - { - LPSTR next = p + strlen(p) + 1; /* We know there is a next one */ - memmove( next + len, next, old_size - (next - env) ); + RtlCreateUnicodeStringFromAsciiz( &us_value, value ); + ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer ); + RtlFreeUnicodeString( &us_value ); } - if (!(new_env = HeapReAlloc( GetProcessHeap(), 0, env, old_size + len ))) - goto done; - if (env_sel) env_sel = SELECTOR_ReallocBlock( env_sel, new_env, old_size + len ); - p = new_env + (p - env); - if (len > 0) memmove( p + len, p, old_size - (p - new_env) ); - - /* Set the new string */ + else ret = SetEnvironmentVariableW( us_name.Buffer, NULL ); - if (value) - { - strcpy( p, name ); - strcat( p, "=" ); - strcat( p, value ); - } - current_envdb.env = new_env; - ret = TRUE; + RtlFreeUnicodeString( &us_name ); -done: - RtlReleasePebLock(); return ret; } @@ -661,12 +331,36 @@ */ BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value ) { - LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name ); - LPSTR valueA = HEAP_strdupWtoA( GetProcessHeap(), 0, value ); - BOOL ret = SetEnvironmentVariableA( nameA, valueA ); - HeapFree( GetProcessHeap(), 0, nameA ); - HeapFree( GetProcessHeap(), 0, valueA ); - return ret; + UNICODE_STRING us_name; + NTSTATUS status; + + TRACE("(%s %s)\n", debugstr_w(name), debugstr_w(value)); + + if (!name) + { + SetLastError(ERROR_ENVVAR_NOT_FOUND); + return 0; + } + + RtlInitUnicodeString(&us_name, name); + if (value) + { + UNICODE_STRING us_value; + + RtlInitUnicodeString(&us_value, value); + status = RtlSetEnvironmentVariable(NULL, &us_name, &us_value); + } + else status = RtlSetEnvironmentVariable(NULL, &us_name, NULL); + + if (status != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; + } + + /* FIXME: see comments in generate_env_block16 */ + if (env_sel) generate_env_block16(); + return TRUE; } @@ -677,63 +371,25 @@ */ DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count ) { - DWORD len, total_size = 1; /* 1 for terminating '\0' */ - LPCSTR p, var; - - if (!count) dst = NULL; - RtlAcquirePebLock(); - - while (*src) - { - if (*src != '%') - { - if ((p = strchr( src, '%' ))) len = p - src; - else len = strlen(src); - var = src; - src += len; - } - else /* we are at the start of a variable */ - { - if ((p = strchr( src + 1, '%' ))) - { - len = p - src - 1; /* Length of the variable name */ - if ((var = ENV_FindVariable( current_envdb.env, src + 1, len ))) - { - src += len + 2; /* Skip the variable name */ - len = strlen(var); - } - else - { - var = src; /* Copy original name instead */ - len += 2; - src += len; - } - } - else /* unfinished variable name, ignore it */ - { - var = src; - len = strlen(src); /* Copy whole string */ - src += len; - } - } - total_size += len; - if (dst) - { - if (count < len) len = count; - memcpy( dst, var, len ); - dst += len; - count -= len; - } - } - RtlReleasePebLock(); + UNICODE_STRING us_src; + PWSTR dstW = NULL; + DWORD ret; + + RtlCreateUnicodeStringFromAsciiz( &us_src, src ); + if (count) + { + if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR)))) + return 0; + ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count); + if (ret) + WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL ); + } + else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0); + + RtlFreeUnicodeString( &us_src ); + if (dstW) HeapFree(GetProcessHeap(), 0, dstW); - /* Null-terminate the string */ - if (dst) - { - if (!count) dst--; - *dst = '\0'; - } - return total_size; + return ret; } @@ -742,16 +398,29 @@ */ DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len ) { - LPSTR srcA = HEAP_strdupWtoA( GetProcessHeap(), 0, src ); - LPSTR dstA = dst ? HeapAlloc( GetProcessHeap(), 0, len ) : NULL; - DWORD ret = ExpandEnvironmentStringsA( srcA, dstA, len ); - if (dstA) + UNICODE_STRING us_src; + UNICODE_STRING us_dst; + NTSTATUS status; + DWORD res; + + TRACE("(%s %p %lu)\n", debugstr_w(src), dst, len); + + RtlInitUnicodeString(&us_src, src); + us_dst.Length = 0; + us_dst.MaximumLength = len * sizeof(WCHAR); + us_dst.Buffer = dst; + + res = 0; + status = RtlExpandEnvironmentStrings_U(NULL, &us_src, &us_dst, &res); + res /= sizeof(WCHAR); + if (status != STATUS_SUCCESS) { - ret = MultiByteToWideChar( CP_ACP, 0, dstA, -1, dst, len ); - HeapFree( GetProcessHeap(), 0, dstA ); + SetLastError( RtlNtStatusToDosError(status) ); + if (status != STATUS_BUFFER_TOO_SMALL) return 0; + if (len && dst) dst[len - 1] = '\0'; } - HeapFree( GetProcessHeap(), 0, srcA ); - return ret; + + return res; } @@ -760,7 +429,7 @@ */ SEGPTR WINAPI GetDOSEnvironment16(void) { - return MAKESEGPTR( env_sel, 0 ); + return generate_env_block16(); } @@ -769,11 +438,11 @@ */ HANDLE WINAPI GetStdHandle( DWORD std_handle ) { - switch(std_handle) + switch (std_handle) { - case STD_INPUT_HANDLE: return current_envdb.hStdin; - case STD_OUTPUT_HANDLE: return current_envdb.hStdout; - case STD_ERROR_HANDLE: return current_envdb.hStderr; + case STD_INPUT_HANDLE: return ntdll_get_process_pmts()->hStdInput; + case STD_OUTPUT_HANDLE: return ntdll_get_process_pmts()->hStdOutput; + case STD_ERROR_HANDLE: return ntdll_get_process_pmts()->hStdError; } SetLastError( ERROR_INVALID_PARAMETER ); return INVALID_HANDLE_VALUE; @@ -785,23 +454,23 @@ */ BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle ) { - switch(std_handle) + switch (std_handle) { - case STD_INPUT_HANDLE: current_envdb.hStdin = handle; return TRUE; - case STD_OUTPUT_HANDLE: current_envdb.hStdout = handle; return TRUE; - case STD_ERROR_HANDLE: current_envdb.hStderr = handle; return TRUE; + case STD_INPUT_HANDLE: ntdll_get_process_pmts()->hStdInput = handle; return TRUE; + case STD_OUTPUT_HANDLE: ntdll_get_process_pmts()->hStdOutput = handle; return TRUE; + case STD_ERROR_HANDLE: ntdll_get_process_pmts()->hStdError = handle; return TRUE; } SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } - /*********************************************************************** * GetStartupInfoA (KERNEL32.@) */ VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info ) { - *info = current_startupinfo; + assert(startup_infoA.cb); + memcpy(info, &startup_infoA, sizeof(startup_infoA)); } @@ -810,25 +479,67 @@ */ VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info ) { - UNICODE_STRING usBuffer; - info->cb = sizeof(STARTUPINFOW); - info->dwX = current_startupinfo.dwX; - info->dwY = current_startupinfo.dwY; - info->dwXSize = current_startupinfo.dwXSize; - info->dwXCountChars = current_startupinfo.dwXCountChars; - info->dwYCountChars = current_startupinfo.dwYCountChars; - info->dwFillAttribute = current_startupinfo.dwFillAttribute; - info->dwFlags = current_startupinfo.dwFlags; - info->wShowWindow = current_startupinfo.wShowWindow; - info->cbReserved2 = current_startupinfo.cbReserved2; - info->lpReserved2 = current_startupinfo.lpReserved2; - info->hStdInput = current_startupinfo.hStdInput; - info->hStdOutput = current_startupinfo.hStdOutput; - info->hStdError = current_startupinfo.hStdError; - RtlCreateUnicodeStringFromAsciiz (&usBuffer,current_startupinfo.lpReserved); - info->lpReserved = usBuffer.Buffer; - RtlCreateUnicodeStringFromAsciiz (&usBuffer,current_startupinfo.lpDesktop); - info->lpDesktop = usBuffer.Buffer; - RtlCreateUnicodeStringFromAsciiz (&usBuffer,current_startupinfo.lpTitle); - info->lpTitle = usBuffer.Buffer; + assert(startup_infoW.cb); + memcpy(info, &startup_infoW, sizeof(startup_infoW)); +} + +/****************************************************************** + * ENV_CopyStartupInformation (internal) + * + * Creates the STARTUPINFO information from the ntdll information + */ +STARTUPINFOA* ENV_CopyStartupInformation(void) +{ + PROCESS_PARAMETERS* rupp; + ANSI_STRING ansi; + + RtlAcquirePebLock(); + + rupp = ntdll_get_process_pmts(); + + startup_infoW.cb = sizeof(startup_infoW); + startup_infoW.lpReserved = NULL; + startup_infoW.lpDesktop = rupp->Desktop.Buffer; + startup_infoW.lpTitle = rupp->WindowTitle.Buffer; + startup_infoW.dwX = rupp->dwX; + startup_infoW.dwY = rupp->dwY; + startup_infoW.dwXSize = rupp->dwXSize; + startup_infoW.dwYSize = rupp->dwYSize; + startup_infoW.dwXCountChars = rupp->dwXCountChars; + startup_infoW.dwYCountChars = rupp->dwYCountChars; + startup_infoW.dwFillAttribute = rupp->dwFillAttribute; + startup_infoW.dwFlags = rupp->dwFlags; + startup_infoW.wShowWindow = rupp->wShowWindow; + startup_infoW.cbReserved2 = 0; + startup_infoW.lpReserved2 = NULL; + startup_infoW.hStdInput = rupp->hStdInput; + startup_infoW.hStdOutput = rupp->hStdOutput; + startup_infoW.hStdError = rupp->hStdError; + + startup_infoA.cb = sizeof(startup_infoW); + startup_infoA.lpReserved = NULL; + startup_infoA.lpDesktop = (rupp->Desktop.Length && + RtlUnicodeStringToAnsiString( &ansi, &rupp->Desktop, TRUE) == STATUS_SUCCESS) ? + ansi.Buffer : NULL; + startup_infoA.lpTitle = (rupp->WindowTitle.Length && + RtlUnicodeStringToAnsiString( &ansi, &rupp->WindowTitle, TRUE) == STATUS_SUCCESS) ? + ansi.Buffer : NULL; + startup_infoA.dwX = rupp->dwX; + startup_infoA.dwY = rupp->dwY; + startup_infoA.dwXSize = rupp->dwXSize; + startup_infoA.dwYSize = rupp->dwYSize; + startup_infoA.dwXCountChars = rupp->dwXCountChars; + startup_infoA.dwYCountChars = rupp->dwYCountChars; + startup_infoA.dwFillAttribute = rupp->dwFillAttribute; + startup_infoA.dwFlags = rupp->dwFlags; + startup_infoA.wShowWindow = rupp->wShowWindow; + startup_infoA.cbReserved2 = 0; + startup_infoA.lpReserved2 = NULL; + startup_infoA.hStdInput = rupp->hStdInput; + startup_infoA.hStdOutput = rupp->hStdOutput; + startup_infoA.hStdError = rupp->hStdError; + + RtlReleasePebLock(); + + return &startup_infoA; } diff -u -N -r -x '*~' -x '.#*' -x CVS scheduler24/process.c scheduler/process.c --- scheduler24/process.c 2003-05-17 11:29:13.000000000 +0200 +++ scheduler/process.c 2003-05-18 17:59:21.000000000 +0200 @@ -53,7 +53,25 @@ WINE_DECLARE_DEBUG_CHANNEL(snoop); WINE_DECLARE_DEBUG_CHANNEL(win32); -struct _ENVDB; +/* Win32 process environment database */ +typedef struct _ENVDB +{ + LPSTR env; /* 00 Process environment strings */ + DWORD unknown1; /* 04 Unknown */ + LPSTR cmd_line; /* 08 Command line */ + LPSTR cur_dir; /* 0c Current directory */ + STARTUPINFOA *startup_info; /* 10 Startup information */ + HANDLE hStdin; /* 14 Handle for standard input */ + HANDLE hStdout; /* 18 Handle for standard output */ + HANDLE hStderr; /* 1c Handle for standard error */ + DWORD unknown2; /* 20 Unknown */ + DWORD inherit_console; /* 24 Inherit console flag */ + DWORD break_type; /* 28 Console events flag */ + void *break_sem; /* 2c SetConsoleCtrlHandler semaphore */ + void *break_event; /* 30 SetConsoleCtrlHandler event */ + void *break_thread; /* 34 SetConsoleCtrlHandler thread */ + void *break_handlers; /* 38 List of console handlers */ +} ENVDB; /* Win32 process database */ typedef struct _PDB @@ -105,9 +123,15 @@ LCID locale; /* c4 Locale to be queried by GetThreadLocale (NT) */ } PDB; +static ENVDB current_envdb; + PDB current_process; -RTL_USER_PROCESS_PARAMETERS process_pmts; +static PROCESS_PARAMETERS process_pmts; +PROCESS_PARAMETERS* ntdll_get_process_pmts(void) +{ + return &process_pmts; +} /* Process flags */ #define PDB32_DEBUGGED 0x0001 /* Process is being debugged */ @@ -125,14 +149,15 @@ 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; +STARTUPINFOA* ENV_CopyStartupInformation(void); /* scheduler/pthread.c */ extern void PTHREAD_init_done(void); +/* dlls/ntdll/env.c */ +extern BOOL init_user_process_pmts( size_t info_size, char *main_exe_name, size_t main_exe_size ); +extern BOOL build_command_line( char **argv ); + extern void RELAY_InitDebugLists(void); extern BOOL MAIN_MainInit(void); extern void VERSION_Init( const char *appname ); @@ -302,6 +327,7 @@ current_process.ring0_threads = 1; current_process.group = ¤t_process; current_process.priority = 8; /* Normal */ + current_process.env_db = ¤t_envdb; /* Setup the server connection */ CLIENT_InitServer(); @@ -316,9 +342,9 @@ 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; @@ -328,41 +354,32 @@ 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; + current_process.env_db->startup_info = ENV_CopyStartupInformation(); + if (!current_process.env_db->startup_info) 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); @@ -563,7 +580,7 @@ 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; @@ -845,7 +862,7 @@ int execfd[2]; pid_t pid; int err; - char dummy; + char dummy = 0; if (!env) { @@ -1389,7 +1406,8 @@ */ DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset ) { - DWORD x, y; + DWORD x, y; + STARTUPINFOW siw; TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset ); @@ -1420,30 +1438,32 @@ return (DWORD)¤t_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; + return process_pmts.wShowWindow; case GPD_STARTF_SIZE: - x = current_startupinfo.dwXSize; + x = process_pmts.dwXSize; if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16; - y = current_startupinfo.dwYSize; + y = process_pmts.dwYSize; if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16; return MAKELONG( x, y ); case GPD_STARTF_POSITION: - x = current_startupinfo.dwX; + x = process_pmts.dwX; if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16; - y = current_startupinfo.dwY; + y = process_pmts.dwY; if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16; return MAKELONG( x, y ); case GPD_STARTF_FLAGS: - return current_startupinfo.dwFlags; + return process_pmts.dwFlags; case GPD_PARENT: return 0;