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
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_STAT_H
28 # include <sys/stat.h>
38 #define WIN32_NO_STATUS
41 #include "wine/library.h"
42 #include "wine/debug.h"
43 #include "ntdll_misc.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(environ
);
48 static WCHAR empty
[] = {0};
49 static const UNICODE_STRING empty_str
= { 0, sizeof(empty
), empty
};
50 static const UNICODE_STRING null_str
= { 0, 0, NULL
};
52 static const BOOL is_win64
= (sizeof(void *) > sizeof(int));
54 static const WCHAR windows_dir
[] = {'C',':','\\','w','i','n','d','o','w','s',0};
56 static BOOL first_prefix_start
; /* first ever process start in this prefix? */
58 static inline SIZE_T
get_env_length( const WCHAR
*env
)
60 const WCHAR
*end
= env
;
61 while (*end
) end
+= wcslen(end
) + 1;
66 extern char **__wine_get_main_environment(void);
68 extern char **__wine_main_environ
;
69 static char **__wine_get_main_environment(void) { return __wine_main_environ
; }
73 /***********************************************************************
76 * Check if an environment variable needs to be handled specially when
77 * passed through the Unix environment (i.e. prefixed with "WINE").
79 static inline BOOL
is_special_env_var( const char *var
)
81 return (!strncmp( var
, "PATH=", sizeof("PATH=")-1 ) ||
82 !strncmp( var
, "PWD=", sizeof("PWD=")-1 ) ||
83 !strncmp( var
, "HOME=", sizeof("HOME=")-1 ) ||
84 !strncmp( var
, "TEMP=", sizeof("TEMP=")-1 ) ||
85 !strncmp( var
, "TMP=", sizeof("TMP=")-1 ) ||
86 !strncmp( var
, "QT_", sizeof("QT_")-1 ) ||
87 !strncmp( var
, "VK_", sizeof("VK_")-1 ));
91 /***********************************************************************
94 static void set_env_var( WCHAR
**env
, const WCHAR
*name
, const WCHAR
*val
)
96 UNICODE_STRING nameW
, valW
;
98 RtlInitUnicodeString( &nameW
, name
);
99 RtlInitUnicodeString( &valW
, val
);
100 RtlSetEnvironmentVariable( env
, &nameW
, &valW
);
104 /***********************************************************************
105 * set_registry_variables
107 * Set environment variables by enumerating the values of a key;
108 * helper for set_registry_environment().
109 * Note that Windows happily truncates the value if it's too big.
111 static void set_registry_variables( WCHAR
**env
, HANDLE hkey
, ULONG type
)
113 static const WCHAR pathW
[] = {'P','A','T','H'};
114 static const WCHAR sep
[] = {';',0};
115 UNICODE_STRING env_name
, env_value
;
119 char buffer
[1024*sizeof(WCHAR
) + sizeof(KEY_VALUE_FULL_INFORMATION
)];
122 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
125 tmp
.MaximumLength
= sizeof(tmpbuf
);
127 for (index
= 0; ; index
++)
129 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
130 buffer
, sizeof(buffer
), &size
);
131 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_OVERFLOW
) break;
132 if (info
->Type
!= type
) continue;
133 env_name
.Buffer
= info
->Name
;
134 env_name
.Length
= env_name
.MaximumLength
= info
->NameLength
;
135 env_value
.Buffer
= (WCHAR
*)(buffer
+ info
->DataOffset
);
136 env_value
.Length
= info
->DataLength
;
137 env_value
.MaximumLength
= sizeof(buffer
) - info
->DataOffset
;
138 if (env_value
.Length
&& !env_value
.Buffer
[env_value
.Length
/sizeof(WCHAR
)-1])
139 env_value
.Length
-= sizeof(WCHAR
); /* don't count terminating null if any */
140 if (!env_value
.Length
) continue;
141 if (info
->Type
== REG_EXPAND_SZ
)
143 status
= RtlExpandEnvironmentStrings_U( *env
, &env_value
, &tmp
, NULL
);
144 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_OVERFLOW
) continue;
145 RtlCopyUnicodeString( &env_value
, &tmp
);
148 if (env_name
.Length
== sizeof(pathW
) &&
149 !wcsnicmp( env_name
.Buffer
, pathW
, ARRAY_SIZE( pathW
)) &&
150 !RtlQueryEnvironmentVariable_U( *env
, &env_name
, &tmp
))
152 RtlAppendUnicodeToString( &tmp
, sep
);
153 if (RtlAppendUnicodeStringToString( &tmp
, &env_value
)) continue;
154 RtlCopyUnicodeString( &env_value
, &tmp
);
156 RtlSetEnvironmentVariable( env
, &env_name
, &env_value
);
161 /***********************************************************************
162 * set_registry_environment
164 * Set the environment variables specified in the registry.
166 * Note: Windows handles REG_SZ and REG_EXPAND_SZ in one pass with the
167 * consequence that REG_EXPAND_SZ cannot be used reliably as it depends
168 * on the order in which the variables are processed. But on Windows it
169 * does not really matter since they only use %SystemDrive% and
170 * %SystemRoot% which are predefined. But Wine defines these in the
171 * registry, so we need two passes.
173 static BOOL
set_registry_environment( WCHAR
**env
, BOOL first_time
)
175 static const WCHAR env_keyW
[] = {'\\','R','e','g','i','s','t','r','y','\\',
176 'M','a','c','h','i','n','e','\\',
177 'S','y','s','t','e','m','\\',
178 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
179 'C','o','n','t','r','o','l','\\',
180 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
181 'E','n','v','i','r','o','n','m','e','n','t',0};
182 static const WCHAR envW
[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
183 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};
185 OBJECT_ATTRIBUTES attr
;
186 UNICODE_STRING nameW
;
190 /* first the system environment variables */
191 InitializeObjectAttributes( &attr
, &nameW
, 0, 0, NULL
);
192 RtlInitUnicodeString( &nameW
, env_keyW
);
193 if (first_time
&& !NtOpenKey( &hkey
, KEY_READ
, &attr
))
195 set_registry_variables( env
, hkey
, REG_SZ
);
196 set_registry_variables( env
, hkey
, REG_EXPAND_SZ
);
201 /* then the ones for the current user */
202 if (RtlOpenCurrentUser( KEY_READ
, &attr
.RootDirectory
) != STATUS_SUCCESS
) return ret
;
203 RtlInitUnicodeString( &nameW
, envW
);
204 if (first_time
&& !NtOpenKey( &hkey
, KEY_READ
, &attr
))
206 set_registry_variables( env
, hkey
, REG_SZ
);
207 set_registry_variables( env
, hkey
, REG_EXPAND_SZ
);
211 RtlInitUnicodeString( &nameW
, volatile_envW
);
212 if (!NtOpenKey( &hkey
, KEY_READ
, &attr
))
214 set_registry_variables( env
, hkey
, REG_SZ
);
215 set_registry_variables( env
, hkey
, REG_EXPAND_SZ
);
219 NtClose( attr
.RootDirectory
);
224 /***********************************************************************
227 static WCHAR
*get_registry_value( WCHAR
*env
, HKEY hkey
, const WCHAR
*name
)
229 char buffer
[1024 * sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
230 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
231 DWORD len
, size
= sizeof(buffer
);
233 UNICODE_STRING nameW
;
235 RtlInitUnicodeString( &nameW
, name
);
236 if (NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
, buffer
, size
, &size
))
239 if (size
<= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
)) return NULL
;
240 len
= (size
- FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
)) / sizeof(WCHAR
);
242 if (info
->Type
== REG_EXPAND_SZ
)
244 UNICODE_STRING value
, expanded
;
246 value
.MaximumLength
= len
* sizeof(WCHAR
);
247 value
.Buffer
= (WCHAR
*)info
->Data
;
248 if (!value
.Buffer
[len
- 1]) len
--; /* don't count terminating null if any */
249 value
.Length
= len
* sizeof(WCHAR
);
250 expanded
.Length
= expanded
.MaximumLength
= 1024 * sizeof(WCHAR
);
251 if (!(expanded
.Buffer
= RtlAllocateHeap( GetProcessHeap(), 0, expanded
.MaximumLength
)))
253 if (!RtlExpandEnvironmentStrings_U( env
, &value
, &expanded
, NULL
)) ret
= expanded
.Buffer
;
254 else RtlFreeUnicodeString( &expanded
);
256 else if (info
->Type
== REG_SZ
)
258 if ((ret
= RtlAllocateHeap( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) )))
260 memcpy( ret
, info
->Data
, len
* sizeof(WCHAR
) );
268 /***********************************************************************
269 * set_additional_environment
271 * Set some additional environment variables not specified in the registry.
273 static void set_additional_environment( WCHAR
**env
)
275 static const WCHAR profile_keyW
[] = {'\\','R','e','g','i','s','t','r','y','\\',
276 'M','a','c','h','i','n','e','\\',
277 'S','o','f','t','w','a','r','e','\\',
278 'M','i','c','r','o','s','o','f','t','\\',
279 'W','i','n','d','o','w','s',' ','N','T','\\',
280 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
281 'P','r','o','f','i','l','e','L','i','s','t',0};
282 static const WCHAR computer_keyW
[] = {'\\','R','e','g','i','s','t','r','y','\\',
283 'M','a','c','h','i','n','e','\\',
284 'S','y','s','t','e','m','\\',
285 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
286 'C','o','n','t','r','o','l','\\',
287 'C','o','m','p','u','t','e','r','N','a','m','e','\\',
288 'A','c','t','i','v','e','C','o','m','p','u','t','e','r','N','a','m','e',0};
289 static const WCHAR computer_valueW
[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
290 static const WCHAR public_valueW
[] = {'P','u','b','l','i','c',0};
291 static const WCHAR computernameW
[] = {'C','O','M','P','U','T','E','R','N','A','M','E',0};
292 static const WCHAR allusersW
[] = {'A','L','L','U','S','E','R','S','P','R','O','F','I','L','E',0};
293 static const WCHAR programdataW
[] = {'P','r','o','g','r','a','m','D','a','t','a',0};
294 static const WCHAR publicW
[] = {'P','U','B','L','I','C',0};
295 OBJECT_ATTRIBUTES attr
;
296 UNICODE_STRING nameW
;
300 /* set the user profile variables */
302 InitializeObjectAttributes( &attr
, &nameW
, 0, 0, NULL
);
303 RtlInitUnicodeString( &nameW
, profile_keyW
);
304 if (!NtOpenKey( &hkey
, KEY_READ
, &attr
))
306 if ((val
= get_registry_value( *env
, hkey
, programdataW
)))
308 set_env_var( env
, allusersW
, val
);
309 set_env_var( env
, programdataW
, val
);
310 RtlFreeHeap( GetProcessHeap(), 0, val
);
312 if ((val
= get_registry_value( *env
, hkey
, public_valueW
)))
314 set_env_var( env
, publicW
, val
);
315 RtlFreeHeap( GetProcessHeap(), 0, val
);
320 /* set the computer name */
322 RtlInitUnicodeString( &nameW
, computer_keyW
);
323 if (!NtOpenKey( &hkey
, KEY_READ
, &attr
))
325 if ((val
= get_registry_value( *env
, hkey
, computer_valueW
)))
327 set_env_var( env
, computernameW
, val
);
328 RtlFreeHeap( GetProcessHeap(), 0, val
);
335 /* set an environment variable for one of the wine path variables */
336 static void set_wine_path_variable( WCHAR
**env
, const WCHAR
*name
, const char *unix_path
)
338 UNICODE_STRING nt_name
, var_name
;
339 ANSI_STRING unix_name
;
341 RtlInitUnicodeString( &var_name
, name
);
344 RtlInitAnsiString( &unix_name
, unix_path
);
345 if (wine_unix_to_nt_file_name( &unix_name
, &nt_name
)) return;
346 RtlSetEnvironmentVariable( env
, &var_name
, &nt_name
);
347 RtlFreeUnicodeString( &nt_name
);
349 else RtlSetEnvironmentVariable( env
, &var_name
, NULL
);
353 /***********************************************************************
354 * set_wow64_environment
356 * Set the environment variables that change across 32/64/Wow64.
358 static void set_wow64_environment( WCHAR
**env
)
360 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};
361 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};
362 static const WCHAR x86W
[] = {'x','8','6',0};
363 static const WCHAR versionW
[] = {'\\','R','e','g','i','s','t','r','y','\\',
364 'M','a','c','h','i','n','e','\\',
365 'S','o','f','t','w','a','r','e','\\',
366 'M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
369 static const WCHAR progdirW
[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',0};
370 static const WCHAR progdir86W
[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0};
371 static const WCHAR progfilesW
[] = {'P','r','o','g','r','a','m','F','i','l','e','s',0};
372 static const WCHAR progfiles86W
[] = {'P','r','o','g','r','a','m','F','i','l','e','s','(','x','8','6',')',0};
373 static const WCHAR progw6432W
[] = {'P','r','o','g','r','a','m','W','6','4','3','2',0};
374 static const WCHAR commondirW
[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',0};
375 static const WCHAR commondir86W
[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0};
376 static const WCHAR commonfilesW
[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s',0};
377 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};
378 static const WCHAR commonw6432W
[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','W','6','4','3','2',0};
379 static const WCHAR winedlldirW
[] = {'W','I','N','E','D','L','L','D','I','R','%','u',0};
380 static const WCHAR winehomedirW
[] = {'W','I','N','E','H','O','M','E','D','I','R',0};
381 static const WCHAR winedatadirW
[] = {'W','I','N','E','D','A','T','A','D','I','R',0};
382 static const WCHAR winebuilddirW
[] = {'W','I','N','E','B','U','I','L','D','D','I','R',0};
383 static const WCHAR wineusernameW
[] = {'W','I','N','E','U','S','E','R','N','A','M','E',0};
384 static const WCHAR wineconfigdirW
[] = {'W','I','N','E','C','O','N','F','I','G','D','I','R',0};
387 UNICODE_STRING arch_strW
= { sizeof(archW
) - sizeof(WCHAR
), sizeof(archW
), archW
};
388 UNICODE_STRING arch6432_strW
= { sizeof(arch6432W
) - sizeof(WCHAR
), sizeof(arch6432W
), arch6432W
};
389 UNICODE_STRING valW
= { 0, sizeof(buf
), buf
};
390 OBJECT_ATTRIBUTES attr
;
391 UNICODE_STRING nameW
;
393 const char *home
= getenv( "HOME" );
394 const char *name
= getenv( "USER" );
401 struct passwd
*pwd
= getpwuid( getuid() );
404 if (!home
) home
= pwd
->pw_dir
;
405 if (!name
) name
= pwd
->pw_name
;
409 /* set the Wine paths */
411 set_wine_path_variable( env
, winedatadirW
, wine_get_data_dir() );
412 set_wine_path_variable( env
, winehomedirW
, home
);
413 set_wine_path_variable( env
, winebuilddirW
, wine_get_build_dir() );
414 set_wine_path_variable( env
, wineconfigdirW
, config_dir
);
415 for (i
= 0; (p
= wine_dll_enum_load_path( i
)); i
++)
417 NTDLL_swprintf( buf
, winedlldirW
, i
);
418 set_wine_path_variable( env
, buf
, p
);
420 NTDLL_swprintf( buf
, winedlldirW
, i
);
421 set_wine_path_variable( env
, buf
, NULL
);
425 if (!name
) name
= "wine";
426 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
427 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
428 ntdll_umbstowcs( name
, strlen(name
) + 1, buf
, ARRAY_SIZE(buf
) );
429 set_env_var( env
, wineusernameW
, buf
);
431 /* set the PROCESSOR_ARCHITECTURE variable */
433 if (!RtlQueryEnvironmentVariable_U( *env
, &arch6432_strW
, &valW
))
437 RtlSetEnvironmentVariable( env
, &arch_strW
, &valW
);
438 RtlSetEnvironmentVariable( env
, &arch6432_strW
, NULL
);
441 else if (!RtlQueryEnvironmentVariable_U( *env
, &arch_strW
, &valW
))
445 RtlSetEnvironmentVariable( env
, &arch6432_strW
, &valW
);
446 RtlInitUnicodeString( &nameW
, x86W
);
447 RtlSetEnvironmentVariable( env
, &arch_strW
, &nameW
);
451 InitializeObjectAttributes( &attr
, &nameW
, 0, 0, NULL
);
452 RtlInitUnicodeString( &nameW
, versionW
);
453 if (NtOpenKey( &hkey
, KEY_READ
| KEY_WOW64_64KEY
, &attr
)) return;
455 /* set the ProgramFiles variables */
457 if ((val
= get_registry_value( *env
, hkey
, progdirW
)))
459 if (is_win64
|| is_wow64
) set_env_var( env
, progw6432W
, val
);
460 if (is_win64
|| !is_wow64
) set_env_var( env
, progfilesW
, val
);
461 RtlFreeHeap( GetProcessHeap(), 0, val
);
463 if ((val
= get_registry_value( *env
, hkey
, progdir86W
)))
465 if (is_win64
|| is_wow64
) set_env_var( env
, progfiles86W
, val
);
466 if (is_wow64
) set_env_var( env
, progfilesW
, val
);
467 RtlFreeHeap( GetProcessHeap(), 0, val
);
470 /* set the CommonProgramFiles variables */
472 if ((val
= get_registry_value( *env
, hkey
, commondirW
)))
474 if (is_win64
|| is_wow64
) set_env_var( env
, commonw6432W
, val
);
475 if (is_win64
|| !is_wow64
) set_env_var( env
, commonfilesW
, val
);
476 RtlFreeHeap( GetProcessHeap(), 0, val
);
478 if ((val
= get_registry_value( *env
, hkey
, commondir86W
)))
480 if (is_win64
|| is_wow64
) set_env_var( env
, commonfiles86W
, val
);
481 if (is_wow64
) set_env_var( env
, commonfilesW
, val
);
482 RtlFreeHeap( GetProcessHeap(), 0, val
);
488 /***********************************************************************
489 * build_initial_environment
491 * Build the Win32 environment from the Unix environment
493 static WCHAR
*build_initial_environment( char **env
)
499 /* compute the total size of the Unix environment */
501 for (e
= env
; *e
; e
++)
503 if (is_special_env_var( *e
)) continue;
504 size
+= strlen(*e
) + 1;
507 if (!(ptr
= RtlAllocateHeap( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return NULL
;
510 /* and fill it with the Unix environment */
512 for (e
= env
; *e
; e
++)
516 /* skip Unix special variables and use the Wine variants instead */
517 if (!strncmp( str
, "WINE", 4 ))
519 if (is_special_env_var( str
+ 4 )) str
+= 4;
520 else if (!strncmp( str
, "WINEPRELOADRESERVE=", 19 )) continue; /* skip it */
522 else if (is_special_env_var( str
)) continue; /* skip it */
524 ntdll_umbstowcs( str
, strlen(str
) + 1, p
, size
- (p
- ptr
) );
528 first_prefix_start
= set_registry_environment( &ptr
, TRUE
);
529 set_additional_environment( &ptr
);
534 /***********************************************************************
537 * Build the environment of a new child process.
539 char **build_envp( const WCHAR
*envW
)
541 static const char * const unix_vars
[] = { "PATH", "TEMP", "TMP", "HOME" };
544 int count
= 1, length
, lenW
;
547 lenW
= get_env_length( envW
);
548 if (!(env
= RtlAllocateHeap( GetProcessHeap(), 0, lenW
* 3 ))) return NULL
;
549 length
= ntdll_wcstoumbs( envW
, lenW
, env
, lenW
* 3, FALSE
);
551 for (p
= env
; *p
; p
+= strlen(p
) + 1, count
++)
552 if (is_special_env_var( p
)) length
+= 4; /* prefix it with "WINE" */
554 for (i
= 0; i
< ARRAY_SIZE( unix_vars
); i
++)
556 if (!(p
= getenv(unix_vars
[i
]))) continue;
557 length
+= strlen(unix_vars
[i
]) + strlen(p
) + 2;
561 if ((envp
= RtlAllocateHeap( GetProcessHeap(), 0, count
* sizeof(*envp
) + length
)))
563 char **envptr
= envp
;
564 char *dst
= (char *)(envp
+ count
);
566 /* some variables must not be modified, so we get them directly from the unix env */
567 for (i
= 0; i
< ARRAY_SIZE( unix_vars
); i
++)
569 if (!(p
= getenv( unix_vars
[i
] ))) continue;
570 *envptr
++ = strcpy( dst
, unix_vars
[i
] );
573 dst
+= strlen(dst
) + 1;
576 /* now put the Windows environment strings */
577 for (p
= env
; *p
; p
+= strlen(p
) + 1)
579 if (*p
== '=') continue; /* skip drive curdirs, this crashes some unix apps */
580 if (!strncmp( p
, "WINEPRELOADRESERVE=", sizeof("WINEPRELOADRESERVE=")-1 )) continue;
581 if (!strncmp( p
, "WINELOADERNOEXEC=", sizeof("WINELOADERNOEXEC=")-1 )) continue;
582 if (!strncmp( p
, "WINESERVERSOCKET=", sizeof("WINESERVERSOCKET=")-1 )) continue;
583 if (is_special_env_var( p
)) /* prefix it with "WINE" */
585 *envptr
++ = strcpy( dst
, "WINE" );
590 *envptr
++ = strcpy( dst
, p
);
592 dst
+= strlen(dst
) + 1;
596 RtlFreeHeap( GetProcessHeap(), 0, env
);
601 /***********************************************************************
602 * get_current_directory
604 * Initialize the current directory from the Unix cwd.
606 static void get_current_directory( UNICODE_STRING
*dir
)
614 /* try to get it from the Unix cwd */
616 for (size
= 1024; ; size
*= 2)
618 if (!(cwd
= RtlAllocateHeap( GetProcessHeap(), 0, size
))) break;
619 if (getcwd( cwd
, size
)) break;
620 RtlFreeHeap( GetProcessHeap(), 0, cwd
);
621 if (errno
== ERANGE
) continue;
626 /* try to use PWD if it is valid, so that we don't resolve symlinks */
628 pwd
= getenv( "PWD" );
631 struct stat st1
, st2
;
633 if (!pwd
|| stat( pwd
, &st1
) == -1 ||
634 (!stat( cwd
, &st2
) && (st1
.st_dev
!= st2
.st_dev
|| st1
.st_ino
!= st2
.st_ino
)))
640 ANSI_STRING unix_name
;
641 UNICODE_STRING nt_name
;
643 RtlInitAnsiString( &unix_name
, pwd
);
644 if (!wine_unix_to_nt_file_name( &unix_name
, &nt_name
))
646 /* skip the \??\ prefix */
647 if (nt_name
.Length
> 6 * sizeof(WCHAR
) && nt_name
.Buffer
[5] == ':')
649 dir
->Length
= nt_name
.Length
- 4 * sizeof(WCHAR
);
650 memcpy( dir
->Buffer
, nt_name
.Buffer
+ 4, dir
->Length
);
652 else /* change \??\ to \\?\ */
654 dir
->Length
= nt_name
.Length
;
655 memcpy( dir
->Buffer
, nt_name
.Buffer
, dir
->Length
);
656 dir
->Buffer
[1] = '\\';
658 RtlFreeUnicodeString( &nt_name
);
662 if (!dir
->Length
) /* still not initialized */
664 MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
665 "starting in the Windows directory.\n", cwd
? cwd
: "" );
666 dir
->Length
= wcslen( windows_dir
) * sizeof(WCHAR
);
667 memcpy( dir
->Buffer
, windows_dir
, dir
->Length
);
669 RtlFreeHeap( GetProcessHeap(), 0, cwd
);
671 /* add trailing backslash */
672 if (dir
->Buffer
[dir
->Length
/ sizeof(WCHAR
) - 1] != '\\')
674 dir
->Buffer
[dir
->Length
/ sizeof(WCHAR
)] = '\\';
675 dir
->Length
+= sizeof(WCHAR
);
677 dir
->Buffer
[dir
->Length
/ sizeof(WCHAR
)] = 0;
681 /***********************************************************************
684 static inline BOOL
is_path_prefix( const WCHAR
*prefix
, const WCHAR
*path
, const WCHAR
*file
)
686 DWORD len
= wcslen( prefix
);
688 if (wcsnicmp( path
, prefix
, len
)) return FALSE
;
689 while (path
[len
] == '\\') len
++;
690 return path
+ len
== file
;
694 /***********************************************************************
697 static void get_image_path( const char *argv0
, UNICODE_STRING
*path
)
699 static const WCHAR exeW
[] = {'.','e','x','e',0};
700 WCHAR
*load_path
, *file_part
, *name
, full_name
[MAX_PATH
];
701 DWORD len
= strlen(argv0
) + 1;
703 if (!(name
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) goto failed
;
704 ntdll_umbstowcs( argv0
, len
, name
, len
);
706 if (RtlDetermineDosPathNameType_U( name
) != RELATIVE_PATH
||
707 wcschr( name
, '/' ) || wcschr( name
, '\\' ))
709 len
= RtlGetFullPathName_U( name
, sizeof(full_name
), full_name
, &file_part
);
710 if (!len
|| len
> sizeof(full_name
)) goto failed
;
711 /* try first without extension */
712 if (RtlDoesFileExists_U( full_name
)) goto done
;
713 if (len
< (MAX_PATH
- 4) * sizeof(WCHAR
) && !wcschr( file_part
, '.' ))
715 wcscat( file_part
, exeW
);
716 if (RtlDoesFileExists_U( full_name
)) goto done
;
718 /* check for builtin path inside system directory */
719 if (!is_path_prefix( system_dir
, full_name
, file_part
))
721 if (!is_win64
&& !is_wow64
) goto failed
;
722 if (!is_path_prefix( syswow64_dir
, full_name
, file_part
)) goto failed
;
727 RtlGetExePath( name
, &load_path
);
728 len
= RtlDosSearchPath_U( load_path
, name
, exeW
, sizeof(full_name
), full_name
, &file_part
);
729 RtlReleasePath( load_path
);
730 if (!len
|| len
> sizeof(full_name
))
732 /* build builtin path inside system directory */
733 len
= wcslen( system_dir
);
734 if (wcslen( name
) >= MAX_PATH
- 4 - len
) goto failed
;
735 wcscpy( full_name
, system_dir
);
736 wcscat( full_name
, name
);
737 if (!wcschr( name
, '.' )) wcscat( full_name
, exeW
);
741 RtlCreateUnicodeString( path
, full_name
);
742 RtlFreeHeap( GetProcessHeap(), 0, name
);
746 MESSAGE( "wine: cannot find '%s'\n", argv0
);
747 RtlExitUserProcess( GetLastError() );
751 /***********************************************************************
754 * Set the Wine library Unicode argv global variables.
756 static void set_library_wargv( char **argv
, const UNICODE_STRING
*image
)
762 if (image
) total
+= 1 + image
->Length
/ sizeof(WCHAR
);
763 for (argc
= (image
!= NULL
); argv
[argc
]; argc
++) total
+= strlen(argv
[argc
]) + 1;
765 wargv
= RtlAllocateHeap( GetProcessHeap(), 0,
766 total
* sizeof(WCHAR
) + (argc
+ 1) * sizeof(*wargv
) );
767 p
= (WCHAR
*)(wargv
+ argc
+ 1);
770 wcscpy( p
, image
->Buffer
);
772 p
+= 1 + image
->Length
/ sizeof(WCHAR
);
773 total
-= 1 + image
->Length
/ sizeof(WCHAR
);
775 for (argc
= (image
!= NULL
); argv
[argc
]; argc
++)
777 DWORD reslen
= ntdll_umbstowcs( argv
[argc
], strlen(argv
[argc
]) + 1, p
, total
);
784 __wine_main_argc
= argc
;
785 __wine_main_wargv
= wargv
;
789 /***********************************************************************
792 * Build the command line of a process from the argv array.
794 * Note that it does NOT necessarily include the file name.
795 * Sometimes we don't even have any command line options at all.
797 * We must quote and escape characters so that the argv array can be rebuilt
798 * from the command line:
799 * - spaces and tabs must be quoted
801 * - quotes must be escaped
803 * - if '\'s are followed by a '"', they must be doubled and followed by '\"',
804 * resulting in an odd number of '\' followed by a '"'
807 * - '\'s are followed by the closing '"' must be doubled,
808 * resulting in an even number of '\' followed by a '"'
811 * - '\'s that are not followed by a '"' can be left as is
815 static void build_command_line( WCHAR
**argv
, UNICODE_STRING
*cmdline
)
822 for (arg
= argv
; *arg
; arg
++) len
+= 3 + 2 * wcslen( *arg
);
823 cmdline
->MaximumLength
= len
* sizeof(WCHAR
);
824 if (!(cmdline
->Buffer
= RtlAllocateHeap( GetProcessHeap(), 0, cmdline
->MaximumLength
))) return;
827 for (arg
= argv
; *arg
; arg
++)
829 BOOL has_space
, has_quote
;
833 /* check for quotes and spaces in this argument */
834 if (arg
== argv
|| !**arg
) has_space
= TRUE
;
835 else has_space
= wcschr( *arg
, ' ' ) || wcschr( *arg
, '\t' );
836 has_quote
= wcschr( *arg
, '"' ) != NULL
;
838 /* now transfer it to the command line */
839 if (has_space
) *p
++ = '"';
840 if (has_quote
|| has_space
)
843 for (a
= *arg
; *a
; a
++)
845 if (*a
== '\\') bcount
++;
848 if (*a
== '"') /* double all the '\\' preceding this '"', plus one */
849 for (i
= 0; i
<= bcount
; i
++) *p
++ = '\\';
862 /* Double all the '\' preceding the closing quote */
863 for (i
= 0; i
< bcount
; i
++) *p
++ = '\\';
868 if (p
> cmdline
->Buffer
) p
--; /* remove last space */
870 cmdline
->Length
= (p
- cmdline
->Buffer
) * sizeof(WCHAR
);
874 /******************************************************************************
875 * NtQuerySystemEnvironmentValue [NTDLL.@]
877 NTSYSAPI NTSTATUS WINAPI
NtQuerySystemEnvironmentValue(PUNICODE_STRING VariableName
,
879 ULONG ValueBufferLength
,
880 PULONG RequiredLength
)
882 FIXME("(%s, %p, %u, %p), stub\n", debugstr_us(VariableName
), Value
, ValueBufferLength
, RequiredLength
);
883 return STATUS_NOT_IMPLEMENTED
;
886 /******************************************************************************
887 * NtQuerySystemEnvironmentValueEx [NTDLL.@]
889 NTSYSAPI NTSTATUS WINAPI
NtQuerySystemEnvironmentValueEx(PUNICODE_STRING name
, LPGUID vendor
,
890 PVOID value
, PULONG retlength
, PULONG attrib
)
892 FIXME("(%s, %s, %p, %p, %p), stub\n", debugstr_us(name
), debugstr_guid(vendor
), value
, retlength
, attrib
);
893 return STATUS_NOT_IMPLEMENTED
;
896 /******************************************************************************
897 * RtlCreateEnvironment [NTDLL.@]
899 NTSTATUS WINAPI
RtlCreateEnvironment(BOOLEAN inherit
, PWSTR
* env
)
903 TRACE("(%u,%p)!\n", inherit
, env
);
908 size
= get_env_length( NtCurrentTeb()->Peb
->ProcessParameters
->Environment
) * sizeof(WCHAR
);
909 if ((*env
= RtlAllocateHeap( GetProcessHeap(), 0, size
)))
910 memcpy( *env
, NtCurrentTeb()->Peb
->ProcessParameters
->Environment
, size
);
913 else *env
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WCHAR
) );
915 return *env
? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
918 /******************************************************************************
919 * RtlDestroyEnvironment [NTDLL.@]
921 NTSTATUS WINAPI
RtlDestroyEnvironment(PWSTR env
)
923 RtlFreeHeap( GetProcessHeap(), 0, env
);
924 return STATUS_SUCCESS
;
927 static LPCWSTR
ENV_FindVariable(PCWSTR var
, PCWSTR name
, unsigned namelen
)
931 /* match var names, but avoid setting a var with a name including a '='
932 * (a starting '=' is valid though)
934 unsigned int len
= wcslen( var
);
936 var
[namelen
] == '=' &&
937 !RtlCompareUnicodeStrings( var
, namelen
, name
, namelen
, TRUE
) &&
938 wcschr(var
+ 1, '=') == var
+ namelen
)
940 return var
+ namelen
+ 1;
947 /******************************************************************
948 * RtlQueryEnvironmentVariable_U [NTDLL.@]
950 * NOTES: when the buffer is too small, the string is not written, but if the
951 * terminating null char is the only char that cannot be written, then
952 * all chars (except the null) are written and success is returned
953 * (behavior of Win2k at least)
955 NTSTATUS WINAPI
RtlQueryEnvironmentVariable_U(PWSTR env
,
956 PUNICODE_STRING name
,
957 PUNICODE_STRING value
)
959 NTSTATUS nts
= STATUS_VARIABLE_NOT_FOUND
;
963 TRACE("%p %s %p\n", env
, debugstr_us(name
), value
);
966 namelen
= name
->Length
/ sizeof(WCHAR
);
967 if (!namelen
) return nts
;
972 var
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
976 var
= ENV_FindVariable(var
, name
->Buffer
, namelen
);
979 value
->Length
= wcslen(var
) * sizeof(WCHAR
);
981 if (value
->Length
<= value
->MaximumLength
)
983 memmove(value
->Buffer
, var
, min(value
->Length
+ sizeof(WCHAR
), value
->MaximumLength
));
984 nts
= STATUS_SUCCESS
;
986 else nts
= STATUS_BUFFER_TOO_SMALL
;
989 if (!env
) RtlReleasePebLock();
994 /******************************************************************
995 * RtlSetCurrentEnvironment [NTDLL.@]
998 void WINAPI
RtlSetCurrentEnvironment(PWSTR new_env
, PWSTR
* old_env
)
1000 TRACE("(%p %p)\n", new_env
, old_env
);
1002 RtlAcquirePebLock();
1004 if (old_env
) *old_env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
1005 NtCurrentTeb()->Peb
->ProcessParameters
->Environment
= new_env
;
1007 RtlReleasePebLock();
1011 /******************************************************************************
1012 * RtlSetEnvironmentVariable [NTDLL.@]
1014 NTSTATUS WINAPI
RtlSetEnvironmentVariable(PWSTR
* penv
, PUNICODE_STRING name
,
1015 PUNICODE_STRING value
)
1017 INT varlen
, len
, old_size
;
1019 NTSTATUS nts
= STATUS_VARIABLE_NOT_FOUND
;
1021 TRACE("(%p, %s, %s)\n", penv
, debugstr_us(name
), debugstr_us(value
));
1023 if (!name
|| !name
->Buffer
|| !name
->Length
)
1024 return STATUS_INVALID_PARAMETER_1
;
1026 len
= name
->Length
/ sizeof(WCHAR
);
1028 /* variable names can't contain a '=' except as a first character */
1029 for (p
= name
->Buffer
+ 1; p
< name
->Buffer
+ len
; p
++)
1030 if (*p
== '=') return STATUS_INVALID_PARAMETER
;
1034 RtlAcquirePebLock();
1035 env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
1038 old_size
= get_env_length( env
);
1040 /* Find a place to insert the string */
1041 for (p
= env
; *p
; p
+= varlen
+ 1)
1044 if (varlen
> len
&& p
[len
] == '=' &&
1045 !RtlCompareUnicodeStrings( name
->Buffer
, len
, p
, len
, TRUE
)) break;
1047 if (!value
&& !*p
) goto done
; /* Value to remove doesn't exist */
1049 /* Realloc the buffer */
1050 len
= value
? len
+ value
->Length
/ sizeof(WCHAR
) + 2 : 0;
1051 if (*p
) len
-= wcslen(p
) + 1; /* The name already exists */
1055 LPWSTR next
= p
+ wcslen(p
) + 1; /* We know there is a next one */
1056 memmove(next
+ len
, next
, (old_size
- (next
- env
)) * sizeof(WCHAR
));
1059 if ((old_size
+ len
) * sizeof(WCHAR
) > RtlSizeHeap( GetProcessHeap(), 0, env
))
1061 SIZE_T new_size
= max( old_size
* 2, old_size
+ len
) * sizeof(WCHAR
);
1062 LPWSTR new_env
= RtlAllocateHeap( GetProcessHeap(), 0, new_size
);
1066 nts
= STATUS_NO_MEMORY
;
1069 memmove(new_env
, env
, (p
- env
) * sizeof(WCHAR
));
1071 memmove(new_env
+ (p
- env
) + len
, p
, (old_size
- (p
- env
)) * sizeof(WCHAR
));
1072 p
= new_env
+ (p
- env
);
1074 RtlDestroyEnvironment(env
);
1075 if (!penv
) NtCurrentTeb()->Peb
->ProcessParameters
->Environment
= new_env
;
1076 else *penv
= new_env
;
1080 if (len
> 0) memmove(p
+ len
, p
, (old_size
- (p
- env
)) * sizeof(WCHAR
));
1083 /* Set the new string */
1086 memcpy( p
, name
->Buffer
, name
->Length
);
1087 p
+= name
->Length
/ sizeof(WCHAR
);
1089 memcpy( p
, value
->Buffer
, value
->Length
);
1090 p
[value
->Length
/ sizeof(WCHAR
)] = 0;
1092 nts
= STATUS_SUCCESS
;
1095 if (!penv
) RtlReleasePebLock();
1100 /******************************************************************************
1101 * RtlExpandEnvironmentStrings (NTDLL.@)
1103 NTSTATUS WINAPI
RtlExpandEnvironmentStrings( const WCHAR
*renv
, WCHAR
*src
, SIZE_T src_len
,
1104 WCHAR
*dst
, SIZE_T count
, SIZE_T
*plen
)
1106 SIZE_T len
, total_size
= 1; /* 1 for terminating '\0' */
1111 RtlAcquirePebLock();
1112 env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
1120 for (len
= 0; len
< src_len
; len
++) if (src
[len
] == '%') break;
1125 else /* we are at the start of a variable */
1127 for (len
= 1; len
< src_len
; len
++) if (src
[len
] == '%') break;
1130 if ((var
= ENV_FindVariable( env
, src
+ 1, len
- 1 )))
1132 src
+= len
+ 1; /* Skip the variable name */
1138 var
= src
; /* Copy original name instead */
1144 else /* unfinished variable name, ignore it */
1154 if (count
< len
) len
= count
;
1155 memcpy(dst
, var
, len
* sizeof(WCHAR
));
1161 if (!renv
) RtlReleasePebLock();
1163 if (dst
&& count
) *dst
= '\0';
1164 if (plen
) *plen
= total_size
;
1166 return (count
) ? STATUS_SUCCESS
: STATUS_BUFFER_TOO_SMALL
;
1169 /******************************************************************
1170 * RtlExpandEnvironmentStrings_U (NTDLL.@)
1172 NTSTATUS WINAPI
RtlExpandEnvironmentStrings_U( const WCHAR
*env
, const UNICODE_STRING
*src
,
1173 UNICODE_STRING
*dst
, ULONG
*plen
)
1178 ret
= RtlExpandEnvironmentStrings( env
, src
->Buffer
, src
->Length
/ sizeof(WCHAR
),
1179 dst
->Buffer
, dst
->MaximumLength
/ sizeof(WCHAR
), &len
);
1180 if (plen
) *plen
= len
* sizeof(WCHAR
); /* FIXME: check for overflow? */
1181 if (len
> UNICODE_STRING_MAX_CHARS
) ret
= STATUS_BUFFER_TOO_SMALL
;
1182 if (!ret
) dst
->Length
= (len
- 1) * sizeof(WCHAR
);
1186 static inline void normalize( void *base
, WCHAR
**ptr
)
1188 if (*ptr
) *ptr
= (WCHAR
*)((char *)base
+ (UINT_PTR
)*ptr
);
1191 /******************************************************************************
1192 * RtlNormalizeProcessParams [NTDLL.@]
1194 PRTL_USER_PROCESS_PARAMETERS WINAPI
RtlNormalizeProcessParams( RTL_USER_PROCESS_PARAMETERS
*params
)
1196 if (params
&& !(params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
))
1198 normalize( params
, ¶ms
->CurrentDirectory
.DosPath
.Buffer
);
1199 normalize( params
, ¶ms
->DllPath
.Buffer
);
1200 normalize( params
, ¶ms
->ImagePathName
.Buffer
);
1201 normalize( params
, ¶ms
->CommandLine
.Buffer
);
1202 normalize( params
, ¶ms
->WindowTitle
.Buffer
);
1203 normalize( params
, ¶ms
->Desktop
.Buffer
);
1204 normalize( params
, ¶ms
->ShellInfo
.Buffer
);
1205 normalize( params
, ¶ms
->RuntimeInfo
.Buffer
);
1206 params
->Flags
|= PROCESS_PARAMS_FLAG_NORMALIZED
;
1212 static inline void denormalize( const void *base
, WCHAR
**ptr
)
1214 if (*ptr
) *ptr
= (WCHAR
*)(UINT_PTR
)((char *)*ptr
- (const char *)base
);
1217 /******************************************************************************
1218 * RtlDeNormalizeProcessParams [NTDLL.@]
1220 PRTL_USER_PROCESS_PARAMETERS WINAPI
RtlDeNormalizeProcessParams( RTL_USER_PROCESS_PARAMETERS
*params
)
1222 if (params
&& (params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
))
1224 denormalize( params
, ¶ms
->CurrentDirectory
.DosPath
.Buffer
);
1225 denormalize( params
, ¶ms
->DllPath
.Buffer
);
1226 denormalize( params
, ¶ms
->ImagePathName
.Buffer
);
1227 denormalize( params
, ¶ms
->CommandLine
.Buffer
);
1228 denormalize( params
, ¶ms
->WindowTitle
.Buffer
);
1229 denormalize( params
, ¶ms
->Desktop
.Buffer
);
1230 denormalize( params
, ¶ms
->ShellInfo
.Buffer
);
1231 denormalize( params
, ¶ms
->RuntimeInfo
.Buffer
);
1232 params
->Flags
&= ~PROCESS_PARAMS_FLAG_NORMALIZED
;
1238 #define ROUND_SIZE(size) (((size) + sizeof(void *) - 1) & ~(sizeof(void *) - 1))
1240 /* append a unicode string to the process params data; helper for RtlCreateProcessParameters */
1241 static void append_unicode_string( void **data
, const UNICODE_STRING
*src
,
1242 UNICODE_STRING
*dst
)
1244 dst
->Length
= src
->Length
;
1245 dst
->MaximumLength
= src
->MaximumLength
;
1246 if (dst
->MaximumLength
)
1248 dst
->Buffer
= *data
;
1249 memcpy( dst
->Buffer
, src
->Buffer
, dst
->Length
);
1250 *data
= (char *)dst
->Buffer
+ ROUND_SIZE( dst
->MaximumLength
);
1252 else dst
->Buffer
= NULL
;
1256 /******************************************************************************
1257 * RtlCreateProcessParametersEx [NTDLL.@]
1259 NTSTATUS WINAPI
RtlCreateProcessParametersEx( RTL_USER_PROCESS_PARAMETERS
**result
,
1260 const UNICODE_STRING
*ImagePathName
,
1261 const UNICODE_STRING
*DllPath
,
1262 const UNICODE_STRING
*CurrentDirectoryName
,
1263 const UNICODE_STRING
*CommandLine
,
1265 const UNICODE_STRING
*WindowTitle
,
1266 const UNICODE_STRING
*Desktop
,
1267 const UNICODE_STRING
*ShellInfo
,
1268 const UNICODE_STRING
*RuntimeInfo
,
1271 UNICODE_STRING curdir
;
1272 const RTL_USER_PROCESS_PARAMETERS
*cur_params
;
1273 SIZE_T size
, env_size
= 0;
1275 NTSTATUS status
= STATUS_SUCCESS
;
1277 RtlAcquirePebLock();
1278 cur_params
= NtCurrentTeb()->Peb
->ProcessParameters
;
1279 if (!DllPath
) DllPath
= &cur_params
->DllPath
;
1280 if (!CurrentDirectoryName
)
1282 if (NtCurrentTeb()->Tib
.SubSystemTib
) /* FIXME: hack */
1283 curdir
= ((WIN16_SUBSYSTEM_TIB
*)NtCurrentTeb()->Tib
.SubSystemTib
)->curdir
.DosPath
;
1285 curdir
= cur_params
->CurrentDirectory
.DosPath
;
1287 else curdir
= *CurrentDirectoryName
;
1288 curdir
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1290 if (!CommandLine
) CommandLine
= ImagePathName
;
1291 if (!Environment
&& cur_params
) Environment
= cur_params
->Environment
;
1292 if (!WindowTitle
) WindowTitle
= &empty_str
;
1293 if (!Desktop
) Desktop
= &empty_str
;
1294 if (!ShellInfo
) ShellInfo
= &empty_str
;
1295 if (!RuntimeInfo
) RuntimeInfo
= &null_str
;
1297 if (Environment
) env_size
= get_env_length( Environment
) * sizeof(WCHAR
);
1299 size
= (sizeof(RTL_USER_PROCESS_PARAMETERS
)
1300 + ROUND_SIZE( ImagePathName
->MaximumLength
)
1301 + ROUND_SIZE( DllPath
->MaximumLength
)
1302 + ROUND_SIZE( curdir
.MaximumLength
)
1303 + ROUND_SIZE( CommandLine
->MaximumLength
)
1304 + ROUND_SIZE( WindowTitle
->MaximumLength
)
1305 + ROUND_SIZE( Desktop
->MaximumLength
)
1306 + ROUND_SIZE( ShellInfo
->MaximumLength
)
1307 + ROUND_SIZE( RuntimeInfo
->MaximumLength
));
1309 if ((ptr
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ ROUND_SIZE(env_size
) )))
1311 RTL_USER_PROCESS_PARAMETERS
*params
= ptr
;
1312 params
->AllocationSize
= size
;
1313 params
->Size
= size
;
1314 params
->Flags
= PROCESS_PARAMS_FLAG_NORMALIZED
;
1315 if (cur_params
) params
->ConsoleFlags
= cur_params
->ConsoleFlags
;
1316 /* all other fields are zero */
1319 append_unicode_string( &ptr
, &curdir
, ¶ms
->CurrentDirectory
.DosPath
);
1320 append_unicode_string( &ptr
, DllPath
, ¶ms
->DllPath
);
1321 append_unicode_string( &ptr
, ImagePathName
, ¶ms
->ImagePathName
);
1322 append_unicode_string( &ptr
, CommandLine
, ¶ms
->CommandLine
);
1323 append_unicode_string( &ptr
, WindowTitle
, ¶ms
->WindowTitle
);
1324 append_unicode_string( &ptr
, Desktop
, ¶ms
->Desktop
);
1325 append_unicode_string( &ptr
, ShellInfo
, ¶ms
->ShellInfo
);
1326 append_unicode_string( &ptr
, RuntimeInfo
, ¶ms
->RuntimeInfo
);
1327 if (Environment
) params
->Environment
= memcpy( ptr
, Environment
, env_size
);
1329 if (!(flags
& PROCESS_PARAMS_FLAG_NORMALIZED
)) RtlDeNormalizeProcessParams( params
);
1331 else status
= STATUS_NO_MEMORY
;
1333 RtlReleasePebLock();
1338 /******************************************************************************
1339 * RtlCreateProcessParameters [NTDLL.@]
1341 NTSTATUS WINAPI
RtlCreateProcessParameters( RTL_USER_PROCESS_PARAMETERS
**result
,
1342 const UNICODE_STRING
*image
,
1343 const UNICODE_STRING
*dllpath
,
1344 const UNICODE_STRING
*curdir
,
1345 const UNICODE_STRING
*cmdline
,
1347 const UNICODE_STRING
*title
,
1348 const UNICODE_STRING
*desktop
,
1349 const UNICODE_STRING
*shellinfo
,
1350 const UNICODE_STRING
*runtime
)
1352 return RtlCreateProcessParametersEx( result
, image
, dllpath
, curdir
, cmdline
,
1353 env
, title
, desktop
, shellinfo
, runtime
, 0 );
1357 /******************************************************************************
1358 * RtlDestroyProcessParameters [NTDLL.@]
1360 void WINAPI
RtlDestroyProcessParameters( RTL_USER_PROCESS_PARAMETERS
*params
)
1362 RtlFreeHeap( GetProcessHeap(), 0, params
);
1366 static inline void get_unicode_string( UNICODE_STRING
*str
, WCHAR
**src
, UINT len
)
1370 str
->MaximumLength
= len
+ sizeof(WCHAR
);
1371 *src
+= len
/ sizeof(WCHAR
);
1375 /***********************************************************************
1378 static void run_wineboot( WCHAR
**env
)
1380 static const WCHAR wineboot_eventW
[] = {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s',
1381 '\\','_','_','w','i','n','e','b','o','o','t','_','e','v','e','n','t',0};
1382 static const WCHAR wineboot
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
1383 's','y','s','t','e','m','3','2','\\',
1384 'w','i','n','e','b','o','o','t','.','e','x','e',0};
1385 static const WCHAR cmdline
[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
1386 's','y','s','t','e','m','3','2','\\',
1387 'w','i','n','e','b','o','o','t','.','e','x','e',' ',
1388 '-','-','i','n','i','t',0};
1389 UNICODE_STRING nameW
, cmdlineW
, dllpathW
;
1390 RTL_USER_PROCESS_PARAMETERS
*params
;
1391 RTL_USER_PROCESS_INFORMATION info
;
1392 WCHAR
*load_path
, *dummy
;
1393 OBJECT_ATTRIBUTES attr
;
1394 LARGE_INTEGER timeout
;
1400 RtlInitUnicodeString( &nameW
, wineboot_eventW
);
1401 InitializeObjectAttributes( &attr
, &nameW
, OBJ_OPENIF
, 0, NULL
);
1403 status
= NtCreateEvent( &handles
[0], EVENT_ALL_ACCESS
, &attr
, NotificationEvent
, 0 );
1404 if (status
== STATUS_OBJECT_NAME_EXISTS
) goto wait
;
1407 ERR( "failed to create wineboot event, expect trouble\n" );
1410 LdrGetDllPath( wineboot
+ 4, LOAD_WITH_ALTERED_SEARCH_PATH
, &load_path
, &dummy
);
1411 RtlInitUnicodeString( &nameW
, wineboot
+ 4 );
1412 RtlInitUnicodeString( &dllpathW
, load_path
);
1413 RtlInitUnicodeString( &cmdlineW
, cmdline
);
1414 RtlCreateProcessParametersEx( ¶ms
, &nameW
, &dllpathW
, NULL
, &cmdlineW
, *env
, NULL
, NULL
,
1415 NULL
, NULL
, PROCESS_PARAMS_FLAG_NORMALIZED
);
1416 params
->hStdInput
= 0;
1417 params
->hStdOutput
= 0;
1418 params
->hStdError
= NtCurrentTeb()->Peb
->ProcessParameters
->hStdError
;
1420 RtlInitUnicodeString( &nameW
, wineboot
);
1421 RtlWow64EnableFsRedirectionEx( TRUE
, &redir
);
1422 status
= RtlCreateUserProcess( &nameW
, OBJ_CASE_INSENSITIVE
, params
,
1423 NULL
, NULL
, 0, FALSE
, 0, 0, &info
);
1424 RtlWow64EnableFsRedirection( !redir
);
1425 RtlReleasePath( load_path
);
1426 RtlDestroyProcessParameters( params
);
1429 ERR( "failed to start wineboot %x\n", status
);
1430 NtClose( handles
[0] );
1433 NtResumeThread( info
.Thread
, NULL
);
1434 NtClose( info
.Thread
);
1435 handles
[count
++] = info
.Process
;
1438 timeout
.QuadPart
= (ULONGLONG
)(first_prefix_start
? 5 : 2) * 60 * 1000 * -10000;
1439 if (NtWaitForMultipleObjects( count
, handles
, TRUE
, FALSE
, &timeout
) == WAIT_TIMEOUT
)
1440 ERR( "boot event wait timed out\n" );
1441 while (count
) NtClose( handles
[--count
] );
1443 /* reload environment now that wineboot has run */
1444 set_registry_environment( env
, first_prefix_start
);
1445 set_additional_environment( env
);
1449 /***********************************************************************
1450 * init_user_process_params
1452 * Fill the initial RTL_USER_PROCESS_PARAMETERS structure from the server.
1454 void init_user_process_params( SIZE_T data_size
)
1456 WCHAR
*src
, *load_path
, *dummy
;
1457 SIZE_T info_size
, env_size
;
1459 startup_info_t
*info
= NULL
;
1460 RTL_USER_PROCESS_PARAMETERS
*params
= NULL
;
1461 UNICODE_STRING curdir
, dllpath
, imagepath
, cmdline
, title
, desktop
, shellinfo
, runtime
;
1465 RTL_USER_PROCESS_PARAMETERS initial_params
= {0};
1466 WCHAR
*env
, curdir_buffer
[MAX_PATH
];
1468 NtCurrentTeb()->Peb
->ProcessParameters
= &initial_params
;
1469 initial_params
.Environment
= build_initial_environment( __wine_get_main_environment() );
1470 curdir
.Buffer
= curdir_buffer
;
1471 curdir
.MaximumLength
= sizeof(curdir_buffer
);
1472 get_current_directory( &curdir
);
1473 initial_params
.CurrentDirectory
.DosPath
= curdir
;
1474 get_image_path( __wine_main_argv
[0], &initial_params
.ImagePathName
);
1475 set_library_wargv( __wine_main_argv
, &initial_params
.ImagePathName
);
1476 build_command_line( __wine_main_wargv
, &cmdline
);
1477 LdrGetDllPath( initial_params
.ImagePathName
.Buffer
, 0, &load_path
, &dummy
);
1478 RtlInitUnicodeString( &dllpath
, load_path
);
1480 env
= initial_params
.Environment
;
1481 initial_params
.Environment
= NULL
; /* avoid copying it */
1482 if (RtlCreateProcessParametersEx( ¶ms
, &initial_params
.ImagePathName
, &dllpath
, &curdir
,
1483 &cmdline
, NULL
, &initial_params
.ImagePathName
, NULL
, NULL
, NULL
,
1484 PROCESS_PARAMS_FLAG_NORMALIZED
))
1487 params
->Environment
= env
;
1488 NtCurrentTeb()->Peb
->ProcessParameters
= params
;
1489 RtlFreeUnicodeString( &initial_params
.ImagePathName
);
1490 RtlFreeUnicodeString( &cmdline
);
1491 RtlReleasePath( load_path
);
1493 if (isatty(0) || isatty(1) || isatty(2))
1494 params
->ConsoleHandle
= (HANDLE
)2; /* see kernel32/kernel_private.h */
1496 wine_server_fd_to_handle( 0, GENERIC_READ
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
->hStdInput
);
1498 wine_server_fd_to_handle( 1, GENERIC_WRITE
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
->hStdOutput
);
1500 wine_server_fd_to_handle( 2, GENERIC_WRITE
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
->hStdError
);
1501 params
->wShowWindow
= 1; /* SW_SHOWNORMAL */
1503 run_wineboot( ¶ms
->Environment
);
1507 if (!(info
= RtlAllocateHeap( GetProcessHeap(), 0, data_size
))) return;
1509 SERVER_START_REQ( get_startup_info
)
1511 wine_server_set_reply( req
, info
, data_size
);
1512 if (!(status
= wine_server_call( req
)))
1514 data_size
= wine_server_reply_size( reply
);
1515 info_size
= reply
->info_size
;
1516 env_size
= data_size
- info_size
;
1520 if (status
) goto done
;
1522 src
= (WCHAR
*)(info
+ 1);
1523 get_unicode_string( &curdir
, &src
, info
->curdir_len
);
1524 get_unicode_string( &dllpath
, &src
, info
->dllpath_len
);
1525 get_unicode_string( &imagepath
, &src
, info
->imagepath_len
);
1526 get_unicode_string( &cmdline
, &src
, info
->cmdline_len
);
1527 get_unicode_string( &title
, &src
, info
->title_len
);
1528 get_unicode_string( &desktop
, &src
, info
->desktop_len
);
1529 get_unicode_string( &shellinfo
, &src
, info
->shellinfo_len
);
1530 get_unicode_string( &runtime
, &src
, info
->runtime_len
);
1532 runtime
.MaximumLength
= runtime
.Length
; /* runtime info isn't a real string */
1534 if (RtlCreateProcessParametersEx( ¶ms
, &imagepath
, &dllpath
, &curdir
, &cmdline
, NULL
,
1535 &title
, &desktop
, &shellinfo
, &runtime
,
1536 PROCESS_PARAMS_FLAG_NORMALIZED
))
1539 NtCurrentTeb()->Peb
->ProcessParameters
= params
;
1540 params
->DebugFlags
= info
->debug_flags
;
1541 params
->ConsoleHandle
= wine_server_ptr_handle( info
->console
);
1542 params
->ConsoleFlags
= info
->console_flags
;
1543 params
->hStdInput
= wine_server_ptr_handle( info
->hstdin
);
1544 params
->hStdOutput
= wine_server_ptr_handle( info
->hstdout
);
1545 params
->hStdError
= wine_server_ptr_handle( info
->hstderr
);
1546 params
->dwX
= info
->x
;
1547 params
->dwY
= info
->y
;
1548 params
->dwXSize
= info
->xsize
;
1549 params
->dwYSize
= info
->ysize
;
1550 params
->dwXCountChars
= info
->xchars
;
1551 params
->dwYCountChars
= info
->ychars
;
1552 params
->dwFillAttribute
= info
->attribute
;
1553 params
->dwFlags
= info
->flags
;
1554 params
->wShowWindow
= info
->show
;
1556 /* environment needs to be a separate memory block */
1557 if ((params
->Environment
= RtlAllocateHeap( GetProcessHeap(), 0, max( env_size
, sizeof(WCHAR
) ))))
1559 if (env_size
) memcpy( params
->Environment
, (char *)info
+ info_size
, env_size
);
1560 else params
->Environment
[0] = 0;
1563 set_library_wargv( __wine_main_argv
, NULL
);
1566 RtlFreeHeap( GetProcessHeap(), 0, info
);
1567 if (RtlSetCurrentDirectory_U( ¶ms
->CurrentDirectory
.DosPath
))
1569 MESSAGE("wine: could not open working directory %s, starting in the Windows directory.\n",
1570 debugstr_w( params
->CurrentDirectory
.DosPath
.Buffer
));
1571 RtlInitUnicodeString( &curdir
, windows_dir
);
1572 RtlSetCurrentDirectory_U( &curdir
);
1574 if (!params
->CurrentDirectory
.Handle
) chdir("/"); /* avoid locking removable devices */
1575 set_wow64_environment( ¶ms
->Environment
);