Fix the case of product and company names.
[wine] / memory / environ.c
1 /*
2  * Process environment management
3  *
4  * Copyright 1996, 1998 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "ntstatus.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "thread.h"
34 #include "wine/winbase16.h"
35 #include "wine/server.h"
36 #include "wine/library.h"
37 #include "heap.h"
38 #include "winternl.h"
39 #include "selectors.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(environ);
44
45 /* TODO:
46  * - 16 bit environment ??? (see generate_env_block16 for the details)
47  */
48
49 /* Format of an environment block:
50  * ASCIIZ   string 1 (xx=yy format)
51  * ...
52  * ASCIIZ   string n
53  * BYTE     0
54  * WORD     1
55  * ASCIIZ   program name (e.g. C:\WINDOWS\SYSTEM\KRNL386.EXE)
56  *
57  * Notes:
58  * - contrary to Microsoft docs, the environment strings do not appear
59  *   to be sorted on Win95 (although they are on NT); so we don't bother
60  *   to sort them either.
61  * - on Win2K (and likely most of NT versions) the last part (WORD 1 and 
62  *   program name no longer appear in the environment block (from the 32
63  *   bit interface)
64  */
65
66 static const char ENV_program_name[] = "C:\\WINDOWS\\SYSTEM\\KRNL386.EXE";
67
68 static STARTUPINFOW startup_infoW;
69 static STARTUPINFOA startup_infoA;
70
71 /* Maximum length of a Win16 environment string (including NULL) */
72 #define MAX_WIN16_LEN  128
73
74 static WORD env_sel;     /* selector to the 16 bit environment */
75
76 /******************************************************************
77  *              generate_env_block16
78  *
79  * This internal function generates a suitable environment for the 16 bit
80  * subsystem and returns the value as a segmented pointer.
81  *
82  * FIXME: current implementation will allocate a private copy of the
83  *        environment strings, but will not follow the modifications (if any)
84  *        from the unicode env block stored in the PEB
85  *              => how should this be updated from the ntdll modifications ?
86  *                 should we use the peb->EnvironmentUpdateCount field to 
87  *                 know when environment has changed ???
88  *        we currently regenerate this block each time an environment 
89  *        variable is modified from a Win32 API call, but we'll miss all
90  *        direct access to the NTDLL APIs
91  */
92 static SEGPTR generate_env_block16(void)
93 {
94     static LPSTR env16;
95
96     DWORD       size, new_size;
97     WORD        one = 1;
98
99     if (env16) FreeEnvironmentStringsA( env16 );
100
101     env16 = GetEnvironmentStringsA();
102     size = HeapSize(GetProcessHeap(), 0, env16);
103     new_size = size + sizeof(WORD) + sizeof(ENV_program_name);
104     if (!(env16 = HeapReAlloc( GetProcessHeap(), 0, env16, new_size ))) return 0;
105
106     memcpy(env16 + size, &one, sizeof(one));
107     memcpy(env16 + size + sizeof(WORD), ENV_program_name, sizeof(ENV_program_name));
108     if (env_sel)
109         env_sel = SELECTOR_ReallocBlock( env_sel, env16, new_size );
110     else
111         env_sel = SELECTOR_AllocBlock( env16, 0x10000, WINE_LDT_FLAGS_DATA );
112
113     return MAKESEGPTR( env_sel, 0 );
114 }
115
116 /***********************************************************************
117  *           GetCommandLineA      (KERNEL32.@)
118  *
119  * WARNING: there's a Windows incompatibility lurking here !
120  * Win32s always includes the full path of the program file,
121  * whereas Windows NT only returns the full file path plus arguments
122  * in case the program has been started with a full path.
123  * Win9x seems to have inherited NT behaviour.
124  *
125  * Note that both Start Menu Execute and Explorer start programs with
126  * fully specified quoted app file paths, which is why probably the only case
127  * where you'll see single file names is in case of direct launch
128  * via CreateProcess or WinExec.
129  *
130  * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
131  *
132  * References: MS KB article q102762.txt (special Win32s handling)
133  */
134 LPSTR WINAPI GetCommandLineA(void)
135 {
136     static char *cmdlineA;  /* ASCII command line */
137     
138     if (!cmdlineA) /* make an ansi version if we don't have it */
139     {
140         ANSI_STRING     ansi;
141         RtlAcquirePebLock();
142
143         cmdlineA = (RtlUnicodeStringToAnsiString( &ansi, &NtCurrentTeb()->Peb->ProcessParameters->CommandLine, TRUE) == STATUS_SUCCESS) ?
144             ansi.Buffer : NULL;
145         RtlReleasePebLock();
146     }
147     return cmdlineA;
148 }
149
150 /***********************************************************************
151  *           GetCommandLineW      (KERNEL32.@)
152  */
153 LPWSTR WINAPI GetCommandLineW(void)
154 {
155     return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
156 }
157
158
159 /***********************************************************************
160  *           GetEnvironmentStrings    (KERNEL32.@)
161  *           GetEnvironmentStringsA   (KERNEL32.@)
162  */
163 LPSTR WINAPI GetEnvironmentStringsA(void)
164 {
165     LPWSTR      ptrW;
166     unsigned    len, slen;
167     LPSTR       ret, ptrA;
168
169     RtlAcquirePebLock();
170
171     len = 1;
172
173     ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
174     while (*ptrW)
175     {
176         slen = strlenW(ptrW) + 1;
177         len += WideCharToMultiByte( CP_ACP, 0, ptrW, slen, NULL, 0, NULL, NULL );
178         ptrW += slen;
179     }
180
181     if ((ret = HeapAlloc( GetProcessHeap(), 0, len )) != NULL)
182     {
183         ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
184         ptrA = ret;
185         while (*ptrW)
186         {
187             slen = strlenW(ptrW) + 1;
188             WideCharToMultiByte( CP_ACP, 0, ptrW, slen, ptrA, len, NULL, NULL );
189             ptrW += slen;
190             ptrA += strlen(ptrA) + 1;
191         }
192         *ptrA = 0;
193     }
194
195     RtlReleasePebLock();
196     return ret;
197 }
198
199
200 /***********************************************************************
201  *           GetEnvironmentStringsW   (KERNEL32.@)
202  */
203 LPWSTR WINAPI GetEnvironmentStringsW(void)
204 {
205     return NtCurrentTeb()->Peb->ProcessParameters->Environment;
206 }
207
208
209 /***********************************************************************
210  *           FreeEnvironmentStringsA   (KERNEL32.@)
211  */
212 BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr )
213 {
214     return HeapFree( GetProcessHeap(), 0, ptr );
215 }
216
217
218 /***********************************************************************
219  *           FreeEnvironmentStringsW   (KERNEL32.@)
220  */
221 BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr )
222 {
223     return TRUE;
224 }
225
226
227 /***********************************************************************
228  *           GetEnvironmentVariableA   (KERNEL32.@)
229  */
230 DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
231 {
232     UNICODE_STRING      us_name;
233     PWSTR               valueW;
234     DWORD               ret;
235
236     if (!name || !*name)
237     {
238         SetLastError(ERROR_ENVVAR_NOT_FOUND);
239         return 0;
240     }
241
242     if (!(valueW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
243         return 0;
244
245     RtlCreateUnicodeStringFromAsciiz( &us_name, name );
246     SetLastError(0);
247     ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size);
248     if (ret && ret < size)
249     {
250         WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL );
251     }
252     /* this is needed to tell, with 0 as a return value, the difference between:
253      * - an error (GetLastError() != 0)
254      * - returning an empty string (in this case, we need to update the buffer)
255      */
256     if (ret == 0 && size && GetLastError() == 0)
257         value[0] = '\0';
258
259     RtlFreeUnicodeString( &us_name );
260     HeapFree(GetProcessHeap(), 0, valueW);
261
262     return ret;
263 }
264
265
266 /***********************************************************************
267  *           GetEnvironmentVariableW   (KERNEL32.@)
268  */
269 DWORD WINAPI GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
270 {
271     UNICODE_STRING      us_name;
272     UNICODE_STRING      us_value;
273     NTSTATUS            status;
274     unsigned            len;
275
276     TRACE("(%s %p %lu)\n", debugstr_w(name), val, size);
277
278     if (!name || !*name)
279     {
280         SetLastError(ERROR_ENVVAR_NOT_FOUND);
281         return 0;
282     }
283
284     RtlInitUnicodeString(&us_name, name);
285     us_value.Length = 0;
286     us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
287     us_value.Buffer = val;
288
289     status = RtlQueryEnvironmentVariable_U(NULL, &us_name, &us_value);
290     len = us_value.Length / sizeof(WCHAR);
291     if (status != STATUS_SUCCESS)
292     {
293         SetLastError( RtlNtStatusToDosError(status) );
294         return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0;
295     }
296     if (size) val[len] = '\0';
297
298     return us_value.Length / sizeof(WCHAR);
299 }
300
301
302 /***********************************************************************
303  *           SetEnvironmentVariableA   (KERNEL32.@)
304  */
305 BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
306 {
307     UNICODE_STRING      us_name;
308     BOOL                ret;
309
310     if (!name)
311     {
312         SetLastError(ERROR_ENVVAR_NOT_FOUND);
313         return 0;
314     }
315
316     RtlCreateUnicodeStringFromAsciiz( &us_name, name );
317     if (value)
318     {
319         UNICODE_STRING      us_value;
320
321         RtlCreateUnicodeStringFromAsciiz( &us_value, value );
322         ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
323         RtlFreeUnicodeString( &us_value );
324     }
325     else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
326
327     RtlFreeUnicodeString( &us_name );
328
329     return ret;
330 }
331
332
333 /***********************************************************************
334  *           SetEnvironmentVariableW   (KERNEL32.@)
335  */
336 BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
337 {
338     UNICODE_STRING      us_name;
339     NTSTATUS            status;
340
341     TRACE("(%s %s)\n", debugstr_w(name), debugstr_w(value));
342
343     if (!name)
344     {
345         SetLastError(ERROR_ENVVAR_NOT_FOUND);
346         return 0;
347     }
348
349     RtlInitUnicodeString(&us_name, name);
350     if (value)
351     {
352         UNICODE_STRING      us_value;
353
354         RtlInitUnicodeString(&us_value, value);
355         status = RtlSetEnvironmentVariable(NULL, &us_name, &us_value);
356     }
357     else status = RtlSetEnvironmentVariable(NULL, &us_name, NULL);
358
359     if (status != STATUS_SUCCESS)
360     {
361         SetLastError( RtlNtStatusToDosError(status) );
362         return FALSE;
363     }
364
365     /* FIXME: see comments in generate_env_block16 */
366     if (env_sel) generate_env_block16();
367     return TRUE;
368 }
369
370
371 /***********************************************************************
372  *           ExpandEnvironmentStringsA   (KERNEL32.@)
373  *
374  * Note: overlapping buffers are not supported; this is how it should be.
375  * FIXME: return value is wrong for MBCS
376  */
377 DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
378 {
379     UNICODE_STRING      us_src;
380     PWSTR               dstW = NULL;
381     DWORD               ret;
382
383     RtlCreateUnicodeStringFromAsciiz( &us_src, src );
384     if (count)
385     {
386         if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR))))
387             return 0;
388         ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count);
389         if (ret)
390             WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL );
391     }
392     else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0);
393
394     RtlFreeUnicodeString( &us_src );
395     if (dstW) HeapFree(GetProcessHeap(), 0, dstW);
396
397     return ret;
398 }
399
400
401 /***********************************************************************
402  *           ExpandEnvironmentStringsW   (KERNEL32.@)
403  */
404 DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
405 {
406     UNICODE_STRING      us_src;
407     UNICODE_STRING      us_dst;
408     NTSTATUS            status;
409     DWORD               res;
410
411     TRACE("(%s %p %lu)\n", debugstr_w(src), dst, len);
412
413     RtlInitUnicodeString(&us_src, src);
414     us_dst.Length = 0;
415     us_dst.MaximumLength = len * sizeof(WCHAR);
416     us_dst.Buffer = dst;
417
418     res = 0;
419     status = RtlExpandEnvironmentStrings_U(NULL, &us_src, &us_dst, &res);
420     res /= sizeof(WCHAR);
421     if (status != STATUS_SUCCESS)
422     {
423         SetLastError( RtlNtStatusToDosError(status) );
424         if (status != STATUS_BUFFER_TOO_SMALL) return 0;
425         if (len && dst) dst[len - 1] = '\0';
426     }
427
428     return res;
429 }
430
431
432 /***********************************************************************
433  *           GetDOSEnvironment     (KERNEL.131)
434  */
435 SEGPTR WINAPI GetDOSEnvironment16(void)
436 {
437     return generate_env_block16();
438 }
439
440
441 /***********************************************************************
442  *           GetStdHandle    (KERNEL32.@)
443  */
444 HANDLE WINAPI GetStdHandle( DWORD std_handle )
445 {
446     switch (std_handle)
447     {
448         case STD_INPUT_HANDLE:  return NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
449         case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
450         case STD_ERROR_HANDLE:  return NtCurrentTeb()->Peb->ProcessParameters->hStdError;
451     }
452     SetLastError( ERROR_INVALID_PARAMETER );
453     return INVALID_HANDLE_VALUE;
454 }
455
456
457 /***********************************************************************
458  *           SetStdHandle    (KERNEL32.@)
459  */
460 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
461 {
462     switch (std_handle)
463     {
464         case STD_INPUT_HANDLE:  NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle;  return TRUE;
465         case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE;
466         case STD_ERROR_HANDLE:  NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle;  return TRUE;
467     }
468     SetLastError( ERROR_INVALID_PARAMETER );
469     return FALSE;
470 }
471
472 /***********************************************************************
473  *              GetStartupInfoA         (KERNEL32.@)
474  */
475 VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
476 {
477     assert(startup_infoA.cb);
478     memcpy(info, &startup_infoA, sizeof(startup_infoA));
479 }
480
481
482 /***********************************************************************
483  *              GetStartupInfoW         (KERNEL32.@)
484  */
485 VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
486 {
487     assert(startup_infoW.cb);
488     memcpy(info, &startup_infoW, sizeof(startup_infoW));
489 }
490
491 /******************************************************************
492  *              ENV_CopyStartupInformation (internal)
493  *
494  * Creates the STARTUPINFO information from the ntdll information
495  */
496 void ENV_CopyStartupInformation(void)
497 {
498     RTL_USER_PROCESS_PARAMETERS* rupp;
499     ANSI_STRING         ansi;
500
501     RtlAcquirePebLock();
502     
503     rupp = NtCurrentTeb()->Peb->ProcessParameters;
504
505     startup_infoW.cb                   = sizeof(startup_infoW);
506     startup_infoW.lpReserved           = NULL;
507     startup_infoW.lpDesktop            = rupp->Desktop.Buffer;
508     startup_infoW.lpTitle              = rupp->WindowTitle.Buffer;
509     startup_infoW.dwX                  = rupp->dwX;
510     startup_infoW.dwY                  = rupp->dwY;
511     startup_infoW.dwXSize              = rupp->dwXSize;
512     startup_infoW.dwYSize              = rupp->dwYSize;
513     startup_infoW.dwXCountChars        = rupp->dwXCountChars;
514     startup_infoW.dwYCountChars        = rupp->dwYCountChars;
515     startup_infoW.dwFillAttribute      = rupp->dwFillAttribute;
516     startup_infoW.dwFlags              = rupp->dwFlags;
517     startup_infoW.wShowWindow          = rupp->wShowWindow;
518     startup_infoW.cbReserved2          = 0;
519     startup_infoW.lpReserved2          = NULL;
520     startup_infoW.hStdInput            = rupp->hStdInput;
521     startup_infoW.hStdOutput           = rupp->hStdOutput;
522     startup_infoW.hStdError            = rupp->hStdError;
523
524     startup_infoA.cb                   = sizeof(startup_infoW);
525     startup_infoA.lpReserved           = NULL;
526     startup_infoA.lpDesktop = (rupp->Desktop.Length &&
527                                RtlUnicodeStringToAnsiString( &ansi, &rupp->Desktop, TRUE) == STATUS_SUCCESS) ?
528         ansi.Buffer : NULL;
529     startup_infoA.lpTitle = (rupp->WindowTitle.Length &&
530                              RtlUnicodeStringToAnsiString( &ansi, &rupp->WindowTitle, TRUE) == STATUS_SUCCESS) ?
531         ansi.Buffer : NULL;
532     startup_infoA.dwX                  = rupp->dwX;
533     startup_infoA.dwY                  = rupp->dwY;
534     startup_infoA.dwXSize              = rupp->dwXSize;
535     startup_infoA.dwYSize              = rupp->dwYSize;
536     startup_infoA.dwXCountChars        = rupp->dwXCountChars;
537     startup_infoA.dwYCountChars        = rupp->dwYCountChars;
538     startup_infoA.dwFillAttribute      = rupp->dwFillAttribute;
539     startup_infoA.dwFlags              = rupp->dwFlags;
540     startup_infoA.wShowWindow          = rupp->wShowWindow;
541     startup_infoA.cbReserved2          = 0;
542     startup_infoA.lpReserved2          = NULL;
543     startup_infoA.hStdInput            = rupp->hStdInput;
544     startup_infoA.hStdOutput           = rupp->hStdOutput;
545     startup_infoA.hStdError            = rupp->hStdError;
546
547     RtlReleasePebLock();
548 }