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
24 #include <sys/types.h>
27 #define WIN32_NO_STATUS
30 #include "wine/debug.h"
31 #include "ntdll_misc.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;
52 /***********************************************************************
55 static void set_env_var( WCHAR
**env
, const WCHAR
*name
, const WCHAR
*val
)
57 UNICODE_STRING nameW
, valW
;
59 RtlInitUnicodeString( &nameW
, name
);
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
;
84 char buffer
[1024*sizeof(WCHAR
) + sizeof(KEY_VALUE_FULL_INFORMATION
)];
87 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
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
);
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
;
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
);
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
);
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
);
184 NtClose( attr
.RootDirectory
);
189 /***********************************************************************
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
);
198 UNICODE_STRING nameW
;
200 RtlInitUnicodeString( &nameW
, name
);
201 if (NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, buffer
, size
, &size
))
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
)))
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
) );
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
;
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
);
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
);
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};
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
;
335 WCHAR
*ptr
, *val
, *p
;
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
);
349 RtlFreeHeap( GetProcessHeap(), 0, ptr
);
351 /* set the PROCESSOR_ARCHITECTURE variable */
353 if (!RtlQueryEnvironmentVariable_U( *env
, &arch6432_strW
, &valW
))
357 RtlSetEnvironmentVariable( env
, &arch_strW
, &valW
);
358 RtlSetEnvironmentVariable( env
, &arch6432_strW
, NULL
);
361 else if (!RtlQueryEnvironmentVariable_U( *env
, &arch_strW
, &valW
))
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
);
408 /***********************************************************************
409 * build_initial_environment
411 * Build the Win32 environment from the Unix environment
413 static WCHAR
*build_initial_environment( WCHAR
**wargv
[] )
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
);
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 /***********************************************************************
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 /***********************************************************************
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
];
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
;
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
);
511 RtlCreateUnicodeString( path
, full_name
);
515 MESSAGE( "wine: cannot find %s\n", debugstr_w(name
) );
516 RtlExitUserProcess( STATUS_DLL_NOT_FOUND
);
520 /***********************************************************************
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
532 * - quotes must be escaped
534 * - if '\'s are followed by a '"', they must be doubled and followed by '\"',
535 * resulting in an odd number of '\' followed by a '"'
538 * - '\'s are followed by the closing '"' must be doubled,
539 * resulting in an even number of '\' followed by a '"'
542 * - '\'s that are not followed by a '"' can be left as is
546 static void build_command_line( WCHAR
**argv
, UNICODE_STRING
*cmdline
)
553 for (arg
= argv
; *arg
; arg
++) len
+= 3 + 2 * wcslen( *arg
);
554 if (!(cmdline
->Buffer
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return;
557 for (arg
= argv
; *arg
; arg
++)
559 BOOL has_space
, has_quote
;
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
)
573 for (a
= *arg
; *a
; a
++)
575 if (*a
== '\\') bcount
++;
578 if (*a
== '"') /* double all the '\\' preceding this '"', plus one */
579 for (i
= 0; i
<= bcount
; i
++) *p
++ = '\\';
592 /* Double all the '\' preceding the closing quote */
593 for (i
= 0; i
< bcount
; i
++) *p
++ = '\\';
598 if (p
> cmdline
->Buffer
) p
--; /* remove last space */
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
)
617 TRACE("(%u,%p)!\n", inherit
, env
);
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
);
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
)
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
);
650 var
[namelen
] == '=' &&
651 !RtlCompareUnicodeStrings( var
, namelen
, name
, namelen
, TRUE
) &&
652 wcschr(var
+ 1, '=') == var
+ namelen
)
654 return var
+ namelen
+ 1;
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
;
677 TRACE("%p %s %p\n", env
, debugstr_us(name
), value
);
680 namelen
= name
->Length
/ sizeof(WCHAR
);
681 if (!namelen
) return nts
;
686 var
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
690 var
= ENV_FindVariable(var
, name
->Buffer
, namelen
);
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();
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
;
719 if (!namelen
) return nts
;
724 var
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
728 var
= ENV_FindVariable(var
, name
, namelen
);
732 if (len
<= value_length
)
734 memcpy(value
, var
, min(len
+ 1, value_length
) * sizeof(WCHAR
));
735 nts
= STATUS_SUCCESS
;
740 nts
= STATUS_BUFFER_TOO_SMALL
;
743 *return_length
= len
;
745 if (!env
) RtlReleasePebLock();
750 /******************************************************************
751 * RtlSetCurrentEnvironment [NTDLL.@]
754 void WINAPI
RtlSetCurrentEnvironment(PWSTR new_env
, PWSTR
* old_env
)
758 TRACE("(%p %p)\n", new_env
, old_env
);
762 prev
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
763 NtCurrentTeb()->Peb
->ProcessParameters
->Environment
= new_env
;
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
;
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
;
798 env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
801 old_size
= get_env_length( env
);
803 /* Find a place to insert the string */
804 for (p
= env
; *p
; p
+= varlen
+ 1)
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 */
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
);
829 nts
= STATUS_NO_MEMORY
;
832 memmove(new_env
, env
, (p
- env
) * sizeof(WCHAR
));
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
;
843 if (len
> 0) memmove(p
+ len
, p
, (old_size
- (p
- env
)) * sizeof(WCHAR
));
846 /* Set the new string */
849 memcpy( p
, name
->Buffer
, name
->Length
);
850 p
+= name
->Length
/ sizeof(WCHAR
);
852 memcpy( p
, value
->Buffer
, value
->Length
);
853 p
[value
->Length
/ sizeof(WCHAR
)] = 0;
855 nts
= STATUS_SUCCESS
;
858 if (!penv
) RtlReleasePebLock();
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' */
875 env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
883 for (len
= 0; len
< src_len
; len
++) if (src
[len
] == '%') break;
888 else /* we are at the start of a variable */
890 for (len
= 1; len
< src_len
; len
++) if (src
[len
] == '%') break;
893 if ((var
= ENV_FindVariable( env
, src
+ 1, len
- 1 )))
895 src
+= len
+ 1; /* Skip the variable name */
901 var
= src
; /* Copy original name instead */
907 else /* unfinished variable name, ignore it */
917 if (count
< len
) len
= count
;
918 memcpy(dst
, var
, len
* sizeof(WCHAR
));
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
)
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
);
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
, ¶ms
->CurrentDirectory
.DosPath
.Buffer
);
962 normalize( params
, ¶ms
->DllPath
.Buffer
);
963 normalize( params
, ¶ms
->ImagePathName
.Buffer
);
964 normalize( params
, ¶ms
->CommandLine
.Buffer
);
965 normalize( params
, ¶ms
->WindowTitle
.Buffer
);
966 normalize( params
, ¶ms
->Desktop
.Buffer
);
967 normalize( params
, ¶ms
->ShellInfo
.Buffer
);
968 normalize( params
, ¶ms
->RuntimeInfo
.Buffer
);
969 params
->Flags
|= PROCESS_PARAMS_FLAG_NORMALIZED
;
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
, ¶ms
->CurrentDirectory
.DosPath
.Buffer
);
988 denormalize( params
, ¶ms
->DllPath
.Buffer
);
989 denormalize( params
, ¶ms
->ImagePathName
.Buffer
);
990 denormalize( params
, ¶ms
->CommandLine
.Buffer
);
991 denormalize( params
, ¶ms
->WindowTitle
.Buffer
);
992 denormalize( params
, ¶ms
->Desktop
.Buffer
);
993 denormalize( params
, ¶ms
->ShellInfo
.Buffer
);
994 denormalize( params
, ¶ms
->RuntimeInfo
.Buffer
);
995 params
->Flags
&= ~PROCESS_PARAMS_FLAG_NORMALIZED
;
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
,
1028 const UNICODE_STRING
*WindowTitle
,
1029 const UNICODE_STRING
*Desktop
,
1030 const UNICODE_STRING
*ShellInfo
,
1031 const UNICODE_STRING
*RuntimeInfo
,
1034 UNICODE_STRING curdir
;
1035 const RTL_USER_PROCESS_PARAMETERS
*cur_params
;
1036 SIZE_T size
, env_size
= 0;
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
;
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 */
1082 append_unicode_string( &ptr
, &curdir
, ¶ms
->CurrentDirectory
.DosPath
);
1083 append_unicode_string( &ptr
, DllPath
, ¶ms
->DllPath
);
1084 append_unicode_string( &ptr
, ImagePathName
, ¶ms
->ImagePathName
);
1085 append_unicode_string( &ptr
, CommandLine
, ¶ms
->CommandLine
);
1086 append_unicode_string( &ptr
, WindowTitle
, ¶ms
->WindowTitle
);
1087 append_unicode_string( &ptr
, Desktop
, ¶ms
->Desktop
);
1088 append_unicode_string( &ptr
, ShellInfo
, ¶ms
->ShellInfo
);
1089 append_unicode_string( &ptr
, RuntimeInfo
, ¶ms
->RuntimeInfo
);
1090 if (Environment
) params
->Environment
= memcpy( ptr
, Environment
, env_size
);
1092 if (!(flags
& PROCESS_PARAMS_FLAG_NORMALIZED
)) RtlDeNormalizeProcessParams( params
);
1094 else status
= STATUS_NO_MEMORY
;
1096 RtlReleasePebLock();
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
,
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
)
1133 str
->MaximumLength
= len
+ sizeof(WCHAR
);
1134 *src
+= len
/ sizeof(WCHAR
);
1138 /***********************************************************************
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
;
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
;
1170 ERR( "failed to create wineboot event, expect trouble\n" );
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( ¶ms
, &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
);
1192 ERR( "failed to start wineboot %x\n", status
);
1193 NtClose( handles
[0] );
1196 NtResumeThread( info
.Thread
, NULL
);
1197 NtClose( info
.Thread
);
1198 handles
[count
++] = info
.Process
;
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
;
1226 unix_funcs
->get_startup_info( NULL
, &data_size
, &info_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( ¶ms
, &initial_params
.ImagePathName
, &dllpath
, &curdir
,
1247 &cmdline
, NULL
, &initial_params
.ImagePathName
, NULL
, NULL
, NULL
,
1248 PROCESS_PARAMS_FLAG_NORMALIZED
))
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( ¶ms
->Environment
);
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( ¶ms
, &imagepath
, &dllpath
, &curdir
, &cmdline
, NULL
,
1281 &title
, &desktop
, &shellinfo
, &runtime
,
1282 PROCESS_PARAMS_FLAG_NORMALIZED
))
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;
1311 RtlFreeHeap( GetProcessHeap(), 0, info
);
1312 if (RtlSetCurrentDirectory_U( ¶ms
->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( ¶ms
->Environment
);