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