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
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
38 #ifdef HAVE_SYS_PRCTL_H
39 # include <sys/prctl.h>
45 # include <CoreFoundation/CFLocale.h>
46 # include <CoreFoundation/CFString.h>
50 #define WIN32_NO_STATUS
55 #include "wine/condrv.h"
56 #include "wine/debug.h"
57 #include "unix_private.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(environ
);
63 USHORT
*uctable
= NULL
, *lctable
= NULL
;
64 SIZE_T startup_info_size
= 0;
65 BOOL is_prefix_bootstrap
= FALSE
;
67 static const WCHAR bootstrapW
[] = {'W','I','N','E','B','O','O','T','S','T','R','A','P','M','O','D','E'};
70 char **main_argv
= NULL
;
71 char **main_envp
= NULL
;
72 WCHAR
**main_wargv
= NULL
;
74 static LCID user_lcid
, system_lcid
;
75 static LANGID user_ui_language
, system_ui_language
;
77 static char system_locale
[LOCALE_NAME_MAX_LENGTH
];
78 static char user_locale
[LOCALE_NAME_MAX_LENGTH
];
80 /* system directory with trailing backslash */
81 const WCHAR system_dir
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
82 's','y','s','t','e','m','3','2','\\',0};
94 NLS_SECTION_SORTKEYS
= 9,
95 NLS_SECTION_CASEMAP
= 10,
96 NLS_SECTION_CODEPAGE
= 11,
97 NLS_SECTION_NORMALIZE
= 12
100 static char *get_nls_file_path( ULONG type
, ULONG id
)
102 const char *dir
= build_dir
? build_dir
: data_dir
;
103 const char *name
= NULL
;
108 case NLS_SECTION_SORTKEYS
: name
= "sortdefault"; break;
109 case NLS_SECTION_CASEMAP
: name
= "l_intl"; break;
110 case NLS_SECTION_CODEPAGE
: name
= tmp
; sprintf( tmp
, "c_%03u", id
); break;
111 case NLS_SECTION_NORMALIZE
:
114 case NormalizationC
: name
= "normnfc"; break;
115 case NormalizationD
: name
= "normnfd"; break;
116 case NormalizationKC
: name
= "normnfkc"; break;
117 case NormalizationKD
: name
= "normnfkd"; break;
118 case 13: name
= "normidna"; break;
122 if (!name
) return NULL
;
123 if (!(path
= malloc( strlen(dir
) + strlen(name
) + 10 ))) return NULL
;
124 sprintf( path
, "%s/nls/%s.nls", dir
, name
);
128 static void *read_nls_file( ULONG type
, ULONG id
)
130 char *path
= get_nls_file_path( type
, id
);
132 void *data
, *ret
= NULL
;
135 if ((fd
= open( path
, O_RDONLY
)) != -1)
138 if ((data
= malloc( st
.st_size
)) && st
.st_size
> 0x1000 &&
139 read( fd
, data
, st
.st_size
) == st
.st_size
)
150 else ERR( "failed to load %u/%u\n", type
, id
);
155 static NTSTATUS
open_nls_data_file( ULONG type
, ULONG id
, HANDLE
*file
)
157 static const WCHAR sortdirW
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
158 'g','l','o','b','a','l','i','z','a','t','i','o','n','\\',
159 's','o','r','t','i','n','g','\\',0};
161 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
162 OBJECT_ATTRIBUTES attr
;
163 UNICODE_STRING valueW
;
164 WCHAR buffer
[ARRAY_SIZE(sortdirW
) + 16];
165 char *p
, *path
= get_nls_file_path( type
, id
);
167 if (!path
) return STATUS_OBJECT_NAME_NOT_FOUND
;
169 /* try to open file in system dir */
170 wcscpy( buffer
, type
== NLS_SECTION_SORTKEYS
? sortdirW
: system_dir
);
171 p
= strrchr( path
, '/' ) + 1;
172 ascii_to_unicode( buffer
+ wcslen(buffer
), p
, strlen(p
) + 1 );
173 init_unicode_string( &valueW
, buffer
);
174 InitializeObjectAttributes( &attr
, &valueW
, 0, 0, NULL
);
176 status
= open_unix_file( file
, path
, GENERIC_READ
, &attr
, 0, FILE_SHARE_READ
,
177 FILE_OPEN
, FILE_SYNCHRONOUS_IO_ALERT
, NULL
, 0 );
179 if (status
!= STATUS_NO_SUCH_FILE
) return status
;
181 if ((status
= nt_to_unix_file_name( &attr
, &path
, FILE_OPEN
))) return status
;
182 status
= open_unix_file( file
, path
, GENERIC_READ
, &attr
, 0, FILE_SHARE_READ
,
183 FILE_OPEN
, FILE_SYNCHRONOUS_IO_ALERT
, NULL
, 0 );
188 static NTSTATUS
get_nls_section_name( ULONG type
, ULONG id
, WCHAR name
[32] )
194 case NLS_SECTION_SORTKEYS
:
195 if (id
) return STATUS_INVALID_PARAMETER_1
;
196 strcpy( buffer
, "\\NLS\\NlsSectionSORTDEFAULT" );
198 case NLS_SECTION_CASEMAP
:
199 if (id
) return STATUS_UNSUCCESSFUL
;
200 strcpy( buffer
, "\\NLS\\NlsSectionLANG_INTL" );
202 case NLS_SECTION_CODEPAGE
:
203 sprintf( buffer
, "\\NLS\\NlsSectionCP%03u", id
);
205 case NLS_SECTION_NORMALIZE
:
206 sprintf( buffer
, "\\NLS\\NlsSectionNORM%08x", id
);
209 return STATUS_INVALID_PARAMETER_1
;
211 ascii_to_unicode( name
, buffer
, strlen(buffer
) + 1 );
212 return STATUS_SUCCESS
;
216 static int get_utf16( const WCHAR
*src
, unsigned int srclen
, unsigned int *ch
)
218 if (IS_HIGH_SURROGATE( src
[0] ))
220 if (srclen
<= 1) return 0;
221 if (!IS_LOW_SURROGATE( src
[1] )) return 0;
222 *ch
= 0x10000 + ((src
[0] & 0x3ff) << 10) + (src
[1] & 0x3ff);
225 if (IS_LOW_SURROGATE( src
[0] )) return 0;
233 /* The Apple filesystem enforces NFD so we need the compose tables to put it back into NFC */
237 WCHAR name
[13]; /* 00 file name */
238 USHORT checksum
[3]; /* 1a checksum? */
239 USHORT version
[4]; /* 20 Unicode version */
240 USHORT form
; /* 28 normalization form */
241 USHORT len_factor
; /* 2a factor for length estimates */
242 USHORT unknown1
; /* 2c */
243 USHORT decomp_size
; /* 2e decomposition hash size */
244 USHORT comp_size
; /* 30 composition hash size */
245 USHORT unknown2
; /* 32 */
246 USHORT classes
; /* 34 combining classes table offset */
247 USHORT props_level1
; /* 36 char properties table level 1 offset */
248 USHORT props_level2
; /* 38 char properties table level 2 offset */
249 USHORT decomp_hash
; /* 3a decomposition hash table offset */
250 USHORT decomp_map
; /* 3c decomposition character map table offset */
251 USHORT decomp_seq
; /* 3e decomposition character sequences offset */
252 USHORT comp_hash
; /* 40 composition hash table offset */
253 USHORT comp_seq
; /* 42 composition character sequences offset */
254 /* BYTE[] combining class values */
255 /* BYTE[0x2200] char properties index level 1 */
256 /* BYTE[] char properties index level 2 */
257 /* WORD[] decomposition hash table */
258 /* WORD[] decomposition character map */
259 /* WORD[] decomposition character sequences */
260 /* WORD[] composition hash table */
261 /* WORD[] composition character sequences */
264 static struct norm_table
*nfc_table
;
266 static void init_unix_codepage(void)
268 nfc_table
= read_nls_file( NLS_SECTION_NORMALIZE
, NormalizationC
);
271 static void put_utf16( WCHAR
*dst
, unsigned int ch
)
276 dst
[0] = 0xd800 | (ch
>> 10);
277 dst
[1] = 0xdc00 | (ch
& 0x3ff);
282 static BYTE
rol( BYTE val
, BYTE count
)
284 return (val
<< count
) | (val
>> (8 - count
));
288 static BYTE
get_char_props( const struct norm_table
*info
, unsigned int ch
)
290 const BYTE
*level1
= (const BYTE
*)((const USHORT
*)info
+ info
->props_level1
);
291 const BYTE
*level2
= (const BYTE
*)((const USHORT
*)info
+ info
->props_level2
);
292 BYTE off
= level1
[ch
/ 128];
294 if (!off
|| off
>= 0xfb) return rol( off
, 5 );
295 return level2
[(off
- 1) * 128 + ch
% 128];
298 static BYTE
get_combining_class( const struct norm_table
*info
, unsigned int c
)
300 const BYTE
*classes
= (const BYTE
*)((const USHORT
*)info
+ info
->classes
);
301 BYTE
class = get_char_props( info
, c
) & 0x3f;
303 if (class == 0x3f) return 0;
304 return classes
[class];
307 #define HANGUL_SBASE 0xac00
308 #define HANGUL_LBASE 0x1100
309 #define HANGUL_VBASE 0x1161
310 #define HANGUL_TBASE 0x11a7
311 #define HANGUL_LCOUNT 19
312 #define HANGUL_VCOUNT 21
313 #define HANGUL_TCOUNT 28
314 #define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT)
315 #define HANGUL_SCOUNT (HANGUL_LCOUNT * HANGUL_NCOUNT)
317 static unsigned int compose_hangul( unsigned int ch1
, unsigned int ch2
)
319 if (ch1
>= HANGUL_LBASE
&& ch1
< HANGUL_LBASE
+ HANGUL_LCOUNT
)
321 int lindex
= ch1
- HANGUL_LBASE
;
322 int vindex
= ch2
- HANGUL_VBASE
;
323 if (vindex
>= 0 && vindex
< HANGUL_VCOUNT
)
324 return HANGUL_SBASE
+ (lindex
* HANGUL_VCOUNT
+ vindex
) * HANGUL_TCOUNT
;
326 if (ch1
>= HANGUL_SBASE
&& ch1
< HANGUL_SBASE
+ HANGUL_SCOUNT
)
328 int sindex
= ch1
- HANGUL_SBASE
;
329 if (!(sindex
% HANGUL_TCOUNT
))
331 int tindex
= ch2
- HANGUL_TBASE
;
332 if (tindex
> 0 && tindex
< HANGUL_TCOUNT
) return ch1
+ tindex
;
338 static unsigned int compose_chars( const struct norm_table
*info
, unsigned int ch1
, unsigned int ch2
)
340 const USHORT
*table
= (const USHORT
*)info
+ info
->comp_hash
;
341 const WCHAR
*chars
= (const USHORT
*)info
+ info
->comp_seq
;
342 unsigned int hash
, start
, end
, i
, len
, ch
[3];
344 hash
= (ch1
+ 95 * ch2
) % info
->comp_size
;
346 end
= table
[hash
+ 1];
349 for (i
= 0; i
< 3; i
++, start
+= len
) len
= get_utf16( chars
+ start
, end
- start
, ch
+ i
);
350 if (ch
[0] == ch1
&& ch
[1] == ch2
) return ch
[2];
355 static unsigned int compose_string( const struct norm_table
*info
, WCHAR
*str
, unsigned int srclen
)
357 unsigned int i
, ch
, comp
, len
, start_ch
= 0, last_starter
= srclen
;
358 BYTE
class, prev_class
= 0;
360 for (i
= 0; i
< srclen
; i
+= len
)
362 if (!(len
= get_utf16( str
+ i
, srclen
- i
, &ch
))) return 0;
363 class = get_combining_class( info
, ch
);
364 if (last_starter
== srclen
|| (prev_class
&& prev_class
>= class) ||
365 (!(comp
= compose_hangul( start_ch
, ch
)) &&
366 !(comp
= compose_chars( info
, start_ch
, ch
))))
377 int comp_len
= 1 + (comp
>= 0x10000);
378 int start_len
= 1 + (start_ch
>= 0x10000);
380 if (comp_len
!= start_len
)
381 memmove( str
+ last_starter
+ comp_len
, str
+ last_starter
+ start_len
,
382 (i
- (last_starter
+ start_len
)) * sizeof(WCHAR
) );
383 memmove( str
+ i
+ comp_len
- start_len
, str
+ i
+ len
, (srclen
- i
- len
) * sizeof(WCHAR
) );
384 srclen
+= comp_len
- start_len
- len
;
389 put_utf16( str
+ i
, comp
);
395 #elif defined(__ANDROID__) /* Android always uses UTF-8 */
397 static void init_unix_codepage(void) { }
399 #else /* __APPLE__ || __ANDROID__ */
401 /* charset to codepage map, sorted by name */
402 static const struct { const char *name
; UINT cp
; } charset_names
[] =
404 { "ANSIX341968", 20127 },
406 { "BIG5HKSCS", 950 },
422 { "GB18030", 936 /* 54936 */ },
444 { "ISO88591", 28591 },
445 { "ISO885913", 28603 },
446 { "ISO885915", 28605 },
447 { "ISO88592", 28592 },
448 { "ISO88593", 28593 },
449 { "ISO88594", 28594 },
450 { "ISO88595", 28595 },
451 { "ISO88596", 28596 },
452 { "ISO88597", 28597 },
453 { "ISO88598", 28598 },
454 { "ISO88599", 28599 },
461 static void init_unix_cptable( USHORT
*ptr
)
465 unix_cp
.wctable
= ptr
+ ptr
[0] + 1;
466 unix_cp
.mbtable
= ++ptr
;
468 if (*ptr
++) ptr
+= 256; /* glyph table */
469 if (*ptr
) unix_cp
.dbcs
= ptr
+ 1; /* dbcs ranges */
472 static void init_unix_codepage(void)
474 char charset_name
[16];
477 int min
= 0, max
= ARRAY_SIZE(charset_names
) - 1;
479 setlocale( LC_CTYPE
, "" );
480 if (!(name
= nl_langinfo( CODESET
))) return;
482 /* remove punctuation characters from charset name */
483 for (i
= j
= 0; name
[i
] && j
< sizeof(charset_name
)-1; i
++)
485 if (name
[i
] >= '0' && name
[i
] <= '9') charset_name
[j
++] = name
[i
];
486 else if (name
[i
] >= 'A' && name
[i
] <= 'Z') charset_name
[j
++] = name
[i
];
487 else if (name
[i
] >= 'a' && name
[i
] <= 'z') charset_name
[j
++] = name
[i
] + ('A' - 'a');
493 int pos
= (min
+ max
) / 2;
494 int res
= strcmp( charset_names
[pos
].name
, charset_name
);
497 if (charset_names
[pos
].cp
!= CP_UTF8
)
499 void *data
= read_nls_file( NLS_SECTION_CODEPAGE
, charset_names
[pos
].cp
);
500 if (data
) init_unix_cptable( data
);
504 if (res
> 0) max
= pos
- 1;
507 ERR( "unrecognized charset '%s'\n", name
);
510 #endif /* __APPLE__ || __ANDROID__ */
513 static inline SIZE_T
get_env_length( const WCHAR
*env
)
515 const WCHAR
*end
= env
;
516 while (*end
) end
+= wcslen(end
) + 1;
517 return end
+ 1 - env
;
521 #define STARTS_WITH(var,str) (!strncmp( var, str, sizeof(str) - 1 ))
523 /***********************************************************************
526 * Check if an environment variable needs to be handled specially when
527 * passed through the Unix environment (i.e. prefixed with "WINE").
529 static BOOL
is_special_env_var( const char *var
)
531 return (STARTS_WITH( var
, "PATH=" ) ||
532 STARTS_WITH( var
, "PWD=" ) ||
533 STARTS_WITH( var
, "HOME=" ) ||
534 STARTS_WITH( var
, "TEMP=" ) ||
535 STARTS_WITH( var
, "TMP=" ) ||
536 STARTS_WITH( var
, "QT_" ) ||
537 STARTS_WITH( var
, "VK_" ));
540 /* check if an environment variable changes dynamically in every new process */
541 static BOOL
is_dynamic_env_var( const char *var
)
543 return (STARTS_WITH( var
, "WINEDLLOVERRIDES=" ) ||
544 STARTS_WITH( var
, "WINEDATADIR=" ) ||
545 STARTS_WITH( var
, "WINEHOMEDIR=" ) ||
546 STARTS_WITH( var
, "WINEBUILDDIR=" ) ||
547 STARTS_WITH( var
, "WINECONFIGDIR=" ) ||
548 STARTS_WITH( var
, "WINEDLLDIR" ) ||
549 STARTS_WITH( var
, "WINEUNIXCP=" ) ||
550 STARTS_WITH( var
, "WINELOCALE=" ) ||
551 STARTS_WITH( var
, "WINEUSERLOCALE=" ) ||
552 STARTS_WITH( var
, "WINEUSERNAME=" ) ||
553 STARTS_WITH( var
, "WINEPRELOADRESERVE=" ) ||
554 STARTS_WITH( var
, "WINELOADERNOEXEC=" ) ||
555 STARTS_WITH( var
, "WINESERVERSOCKET=" ));
558 static unsigned int decode_utf8_char( unsigned char ch
, const char **str
, const char *strend
)
560 /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
561 static const char utf8_length
[128] =
563 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
564 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
565 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
566 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
567 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
568 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
569 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
570 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
573 /* first byte mask depending on UTF-8 sequence length */
574 static const unsigned char utf8_mask
[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
576 unsigned int len
= utf8_length
[ch
- 0x80];
577 unsigned int res
= ch
& utf8_mask
[len
];
578 const char *end
= *str
+ len
;
588 if ((ch
= end
[-3] ^ 0x80) >= 0x40) break;
589 res
= (res
<< 6) | ch
;
591 if (res
< 0x10) break;
593 if ((ch
= end
[-2] ^ 0x80) >= 0x40) break;
594 res
= (res
<< 6) | ch
;
595 if (res
>= 0x110000 >> 6) break;
597 if (res
< 0x20) break;
598 if (res
>= 0xd800 >> 6 && res
<= 0xdfff >> 6) break;
600 if ((ch
= end
[-1] ^ 0x80) >= 0x40) break;
601 res
= (res
<< 6) | ch
;
603 if (res
< 0x80) break;
610 /******************************************************************
611 * ntdll_umbstowcs (ntdll.so)
613 DWORD
ntdll_umbstowcs( const char *src
, DWORD srclen
, WCHAR
*dst
, DWORD dstlen
)
623 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++, dst
++)
625 USHORT off
= unix_cp
.dbcs
[(unsigned char)*src
];
626 if (off
&& srclen
> 1)
630 *dst
= unix_cp
.dbcs
[off
+ (unsigned char)*src
];
632 else *dst
= unix_cp
.mbtable
[(unsigned char)*src
];
638 reslen
= min( srclen
, dstlen
);
639 for (i
= 0; i
< reslen
; i
++) dst
[i
] = unix_cp
.mbtable
[(unsigned char)src
[i
]];
645 RtlUTF8ToUnicodeN( dst
, dstlen
* sizeof(WCHAR
), &reslen
, src
, srclen
);
646 reslen
/= sizeof(WCHAR
);
647 #ifdef __APPLE__ /* work around broken Mac OS X filesystem that enforces NFD */
648 if (reslen
&& nfc_table
) reslen
= compose_string( nfc_table
, dst
, reslen
);
655 /******************************************************************
656 * ntdll_wcstoumbs (ntdll.so)
658 int ntdll_wcstoumbs( const WCHAR
*src
, DWORD srclen
, char *dst
, DWORD dstlen
, BOOL strict
)
666 const unsigned short *uni2cp
= unix_cp
.wctable
;
667 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++)
669 unsigned short ch
= uni2cp
[*src
];
672 if (strict
&& unix_cp
.dbcs
[unix_cp
.dbcs
[ch
>> 8] + (ch
& 0xff)] != *src
) return -1;
673 if (i
== 1) break; /* do not output a partial char */
679 if (unix_cp
.mbtable
[ch
] != *src
) return -1;
687 const unsigned char *uni2cp
= unix_cp
.wctable
;
688 reslen
= min( srclen
, dstlen
);
689 for (i
= 0; i
< reslen
; i
++)
691 unsigned char ch
= uni2cp
[src
[i
]];
692 if (strict
&& unix_cp
.mbtable
[ch
] != src
[i
]) return -1;
702 for (end
= dst
+ dstlen
; srclen
; srclen
--, src
++)
706 if (ch
< 0x80) /* 0x00-0x7f: 1 byte */
708 if (dst
> end
- 1) break;
712 if (ch
< 0x800) /* 0x80-0x7ff: 2 bytes */
714 if (dst
> end
- 2) break;
715 dst
[1] = 0x80 | (ch
& 0x3f);
721 if (!get_utf16( src
, srclen
, &val
))
723 if (strict
) return -1;
726 if (val
< 0x10000) /* 0x800-0xffff: 3 bytes */
728 if (dst
> end
- 3) break;
729 dst
[2] = 0x80 | (val
& 0x3f);
731 dst
[1] = 0x80 | (val
& 0x3f);
736 else /* 0x10000-0x10ffff: 4 bytes */
738 if (dst
> end
- 4) break;
739 dst
[3] = 0x80 | (val
& 0x3f);
741 dst
[2] = 0x80 | (val
& 0x3f);
743 dst
[1] = 0x80 | (val
& 0x3f);
751 reslen
= dstlen
- (end
- dst
);
757 /**********************************************************************
758 * ntdll_wcsicmp (ntdll.so)
760 int ntdll_wcsicmp( const WCHAR
*str1
, const WCHAR
*str2
)
765 if ((ret
= ntdll_towupper( *str1
) - ntdll_towupper( *str2
)) || !*str1
) return ret
;
772 /**********************************************************************
773 * ntdll_wcsnicmp (ntdll.so)
775 int ntdll_wcsnicmp( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
778 for (ret
= 0; n
> 0; n
--, str1
++, str2
++)
779 if ((ret
= ntdll_towupper(*str1
) - ntdll_towupper(*str2
)) || !*str1
) break;
784 /***********************************************************************
785 * ntdll_get_build_dir (ntdll.so)
787 const char *ntdll_get_build_dir(void)
793 /***********************************************************************
794 * ntdll_get_data_dir (ntdll.so)
796 const char *ntdll_get_data_dir(void)
802 /***********************************************************************
805 * Build the environment of a new child process.
807 char **build_envp( const WCHAR
*envW
)
809 static const char * const unix_vars
[] = { "PATH", "TEMP", "TMP", "HOME" };
812 int count
= 1, length
, lenW
;
815 lenW
= get_env_length( envW
);
816 if (!(env
= malloc( lenW
* 3 ))) return NULL
;
817 length
= ntdll_wcstoumbs( envW
, lenW
, env
, lenW
* 3, FALSE
);
819 for (p
= env
; *p
; p
+= strlen(p
) + 1, count
++)
821 if (is_dynamic_env_var( p
)) continue;
822 if (is_special_env_var( p
)) length
+= 4; /* prefix it with "WINE" */
825 for (i
= 0; i
< ARRAY_SIZE( unix_vars
); i
++)
827 if (!(p
= getenv(unix_vars
[i
]))) continue;
828 length
+= strlen(unix_vars
[i
]) + strlen(p
) + 2;
832 if ((envp
= malloc( count
* sizeof(*envp
) + length
)))
834 char **envptr
= envp
;
835 char *dst
= (char *)(envp
+ count
);
837 /* some variables must not be modified, so we get them directly from the unix env */
838 for (i
= 0; i
< ARRAY_SIZE( unix_vars
); i
++)
840 if (!(p
= getenv( unix_vars
[i
] ))) continue;
841 *envptr
++ = strcpy( dst
, unix_vars
[i
] );
844 dst
+= strlen(dst
) + 1;
847 /* now put the Windows environment strings */
848 for (p
= env
; *p
; p
+= strlen(p
) + 1)
850 if (*p
== '=') continue; /* skip drive curdirs, this crashes some unix apps */
851 if (is_dynamic_env_var( p
)) continue;
852 if (is_special_env_var( p
)) /* prefix it with "WINE" */
854 *envptr
++ = strcpy( dst
, "WINE" );
859 *envptr
++ = strcpy( dst
, p
);
861 dst
+= strlen(dst
) + 1;
870 /***********************************************************************
873 * Change the process name in the ps output.
875 static void set_process_name( const char *name
)
879 #ifdef HAVE_SETPROCTITLE
880 setproctitle("-%s", name
);
882 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
883 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
884 #ifdef HAVE_SETPROGNAME
889 # define PR_SET_NAME 15
891 prctl( PR_SET_NAME
, name
);
896 /***********************************************************************
899 * Build the main argv by removing argv[0].
901 static void rebuild_argv(void)
903 BOOL shift_strings
= FALSE
;
906 #ifndef HAVE_SETPROCTITLE
907 for (i
= 1; i
< main_argc
; i
++)
908 if (main_argv
[i
- 1] + strlen( main_argv
[i
- 1] ) + 1 != main_argv
[i
]) break;
909 shift_strings
= (i
== main_argc
);
913 int offset
= main_argv
[1] - main_argv
[0];
914 char *end
= main_argv
[main_argc
- 1] + strlen(main_argv
[main_argc
- 1]) + 1;
915 memmove( main_argv
[0], main_argv
[1], end
- main_argv
[1] );
916 memset( end
- offset
, 0, offset
);
917 for (i
= 1; i
< main_argc
; i
++) main_argv
[i
- 1] = main_argv
[i
] - offset
;
919 else memmove( main_argv
, main_argv
+ 1, (main_argc
- 1) * sizeof(main_argv
[0]) );
921 main_argv
[--main_argc
] = NULL
;
922 set_process_name( main_argv
[0] );
926 /***********************************************************************
929 * Prepend values to the main argv, removing the original argv[0].
931 static void prepend_argv( const char **args
, int count
)
935 BOOL write_strings
= FALSE
;
936 int i
, total
= 0, new_argc
= main_argc
+ count
- 1;
938 for (i
= 0; i
< count
; i
++) total
+= strlen(args
[i
]) + 1;
939 for (i
= 1; i
< main_argc
; i
++) total
+= strlen(main_argv
[i
]) + 1;
941 new_argv
= malloc( (new_argc
+ 1) * sizeof(*new_argv
) + total
);
942 p
= (char *)(new_argv
+ new_argc
+ 1);
943 for (i
= 0; i
< count
; i
++)
946 strcpy( p
, args
[i
] );
949 for (i
= 1; i
< main_argc
; i
++)
951 new_argv
[count
+ i
- 1] = p
;
952 strcpy( p
, main_argv
[i
] );
955 new_argv
[new_argc
] = NULL
;
957 /* copy what we can over the original argv */
959 #ifndef HAVE_SETPROCTITLE
960 for (i
= 1; i
< main_argc
; i
++)
961 if (main_argv
[i
- 1] + strlen(main_argv
[i
- 1]) + 1 != main_argv
[i
]) break;
962 write_strings
= (i
== main_argc
);
967 end
= main_argv
[main_argc
- 1] + strlen(main_argv
[main_argc
- 1]) + 1;
969 for (i
= 0; i
< min( new_argc
, main_argc
) && p
< end
; i
++)
971 int len
= min( end
- p
- 1, strlen(new_argv
[i
]) );
973 memcpy( p
, new_argv
[i
], len
);
978 memset( p
, 0, end
- p
);
983 memcpy( main_argv
, new_argv
, min( new_argc
, main_argc
) * sizeof(*new_argv
) );
984 main_argv
[min( new_argc
, main_argc
)] = NULL
;
987 main_argc
= new_argc
;
988 main_argv
= new_argv
;
989 set_process_name( main_argv
[0] );
993 /***********************************************************************
996 * Build the Unicode argv array, replacing argv[0] by the image name.
998 static WCHAR
**build_wargv( const WCHAR
*image
)
1002 DWORD total
= wcslen(image
) + 1;
1004 for (argc
= 1; main_argv
[argc
]; argc
++) total
+= strlen(main_argv
[argc
]) + 1;
1006 wargv
= malloc( total
* sizeof(WCHAR
) + (argc
+ 1) * sizeof(*wargv
) );
1007 p
= (WCHAR
*)(wargv
+ argc
+ 1);
1010 total
-= wcslen( p
) + 1;
1011 p
+= wcslen( p
) + 1;
1012 for (argc
= 1; main_argv
[argc
]; argc
++)
1014 DWORD reslen
= ntdll_umbstowcs( main_argv
[argc
], strlen(main_argv
[argc
]) + 1, p
, total
);
1024 /* Unix format is: lang[_country][.charset][@modifier]
1025 * Windows format is: lang[-script][-country][_modifier] */
1026 static BOOL
unix_to_win_locale( const char *unix_name
, char *win_name
)
1028 static const char sep
[] = "_.@";
1029 char buffer
[LOCALE_NAME_MAX_LENGTH
];
1030 char *p
, *country
= NULL
, *modifier
= NULL
;
1032 if (!unix_name
|| !unix_name
[0] || !strcmp( unix_name
, "C" ))
1034 unix_name
= getenv( "LC_ALL" );
1035 if (!unix_name
|| !unix_name
[0]) return FALSE
;
1038 if (strlen( unix_name
) >= LOCALE_NAME_MAX_LENGTH
) return FALSE
;
1039 strcpy( buffer
, unix_name
);
1040 if (!(p
= strpbrk( buffer
, sep
)))
1042 if (!strcmp( buffer
, "POSIX" ) || !strcmp( buffer
, "C" ))
1043 strcpy( win_name
, "en-US" );
1045 strcpy( win_name
, buffer
);
1053 p
= strpbrk( p
, sep
+ 1 );
1058 /* charset, ignore */
1059 p
= strchr( p
, '@' );
1067 /* rebuild a Windows name */
1069 strcpy( win_name
, buffer
);
1072 if (!strcmp( modifier
, "latin" )) strcat( win_name
, "-Latn" );
1073 else if (!strcmp( modifier
, "euro" )) {} /* ignore */
1078 p
= win_name
+ strlen(win_name
);
1080 strcpy( p
, country
);
1086 /******************************************************************
1089 static void init_locale(void)
1091 setlocale( LC_ALL
, "" );
1092 if (!unix_to_win_locale( setlocale( LC_CTYPE
, NULL
), system_locale
)) system_locale
[0] = 0;
1093 if (!unix_to_win_locale( setlocale( LC_MESSAGES
, NULL
), user_locale
)) user_locale
[0] = 0;
1096 if (!system_locale
[0])
1098 CFLocaleRef locale
= CFLocaleCopyCurrent();
1099 CFStringRef lang
= CFLocaleGetValue( locale
, kCFLocaleLanguageCode
);
1100 CFStringRef country
= CFLocaleGetValue( locale
, kCFLocaleCountryCode
);
1101 CFStringRef locale_string
;
1104 locale_string
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-%@"), lang
, country
);
1106 locale_string
= CFStringCreateCopy(NULL
, lang
);
1108 CFStringGetCString(locale_string
, system_locale
, sizeof(system_locale
), kCFStringEncodingUTF8
);
1110 CFRelease(locale_string
);
1112 if (!user_locale
[0])
1114 /* Retrieve the preferred language as chosen in System Preferences. */
1115 CFArrayRef preferred_langs
= CFLocaleCopyPreferredLanguages();
1116 if (preferred_langs
&& CFArrayGetCount( preferred_langs
))
1118 CFStringRef preferred_lang
= CFArrayGetValueAtIndex( preferred_langs
, 0 );
1119 CFDictionaryRef components
= CFLocaleCreateComponentsFromLocaleIdentifier( NULL
, preferred_lang
);
1122 CFStringRef lang
= CFDictionaryGetValue( components
, kCFLocaleLanguageCode
);
1123 CFStringRef country
= CFDictionaryGetValue( components
, kCFLocaleCountryCode
);
1124 CFLocaleRef locale
= NULL
;
1125 CFStringRef locale_string
;
1129 locale
= CFLocaleCopyCurrent();
1130 country
= CFLocaleGetValue( locale
, kCFLocaleCountryCode
);
1133 locale_string
= CFStringCreateWithFormat( NULL
, NULL
, CFSTR("%@-%@"), lang
, country
);
1135 locale_string
= CFStringCreateCopy( NULL
, lang
);
1136 CFStringGetCString( locale_string
, user_locale
, sizeof(user_locale
), kCFStringEncodingUTF8
);
1137 CFRelease( locale_string
);
1138 if (locale
) CFRelease( locale
);
1139 CFRelease( components
);
1142 if (preferred_langs
) CFRelease( preferred_langs
);
1145 setlocale( LC_NUMERIC
, "C" ); /* FIXME: oleaut32 depends on this */
1149 /***********************************************************************
1152 void init_environment( int argc
, char *argv
[], char *envp
[] )
1156 init_unix_codepage();
1159 if ((case_table
= read_nls_file( NLS_SECTION_CASEMAP
, 0 )))
1161 uctable
= case_table
+ 2;
1162 lctable
= case_table
+ case_table
[1] + 2;
1171 static const char overrides_help_message
[] =
1173 " WINEDLLOVERRIDES=\"entry;entry;entry...\"\n"
1174 " where each entry is of the form:\n"
1175 " module[,module...]={native|builtin}[,{b|n}]\n"
1177 " Only the first letter of the override (native or builtin)\n"
1178 " is significant.\n\n"
1180 " WINEDLLOVERRIDES=\"comdlg32=n,b;shell32,shlwapi=b\"\n";
1182 /*************************************************************************
1183 * get_initial_environment
1185 * Return the initial environment.
1187 static WCHAR
*get_initial_environment( SIZE_T
*pos
, SIZE_T
*size
)
1190 WCHAR
*env
, *ptr
, *end
;
1192 /* estimate needed size */
1194 for (e
= main_envp
; *e
; e
++) *size
+= strlen(*e
) + 1;
1196 if (!(env
= malloc( *size
* sizeof(WCHAR
) ))) return NULL
;
1198 end
= env
+ *size
- 1;
1199 for (e
= main_envp
; *e
&& ptr
< end
; e
++)
1203 /* skip Unix special variables and use the Wine variants instead */
1204 if (!strncmp( str
, "WINE", 4 ))
1206 if (is_special_env_var( str
+ 4 )) str
+= 4;
1207 else if (!strcmp( str
, "WINEDLLOVERRIDES=help" ))
1209 MESSAGE( overrides_help_message
);
1213 else if (is_special_env_var( str
)) continue; /* skip it */
1215 if (is_dynamic_env_var( str
)) continue;
1216 ptr
+= ntdll_umbstowcs( str
, strlen(str
) + 1, ptr
, end
- ptr
);
1223 static WCHAR
*find_env_var( WCHAR
*env
, SIZE_T size
, const WCHAR
*name
, SIZE_T namelen
)
1227 while (p
< env
+ size
)
1229 if (!wcsnicmp( p
, name
, namelen
) && p
[namelen
] == '=') return p
;
1235 static WCHAR
*get_env_var( WCHAR
*env
, SIZE_T size
, const WCHAR
*name
, SIZE_T namelen
)
1237 WCHAR
*ret
= NULL
, *var
= find_env_var( env
, size
, name
, namelen
);
1241 var
+= namelen
+ 1; /* skip name */
1242 if ((ret
= malloc( (wcslen(var
) + 1) * sizeof(WCHAR
) ))) wcscpy( ret
, var
);
1247 /* set an environment variable, replacing it if it exists */
1248 static void set_env_var( WCHAR
**env
, SIZE_T
*pos
, SIZE_T
*size
,
1249 const WCHAR
*name
, SIZE_T namelen
, const WCHAR
*value
)
1254 /* remove existing string */
1255 if ((p
= find_env_var( *env
, *pos
, name
, namelen
)))
1257 len
= wcslen(p
) + 1;
1258 memmove( p
, p
+ len
, (*pos
- (p
+ len
- *env
)) * sizeof(WCHAR
) );
1263 len
= wcslen( value
);
1264 if (*pos
+ namelen
+ len
+ 3 > *size
)
1266 *size
= max( *size
* 2, *pos
+ namelen
+ len
+ 3 );
1267 *env
= realloc( *env
, *size
* sizeof(WCHAR
) );
1269 memcpy( *env
+ *pos
, name
, namelen
* sizeof(WCHAR
) );
1270 (*env
)[*pos
+ namelen
] = '=';
1271 memcpy( *env
+ *pos
+ namelen
+ 1, value
, (len
+ 1) * sizeof(WCHAR
) );
1272 *pos
+= namelen
+ len
+ 2;
1275 static void append_envW( WCHAR
**env
, SIZE_T
*pos
, SIZE_T
*size
, const char *name
, const WCHAR
*value
)
1279 ascii_to_unicode( nameW
, name
, strlen(name
) + 1 );
1280 set_env_var( env
, pos
, size
, nameW
, wcslen(nameW
), value
);
1283 static void append_envA( WCHAR
**env
, SIZE_T
*pos
, SIZE_T
*size
, const char *name
, const char *value
)
1287 SIZE_T len
= strlen(value
) + 1;
1288 WCHAR
*valueW
= malloc( len
* sizeof(WCHAR
) );
1289 ntdll_umbstowcs( value
, len
, valueW
, len
);
1290 append_envW( env
, pos
, size
, name
, valueW
);
1293 else append_envW( env
, pos
, size
, name
, NULL
);
1296 /* set an environment variable for one of the wine path variables */
1297 static void add_path_var( WCHAR
**env
, SIZE_T
*pos
, SIZE_T
*size
, const char *name
, const char *path
)
1299 WCHAR
*nt_name
= NULL
;
1301 if (path
&& unix_to_nt_file_name( path
, &nt_name
)) return;
1302 append_envW( env
, pos
, size
, name
, nt_name
);
1307 static void add_system_dll_path_var( WCHAR
**env
, SIZE_T
*pos
, SIZE_T
*size
)
1310 size_t path_len
= 0;
1313 for (i
= 0; system_dll_paths
[i
]; ++i
)
1315 WCHAR
*nt_name
= NULL
;
1317 if (!unix_to_nt_file_name( system_dll_paths
[i
], &nt_name
))
1319 size_t len
= wcslen( nt_name
);
1320 path
= realloc( path
, (path_len
+ len
+ 1) * sizeof(WCHAR
) );
1321 memcpy( path
+ path_len
, nt_name
, len
* sizeof(WCHAR
) );
1322 path
[path_len
+ len
] = ';';
1323 path_len
+= len
+ 1;
1329 path
[path_len
- 1] = 0;
1330 append_envW( env
, pos
, size
, "WINESYSTEMDLLPATH", path
);
1336 /*************************************************************************
1337 * add_dynamic_environment
1339 * Add the environment variables that can differ between processes.
1341 static void add_dynamic_environment( WCHAR
**env
, SIZE_T
*pos
, SIZE_T
*size
)
1343 const char *overrides
= getenv( "WINEDLLOVERRIDES" );
1347 add_path_var( env
, pos
, size
, "WINEDATADIR", data_dir
);
1348 add_path_var( env
, pos
, size
, "WINEHOMEDIR", home_dir
);
1349 add_path_var( env
, pos
, size
, "WINEBUILDDIR", build_dir
);
1350 add_path_var( env
, pos
, size
, "WINECONFIGDIR", config_dir
);
1351 for (i
= 0; dll_paths
[i
]; i
++)
1353 sprintf( str
, "WINEDLLDIR%u", i
);
1354 add_path_var( env
, pos
, size
, str
, dll_paths
[i
] );
1356 sprintf( str
, "WINEDLLDIR%u", i
);
1357 append_envW( env
, pos
, size
, str
, NULL
);
1358 add_system_dll_path_var( env
, pos
, size
);
1359 append_envA( env
, pos
, size
, "WINEUSERNAME", user_name
);
1360 append_envA( env
, pos
, size
, "WINEDLLOVERRIDES", overrides
);
1363 sprintf( str
, "%u", unix_cp
.data
[1] );
1364 append_envA( env
, pos
, size
, "WINEUNIXCP", str
);
1366 else append_envW( env
, pos
, size
, "WINEUNIXCP", NULL
);
1367 append_envA( env
, pos
, size
, "WINELOCALE", system_locale
);
1368 append_envA( env
, pos
, size
, "WINEUSERLOCALE",
1369 strcmp( user_locale
, system_locale
) ? user_locale
: NULL
);
1370 append_envA( env
, pos
, size
, "SystemDrive", "C:" );
1371 append_envA( env
, pos
, size
, "SystemRoot", "C:\\windows" );
1375 static WCHAR
*expand_value( WCHAR
*env
, SIZE_T size
, const WCHAR
*src
, SIZE_T src_len
)
1377 SIZE_T len
, retlen
= src_len
+ 1, count
= 0;
1381 ret
= malloc( retlen
* sizeof(WCHAR
) );
1386 for (len
= 0; len
< src_len
; len
++) if (src
[len
] == '%') break;
1391 else /* we are at the start of a variable */
1393 for (len
= 1; len
< src_len
; len
++) if (src
[len
] == '%') break;
1396 if ((var
= find_env_var( env
, size
, src
+ 1, len
- 1 )))
1398 src
+= len
+ 1; /* skip the variable name */
1405 var
= src
; /* copy original name instead */
1411 else /* unfinished variable name, ignore it */
1418 if (len
>= retlen
- count
)
1420 retlen
= max( retlen
* 2, count
+ len
+ 1 );
1421 ret
= realloc( ret
, retlen
* sizeof(WCHAR
) );
1423 memcpy( ret
+ count
, var
, len
* sizeof(WCHAR
) );
1430 /***********************************************************************
1431 * add_registry_variables
1433 * Set environment variables by enumerating the values of a key;
1434 * helper for add_registry_environment().
1435 * Note that Windows happily truncates the value if it's too big.
1437 static void add_registry_variables( WCHAR
**env
, SIZE_T
*pos
, SIZE_T
*size
, HANDLE key
)
1439 static const WCHAR pathW
[] = {'P','A','T','H'};
1441 DWORD index
= 0, info_size
, namelen
, datalen
;
1442 WCHAR
*data
, *value
, *p
;
1443 WCHAR buffer
[offsetof(KEY_VALUE_FULL_INFORMATION
, Name
[1024]) / sizeof(WCHAR
)];
1444 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1448 status
= NtEnumerateValueKey( key
, index
++, KeyValueFullInformation
,
1449 buffer
, sizeof(buffer
) - sizeof(WCHAR
), &info_size
);
1450 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_OVERFLOW
) break;
1452 value
= data
= buffer
+ info
->DataOffset
/ sizeof(WCHAR
);
1453 datalen
= info
->DataLength
/ sizeof(WCHAR
);
1454 namelen
= info
->NameLength
/ sizeof(WCHAR
);
1456 if (datalen
&& !data
[datalen
- 1]) datalen
--; /* don't count terminating null if any */
1457 if (!datalen
) continue;
1459 if (info
->Type
== REG_EXPAND_SZ
) value
= expand_value( *env
, *pos
, data
, datalen
);
1462 if (namelen
== 4 && !wcsnicmp( info
->Name
, pathW
, 4 ) && (p
= find_env_var( *env
, *pos
, pathW
, 4 )))
1464 static const WCHAR sepW
[] = {';',0};
1465 WCHAR
*newpath
= malloc( (wcslen(p
) - 3 + wcslen(value
)) * sizeof(WCHAR
) );
1466 wcscpy( newpath
, p
+ 5 );
1467 wcscat( newpath
, sepW
);
1468 wcscat( newpath
, value
);
1469 if (value
!= data
) free( value
);
1473 set_env_var( env
, pos
, size
, info
->Name
, namelen
, value
);
1474 if (value
!= data
) free( value
);
1479 /***********************************************************************
1480 * get_registry_value
1482 static WCHAR
*get_registry_value( WCHAR
*env
, SIZE_T pos
, HKEY key
, const WCHAR
*name
)
1484 WCHAR buffer
[offsetof(KEY_VALUE_PARTIAL_INFORMATION
, Data
[1024 * sizeof(WCHAR
)])];
1485 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1486 DWORD len
, size
= sizeof(buffer
) - sizeof(WCHAR
);
1488 UNICODE_STRING nameW
;
1490 init_unicode_string( &nameW
, name
);
1491 if (NtQueryValueKey( key
, &nameW
, KeyValuePartialInformation
, buffer
, size
, &size
)) return NULL
;
1492 if (size
<= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
)) return NULL
;
1493 len
= size
- offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1495 if (info
->Type
== REG_EXPAND_SZ
)
1497 ret
= expand_value( env
, pos
, (WCHAR
*)info
->Data
, len
/ sizeof(WCHAR
) );
1501 ret
= malloc( len
+ sizeof(WCHAR
) );
1502 memcpy( ret
, info
->Data
, len
);
1503 ret
[len
/ sizeof(WCHAR
)] = 0;
1509 /***********************************************************************
1510 * add_registry_environment
1512 * Set the environment variables specified in the registry.
1514 static void add_registry_environment( WCHAR
**env
, SIZE_T
*pos
, SIZE_T
*size
)
1516 static const WCHAR syskeyW
[] = {'\\','R','e','g','i','s','t','r','y',
1517 '\\','M','a','c','h','i','n','e',
1518 '\\','S','y','s','t','e','m',
1519 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
1520 '\\','C','o','n','t','r','o','l',
1521 '\\','S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',
1522 '\\','E','n','v','i','r','o','n','m','e','n','t',0};
1523 static const WCHAR profileW
[] = {'\\','R','e','g','i','s','t','r','y',
1524 '\\','M','a','c','h','i','n','e','\\',
1525 'S','o','f','t','w','a','r','e','\\',
1526 'M','i','c','r','o','s','o','f','t','\\',
1527 'W','i','n','d','o','w','s',' ','N','T','\\',
1528 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1529 'P','r','o','f','i','l','e','L','i','s','t',0};
1530 static const WCHAR computerW
[] = {'\\','R','e','g','i','s','t','r','y',
1531 '\\','M','a','c','h','i','n','e',
1532 '\\','S','y','s','t','e','m',
1533 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
1534 '\\','C','o','n','t','r','o','l',
1535 '\\','C','o','m','p','u','t','e','r','N','a','m','e',
1536 '\\','A','c','t','i','v','e','C','o','m','p','u','t','e','r','N','a','m','e',0};
1537 static const WCHAR curversionW
[] = {'\\','R','e','g','i','s','t','r','y',
1538 '\\','M','a','c','h','i','n','e',
1539 '\\','S','o','f','t','w','a','r','e',
1540 '\\','M','i','c','r','o','s','o','f','t',
1541 '\\','W','i','n','d','o','w','s',
1542 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
1543 OBJECT_ATTRIBUTES attr
;
1544 UNICODE_STRING nameW
;
1548 InitializeObjectAttributes( &attr
, &nameW
, 0, 0, NULL
);
1549 init_unicode_string( &nameW
, syskeyW
);
1550 if (!NtOpenKey( &key
, KEY_READ
, &attr
))
1552 add_registry_variables( env
, pos
, size
, key
);
1555 if (!open_hkcu_key( "Environment", &key
))
1557 add_registry_variables( env
, pos
, size
, key
);
1560 if (!open_hkcu_key( "Volatile Environment", &key
))
1562 add_registry_variables( env
, pos
, size
, key
);
1566 /* set the user profile variables */
1567 init_unicode_string( &nameW
, profileW
);
1568 if (!NtOpenKey( &key
, KEY_READ
, &attr
))
1570 static const WCHAR progdataW
[] = {'P','r','o','g','r','a','m','D','a','t','a',0};
1571 static const WCHAR allusersW
[] = {'A','L','L','U','S','E','R','S','P','R','O','F','I','L','E',0};
1572 static const WCHAR publicW
[] = {'P','U','B','L','I','C',0};
1573 if ((value
= get_registry_value( *env
, *pos
, key
, progdataW
)))
1575 set_env_var( env
, pos
, size
, allusersW
, wcslen(allusersW
), value
);
1576 set_env_var( env
, pos
, size
, progdataW
, wcslen(progdataW
), value
);
1579 if ((value
= get_registry_value( *env
, *pos
, key
, publicW
)))
1581 set_env_var( env
, pos
, size
, publicW
, wcslen(publicW
), value
);
1587 /* set the ProgramFiles variables */
1588 init_unicode_string( &nameW
, curversionW
);
1589 if (!NtOpenKey( &key
, KEY_READ
| KEY_WOW64_64KEY
, &attr
))
1591 static const WCHAR progdirW
[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',0};
1592 static const WCHAR progdirx86W
[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0};
1593 static const WCHAR progfilesW
[] = {'P','r','o','g','r','a','m','F','i','l','e','s',0};
1594 static const WCHAR prog6432W
[] = {'P','r','o','g','r','a','m','W','6','4','3','2',0};
1595 static const WCHAR progx86W
[] = {'P','r','o','g','r','a','m','F','i','l','e','s','(','x','8','6',')',0};
1596 static const WCHAR commondirW
[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',0};
1597 static const WCHAR commondirx86W
[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0};
1598 static const WCHAR commonfilesW
[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s',0};
1599 static const WCHAR common6432W
[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','W','6','4','3','2',0};
1600 static const WCHAR commonx86W
[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s','(','x','8','6',')',0};
1602 if ((value
= get_registry_value( *env
, *pos
, key
, progdirx86W
)))
1604 set_env_var( env
, pos
, size
, progx86W
, wcslen(progx86W
), value
);
1606 if ((value
= get_registry_value( *env
, *pos
, key
, progdirW
)))
1607 set_env_var( env
, pos
, size
, prog6432W
, wcslen(prog6432W
), value
);
1611 if ((value
= get_registry_value( *env
, *pos
, key
, progdirW
)))
1612 set_env_var( env
, pos
, size
, progfilesW
, wcslen(progfilesW
), value
);
1616 if ((value
= get_registry_value( *env
, *pos
, key
, commondirx86W
)))
1618 set_env_var( env
, pos
, size
, commonx86W
, wcslen(commonx86W
), value
);
1620 if ((value
= get_registry_value( *env
, *pos
, key
, commondirW
)))
1621 set_env_var( env
, pos
, size
, common6432W
, wcslen(common6432W
), value
);
1625 if ((value
= get_registry_value( *env
, *pos
, key
, commondirW
)))
1626 set_env_var( env
, pos
, size
, commonfilesW
, wcslen(commonfilesW
), value
);
1632 /* set the computer name */
1633 init_unicode_string( &nameW
, computerW
);
1634 if (!NtOpenKey( &key
, KEY_READ
, &attr
))
1636 static const WCHAR computernameW
[] = {'C','O','M','P','U','T','E','R','N','A','M','E',0};
1637 if ((value
= get_registry_value( *env
, *pos
, key
, computernameW
)))
1639 set_env_var( env
, pos
, size
, computernameW
, wcslen(computernameW
), value
);
1647 /*************************************************************************
1648 * get_initial_console
1650 * Return the initial console handles.
1652 static void get_initial_console( RTL_USER_PROCESS_PARAMETERS
*params
)
1656 wine_server_fd_to_handle( 0, GENERIC_READ
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
->hStdInput
);
1657 wine_server_fd_to_handle( 1, GENERIC_WRITE
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
->hStdOutput
);
1658 wine_server_fd_to_handle( 2, GENERIC_WRITE
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
->hStdError
);
1660 /* mark tty handles for kernelbase, see init_console */
1661 if (params
->hStdInput
&& isatty(0))
1663 params
->ConsoleHandle
= CONSOLE_HANDLE_SHELL
;
1664 params
->hStdInput
= (HANDLE
)((UINT_PTR
)params
->hStdInput
| 1);
1666 if (params
->hStdError
&& isatty(2))
1668 params
->ConsoleHandle
= CONSOLE_HANDLE_SHELL
;
1669 params
->hStdError
= (HANDLE
)((UINT_PTR
)params
->hStdError
| 1);
1672 if (params
->hStdOutput
&& isatty(1))
1674 params
->ConsoleHandle
= CONSOLE_HANDLE_SHELL
;
1675 params
->hStdOutput
= (HANDLE
)((UINT_PTR
)params
->hStdOutput
| 1);
1679 if (output_fd
!= -1)
1681 struct winsize size
;
1682 if (!ioctl( output_fd
, TIOCGWINSZ
, &size
))
1684 params
->dwXCountChars
= size
.ws_col
;
1685 params
->dwYCountChars
= size
.ws_row
;
1691 /*************************************************************************
1692 * get_initial_directory
1694 * Get the current directory at startup.
1696 static WCHAR
*get_initial_directory(void)
1698 static const WCHAR backslashW
[] = {'\\',0};
1699 static const WCHAR windows_dir
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',0};
1705 /* try to get it from the Unix cwd */
1707 for (size
= 1024; ; size
*= 2)
1709 if (!(cwd
= malloc( size
))) break;
1710 if (getcwd( cwd
, size
)) break;
1712 if (errno
== ERANGE
) continue;
1717 /* try to use PWD if it is valid, so that we don't resolve symlinks */
1719 pwd
= getenv( "PWD" );
1722 struct stat st1
, st2
;
1724 if (!pwd
|| stat( pwd
, &st1
) == -1 ||
1725 (!stat( cwd
, &st2
) && (st1
.st_dev
!= st2
.st_dev
|| st1
.st_ino
!= st2
.st_ino
)))
1731 if (!unix_to_nt_file_name( pwd
, &ret
))
1733 ULONG len
= wcslen( ret
);
1734 if (len
&& ret
[len
- 1] != '\\')
1736 /* add trailing backslash */
1737 WCHAR
*tmp
= malloc( (len
+ 2) * sizeof(WCHAR
) );
1739 wcscat( tmp
, backslashW
);
1748 /* still not initialized */
1749 MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
1750 "starting in the Windows directory.\n", cwd
? cwd
: "" );
1751 ret
= malloc( sizeof(windows_dir
) );
1752 wcscpy( ret
, windows_dir
);
1758 /***********************************************************************
1759 * build_command_line
1761 * Build the command line of a process from the argv array.
1763 * We must quote and escape characters so that the argv array can be rebuilt
1764 * from the command line:
1765 * - spaces and tabs must be quoted
1767 * - quotes must be escaped
1769 * - if '\'s are followed by a '"', they must be doubled and followed by '\"',
1770 * resulting in an odd number of '\' followed by a '"'
1773 * - '\'s are followed by the closing '"' must be doubled,
1774 * resulting in an even number of '\' followed by a '"'
1776 * ' \\' -> '" \\\\"'
1777 * - '\'s that are not followed by a '"' can be left as is
1781 static WCHAR
*build_command_line( WCHAR
**wargv
)
1788 for (arg
= wargv
; *arg
; arg
++) len
+= 3 + 2 * wcslen( *arg
);
1789 if (!(ret
= malloc( len
* sizeof(WCHAR
) ))) return NULL
;
1792 for (arg
= wargv
; *arg
; arg
++)
1794 BOOL has_space
, has_quote
;
1798 /* check for quotes and spaces in this argument (first arg is always quoted) */
1799 has_space
= (arg
== wargv
) || !**arg
|| wcschr( *arg
, ' ' ) || wcschr( *arg
, '\t' );
1800 has_quote
= wcschr( *arg
, '"' ) != NULL
;
1802 /* now transfer it to the command line */
1803 if (has_space
) *p
++ = '"';
1804 if (has_quote
|| has_space
)
1807 for (a
= *arg
; *a
; a
++)
1809 if (*a
== '\\') bcount
++;
1812 if (*a
== '"') /* double all the '\\' preceding this '"', plus one */
1813 for (i
= 0; i
<= bcount
; i
++) *p
++ = '\\';
1826 /* Double all the '\' preceding the closing quote */
1827 for (i
= 0; i
< bcount
; i
++) *p
++ = '\\';
1832 if (p
> ret
) p
--; /* remove last space */
1834 if (p
- ret
>= 32767)
1836 ERR( "command line too long (%u)\n", (DWORD
)(p
- ret
) );
1837 NtTerminateProcess( GetCurrentProcess(), 1 );
1843 /***********************************************************************
1846 static void run_wineboot( WCHAR
*env
, SIZE_T size
)
1848 static const WCHAR eventW
[] = {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s',
1849 '\\','_','_','w','i','n','e','b','o','o','t','_','e','v','e','n','t',0};
1850 static const WCHAR appnameW
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s',
1851 '\\','s','y','s','t','e','m','3','2','\\','w','i','n','e','b','o','o','t','.','e','x','e',0};
1852 static const WCHAR cmdlineW
[] = {'"','C',':','\\','w','i','n','d','o','w','s','\\',
1853 's','y','s','t','e','m','3','2','\\','w','i','n','e','b','o','o','t','.','e','x','e','"',
1854 ' ','-','-','i','n','i','t',0};
1855 RTL_USER_PROCESS_PARAMETERS params
= { sizeof(params
), sizeof(params
) };
1856 PS_ATTRIBUTE_LIST ps_attr
;
1857 PS_CREATE_INFO create_info
;
1858 HANDLE process
, thread
, handles
[2];
1859 UNICODE_STRING nameW
;
1860 OBJECT_ATTRIBUTES attr
;
1861 LARGE_INTEGER timeout
;
1865 init_unicode_string( &nameW
, eventW
);
1866 InitializeObjectAttributes( &attr
, &nameW
, OBJ_OPENIF
, 0, NULL
);
1867 status
= NtCreateEvent( &handles
[0], EVENT_ALL_ACCESS
, &attr
, NotificationEvent
, 0 );
1868 if (status
== STATUS_OBJECT_NAME_EXISTS
) goto wait
;
1871 ERR( "failed to create wineboot event, expect trouble\n" );
1876 params
.Flags
= PROCESS_PARAMS_FLAG_NORMALIZED
;
1877 params
.Environment
= env
;
1878 params
.EnvironmentSize
= size
;
1879 init_unicode_string( ¶ms
.CurrentDirectory
.DosPath
, system_dir
+ 4 );
1880 init_unicode_string( ¶ms
.ImagePathName
, appnameW
+ 4 );
1881 init_unicode_string( ¶ms
.CommandLine
, cmdlineW
);
1882 init_unicode_string( ¶ms
.WindowTitle
, appnameW
+ 4 );
1883 init_unicode_string( &nameW
, appnameW
);
1885 ps_attr
.TotalLength
= sizeof(ps_attr
);
1886 ps_attr
.Attributes
[0].Attribute
= PS_ATTRIBUTE_IMAGE_NAME
;
1887 ps_attr
.Attributes
[0].Size
= sizeof(appnameW
) - sizeof(WCHAR
);
1888 ps_attr
.Attributes
[0].ValuePtr
= (WCHAR
*)appnameW
;
1889 ps_attr
.Attributes
[0].ReturnLength
= NULL
;
1891 wine_server_fd_to_handle( 2, GENERIC_WRITE
| SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
.hStdError
);
1893 if (NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
])
1895 NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
] = TRUE
;
1896 status
= NtCreateUserProcess( &process
, &thread
, PROCESS_ALL_ACCESS
, THREAD_ALL_ACCESS
,
1897 NULL
, NULL
, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
, ¶ms
,
1898 &create_info
, &ps_attr
);
1899 NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
] = FALSE
;
1902 status
= NtCreateUserProcess( &process
, &thread
, PROCESS_ALL_ACCESS
, THREAD_ALL_ACCESS
,
1903 NULL
, NULL
, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
, ¶ms
,
1904 &create_info
, &ps_attr
);
1905 NtClose( params
.hStdError
);
1909 ERR( "failed to start wineboot %x\n", status
);
1910 NtClose( handles
[0] );
1913 NtResumeThread( thread
, NULL
);
1915 handles
[count
++] = process
;
1918 timeout
.QuadPart
= (ULONGLONG
)5 * 60 * 1000 * -10000;
1919 if (NtWaitForMultipleObjects( count
, handles
, TRUE
, FALSE
, &timeout
) == WAIT_TIMEOUT
)
1920 ERR( "boot event wait timed out\n" );
1921 while (count
) NtClose( handles
[--count
] );
1925 static inline void copy_unicode_string( WCHAR
**src
, WCHAR
**dst
, UNICODE_STRING
*str
, UINT len
)
1929 str
->MaximumLength
= len
+ sizeof(WCHAR
);
1930 memcpy( *dst
, *src
, len
);
1931 (*dst
)[len
/ sizeof(WCHAR
)] = 0;
1932 *src
+= len
/ sizeof(WCHAR
);
1933 *dst
+= len
/ sizeof(WCHAR
) + 1;
1936 static inline void put_unicode_string( WCHAR
*src
, WCHAR
**dst
, UNICODE_STRING
*str
)
1938 copy_unicode_string( &src
, dst
, str
, wcslen(src
) * sizeof(WCHAR
) );
1941 static inline WCHAR
*get_dos_path( WCHAR
*nt_path
)
1943 if (nt_path
[4] && nt_path
[5] == ':') return nt_path
+ 4; /* skip the \??\ prefix */
1944 nt_path
[1] = '\\'; /* change \??\ to \\?\ */
1948 static inline const WCHAR
*get_params_string( const RTL_USER_PROCESS_PARAMETERS
*params
,
1949 const UNICODE_STRING
*str
)
1951 if (params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
) return str
->Buffer
;
1952 return (const WCHAR
*)((const char *)params
+ (UINT_PTR
)str
->Buffer
);
1955 static inline DWORD
append_string( void **ptr
, const RTL_USER_PROCESS_PARAMETERS
*params
,
1956 const UNICODE_STRING
*str
)
1958 const WCHAR
*buffer
= get_params_string( params
, str
);
1959 memcpy( *ptr
, buffer
, str
->Length
);
1960 *ptr
= (WCHAR
*)*ptr
+ str
->Length
/ sizeof(WCHAR
);
1965 static inline void dup_unicode_string( const UNICODE_STRING
*src
, WCHAR
**dst
, UNICODE_STRING32
*str
)
1967 static inline void dup_unicode_string( const UNICODE_STRING
*src
, WCHAR
**dst
, UNICODE_STRING64
*str
)
1970 if (!src
->Buffer
) return;
1971 str
->Buffer
= PtrToUlong( *dst
);
1972 str
->Length
= src
->Length
;
1973 str
->MaximumLength
= src
->MaximumLength
;
1974 memcpy( *dst
, src
->Buffer
, src
->MaximumLength
);
1975 *dst
+= src
->MaximumLength
/ sizeof(WCHAR
);
1979 /*************************************************************************
1982 static ULONG
get_dword_option( HANDLE key
, const WCHAR
*name
, ULONG defval
)
1987 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1989 init_unicode_string( &str
, name
);
1990 size
= sizeof(buffer
) - sizeof(WCHAR
);
1991 if (NtQueryValueKey( key
, &str
, KeyValuePartialInformation
, buffer
, size
, &size
)) return defval
;
1992 if (info
->Type
!= REG_DWORD
) return defval
;
1993 return *(ULONG
*)info
->Data
;
1997 /*************************************************************************
1998 * load_global_options
2000 static void load_global_options( const UNICODE_STRING
*image
)
2002 static const WCHAR optionsW
[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
2003 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\',
2004 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2005 'I','m','a','g','e',' ','F','i','l','e',' ','E','x','e','c','u','t','i','o','n',' ','O','p','t','i','o','n','s',0};
2006 static const WCHAR sessionW
[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
2007 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2008 'C','o','n','t','r','o','l','\\','S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2009 static const WCHAR globalflagW
[] = {'G','l','o','b','a','l','F','l','a','g',0};
2010 static const WCHAR critsectionW
[] = {'C','r','i','t','i','c','a','l','S','e','c','t','i','o','n','T','i','m','e','o','u','t',0};
2011 static const WCHAR heapreserveW
[] = {'H','e','a','p','S','e','g','m','e','n','t','R','e','s','e','r','v','e',0};
2012 static const WCHAR heapcommitW
[] = {'H','e','a','p','S','e','g','m','e','n','t','C','o','m','m','i','t',0};
2013 static const WCHAR heapdecommittotalW
[] = {'H','e','a','p','D','e','C','o','m','m','i','t','T','o','t','a','l','F','r','e','e','T','h','r','e','s','h','o','l','d',0};
2014 static const WCHAR heapdecommitblockW
[] = {'H','e','a','p','D','e','C','o','m','m','i','t','F','r','e','e','B','l','o','c','k','T','h','r','e','s','h','o','l','d',0};
2015 OBJECT_ATTRIBUTES attr
;
2016 UNICODE_STRING nameW
;
2020 InitializeObjectAttributes( &attr
, &nameW
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
2021 init_unicode_string( &nameW
, sessionW
);
2022 if (!NtOpenKey( &key
, KEY_QUERY_VALUE
, &attr
))
2024 peb
->NtGlobalFlag
= get_dword_option( key
, globalflagW
, 0 );
2025 peb
->CriticalSectionTimeout
.QuadPart
= get_dword_option( key
, critsectionW
, 30 * 24 * 60 * 60 ) * (ULONGLONG
)-10000000;
2026 peb
->HeapSegmentReserve
= get_dword_option( key
, heapreserveW
, 0x100000 );
2027 peb
->HeapSegmentCommit
= get_dword_option( key
, heapcommitW
, 0x10000 );
2028 peb
->HeapDeCommitTotalFreeThreshold
= get_dword_option( key
, heapdecommittotalW
, 0x10000 );
2029 peb
->HeapDeCommitFreeBlockThreshold
= get_dword_option( key
, heapdecommitblockW
, 0x1000 );
2032 init_unicode_string( &nameW
, optionsW
);
2033 if (!NtOpenKey( &key
, KEY_QUERY_VALUE
, &attr
))
2035 attr
.RootDirectory
= key
;
2036 for (i
= image
->Length
/ sizeof(WCHAR
); i
; i
--) if (image
->Buffer
[i
- 1] == '\\') break;
2037 nameW
.Buffer
= image
->Buffer
+ i
;
2038 nameW
.Length
= image
->Length
- i
* sizeof(WCHAR
);
2039 if (!NtOpenKey( &key
, KEY_QUERY_VALUE
, &attr
))
2041 peb
->NtGlobalFlag
= get_dword_option( key
, globalflagW
, peb
->NtGlobalFlag
);
2044 NtClose( attr
.RootDirectory
);
2049 /*************************************************************************
2050 * build_wow64_parameters
2052 static void *build_wow64_parameters( const RTL_USER_PROCESS_PARAMETERS
*params
)
2055 RTL_USER_PROCESS_PARAMETERS32
*wow64_params
= NULL
;
2057 RTL_USER_PROCESS_PARAMETERS64
*wow64_params
= NULL
;
2061 SIZE_T size
= (sizeof(*wow64_params
)
2062 + params
->CurrentDirectory
.DosPath
.MaximumLength
2063 + params
->DllPath
.MaximumLength
2064 + params
->ImagePathName
.MaximumLength
2065 + params
->CommandLine
.MaximumLength
2066 + params
->WindowTitle
.MaximumLength
2067 + params
->Desktop
.MaximumLength
2068 + params
->ShellInfo
.MaximumLength
2069 + params
->RuntimeInfo
.MaximumLength
2070 + params
->EnvironmentSize
);
2072 status
= NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&wow64_params
, 0, &size
,
2073 MEM_COMMIT
, PAGE_READWRITE
);
2076 wow64_params
->AllocationSize
= size
;
2077 wow64_params
->Size
= size
;
2078 wow64_params
->Flags
= params
->Flags
;
2079 wow64_params
->DebugFlags
= params
->DebugFlags
;
2080 wow64_params
->ConsoleHandle
= HandleToULong( params
->ConsoleHandle
);
2081 wow64_params
->ConsoleFlags
= params
->ConsoleFlags
;
2082 wow64_params
->hStdInput
= HandleToULong( params
->hStdInput
);
2083 wow64_params
->hStdOutput
= HandleToULong( params
->hStdOutput
);
2084 wow64_params
->hStdError
= HandleToULong( params
->hStdError
);
2085 wow64_params
->dwX
= params
->dwX
;
2086 wow64_params
->dwY
= params
->dwY
;
2087 wow64_params
->dwXSize
= params
->dwXSize
;
2088 wow64_params
->dwYSize
= params
->dwYSize
;
2089 wow64_params
->dwXCountChars
= params
->dwXCountChars
;
2090 wow64_params
->dwYCountChars
= params
->dwYCountChars
;
2091 wow64_params
->dwFillAttribute
= params
->dwFillAttribute
;
2092 wow64_params
->dwFlags
= params
->dwFlags
;
2093 wow64_params
->wShowWindow
= params
->wShowWindow
;
2095 dst
= (WCHAR
*)(wow64_params
+ 1);
2096 dup_unicode_string( ¶ms
->CurrentDirectory
.DosPath
, &dst
, &wow64_params
->CurrentDirectory
.DosPath
);
2097 dup_unicode_string( ¶ms
->DllPath
, &dst
, &wow64_params
->DllPath
);
2098 dup_unicode_string( ¶ms
->ImagePathName
, &dst
, &wow64_params
->ImagePathName
);
2099 dup_unicode_string( ¶ms
->CommandLine
, &dst
, &wow64_params
->CommandLine
);
2100 dup_unicode_string( ¶ms
->WindowTitle
, &dst
, &wow64_params
->WindowTitle
);
2101 dup_unicode_string( ¶ms
->Desktop
, &dst
, &wow64_params
->Desktop
);
2102 dup_unicode_string( ¶ms
->ShellInfo
, &dst
, &wow64_params
->ShellInfo
);
2103 dup_unicode_string( ¶ms
->RuntimeInfo
, &dst
, &wow64_params
->RuntimeInfo
);
2105 wow64_params
->Environment
= PtrToUlong( dst
);
2106 wow64_params
->EnvironmentSize
= params
->EnvironmentSize
;
2107 memcpy( dst
, params
->Environment
, params
->EnvironmentSize
);
2108 return wow64_params
;
2112 /*************************************************************************
2115 static void init_peb( RTL_USER_PROCESS_PARAMETERS
*params
, void *module
)
2117 peb
->ImageBaseAddress
= module
;
2118 peb
->ProcessParameters
= params
;
2119 peb
->OSMajorVersion
= 6;
2120 peb
->OSMinorVersion
= 1;
2121 peb
->OSBuildNumber
= 0x1db1;
2122 peb
->OSPlatformId
= VER_PLATFORM_WIN32_NT
;
2123 peb
->ImageSubSystem
= main_image_info
.SubSystemType
;
2124 peb
->ImageSubSystemMajorVersion
= main_image_info
.MajorSubsystemVersion
;
2125 peb
->ImageSubSystemMinorVersion
= main_image_info
.MinorSubsystemVersion
;
2128 if (main_image_info
.Machine
!= current_machine
)
2130 NtCurrentTeb()->WowTebOffset
= teb_offset
;
2131 NtCurrentTeb()->Tib
.ExceptionList
= (void *)((char *)NtCurrentTeb() + teb_offset
);
2132 set_thread_id( NtCurrentTeb(), GetCurrentProcessId(), GetCurrentThreadId() );
2136 load_global_options( ¶ms
->ImagePathName
);
2138 if (NtCurrentTeb()->WowTebOffset
)
2140 void *wow64_params
= build_wow64_parameters( params
);
2142 PEB32
*wow64_peb
= (PEB32
*)((char *)peb
+ page_size
);
2144 PEB64
*wow64_peb
= (PEB64
*)((char *)peb
- page_size
);
2146 wow64_peb
->ImageBaseAddress
= PtrToUlong( peb
->ImageBaseAddress
);
2147 wow64_peb
->ProcessParameters
= PtrToUlong( wow64_params
);
2148 wow64_peb
->NumberOfProcessors
= peb
->NumberOfProcessors
;
2149 wow64_peb
->NtGlobalFlag
= peb
->NtGlobalFlag
;
2150 wow64_peb
->CriticalSectionTimeout
.QuadPart
= peb
->CriticalSectionTimeout
.QuadPart
;
2151 wow64_peb
->HeapSegmentReserve
= peb
->HeapSegmentReserve
;
2152 wow64_peb
->HeapSegmentCommit
= peb
->HeapSegmentCommit
;
2153 wow64_peb
->HeapDeCommitTotalFreeThreshold
= peb
->HeapDeCommitTotalFreeThreshold
;
2154 wow64_peb
->HeapDeCommitFreeBlockThreshold
= peb
->HeapDeCommitFreeBlockThreshold
;
2155 wow64_peb
->OSMajorVersion
= peb
->OSMajorVersion
;
2156 wow64_peb
->OSMinorVersion
= peb
->OSMinorVersion
;
2157 wow64_peb
->OSBuildNumber
= peb
->OSBuildNumber
;
2158 wow64_peb
->OSPlatformId
= peb
->OSPlatformId
;
2159 wow64_peb
->ImageSubSystem
= peb
->ImageSubSystem
;
2160 wow64_peb
->ImageSubSystemMajorVersion
= peb
->ImageSubSystemMajorVersion
;
2161 wow64_peb
->ImageSubSystemMinorVersion
= peb
->ImageSubSystemMinorVersion
;
2162 wow64_peb
->SessionId
= peb
->SessionId
;
2167 /*************************************************************************
2168 * build_initial_params
2170 * Build process parameters from scratch, for processes without a parent.
2172 static RTL_USER_PROCESS_PARAMETERS
*build_initial_params( void **module
)
2174 static const WCHAR valueW
[] = {'1',0};
2175 static const WCHAR pathW
[] = {'P','A','T','H'};
2176 RTL_USER_PROCESS_PARAMETERS
*params
= NULL
;
2177 SIZE_T size
, env_pos
, env_size
;
2178 WCHAR
*dst
, *image
, *cmdline
, *path
, *bootstrap
;
2179 WCHAR
*env
= get_initial_environment( &env_pos
, &env_size
);
2180 WCHAR
*curdir
= get_initial_directory();
2183 /* store the initial PATH value */
2184 path
= get_env_var( env
, env_pos
, pathW
, 4 );
2185 add_dynamic_environment( &env
, &env_pos
, &env_size
);
2186 add_registry_environment( &env
, &env_pos
, &env_size
);
2187 bootstrap
= get_env_var( env
, env_pos
, bootstrapW
, ARRAY_SIZE(bootstrapW
) );
2188 set_env_var( &env
, &env_pos
, &env_size
, bootstrapW
, ARRAY_SIZE(bootstrapW
), valueW
);
2189 is_prefix_bootstrap
= TRUE
;
2191 run_wineboot( env
, env_pos
);
2193 /* reload environment now that wineboot has run */
2194 set_env_var( &env
, &env_pos
, &env_size
, pathW
, 4, path
); /* reset PATH */
2196 set_env_var( &env
, &env_pos
, &env_size
, bootstrapW
, ARRAY_SIZE(bootstrapW
), bootstrap
);
2197 is_prefix_bootstrap
= !!bootstrap
;
2199 add_registry_environment( &env
, &env_pos
, &env_size
);
2202 status
= load_main_exe( NULL
, main_argv
[1], curdir
, &image
, module
);
2205 if (main_image_info
.ImageCharacteristics
& IMAGE_FILE_DLL
) status
= STATUS_INVALID_IMAGE_FORMAT
;
2206 if (main_image_info
.Machine
!= current_machine
) status
= STATUS_INVALID_IMAGE_FORMAT
;
2209 if (status
) /* try launching it through start.exe */
2211 static const char *args
[] = { "start.exe", "/exec" };
2213 if (*module
) NtUnmapViewOfSection( GetCurrentProcess(), *module
);
2214 load_start_exe( &image
, module
);
2215 prepend_argv( args
, 2 );
2217 else rebuild_argv();
2219 main_wargv
= build_wargv( get_dos_path( image
));
2220 cmdline
= build_command_line( main_wargv
);
2222 TRACE( "image %s cmdline %s dir %s\n",
2223 debugstr_w(main_wargv
[0]), debugstr_w(cmdline
), debugstr_w(curdir
) );
2225 size
= (sizeof(*params
)
2226 + MAX_PATH
* sizeof(WCHAR
) /* curdir */
2227 + (wcslen( cmdline
) + 1) * sizeof(WCHAR
) /* command line */
2228 + (wcslen( main_wargv
[0] ) + 1) * sizeof(WCHAR
) * 2 /* image path + window title */
2229 + env_pos
* sizeof(WCHAR
));
2231 status
= NtAllocateVirtualMemory( NtCurrentProcess(), (void **)¶ms
, 0, &size
,
2232 MEM_COMMIT
, PAGE_READWRITE
);
2235 params
->AllocationSize
= size
;
2236 params
->Size
= size
;
2237 params
->Flags
= PROCESS_PARAMS_FLAG_NORMALIZED
;
2238 params
->wShowWindow
= 1; /* SW_SHOWNORMAL */
2240 params
->CurrentDirectory
.DosPath
.Buffer
= (WCHAR
*)(params
+ 1);
2241 wcscpy( params
->CurrentDirectory
.DosPath
.Buffer
, get_dos_path( curdir
));
2242 params
->CurrentDirectory
.DosPath
.Length
= wcslen(params
->CurrentDirectory
.DosPath
.Buffer
) * sizeof(WCHAR
);
2243 params
->CurrentDirectory
.DosPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2244 dst
= params
->CurrentDirectory
.DosPath
.Buffer
+ MAX_PATH
;
2246 put_unicode_string( main_wargv
[0], &dst
, ¶ms
->ImagePathName
);
2247 put_unicode_string( cmdline
, &dst
, ¶ms
->CommandLine
);
2248 put_unicode_string( main_wargv
[0], &dst
, ¶ms
->WindowTitle
);
2253 params
->Environment
= dst
;
2254 params
->EnvironmentSize
= env_pos
* sizeof(WCHAR
);
2255 memcpy( dst
, env
, env_pos
* sizeof(WCHAR
) );
2258 get_initial_console( params
);
2264 /*************************************************************************
2267 void init_startup_info(void)
2269 WCHAR
*src
, *dst
, *env
, *image
;
2270 void *module
= NULL
;
2272 SIZE_T size
, info_size
, env_size
, env_pos
;
2273 RTL_USER_PROCESS_PARAMETERS
*params
= NULL
;
2274 startup_info_t
*info
;
2276 if (!startup_info_size
)
2278 params
= build_initial_params( &module
);
2279 init_peb( params
, module
);
2283 info
= malloc( startup_info_size
);
2285 SERVER_START_REQ( get_startup_info
)
2287 wine_server_set_reply( req
, info
, startup_info_size
);
2288 status
= wine_server_call( req
);
2289 info_size
= reply
->info_size
;
2290 env_size
= (wine_server_reply_size( reply
) - info_size
) / sizeof(WCHAR
);
2295 env
= malloc( env_size
* sizeof(WCHAR
) );
2296 memcpy( env
, (char *)info
+ info_size
, env_size
* sizeof(WCHAR
) );
2297 env_pos
= env_size
- 1;
2298 add_dynamic_environment( &env
, &env_pos
, &env_size
);
2299 is_prefix_bootstrap
= !!find_env_var( env
, env_pos
, bootstrapW
, ARRAY_SIZE(bootstrapW
) );
2302 size
= (sizeof(*params
)
2303 + MAX_PATH
* sizeof(WCHAR
) /* curdir */
2304 + info
->dllpath_len
+ sizeof(WCHAR
)
2305 + info
->imagepath_len
+ sizeof(WCHAR
)
2306 + info
->cmdline_len
+ sizeof(WCHAR
)
2307 + info
->title_len
+ sizeof(WCHAR
)
2308 + info
->desktop_len
+ sizeof(WCHAR
)
2309 + info
->shellinfo_len
+ sizeof(WCHAR
)
2310 + info
->runtime_len
+ sizeof(WCHAR
)
2311 + env_pos
* sizeof(WCHAR
));
2313 status
= NtAllocateVirtualMemory( NtCurrentProcess(), (void **)¶ms
, 0, &size
,
2314 MEM_COMMIT
, PAGE_READWRITE
);
2317 params
->AllocationSize
= size
;
2318 params
->Size
= size
;
2319 params
->Flags
= PROCESS_PARAMS_FLAG_NORMALIZED
;
2320 params
->DebugFlags
= info
->debug_flags
;
2321 params
->ConsoleHandle
= wine_server_ptr_handle( info
->console
);
2322 params
->ConsoleFlags
= info
->console_flags
;
2323 params
->hStdInput
= wine_server_ptr_handle( info
->hstdin
);
2324 params
->hStdOutput
= wine_server_ptr_handle( info
->hstdout
);
2325 params
->hStdError
= wine_server_ptr_handle( info
->hstderr
);
2326 params
->dwX
= info
->x
;
2327 params
->dwY
= info
->y
;
2328 params
->dwXSize
= info
->xsize
;
2329 params
->dwYSize
= info
->ysize
;
2330 params
->dwXCountChars
= info
->xchars
;
2331 params
->dwYCountChars
= info
->ychars
;
2332 params
->dwFillAttribute
= info
->attribute
;
2333 params
->dwFlags
= info
->flags
;
2334 params
->wShowWindow
= info
->show
;
2336 src
= (WCHAR
*)(info
+ 1);
2337 dst
= (WCHAR
*)(params
+ 1);
2339 /* curdir is special */
2340 copy_unicode_string( &src
, &dst
, ¶ms
->CurrentDirectory
.DosPath
, info
->curdir_len
);
2341 params
->CurrentDirectory
.DosPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
2342 dst
= params
->CurrentDirectory
.DosPath
.Buffer
+ MAX_PATH
;
2344 if (info
->dllpath_len
) copy_unicode_string( &src
, &dst
, ¶ms
->DllPath
, info
->dllpath_len
);
2345 copy_unicode_string( &src
, &dst
, ¶ms
->ImagePathName
, info
->imagepath_len
);
2346 copy_unicode_string( &src
, &dst
, ¶ms
->CommandLine
, info
->cmdline_len
);
2347 copy_unicode_string( &src
, &dst
, ¶ms
->WindowTitle
, info
->title_len
);
2348 copy_unicode_string( &src
, &dst
, ¶ms
->Desktop
, info
->desktop_len
);
2349 copy_unicode_string( &src
, &dst
, ¶ms
->ShellInfo
, info
->shellinfo_len
);
2350 if (info
->runtime_len
)
2352 /* runtime info isn't a real string */
2353 params
->RuntimeInfo
.MaximumLength
= params
->RuntimeInfo
.Length
= info
->runtime_len
;
2354 params
->RuntimeInfo
.Buffer
= dst
;
2355 memcpy( dst
, src
, info
->runtime_len
);
2356 src
+= (info
->runtime_len
+ 1) / sizeof(WCHAR
);
2357 dst
+= (info
->runtime_len
+ 1) / sizeof(WCHAR
);
2359 assert( (char *)src
== (char *)info
+ info_size
);
2361 params
->Environment
= dst
;
2362 params
->EnvironmentSize
= env_pos
* sizeof(WCHAR
);
2363 memcpy( dst
, env
, env_pos
* sizeof(WCHAR
) );
2367 status
= load_main_exe( params
->ImagePathName
.Buffer
, NULL
,
2368 params
->CommandLine
.Buffer
, &image
, &module
);
2371 MESSAGE( "wine: failed to start %s\n", debugstr_us(¶ms
->ImagePathName
) );
2372 NtTerminateProcess( GetCurrentProcess(), status
);
2375 main_wargv
= build_wargv( get_dos_path( image
));
2377 init_peb( params
, module
);
2381 /***********************************************************************
2382 * create_startup_info
2384 void *create_startup_info( const UNICODE_STRING
*nt_image
, const RTL_USER_PROCESS_PARAMETERS
*params
,
2387 startup_info_t
*info
;
2388 UNICODE_STRING dos_image
= *nt_image
;
2392 dos_image
.Buffer
= get_dos_path( nt_image
->Buffer
);
2393 dos_image
.Length
= nt_image
->Length
- (dos_image
.Buffer
- nt_image
->Buffer
) * sizeof(WCHAR
);
2395 size
= sizeof(*info
);
2396 size
+= params
->CurrentDirectory
.DosPath
.Length
;
2397 size
+= params
->DllPath
.Length
;
2398 size
+= dos_image
.Length
;
2399 size
+= params
->CommandLine
.Length
;
2400 size
+= params
->WindowTitle
.Length
;
2401 size
+= params
->Desktop
.Length
;
2402 size
+= params
->ShellInfo
.Length
;
2403 size
+= params
->RuntimeInfo
.Length
;
2404 size
= (size
+ 1) & ~1;
2407 if (!(info
= calloc( size
, 1 ))) return NULL
;
2409 info
->debug_flags
= params
->DebugFlags
;
2410 info
->console_flags
= params
->ConsoleFlags
;
2411 info
->console
= wine_server_obj_handle( params
->ConsoleHandle
);
2412 info
->hstdin
= wine_server_obj_handle( params
->hStdInput
);
2413 info
->hstdout
= wine_server_obj_handle( params
->hStdOutput
);
2414 info
->hstderr
= wine_server_obj_handle( params
->hStdError
);
2415 info
->x
= params
->dwX
;
2416 info
->y
= params
->dwY
;
2417 info
->xsize
= params
->dwXSize
;
2418 info
->ysize
= params
->dwYSize
;
2419 info
->xchars
= params
->dwXCountChars
;
2420 info
->ychars
= params
->dwYCountChars
;
2421 info
->attribute
= params
->dwFillAttribute
;
2422 info
->flags
= params
->dwFlags
;
2423 info
->show
= params
->wShowWindow
;
2426 info
->curdir_len
= append_string( &ptr
, params
, ¶ms
->CurrentDirectory
.DosPath
);
2427 info
->dllpath_len
= append_string( &ptr
, params
, ¶ms
->DllPath
);
2428 info
->imagepath_len
= append_string( &ptr
, params
, &dos_image
);
2429 info
->cmdline_len
= append_string( &ptr
, params
, ¶ms
->CommandLine
);
2430 info
->title_len
= append_string( &ptr
, params
, ¶ms
->WindowTitle
);
2431 info
->desktop_len
= append_string( &ptr
, params
, ¶ms
->Desktop
);
2432 info
->shellinfo_len
= append_string( &ptr
, params
, ¶ms
->ShellInfo
);
2433 info
->runtime_len
= append_string( &ptr
, params
, ¶ms
->RuntimeInfo
);
2438 /**************************************************************************
2439 * NtGetNlsSectionPtr (NTDLL.@)
2441 NTSTATUS WINAPI
NtGetNlsSectionPtr( ULONG type
, ULONG id
, void *unknown
, void **ptr
, SIZE_T
*size
)
2443 UNICODE_STRING nameW
;
2444 OBJECT_ATTRIBUTES attr
;
2446 HANDLE handle
, file
;
2449 if ((status
= get_nls_section_name( type
, id
, name
))) return status
;
2451 init_unicode_string( &nameW
, name
);
2452 InitializeObjectAttributes( &attr
, &nameW
, 0, 0, NULL
);
2453 if ((status
= NtOpenSection( &handle
, SECTION_MAP_READ
, &attr
)))
2455 if ((status
= open_nls_data_file( type
, id
, &file
))) return status
;
2456 attr
.Attributes
= OBJ_OPENIF
| OBJ_PERMANENT
;
2457 status
= NtCreateSection( &handle
, SECTION_MAP_READ
, &attr
, NULL
, PAGE_READONLY
, SEC_COMMIT
, file
);
2459 if (status
== STATUS_OBJECT_NAME_EXISTS
) status
= STATUS_SUCCESS
;
2465 status
= NtMapViewOfSection( handle
, GetCurrentProcess(), ptr
, 0, 0, NULL
, size
,
2466 ViewShare
, 0, PAGE_READONLY
);
2473 /**********************************************************************
2474 * NtQueryDefaultLocale (NTDLL.@)
2476 NTSTATUS WINAPI
NtQueryDefaultLocale( BOOLEAN user
, LCID
*lcid
)
2478 *lcid
= user
? user_lcid
: system_lcid
;
2479 return STATUS_SUCCESS
;
2483 /**********************************************************************
2484 * NtSetDefaultLocale (NTDLL.@)
2486 NTSTATUS WINAPI
NtSetDefaultLocale( BOOLEAN user
, LCID lcid
)
2488 if (user
) user_lcid
= lcid
;
2492 system_ui_language
= LANGIDFROMLCID(lcid
); /* there is no separate call to set it */
2494 return STATUS_SUCCESS
;
2498 /**********************************************************************
2499 * NtQueryDefaultUILanguage (NTDLL.@)
2501 NTSTATUS WINAPI
NtQueryDefaultUILanguage( LANGID
*lang
)
2503 *lang
= user_ui_language
;
2504 return STATUS_SUCCESS
;
2508 /**********************************************************************
2509 * NtSetDefaultUILanguage (NTDLL.@)
2511 NTSTATUS WINAPI
NtSetDefaultUILanguage( LANGID lang
)
2513 user_ui_language
= lang
;
2514 return STATUS_SUCCESS
;
2518 /**********************************************************************
2519 * NtQueryInstallUILanguage (NTDLL.@)
2521 NTSTATUS WINAPI
NtQueryInstallUILanguage( LANGID
*lang
)
2523 *lang
= system_ui_language
;
2524 return STATUS_SUCCESS
;
2527 /**********************************************************************
2528 * RtlUpcaseUnicodeChar (ntdll.so)
2530 WCHAR WINAPI
RtlUpcaseUnicodeChar( WCHAR wch
)
2532 return ntdll_towupper( wch
);
2535 /**********************************************************************
2536 * RtlDowncaseUnicodeChar (ntdll.so)
2538 WCHAR WINAPI
RtlDowncaseUnicodeChar( WCHAR wch
)
2540 return ntdll_towlower( wch
);
2543 /**********************************************************************
2544 * RtlUTF8ToUnicodeN (ntdll.so)
2546 NTSTATUS WINAPI
RtlUTF8ToUnicodeN( WCHAR
*dst
, DWORD dstlen
, DWORD
*reslen
, const char *src
, DWORD srclen
)
2548 unsigned int res
, len
;
2549 NTSTATUS status
= STATUS_SUCCESS
;
2550 const char *srcend
= src
+ srclen
;
2553 if (!src
) return STATUS_INVALID_PARAMETER_4
;
2554 if (!reslen
) return STATUS_INVALID_PARAMETER
;
2556 dstlen
/= sizeof(WCHAR
);
2557 dstend
= dst
+ dstlen
;
2560 for (len
= 0; src
< srcend
; len
++)
2562 unsigned char ch
= *src
++;
2563 if (ch
< 0x80) continue;
2564 if ((res
= decode_utf8_char( ch
, &src
, srcend
)) > 0x10ffff)
2565 status
= STATUS_SOME_NOT_MAPPED
;
2567 if (res
> 0xffff) len
++;
2569 *reslen
= len
* sizeof(WCHAR
);
2573 while ((dst
< dstend
) && (src
< srcend
))
2575 unsigned char ch
= *src
++;
2576 if (ch
< 0x80) /* special fast case for 7-bit ASCII */
2581 if ((res
= decode_utf8_char( ch
, &src
, srcend
)) <= 0xffff)
2585 else if (res
<= 0x10ffff) /* we need surrogates */
2588 *dst
++ = 0xd800 | (res
>> 10);
2589 if (dst
== dstend
) break;
2590 *dst
++ = 0xdc00 | (res
& 0x3ff);
2595 status
= STATUS_SOME_NOT_MAPPED
;
2598 if (src
< srcend
) status
= STATUS_BUFFER_TOO_SMALL
; /* overflow */
2599 *reslen
= (dstlen
- (dstend
- dst
)) * sizeof(WCHAR
);
2603 /**********************************************************************
2604 * RtlNtStatusToDosError (ntdll.so)
2606 ULONG WINAPI
RtlNtStatusToDosError( NTSTATUS status
)
2608 NtCurrentTeb()->LastStatusValue
= status
;
2610 if (!status
|| (status
& 0x20000000)) return status
;
2611 if ((status
& 0xf0000000) == 0xd0000000) status
&= ~0x10000000;
2613 /* now some special cases */
2614 if (HIWORD(status
) == 0xc001 || HIWORD(status
) == 0x8007 || HIWORD(status
) == 0xc007)
2615 return LOWORD( status
);
2617 return map_status( status
);