Removed some unnecessary inclusions of thread.h
[wine] / dlls / kernel / 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 "wine/server.h"
34 #include "wine/library.h"
35 #include "winternl.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(environ);
40
41 /* Notes:
42  * - contrary to Microsoft docs, the environment strings do not appear
43  *   to be sorted on Win95 (although they are on NT); so we don't bother
44  *   to sort them either.
45  */
46
47 static STARTUPINFOW startup_infoW;
48 static STARTUPINFOA startup_infoA;
49
50
51 /***********************************************************************
52  *           GetCommandLineA      (KERNEL32.@)
53  *
54  * WARNING: there's a Windows incompatibility lurking here !
55  * Win32s always includes the full path of the program file,
56  * whereas Windows NT only returns the full file path plus arguments
57  * in case the program has been started with a full path.
58  * Win9x seems to have inherited NT behaviour.
59  *
60  * Note that both Start Menu Execute and Explorer start programs with
61  * fully specified quoted app file paths, which is why probably the only case
62  * where you'll see single file names is in case of direct launch
63  * via CreateProcess or WinExec.
64  *
65  * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
66  *
67  * References: MS KB article q102762.txt (special Win32s handling)
68  */
69 LPSTR WINAPI GetCommandLineA(void)
70 {
71     static char *cmdlineA;  /* ASCII command line */
72     
73     if (!cmdlineA) /* make an ansi version if we don't have it */
74     {
75         ANSI_STRING     ansi;
76         RtlAcquirePebLock();
77
78         cmdlineA = (RtlUnicodeStringToAnsiString( &ansi, &NtCurrentTeb()->Peb->ProcessParameters->CommandLine, TRUE) == STATUS_SUCCESS) ?
79             ansi.Buffer : NULL;
80         RtlReleasePebLock();
81     }
82     return cmdlineA;
83 }
84
85 /***********************************************************************
86  *           GetCommandLineW      (KERNEL32.@)
87  */
88 LPWSTR WINAPI GetCommandLineW(void)
89 {
90     return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
91 }
92
93
94 /***********************************************************************
95  *           GetEnvironmentStrings    (KERNEL32.@)
96  *           GetEnvironmentStringsA   (KERNEL32.@)
97  */
98 LPSTR WINAPI GetEnvironmentStringsA(void)
99 {
100     LPWSTR      ptrW;
101     unsigned    len, slen;
102     LPSTR       ret, ptrA;
103
104     RtlAcquirePebLock();
105
106     len = 1;
107
108     ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
109     while (*ptrW)
110     {
111         slen = strlenW(ptrW) + 1;
112         len += WideCharToMultiByte( CP_ACP, 0, ptrW, slen, NULL, 0, NULL, NULL );
113         ptrW += slen;
114     }
115
116     if ((ret = HeapAlloc( GetProcessHeap(), 0, len )) != NULL)
117     {
118         ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
119         ptrA = ret;
120         while (*ptrW)
121         {
122             slen = strlenW(ptrW) + 1;
123             WideCharToMultiByte( CP_ACP, 0, ptrW, slen, ptrA, len, NULL, NULL );
124             ptrW += slen;
125             ptrA += strlen(ptrA) + 1;
126         }
127         *ptrA = 0;
128     }
129
130     RtlReleasePebLock();
131     return ret;
132 }
133
134
135 /***********************************************************************
136  *           GetEnvironmentStringsW   (KERNEL32.@)
137  */
138 LPWSTR WINAPI GetEnvironmentStringsW(void)
139 {
140     return NtCurrentTeb()->Peb->ProcessParameters->Environment;
141 }
142
143
144 /***********************************************************************
145  *           FreeEnvironmentStringsA   (KERNEL32.@)
146  */
147 BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr )
148 {
149     return HeapFree( GetProcessHeap(), 0, ptr );
150 }
151
152
153 /***********************************************************************
154  *           FreeEnvironmentStringsW   (KERNEL32.@)
155  */
156 BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr )
157 {
158     return TRUE;
159 }
160
161
162 /***********************************************************************
163  *           GetEnvironmentVariableA   (KERNEL32.@)
164  */
165 DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
166 {
167     UNICODE_STRING      us_name;
168     PWSTR               valueW;
169     DWORD               ret;
170
171     if (!name || !*name)
172     {
173         SetLastError(ERROR_ENVVAR_NOT_FOUND);
174         return 0;
175     }
176
177     if (!(valueW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
178         return 0;
179
180     RtlCreateUnicodeStringFromAsciiz( &us_name, name );
181     SetLastError(0);
182     ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size);
183     if (ret && ret < size)
184     {
185         WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL );
186     }
187     /* this is needed to tell, with 0 as a return value, the difference between:
188      * - an error (GetLastError() != 0)
189      * - returning an empty string (in this case, we need to update the buffer)
190      */
191     if (ret == 0 && size && GetLastError() == 0)
192         value[0] = '\0';
193
194     RtlFreeUnicodeString( &us_name );
195     HeapFree(GetProcessHeap(), 0, valueW);
196
197     return ret;
198 }
199
200
201 /***********************************************************************
202  *           GetEnvironmentVariableW   (KERNEL32.@)
203  */
204 DWORD WINAPI GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
205 {
206     UNICODE_STRING      us_name;
207     UNICODE_STRING      us_value;
208     NTSTATUS            status;
209     unsigned            len;
210
211     TRACE("(%s %p %lu)\n", debugstr_w(name), val, size);
212
213     if (!name || !*name)
214     {
215         SetLastError(ERROR_ENVVAR_NOT_FOUND);
216         return 0;
217     }
218
219     RtlInitUnicodeString(&us_name, name);
220     us_value.Length = 0;
221     us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
222     us_value.Buffer = val;
223
224     status = RtlQueryEnvironmentVariable_U(NULL, &us_name, &us_value);
225     len = us_value.Length / sizeof(WCHAR);
226     if (status != STATUS_SUCCESS)
227     {
228         SetLastError( RtlNtStatusToDosError(status) );
229         return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0;
230     }
231     if (size) val[len] = '\0';
232
233     return us_value.Length / sizeof(WCHAR);
234 }
235
236
237 /***********************************************************************
238  *           SetEnvironmentVariableA   (KERNEL32.@)
239  */
240 BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
241 {
242     UNICODE_STRING      us_name;
243     BOOL                ret;
244
245     if (!name)
246     {
247         SetLastError(ERROR_ENVVAR_NOT_FOUND);
248         return 0;
249     }
250
251     RtlCreateUnicodeStringFromAsciiz( &us_name, name );
252     if (value)
253     {
254         UNICODE_STRING      us_value;
255
256         RtlCreateUnicodeStringFromAsciiz( &us_value, value );
257         ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
258         RtlFreeUnicodeString( &us_value );
259     }
260     else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
261
262     RtlFreeUnicodeString( &us_name );
263
264     return ret;
265 }
266
267
268 /***********************************************************************
269  *           SetEnvironmentVariableW   (KERNEL32.@)
270  */
271 BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
272 {
273     UNICODE_STRING      us_name;
274     NTSTATUS            status;
275
276     TRACE("(%s %s)\n", debugstr_w(name), debugstr_w(value));
277
278     if (!name)
279     {
280         SetLastError(ERROR_ENVVAR_NOT_FOUND);
281         return 0;
282     }
283
284     RtlInitUnicodeString(&us_name, name);
285     if (value)
286     {
287         UNICODE_STRING      us_value;
288
289         RtlInitUnicodeString(&us_value, value);
290         status = RtlSetEnvironmentVariable(NULL, &us_name, &us_value);
291     }
292     else status = RtlSetEnvironmentVariable(NULL, &us_name, NULL);
293
294     if (status != STATUS_SUCCESS)
295     {
296         SetLastError( RtlNtStatusToDosError(status) );
297         return FALSE;
298     }
299     return TRUE;
300 }
301
302
303 /***********************************************************************
304  *           ExpandEnvironmentStringsA   (KERNEL32.@)
305  *
306  * Note: overlapping buffers are not supported; this is how it should be.
307  * FIXME: return value is wrong for MBCS
308  */
309 DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
310 {
311     UNICODE_STRING      us_src;
312     PWSTR               dstW = NULL;
313     DWORD               ret;
314
315     RtlCreateUnicodeStringFromAsciiz( &us_src, src );
316     if (count)
317     {
318         if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR))))
319             return 0;
320         ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count);
321         if (ret)
322             WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL );
323     }
324     else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0);
325
326     RtlFreeUnicodeString( &us_src );
327     HeapFree(GetProcessHeap(), 0, dstW);
328
329     return ret;
330 }
331
332
333 /***********************************************************************
334  *           ExpandEnvironmentStringsW   (KERNEL32.@)
335  */
336 DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
337 {
338     UNICODE_STRING      us_src;
339     UNICODE_STRING      us_dst;
340     NTSTATUS            status;
341     DWORD               res;
342
343     TRACE("(%s %p %lu)\n", debugstr_w(src), dst, len);
344
345     RtlInitUnicodeString(&us_src, src);
346     us_dst.Length = 0;
347     us_dst.MaximumLength = len * sizeof(WCHAR);
348     us_dst.Buffer = dst;
349
350     res = 0;
351     status = RtlExpandEnvironmentStrings_U(NULL, &us_src, &us_dst, &res);
352     res /= sizeof(WCHAR);
353     if (status != STATUS_SUCCESS)
354     {
355         SetLastError( RtlNtStatusToDosError(status) );
356         if (status != STATUS_BUFFER_TOO_SMALL) return 0;
357         if (len && dst) dst[len - 1] = '\0';
358     }
359
360     return res;
361 }
362
363
364 /***********************************************************************
365  *           GetStdHandle    (KERNEL32.@)
366  */
367 HANDLE WINAPI GetStdHandle( DWORD std_handle )
368 {
369     switch (std_handle)
370     {
371         case STD_INPUT_HANDLE:  return NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
372         case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
373         case STD_ERROR_HANDLE:  return NtCurrentTeb()->Peb->ProcessParameters->hStdError;
374     }
375     SetLastError( ERROR_INVALID_PARAMETER );
376     return INVALID_HANDLE_VALUE;
377 }
378
379
380 /***********************************************************************
381  *           SetStdHandle    (KERNEL32.@)
382  */
383 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
384 {
385     switch (std_handle)
386     {
387         case STD_INPUT_HANDLE:  NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle;  return TRUE;
388         case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE;
389         case STD_ERROR_HANDLE:  NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle;  return TRUE;
390     }
391     SetLastError( ERROR_INVALID_PARAMETER );
392     return FALSE;
393 }
394
395 /***********************************************************************
396  *              GetStartupInfoA         (KERNEL32.@)
397  */
398 VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
399 {
400     assert(startup_infoA.cb);
401     memcpy(info, &startup_infoA, sizeof(startup_infoA));
402 }
403
404
405 /***********************************************************************
406  *              GetStartupInfoW         (KERNEL32.@)
407  */
408 VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
409 {
410     assert(startup_infoW.cb);
411     memcpy(info, &startup_infoW, sizeof(startup_infoW));
412 }
413
414 /******************************************************************
415  *              ENV_CopyStartupInformation (internal)
416  *
417  * Creates the STARTUPINFO information from the ntdll information
418  */
419 void ENV_CopyStartupInformation(void)
420 {
421     RTL_USER_PROCESS_PARAMETERS* rupp;
422     ANSI_STRING         ansi;
423
424     RtlAcquirePebLock();
425     
426     rupp = NtCurrentTeb()->Peb->ProcessParameters;
427
428     startup_infoW.cb                   = sizeof(startup_infoW);
429     startup_infoW.lpReserved           = NULL;
430     startup_infoW.lpDesktop            = rupp->Desktop.Buffer;
431     startup_infoW.lpTitle              = rupp->WindowTitle.Buffer;
432     startup_infoW.dwX                  = rupp->dwX;
433     startup_infoW.dwY                  = rupp->dwY;
434     startup_infoW.dwXSize              = rupp->dwXSize;
435     startup_infoW.dwYSize              = rupp->dwYSize;
436     startup_infoW.dwXCountChars        = rupp->dwXCountChars;
437     startup_infoW.dwYCountChars        = rupp->dwYCountChars;
438     startup_infoW.dwFillAttribute      = rupp->dwFillAttribute;
439     startup_infoW.dwFlags              = rupp->dwFlags;
440     startup_infoW.wShowWindow          = rupp->wShowWindow;
441     startup_infoW.cbReserved2          = rupp->RuntimeInfo.MaximumLength;
442     startup_infoW.lpReserved2          = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
443     startup_infoW.hStdInput            = rupp->hStdInput;
444     startup_infoW.hStdOutput           = rupp->hStdOutput;
445     startup_infoW.hStdError            = rupp->hStdError;
446
447     startup_infoA.cb                   = sizeof(startup_infoA);
448     startup_infoA.lpReserved           = NULL;
449     startup_infoA.lpDesktop = (rupp->Desktop.Length &&
450                                RtlUnicodeStringToAnsiString( &ansi, &rupp->Desktop, TRUE) == STATUS_SUCCESS) ?
451         ansi.Buffer : NULL;
452     startup_infoA.lpTitle = (rupp->WindowTitle.Length &&
453                              RtlUnicodeStringToAnsiString( &ansi, &rupp->WindowTitle, TRUE) == STATUS_SUCCESS) ?
454         ansi.Buffer : NULL;
455     startup_infoA.dwX                  = rupp->dwX;
456     startup_infoA.dwY                  = rupp->dwY;
457     startup_infoA.dwXSize              = rupp->dwXSize;
458     startup_infoA.dwYSize              = rupp->dwYSize;
459     startup_infoA.dwXCountChars        = rupp->dwXCountChars;
460     startup_infoA.dwYCountChars        = rupp->dwYCountChars;
461     startup_infoA.dwFillAttribute      = rupp->dwFillAttribute;
462     startup_infoA.dwFlags              = rupp->dwFlags;
463     startup_infoA.wShowWindow          = rupp->wShowWindow;
464     startup_infoA.cbReserved2          = rupp->RuntimeInfo.MaximumLength;
465     startup_infoA.lpReserved2          = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
466     startup_infoA.hStdInput            = rupp->hStdInput;
467     startup_infoA.hStdOutput           = rupp->hStdOutput;
468     startup_infoA.hStdError            = rupp->hStdError;
469
470     RtlReleasePebLock();
471 }