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