msvcrt: Use fpclass constants from public header.
[wine/zf.git] / dlls / ntdll / env.c
blobbf3fedcac670eb22c43ebb0f096ef03a29ceeea3
1 /*
2 * Ntdll environment functions
4 * Copyright 1996, 1998 Alexandre Julliard
5 * Copyright 2003 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <sys/types.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winternl.h"
30 #include "wine/debug.h"
31 #include "ntdll_misc.h"
32 #include "winnt.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(environ);
36 static WCHAR empty[] = {0};
37 static const UNICODE_STRING empty_str = { 0, sizeof(empty), empty };
38 static const UNICODE_STRING null_str = { 0, 0, NULL };
40 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
42 static BOOL first_prefix_start; /* first ever process start in this prefix? */
44 static inline SIZE_T get_env_length( const WCHAR *env )
46 const WCHAR *end = env;
47 while (*end) end += wcslen(end) + 1;
48 return end + 1 - env;
52 /***********************************************************************
53 * set_env_var
55 static void set_env_var( WCHAR **env, const WCHAR *name, const WCHAR *val )
57 UNICODE_STRING nameW, valW;
59 RtlInitUnicodeString( &nameW, name );
60 if (val)
62 RtlInitUnicodeString( &valW, val );
63 RtlSetEnvironmentVariable( env, &nameW, &valW );
65 else RtlSetEnvironmentVariable( env, &nameW, NULL );
69 /***********************************************************************
70 * set_registry_variables
72 * Set environment variables by enumerating the values of a key;
73 * helper for set_registry_environment().
74 * Note that Windows happily truncates the value if it's too big.
76 static void set_registry_variables( WCHAR **env, HANDLE hkey, ULONG type )
78 static const WCHAR pathW[] = {'P','A','T','H'};
79 static const WCHAR sep[] = {';',0};
80 UNICODE_STRING env_name, env_value;
81 NTSTATUS status;
82 DWORD size;
83 int index;
84 char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_FULL_INFORMATION)];
85 WCHAR tmpbuf[1024];
86 UNICODE_STRING tmp;
87 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
89 tmp.Buffer = tmpbuf;
90 tmp.MaximumLength = sizeof(tmpbuf);
92 for (index = 0; ; index++)
94 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
95 buffer, sizeof(buffer), &size );
96 if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) break;
97 if (info->Type != type) continue;
98 env_name.Buffer = info->Name;
99 env_name.Length = env_name.MaximumLength = info->NameLength;
100 env_value.Buffer = (WCHAR *)(buffer + info->DataOffset);
101 env_value.Length = info->DataLength;
102 env_value.MaximumLength = sizeof(buffer) - info->DataOffset;
103 if (env_value.Length && !env_value.Buffer[env_value.Length/sizeof(WCHAR)-1])
104 env_value.Length -= sizeof(WCHAR); /* don't count terminating null if any */
105 if (!env_value.Length) continue;
106 if (info->Type == REG_EXPAND_SZ)
108 status = RtlExpandEnvironmentStrings_U( *env, &env_value, &tmp, NULL );
109 if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue;
110 RtlCopyUnicodeString( &env_value, &tmp );
112 /* PATH is magic */
113 if (env_name.Length == sizeof(pathW) &&
114 !wcsnicmp( env_name.Buffer, pathW, ARRAY_SIZE( pathW )) &&
115 !RtlQueryEnvironmentVariable_U( *env, &env_name, &tmp ))
117 RtlAppendUnicodeToString( &tmp, sep );
118 if (RtlAppendUnicodeStringToString( &tmp, &env_value )) continue;
119 RtlCopyUnicodeString( &env_value, &tmp );
121 RtlSetEnvironmentVariable( env, &env_name, &env_value );
126 /***********************************************************************
127 * set_registry_environment
129 * Set the environment variables specified in the registry.
131 * Note: Windows handles REG_SZ and REG_EXPAND_SZ in one pass with the
132 * consequence that REG_EXPAND_SZ cannot be used reliably as it depends
133 * on the order in which the variables are processed. But on Windows it
134 * does not really matter since they only use %SystemDrive% and
135 * %SystemRoot% which are predefined. But Wine defines these in the
136 * registry, so we need two passes.
138 static BOOL set_registry_environment( WCHAR **env, BOOL first_time )
140 static const WCHAR env_keyW[] = {'\\','R','e','g','i','s','t','r','y','\\',
141 'M','a','c','h','i','n','e','\\',
142 'S','y','s','t','e','m','\\',
143 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
146 'E','n','v','i','r','o','n','m','e','n','t',0};
147 static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
148 static const WCHAR volatile_envW[] = {'V','o','l','a','t','i','l','e',' ','E','n','v','i','r','o','n','m','e','n','t',0};
150 OBJECT_ATTRIBUTES attr;
151 UNICODE_STRING nameW;
152 HANDLE hkey;
153 BOOL ret = FALSE;
155 /* first the system environment variables */
156 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
157 RtlInitUnicodeString( &nameW, env_keyW );
158 if (first_time && !NtOpenKey( &hkey, KEY_READ, &attr ))
160 set_registry_variables( env, hkey, REG_SZ );
161 set_registry_variables( env, hkey, REG_EXPAND_SZ );
162 NtClose( hkey );
164 else ret = TRUE;
166 /* then the ones for the current user */
167 if (RtlOpenCurrentUser( KEY_READ, &attr.RootDirectory ) != STATUS_SUCCESS) return ret;
168 RtlInitUnicodeString( &nameW, envW );
169 if (first_time && !NtOpenKey( &hkey, KEY_READ, &attr ))
171 set_registry_variables( env, hkey, REG_SZ );
172 set_registry_variables( env, hkey, REG_EXPAND_SZ );
173 NtClose( hkey );
176 RtlInitUnicodeString( &nameW, volatile_envW );
177 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
179 set_registry_variables( env, hkey, REG_SZ );
180 set_registry_variables( env, hkey, REG_EXPAND_SZ );
181 NtClose( hkey );
184 NtClose( attr.RootDirectory );
185 return ret;
189 /***********************************************************************
190 * get_registry_value
192 static WCHAR *get_registry_value( WCHAR *env, HKEY hkey, const WCHAR *name )
194 char buffer[1024 * sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
195 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
196 DWORD len, size = sizeof(buffer);
197 WCHAR *ret = NULL;
198 UNICODE_STRING nameW;
200 RtlInitUnicodeString( &nameW, name );
201 if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, buffer, size, &size ))
202 return NULL;
204 if (size <= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data )) return NULL;
205 len = (size - FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data )) / sizeof(WCHAR);
207 if (info->Type == REG_EXPAND_SZ)
209 UNICODE_STRING value, expanded;
211 value.MaximumLength = len * sizeof(WCHAR);
212 value.Buffer = (WCHAR *)info->Data;
213 if (!value.Buffer[len - 1]) len--; /* don't count terminating null if any */
214 value.Length = len * sizeof(WCHAR);
215 expanded.Length = expanded.MaximumLength = 1024 * sizeof(WCHAR);
216 if (!(expanded.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, expanded.MaximumLength )))
217 return NULL;
218 if (!RtlExpandEnvironmentStrings_U( env, &value, &expanded, NULL )) ret = expanded.Buffer;
219 else RtlFreeUnicodeString( &expanded );
221 else if (info->Type == REG_SZ)
223 if ((ret = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
225 memcpy( ret, info->Data, len * sizeof(WCHAR) );
226 ret[len] = 0;
229 return ret;
233 /***********************************************************************
234 * set_additional_environment
236 * Set some additional environment variables not specified in the registry.
238 static void set_additional_environment( WCHAR **env )
240 static const WCHAR profile_keyW[] = {'\\','R','e','g','i','s','t','r','y','\\',
241 'M','a','c','h','i','n','e','\\',
242 'S','o','f','t','w','a','r','e','\\',
243 'M','i','c','r','o','s','o','f','t','\\',
244 'W','i','n','d','o','w','s',' ','N','T','\\',
245 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
246 'P','r','o','f','i','l','e','L','i','s','t',0};
247 static const WCHAR computer_keyW[] = {'\\','R','e','g','i','s','t','r','y','\\',
248 'M','a','c','h','i','n','e','\\',
249 'S','y','s','t','e','m','\\',
250 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
251 'C','o','n','t','r','o','l','\\',
252 'C','o','m','p','u','t','e','r','N','a','m','e','\\',
253 'A','c','t','i','v','e','C','o','m','p','u','t','e','r','N','a','m','e',0};
254 static const WCHAR computer_valueW[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
255 static const WCHAR public_valueW[] = {'P','u','b','l','i','c',0};
256 static const WCHAR computernameW[] = {'C','O','M','P','U','T','E','R','N','A','M','E',0};
257 static const WCHAR allusersW[] = {'A','L','L','U','S','E','R','S','P','R','O','F','I','L','E',0};
258 static const WCHAR programdataW[] = {'P','r','o','g','r','a','m','D','a','t','a',0};
259 static const WCHAR publicW[] = {'P','U','B','L','I','C',0};
260 OBJECT_ATTRIBUTES attr;
261 UNICODE_STRING nameW;
262 WCHAR *val;
263 HANDLE hkey;
265 /* set the user profile variables */
267 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
268 RtlInitUnicodeString( &nameW, profile_keyW );
269 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
271 if ((val = get_registry_value( *env, hkey, programdataW )))
273 set_env_var( env, allusersW, val );
274 set_env_var( env, programdataW, val );
275 RtlFreeHeap( GetProcessHeap(), 0, val );
277 if ((val = get_registry_value( *env, hkey, public_valueW )))
279 set_env_var( env, publicW, val );
280 RtlFreeHeap( GetProcessHeap(), 0, val );
282 NtClose( hkey );
285 /* set the computer name */
287 RtlInitUnicodeString( &nameW, computer_keyW );
288 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
290 if ((val = get_registry_value( *env, hkey, computer_valueW )))
292 set_env_var( env, computernameW, val );
293 RtlFreeHeap( GetProcessHeap(), 0, val );
295 NtClose( hkey );
300 /***********************************************************************
301 * set_wow64_environment
303 * Set the environment variables that change across 32/64/Wow64.
305 static void set_wow64_environment( WCHAR **env )
307 static WCHAR archW[] = {'P','R','O','C','E','S','S','O','R','_','A','R','C','H','I','T','E','C','T','U','R','E',0};
308 static WCHAR arch6432W[] = {'P','R','O','C','E','S','S','O','R','_','A','R','C','H','I','T','E','W','6','4','3','2',0};
309 static const WCHAR x86W[] = {'x','8','6',0};
310 static const WCHAR versionW[] = {'\\','R','e','g','i','s','t','r','y','\\',
311 'M','a','c','h','i','n','e','\\',
312 'S','o','f','t','w','a','r','e','\\',
313 'M','i','c','r','o','s','o','f','t','\\',
314 'W','i','n','d','o','w','s','\\',
315 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
316 static const WCHAR progdirW[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',0};
317 static const WCHAR progdir86W[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0};
318 static const WCHAR progfilesW[] = {'P','r','o','g','r','a','m','F','i','l','e','s',0};
319 static const WCHAR progfiles86W[] = {'P','r','o','g','r','a','m','F','i','l','e','s','(','x','8','6',')',0};
320 static const WCHAR progw6432W[] = {'P','r','o','g','r','a','m','W','6','4','3','2',0};
321 static const WCHAR commondirW[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',0};
322 static const WCHAR commondir86W[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0};
323 static const WCHAR commonfilesW[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s',0};
324 static const WCHAR commonfiles86W[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s','(','x','8','6',')',0};
325 static const WCHAR commonw6432W[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','W','6','4','3','2',0};
327 WCHAR buf[256];
328 UNICODE_STRING arch_strW = { sizeof(archW) - sizeof(WCHAR), sizeof(archW), archW };
329 UNICODE_STRING arch6432_strW = { sizeof(arch6432W) - sizeof(WCHAR), sizeof(arch6432W), arch6432W };
330 UNICODE_STRING valW = { 0, sizeof(buf), buf };
331 OBJECT_ATTRIBUTES attr;
332 UNICODE_STRING nameW;
333 HANDLE hkey;
334 SIZE_T size = 1024;
335 WCHAR *ptr, *val, *p;
337 for (;;)
339 if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) break;
340 if (!unix_funcs->get_dynamic_environment( ptr, &size )) break;
341 RtlFreeHeap( GetProcessHeap(), 0, ptr );
343 for (p = ptr; *p; p += wcslen(p) + 1)
345 if ((val = wcschr( p, '=' ))) *val++ = 0;
346 set_env_var( env, p, val );
347 if (val) p = val;
349 RtlFreeHeap( GetProcessHeap(), 0, ptr );
351 /* set the PROCESSOR_ARCHITECTURE variable */
353 if (!RtlQueryEnvironmentVariable_U( *env, &arch6432_strW, &valW ))
355 if (is_win64)
357 RtlSetEnvironmentVariable( env, &arch_strW, &valW );
358 RtlSetEnvironmentVariable( env, &arch6432_strW, NULL );
361 else if (!RtlQueryEnvironmentVariable_U( *env, &arch_strW, &valW ))
363 if (is_wow64)
365 RtlSetEnvironmentVariable( env, &arch6432_strW, &valW );
366 RtlInitUnicodeString( &nameW, x86W );
367 RtlSetEnvironmentVariable( env, &arch_strW, &nameW );
371 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
372 RtlInitUnicodeString( &nameW, versionW );
373 if (NtOpenKey( &hkey, KEY_READ | KEY_WOW64_64KEY, &attr )) return;
375 /* set the ProgramFiles variables */
377 if ((val = get_registry_value( *env, hkey, progdirW )))
379 if (is_win64 || is_wow64) set_env_var( env, progw6432W, val );
380 if (is_win64 || !is_wow64) set_env_var( env, progfilesW, val );
381 RtlFreeHeap( GetProcessHeap(), 0, val );
383 if ((val = get_registry_value( *env, hkey, progdir86W )))
385 if (is_win64 || is_wow64) set_env_var( env, progfiles86W, val );
386 if (is_wow64) set_env_var( env, progfilesW, val );
387 RtlFreeHeap( GetProcessHeap(), 0, val );
390 /* set the CommonProgramFiles variables */
392 if ((val = get_registry_value( *env, hkey, commondirW )))
394 if (is_win64 || is_wow64) set_env_var( env, commonw6432W, val );
395 if (is_win64 || !is_wow64) set_env_var( env, commonfilesW, val );
396 RtlFreeHeap( GetProcessHeap(), 0, val );
398 if ((val = get_registry_value( *env, hkey, commondir86W )))
400 if (is_win64 || is_wow64) set_env_var( env, commonfiles86W, val );
401 if (is_wow64) set_env_var( env, commonfilesW, val );
402 RtlFreeHeap( GetProcessHeap(), 0, val );
404 NtClose( hkey );
408 /***********************************************************************
409 * build_initial_environment
411 * Build the Win32 environment from the Unix environment
413 static WCHAR *build_initial_environment( WCHAR **wargv[] )
415 SIZE_T size = 1024;
416 WCHAR *ptr;
418 for (;;)
420 if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
421 if (!unix_funcs->get_initial_environment( wargv, ptr, &size )) break;
422 RtlFreeHeap( GetProcessHeap(), 0, ptr );
424 first_prefix_start = set_registry_environment( &ptr, TRUE );
425 set_additional_environment( &ptr );
426 return ptr;
430 /***********************************************************************
431 * get_current_directory
433 * Initialize the current directory from the Unix cwd.
435 static void get_current_directory( UNICODE_STRING *dir )
437 unix_funcs->get_initial_directory( dir );
439 if (!dir->Length) /* still not initialized */
441 dir->Length = wcslen( windows_dir ) * sizeof(WCHAR);
442 memcpy( dir->Buffer, windows_dir, dir->Length );
444 /* add trailing backslash */
445 if (dir->Buffer[dir->Length / sizeof(WCHAR) - 1] != '\\')
447 dir->Buffer[dir->Length / sizeof(WCHAR)] = '\\';
448 dir->Length += sizeof(WCHAR);
450 dir->Buffer[dir->Length / sizeof(WCHAR)] = 0;
454 /***********************************************************************
455 * is_path_prefix
457 static inline BOOL is_path_prefix( const WCHAR *prefix, const WCHAR *path, const WCHAR *file )
459 DWORD len = wcslen( prefix );
461 if (wcsnicmp( path, prefix, len )) return FALSE;
462 while (path[len] == '\\') len++;
463 return path + len == file;
467 /***********************************************************************
468 * get_image_path
470 static void get_image_path( const WCHAR *name, UNICODE_STRING *path )
472 static const WCHAR exeW[] = {'.','e','x','e',0};
473 WCHAR *load_path, *file_part, full_name[MAX_PATH];
474 DWORD len;
476 if (RtlDetermineDosPathNameType_U( name ) != RELATIVE_PATH ||
477 wcschr( name, '/' ) || wcschr( name, '\\' ))
479 len = RtlGetFullPathName_U( name, sizeof(full_name), full_name, &file_part );
480 if (!len || len > sizeof(full_name)) goto failed;
481 /* try first without extension */
482 if (RtlDoesFileExists_U( full_name )) goto done;
483 if (len < (MAX_PATH - 4) * sizeof(WCHAR) && !wcschr( file_part, '.' ))
485 wcscat( file_part, exeW );
486 if (RtlDoesFileExists_U( full_name )) goto done;
488 /* check for builtin path inside system directory */
489 if (!is_path_prefix( system_dir, full_name, file_part ))
491 if (!is_win64 && !is_wow64) goto failed;
492 if (!is_path_prefix( syswow64_dir, full_name, file_part )) goto failed;
495 else
497 RtlGetExePath( name, &load_path );
498 len = RtlDosSearchPath_U( load_path, name, exeW, sizeof(full_name), full_name, &file_part );
499 RtlReleasePath( load_path );
500 if (!len || len > sizeof(full_name))
502 /* build builtin path inside system directory */
503 len = wcslen( system_dir );
504 if (wcslen( name ) >= MAX_PATH - 4 - len) goto failed;
505 wcscpy( full_name, system_dir );
506 wcscat( full_name, name );
507 if (!wcschr( name, '.' )) wcscat( full_name, exeW );
510 done:
511 RtlCreateUnicodeString( path, full_name );
512 return;
514 failed:
515 MESSAGE( "wine: cannot find %s\n", debugstr_w(name) );
516 RtlExitUserProcess( STATUS_DLL_NOT_FOUND );
520 /***********************************************************************
521 * build_command_line
523 * Build the command line of a process from the argv array.
525 * Note that it does NOT necessarily include the file name.
526 * Sometimes we don't even have any command line options at all.
528 * We must quote and escape characters so that the argv array can be rebuilt
529 * from the command line:
530 * - spaces and tabs must be quoted
531 * 'a b' -> '"a b"'
532 * - quotes must be escaped
533 * '"' -> '\"'
534 * - if '\'s are followed by a '"', they must be doubled and followed by '\"',
535 * resulting in an odd number of '\' followed by a '"'
536 * '\"' -> '\\\"'
537 * '\\"' -> '\\\\\"'
538 * - '\'s are followed by the closing '"' must be doubled,
539 * resulting in an even number of '\' followed by a '"'
540 * ' \' -> '" \\"'
541 * ' \\' -> '" \\\\"'
542 * - '\'s that are not followed by a '"' can be left as is
543 * 'a\b' == 'a\b'
544 * 'a\\b' == 'a\\b'
546 static void build_command_line( WCHAR **argv, UNICODE_STRING *cmdline )
548 int len;
549 WCHAR **arg;
550 LPWSTR p;
552 len = 1;
553 for (arg = argv; *arg; arg++) len += 3 + 2 * wcslen( *arg );
554 if (!(cmdline->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
556 p = cmdline->Buffer;
557 for (arg = argv; *arg; arg++)
559 BOOL has_space, has_quote;
560 int i, bcount;
561 WCHAR *a;
563 /* check for quotes and spaces in this argument */
564 if (arg == argv || !**arg) has_space = TRUE;
565 else has_space = wcschr( *arg, ' ' ) || wcschr( *arg, '\t' );
566 has_quote = wcschr( *arg, '"' ) != NULL;
568 /* now transfer it to the command line */
569 if (has_space) *p++ = '"';
570 if (has_quote || has_space)
572 bcount = 0;
573 for (a = *arg; *a; a++)
575 if (*a == '\\') bcount++;
576 else
578 if (*a == '"') /* double all the '\\' preceding this '"', plus one */
579 for (i = 0; i <= bcount; i++) *p++ = '\\';
580 bcount = 0;
582 *p++ = *a;
585 else
587 wcscpy( p, *arg );
588 p += wcslen( p );
590 if (has_space)
592 /* Double all the '\' preceding the closing quote */
593 for (i = 0; i < bcount; i++) *p++ = '\\';
594 *p++ = '"';
596 *p++ = ' ';
598 if (p > cmdline->Buffer) p--; /* remove last space */
599 *p = 0;
600 if (p - cmdline->Buffer >= 32767)
602 ERR( "command line too long (%u)\n", (DWORD)(p - cmdline->Buffer) );
603 NtTerminateProcess( GetCurrentProcess(), 1 );
605 cmdline->Length = (p - cmdline->Buffer) * sizeof(WCHAR);
606 cmdline->MaximumLength = cmdline->Length + sizeof(WCHAR);
610 /******************************************************************************
611 * RtlCreateEnvironment [NTDLL.@]
613 NTSTATUS WINAPI RtlCreateEnvironment(BOOLEAN inherit, PWSTR* env)
615 SIZE_T size;
617 TRACE("(%u,%p)!\n", inherit, env);
619 if (inherit)
621 RtlAcquirePebLock();
622 size = get_env_length( NtCurrentTeb()->Peb->ProcessParameters->Environment ) * sizeof(WCHAR);
623 if ((*env = RtlAllocateHeap( GetProcessHeap(), 0, size )))
624 memcpy( *env, NtCurrentTeb()->Peb->ProcessParameters->Environment, size );
625 RtlReleasePebLock();
627 else *env = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) );
629 return *env ? STATUS_SUCCESS : STATUS_NO_MEMORY;
632 /******************************************************************************
633 * RtlDestroyEnvironment [NTDLL.@]
635 NTSTATUS WINAPI RtlDestroyEnvironment(PWSTR env)
637 RtlFreeHeap( GetProcessHeap(), 0, env );
638 return STATUS_SUCCESS;
641 static LPCWSTR ENV_FindVariable(PCWSTR var, PCWSTR name, unsigned namelen)
643 while (*var)
645 /* match var names, but avoid setting a var with a name including a '='
646 * (a starting '=' is valid though)
648 unsigned int len = wcslen( var );
649 if (len > namelen &&
650 var[namelen] == '=' &&
651 !RtlCompareUnicodeStrings( var, namelen, name, namelen, TRUE ) &&
652 wcschr(var + 1, '=') == var + namelen)
654 return var + namelen + 1;
656 var += len + 1;
658 return NULL;
661 /******************************************************************
662 * RtlQueryEnvironmentVariable_U [NTDLL.@]
664 * NOTES: when the buffer is too small, the string is not written, but if the
665 * terminating null char is the only char that cannot be written, then
666 * all chars (except the null) are written and success is returned
667 * (behavior of Win2k at least)
669 NTSTATUS WINAPI RtlQueryEnvironmentVariable_U(PWSTR env,
670 PUNICODE_STRING name,
671 PUNICODE_STRING value)
673 NTSTATUS nts = STATUS_VARIABLE_NOT_FOUND;
674 PCWSTR var;
675 unsigned namelen;
677 TRACE("%p %s %p\n", env, debugstr_us(name), value);
679 value->Length = 0;
680 namelen = name->Length / sizeof(WCHAR);
681 if (!namelen) return nts;
683 if (!env)
685 RtlAcquirePebLock();
686 var = NtCurrentTeb()->Peb->ProcessParameters->Environment;
688 else var = env;
690 var = ENV_FindVariable(var, name->Buffer, namelen);
691 if (var != NULL)
693 value->Length = wcslen(var) * sizeof(WCHAR);
695 if (value->Length <= value->MaximumLength)
697 memmove(value->Buffer, var, min(value->Length + sizeof(WCHAR), value->MaximumLength));
698 nts = STATUS_SUCCESS;
700 else nts = STATUS_BUFFER_TOO_SMALL;
703 if (!env) RtlReleasePebLock();
705 return nts;
709 /******************************************************************
710 * RtlQueryEnvironmentVariable [NTDLL.@]
712 NTSTATUS WINAPI RtlQueryEnvironmentVariable( WCHAR *env, const WCHAR *name, SIZE_T namelen,
713 WCHAR *value, SIZE_T value_length, SIZE_T *return_length )
715 NTSTATUS nts = STATUS_VARIABLE_NOT_FOUND;
716 SIZE_T len = 0;
717 const WCHAR *var;
719 if (!namelen) return nts;
721 if (!env)
723 RtlAcquirePebLock();
724 var = NtCurrentTeb()->Peb->ProcessParameters->Environment;
726 else var = env;
728 var = ENV_FindVariable(var, name, namelen);
729 if (var != NULL)
731 len = wcslen(var);
732 if (len <= value_length)
734 memcpy(value, var, min(len + 1, value_length) * sizeof(WCHAR));
735 nts = STATUS_SUCCESS;
737 else
739 len++;
740 nts = STATUS_BUFFER_TOO_SMALL;
743 *return_length = len;
745 if (!env) RtlReleasePebLock();
747 return nts;
750 /******************************************************************
751 * RtlSetCurrentEnvironment [NTDLL.@]
754 void WINAPI RtlSetCurrentEnvironment(PWSTR new_env, PWSTR* old_env)
756 WCHAR *prev;
758 TRACE("(%p %p)\n", new_env, old_env);
760 RtlAcquirePebLock();
762 prev = NtCurrentTeb()->Peb->ProcessParameters->Environment;
763 NtCurrentTeb()->Peb->ProcessParameters->Environment = new_env;
765 RtlReleasePebLock();
767 if (old_env)
768 *old_env = prev;
769 else
770 RtlDestroyEnvironment( prev );
774 /******************************************************************************
775 * RtlSetEnvironmentVariable [NTDLL.@]
777 NTSTATUS WINAPI RtlSetEnvironmentVariable(PWSTR* penv, PUNICODE_STRING name,
778 PUNICODE_STRING value)
780 INT varlen, len, old_size;
781 LPWSTR p, env;
782 NTSTATUS nts = STATUS_VARIABLE_NOT_FOUND;
784 TRACE("(%p, %s, %s)\n", penv, debugstr_us(name), debugstr_us(value));
786 if (!name || !name->Buffer || !name->Length)
787 return STATUS_INVALID_PARAMETER_1;
789 len = name->Length / sizeof(WCHAR);
791 /* variable names can't contain a '=' except as a first character */
792 for (p = name->Buffer + 1; p < name->Buffer + len; p++)
793 if (*p == '=') return STATUS_INVALID_PARAMETER;
795 if (!penv)
797 RtlAcquirePebLock();
798 env = NtCurrentTeb()->Peb->ProcessParameters->Environment;
799 } else env = *penv;
801 old_size = get_env_length( env );
803 /* Find a place to insert the string */
804 for (p = env; *p; p += varlen + 1)
806 varlen = wcslen(p);
807 if (varlen > len && p[len] == '=' &&
808 !RtlCompareUnicodeStrings( name->Buffer, len, p, len, TRUE )) break;
810 if (!value && !*p) goto done; /* Value to remove doesn't exist */
812 /* Realloc the buffer */
813 len = value ? len + value->Length / sizeof(WCHAR) + 2 : 0;
814 if (*p) len -= wcslen(p) + 1; /* The name already exists */
816 if (len < 0)
818 LPWSTR next = p + wcslen(p) + 1; /* We know there is a next one */
819 memmove(next + len, next, (old_size - (next - env)) * sizeof(WCHAR));
822 if ((old_size + len) * sizeof(WCHAR) > RtlSizeHeap( GetProcessHeap(), 0, env ))
824 SIZE_T new_size = max( old_size * 2, old_size + len ) * sizeof(WCHAR);
825 LPWSTR new_env = RtlAllocateHeap( GetProcessHeap(), 0, new_size );
827 if (!new_env)
829 nts = STATUS_NO_MEMORY;
830 goto done;
832 memmove(new_env, env, (p - env) * sizeof(WCHAR));
833 assert(len > 0);
834 memmove(new_env + (p - env) + len, p, (old_size - (p - env)) * sizeof(WCHAR));
835 p = new_env + (p - env);
837 RtlDestroyEnvironment(env);
838 if (!penv) NtCurrentTeb()->Peb->ProcessParameters->Environment = new_env;
839 else *penv = new_env;
841 else
843 if (len > 0) memmove(p + len, p, (old_size - (p - env)) * sizeof(WCHAR));
846 /* Set the new string */
847 if (value)
849 memcpy( p, name->Buffer, name->Length );
850 p += name->Length / sizeof(WCHAR);
851 *p++ = '=';
852 memcpy( p, value->Buffer, value->Length );
853 p[value->Length / sizeof(WCHAR)] = 0;
855 nts = STATUS_SUCCESS;
857 done:
858 if (!penv) RtlReleasePebLock();
860 return nts;
863 /******************************************************************************
864 * RtlExpandEnvironmentStrings (NTDLL.@)
866 NTSTATUS WINAPI RtlExpandEnvironmentStrings( const WCHAR *renv, WCHAR *src, SIZE_T src_len,
867 WCHAR *dst, SIZE_T count, SIZE_T *plen )
869 SIZE_T len, total_size = 1; /* 1 for terminating '\0' */
870 LPCWSTR env, var;
872 if (!renv)
874 RtlAcquirePebLock();
875 env = NtCurrentTeb()->Peb->ProcessParameters->Environment;
877 else env = renv;
879 while (src_len)
881 if (*src != '%')
883 for (len = 0; len < src_len; len++) if (src[len] == '%') break;
884 var = src;
885 src += len;
886 src_len -= len;
888 else /* we are at the start of a variable */
890 for (len = 1; len < src_len; len++) if (src[len] == '%') break;
891 if (len < src_len)
893 if ((var = ENV_FindVariable( env, src + 1, len - 1 )))
895 src += len + 1; /* Skip the variable name */
896 src_len -= len + 1;
897 len = wcslen(var);
899 else
901 var = src; /* Copy original name instead */
902 len++;
903 src += len;
904 src_len -= len;
907 else /* unfinished variable name, ignore it */
909 var = src;
910 src += len;
911 src_len = 0;
914 total_size += len;
915 if (dst)
917 if (count < len) len = count;
918 memcpy(dst, var, len * sizeof(WCHAR));
919 count -= len;
920 dst += len;
924 if (!renv) RtlReleasePebLock();
926 if (dst && count) *dst = '\0';
927 if (plen) *plen = total_size;
929 return (count) ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
932 /******************************************************************
933 * RtlExpandEnvironmentStrings_U (NTDLL.@)
935 NTSTATUS WINAPI RtlExpandEnvironmentStrings_U( const WCHAR *env, const UNICODE_STRING *src,
936 UNICODE_STRING *dst, ULONG *plen )
938 SIZE_T len;
939 NTSTATUS ret;
941 ret = RtlExpandEnvironmentStrings( env, src->Buffer, src->Length / sizeof(WCHAR),
942 dst->Buffer, dst->MaximumLength / sizeof(WCHAR), &len );
943 if (plen) *plen = len * sizeof(WCHAR); /* FIXME: check for overflow? */
944 if (len > UNICODE_STRING_MAX_CHARS) ret = STATUS_BUFFER_TOO_SMALL;
945 if (!ret) dst->Length = (len - 1) * sizeof(WCHAR);
946 return ret;
949 static inline void normalize( void *base, WCHAR **ptr )
951 if (*ptr) *ptr = (WCHAR *)((char *)base + (UINT_PTR)*ptr);
954 /******************************************************************************
955 * RtlNormalizeProcessParams [NTDLL.@]
957 PRTL_USER_PROCESS_PARAMETERS WINAPI RtlNormalizeProcessParams( RTL_USER_PROCESS_PARAMETERS *params )
959 if (params && !(params->Flags & PROCESS_PARAMS_FLAG_NORMALIZED))
961 normalize( params, &params->CurrentDirectory.DosPath.Buffer );
962 normalize( params, &params->DllPath.Buffer );
963 normalize( params, &params->ImagePathName.Buffer );
964 normalize( params, &params->CommandLine.Buffer );
965 normalize( params, &params->WindowTitle.Buffer );
966 normalize( params, &params->Desktop.Buffer );
967 normalize( params, &params->ShellInfo.Buffer );
968 normalize( params, &params->RuntimeInfo.Buffer );
969 params->Flags |= PROCESS_PARAMS_FLAG_NORMALIZED;
971 return params;
975 static inline void denormalize( const void *base, WCHAR **ptr )
977 if (*ptr) *ptr = (WCHAR *)(UINT_PTR)((char *)*ptr - (const char *)base);
980 /******************************************************************************
981 * RtlDeNormalizeProcessParams [NTDLL.@]
983 PRTL_USER_PROCESS_PARAMETERS WINAPI RtlDeNormalizeProcessParams( RTL_USER_PROCESS_PARAMETERS *params )
985 if (params && (params->Flags & PROCESS_PARAMS_FLAG_NORMALIZED))
987 denormalize( params, &params->CurrentDirectory.DosPath.Buffer );
988 denormalize( params, &params->DllPath.Buffer );
989 denormalize( params, &params->ImagePathName.Buffer );
990 denormalize( params, &params->CommandLine.Buffer );
991 denormalize( params, &params->WindowTitle.Buffer );
992 denormalize( params, &params->Desktop.Buffer );
993 denormalize( params, &params->ShellInfo.Buffer );
994 denormalize( params, &params->RuntimeInfo.Buffer );
995 params->Flags &= ~PROCESS_PARAMS_FLAG_NORMALIZED;
997 return params;
1001 #define ROUND_SIZE(size) (((size) + sizeof(void *) - 1) & ~(sizeof(void *) - 1))
1003 /* append a unicode string to the process params data; helper for RtlCreateProcessParameters */
1004 static void append_unicode_string( void **data, const UNICODE_STRING *src,
1005 UNICODE_STRING *dst )
1007 dst->Length = src->Length;
1008 dst->MaximumLength = src->MaximumLength;
1009 if (dst->MaximumLength)
1011 dst->Buffer = *data;
1012 memcpy( dst->Buffer, src->Buffer, dst->Length );
1013 *data = (char *)dst->Buffer + ROUND_SIZE( dst->MaximumLength );
1015 else dst->Buffer = NULL;
1019 /******************************************************************************
1020 * RtlCreateProcessParametersEx [NTDLL.@]
1022 NTSTATUS WINAPI RtlCreateProcessParametersEx( RTL_USER_PROCESS_PARAMETERS **result,
1023 const UNICODE_STRING *ImagePathName,
1024 const UNICODE_STRING *DllPath,
1025 const UNICODE_STRING *CurrentDirectoryName,
1026 const UNICODE_STRING *CommandLine,
1027 PWSTR Environment,
1028 const UNICODE_STRING *WindowTitle,
1029 const UNICODE_STRING *Desktop,
1030 const UNICODE_STRING *ShellInfo,
1031 const UNICODE_STRING *RuntimeInfo,
1032 ULONG flags )
1034 UNICODE_STRING curdir;
1035 const RTL_USER_PROCESS_PARAMETERS *cur_params;
1036 SIZE_T size, env_size = 0;
1037 void *ptr;
1038 NTSTATUS status = STATUS_SUCCESS;
1040 RtlAcquirePebLock();
1041 cur_params = NtCurrentTeb()->Peb->ProcessParameters;
1042 if (!DllPath) DllPath = &cur_params->DllPath;
1043 if (!CurrentDirectoryName)
1045 if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */
1046 curdir = ((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir.DosPath;
1047 else
1048 curdir = cur_params->CurrentDirectory.DosPath;
1050 else curdir = *CurrentDirectoryName;
1051 curdir.MaximumLength = MAX_PATH * sizeof(WCHAR);
1053 if (!CommandLine) CommandLine = ImagePathName;
1054 if (!Environment && cur_params) Environment = cur_params->Environment;
1055 if (!WindowTitle) WindowTitle = &empty_str;
1056 if (!Desktop) Desktop = &empty_str;
1057 if (!ShellInfo) ShellInfo = &empty_str;
1058 if (!RuntimeInfo) RuntimeInfo = &null_str;
1060 if (Environment) env_size = get_env_length( Environment ) * sizeof(WCHAR);
1062 size = (sizeof(RTL_USER_PROCESS_PARAMETERS)
1063 + ROUND_SIZE( ImagePathName->MaximumLength )
1064 + ROUND_SIZE( DllPath->MaximumLength )
1065 + ROUND_SIZE( curdir.MaximumLength )
1066 + ROUND_SIZE( CommandLine->MaximumLength )
1067 + ROUND_SIZE( WindowTitle->MaximumLength )
1068 + ROUND_SIZE( Desktop->MaximumLength )
1069 + ROUND_SIZE( ShellInfo->MaximumLength )
1070 + ROUND_SIZE( RuntimeInfo->MaximumLength ));
1072 if ((ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, size + ROUND_SIZE(env_size) )))
1074 RTL_USER_PROCESS_PARAMETERS *params = ptr;
1075 params->AllocationSize = size;
1076 params->Size = size;
1077 params->Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
1078 if (cur_params) params->ConsoleFlags = cur_params->ConsoleFlags;
1079 /* all other fields are zero */
1081 ptr = params + 1;
1082 append_unicode_string( &ptr, &curdir, &params->CurrentDirectory.DosPath );
1083 append_unicode_string( &ptr, DllPath, &params->DllPath );
1084 append_unicode_string( &ptr, ImagePathName, &params->ImagePathName );
1085 append_unicode_string( &ptr, CommandLine, &params->CommandLine );
1086 append_unicode_string( &ptr, WindowTitle, &params->WindowTitle );
1087 append_unicode_string( &ptr, Desktop, &params->Desktop );
1088 append_unicode_string( &ptr, ShellInfo, &params->ShellInfo );
1089 append_unicode_string( &ptr, RuntimeInfo, &params->RuntimeInfo );
1090 if (Environment) params->Environment = memcpy( ptr, Environment, env_size );
1091 *result = params;
1092 if (!(flags & PROCESS_PARAMS_FLAG_NORMALIZED)) RtlDeNormalizeProcessParams( params );
1094 else status = STATUS_NO_MEMORY;
1096 RtlReleasePebLock();
1097 return status;
1101 /******************************************************************************
1102 * RtlCreateProcessParameters [NTDLL.@]
1104 NTSTATUS WINAPI RtlCreateProcessParameters( RTL_USER_PROCESS_PARAMETERS **result,
1105 const UNICODE_STRING *image,
1106 const UNICODE_STRING *dllpath,
1107 const UNICODE_STRING *curdir,
1108 const UNICODE_STRING *cmdline,
1109 PWSTR env,
1110 const UNICODE_STRING *title,
1111 const UNICODE_STRING *desktop,
1112 const UNICODE_STRING *shellinfo,
1113 const UNICODE_STRING *runtime )
1115 return RtlCreateProcessParametersEx( result, image, dllpath, curdir, cmdline,
1116 env, title, desktop, shellinfo, runtime, 0 );
1120 /******************************************************************************
1121 * RtlDestroyProcessParameters [NTDLL.@]
1123 void WINAPI RtlDestroyProcessParameters( RTL_USER_PROCESS_PARAMETERS *params )
1125 RtlFreeHeap( GetProcessHeap(), 0, params );
1129 static inline void get_unicode_string( UNICODE_STRING *str, WCHAR **src, UINT len )
1131 str->Buffer = *src;
1132 str->Length = len;
1133 str->MaximumLength = len + sizeof(WCHAR);
1134 *src += len / sizeof(WCHAR);
1138 /***********************************************************************
1139 * run_wineboot
1141 static void run_wineboot( WCHAR **env )
1143 static const WCHAR wineboot_eventW[] = {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s',
1144 '\\','_','_','w','i','n','e','b','o','o','t','_','e','v','e','n','t',0};
1145 static const WCHAR wineboot[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
1146 's','y','s','t','e','m','3','2','\\',
1147 'w','i','n','e','b','o','o','t','.','e','x','e',0};
1148 static const WCHAR cmdline[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
1149 's','y','s','t','e','m','3','2','\\',
1150 'w','i','n','e','b','o','o','t','.','e','x','e',' ',
1151 '-','-','i','n','i','t',0};
1152 UNICODE_STRING nameW, cmdlineW, dllpathW;
1153 RTL_USER_PROCESS_PARAMETERS *params;
1154 RTL_USER_PROCESS_INFORMATION info;
1155 WCHAR *load_path, *dummy;
1156 OBJECT_ATTRIBUTES attr;
1157 LARGE_INTEGER timeout;
1158 HANDLE handles[2];
1159 NTSTATUS status;
1160 ULONG redir = 0;
1161 int count = 1;
1163 RtlInitUnicodeString( &nameW, wineboot_eventW );
1164 InitializeObjectAttributes( &attr, &nameW, OBJ_OPENIF, 0, NULL );
1166 status = NtCreateEvent( &handles[0], EVENT_ALL_ACCESS, &attr, NotificationEvent, 0 );
1167 if (status == STATUS_OBJECT_NAME_EXISTS) goto wait;
1168 if (status)
1170 ERR( "failed to create wineboot event, expect trouble\n" );
1171 return;
1173 LdrGetDllPath( wineboot + 4, LOAD_WITH_ALTERED_SEARCH_PATH, &load_path, &dummy );
1174 RtlInitUnicodeString( &nameW, wineboot + 4 );
1175 RtlInitUnicodeString( &dllpathW, load_path );
1176 RtlInitUnicodeString( &cmdlineW, cmdline );
1177 RtlCreateProcessParametersEx( &params, &nameW, &dllpathW, NULL, &cmdlineW, *env, NULL, NULL,
1178 NULL, NULL, PROCESS_PARAMS_FLAG_NORMALIZED );
1179 params->hStdInput = 0;
1180 params->hStdOutput = 0;
1181 params->hStdError = NtCurrentTeb()->Peb->ProcessParameters->hStdError;
1183 RtlInitUnicodeString( &nameW, wineboot );
1184 RtlWow64EnableFsRedirectionEx( TRUE, &redir );
1185 status = RtlCreateUserProcess( &nameW, OBJ_CASE_INSENSITIVE, params,
1186 NULL, NULL, 0, FALSE, 0, 0, &info );
1187 RtlWow64EnableFsRedirection( !redir );
1188 RtlReleasePath( load_path );
1189 RtlDestroyProcessParameters( params );
1190 if (status)
1192 ERR( "failed to start wineboot %x\n", status );
1193 NtClose( handles[0] );
1194 return;
1196 NtResumeThread( info.Thread, NULL );
1197 NtClose( info.Thread );
1198 handles[count++] = info.Process;
1200 wait:
1201 timeout.QuadPart = (ULONGLONG)(first_prefix_start ? 5 : 2) * 60 * 1000 * -10000;
1202 if (NtWaitForMultipleObjects( count, handles, TRUE, FALSE, &timeout ) == WAIT_TIMEOUT)
1203 ERR( "boot event wait timed out\n" );
1204 while (count) NtClose( handles[--count] );
1206 /* reload environment now that wineboot has run */
1207 set_registry_environment( env, first_prefix_start );
1208 set_additional_environment( env );
1212 /***********************************************************************
1213 * init_user_process_params
1215 * Fill the initial RTL_USER_PROCESS_PARAMETERS structure from the server.
1217 void init_user_process_params(void)
1219 WCHAR *src, *load_path, *dummy;
1220 SIZE_T info_size, env_size, data_size = 0;
1221 startup_info_t *info = NULL;
1222 RTL_USER_PROCESS_PARAMETERS *params = NULL;
1223 UNICODE_STRING curdir, dllpath, imagepath, cmdline, title, desktop, shellinfo, runtime;
1224 WCHAR **wargv;
1226 unix_funcs->get_startup_info( NULL, &data_size, &info_size );
1227 if (!data_size)
1229 RTL_USER_PROCESS_PARAMETERS initial_params = {0};
1230 WCHAR *env, curdir_buffer[MAX_PATH];
1232 NtCurrentTeb()->Peb->ProcessParameters = &initial_params;
1233 initial_params.Environment = build_initial_environment( &wargv );
1234 curdir.Buffer = curdir_buffer;
1235 curdir.MaximumLength = sizeof(curdir_buffer);
1236 get_current_directory( &curdir );
1237 initial_params.CurrentDirectory.DosPath = curdir;
1238 get_image_path( wargv[0], &initial_params.ImagePathName );
1239 wargv[0] = initial_params.ImagePathName.Buffer;
1240 build_command_line( wargv, &cmdline );
1241 LdrGetDllPath( initial_params.ImagePathName.Buffer, 0, &load_path, &dummy );
1242 RtlInitUnicodeString( &dllpath, load_path );
1244 env = initial_params.Environment;
1245 initial_params.Environment = NULL; /* avoid copying it */
1246 if (RtlCreateProcessParametersEx( &params, &initial_params.ImagePathName, &dllpath, &curdir,
1247 &cmdline, NULL, &initial_params.ImagePathName, NULL, NULL, NULL,
1248 PROCESS_PARAMS_FLAG_NORMALIZED ))
1249 return;
1251 params->Environment = env;
1252 NtCurrentTeb()->Peb->ProcessParameters = params;
1253 RtlFreeUnicodeString( &initial_params.ImagePathName );
1254 RtlFreeUnicodeString( &cmdline );
1255 RtlReleasePath( load_path );
1257 unix_funcs->get_initial_console( params );
1258 params->wShowWindow = 1; /* SW_SHOWNORMAL */
1260 run_wineboot( &params->Environment );
1261 goto done;
1264 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, data_size ))) return;
1266 if (unix_funcs->get_startup_info( info, &data_size, &info_size )) goto done;
1268 src = (WCHAR *)(info + 1);
1269 get_unicode_string( &curdir, &src, info->curdir_len );
1270 get_unicode_string( &dllpath, &src, info->dllpath_len );
1271 get_unicode_string( &imagepath, &src, info->imagepath_len );
1272 get_unicode_string( &cmdline, &src, info->cmdline_len );
1273 get_unicode_string( &title, &src, info->title_len );
1274 get_unicode_string( &desktop, &src, info->desktop_len );
1275 get_unicode_string( &shellinfo, &src, info->shellinfo_len );
1276 get_unicode_string( &runtime, &src, info->runtime_len );
1278 runtime.MaximumLength = runtime.Length; /* runtime info isn't a real string */
1280 if (RtlCreateProcessParametersEx( &params, &imagepath, &dllpath, &curdir, &cmdline, NULL,
1281 &title, &desktop, &shellinfo, &runtime,
1282 PROCESS_PARAMS_FLAG_NORMALIZED ))
1283 goto done;
1285 NtCurrentTeb()->Peb->ProcessParameters = params;
1286 params->DebugFlags = info->debug_flags;
1287 params->ConsoleHandle = wine_server_ptr_handle( info->console );
1288 params->ConsoleFlags = info->console_flags;
1289 params->hStdInput = wine_server_ptr_handle( info->hstdin );
1290 params->hStdOutput = wine_server_ptr_handle( info->hstdout );
1291 params->hStdError = wine_server_ptr_handle( info->hstderr );
1292 params->dwX = info->x;
1293 params->dwY = info->y;
1294 params->dwXSize = info->xsize;
1295 params->dwYSize = info->ysize;
1296 params->dwXCountChars = info->xchars;
1297 params->dwYCountChars = info->ychars;
1298 params->dwFillAttribute = info->attribute;
1299 params->dwFlags = info->flags;
1300 params->wShowWindow = info->show;
1302 /* environment needs to be a separate memory block */
1303 env_size = data_size - info_size;
1304 if ((params->Environment = RtlAllocateHeap( GetProcessHeap(), 0, max( env_size, sizeof(WCHAR) ))))
1306 if (env_size) memcpy( params->Environment, (char *)info + info_size, env_size );
1307 else params->Environment[0] = 0;
1310 done:
1311 RtlFreeHeap( GetProcessHeap(), 0, info );
1312 if (RtlSetCurrentDirectory_U( &params->CurrentDirectory.DosPath ))
1314 MESSAGE("wine: could not open working directory %s, starting in the Windows directory.\n",
1315 debugstr_w( params->CurrentDirectory.DosPath.Buffer ));
1316 RtlInitUnicodeString( &curdir, windows_dir );
1317 RtlSetCurrentDirectory_U( &curdir );
1319 set_wow64_environment( &params->Environment );