Modify CheckRadioButton function to be more consistent with Windows.
[wine/multimedia.git] / memory / environ.c
blobd29ced067b9e1550ed38b8d8caf42935d0da25e0
1 /*
2 * Process environment management
4 * Copyright 1996, 1998 Alexandre Julliard
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
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"
43 WINE_DEFAULT_DEBUG_CHANNEL(environ);
45 /* TODO:
46 * - 16 bit environment ??? (see generate_env_block16 for the details)
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)
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)
66 static const char ENV_program_name[] = "C:\\WINDOWS\\SYSTEM\\KRNL386.EXE";
68 static STARTUPINFOW startup_infoW;
69 static STARTUPINFOA startup_infoA;
71 /* Maximum length of a Win16 environment string (including NULL) */
72 #define MAX_WIN16_LEN 128
74 static WORD env_sel; /* selector to the 16 bit environment */
76 /******************************************************************
77 * generate_env_block16
79 * This internal function generates a suitable environment for the 16 bit
80 * subsystem and returns the value as a segmented pointer.
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
92 static SEGPTR generate_env_block16(void)
94 static LPSTR env16;
96 DWORD size, new_size;
97 WORD one = 1;
99 if (env16) FreeEnvironmentStringsA( env16 );
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;
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 );
113 return MAKESEGPTR( env_sel, 0 );
116 /***********************************************************************
117 * GetCommandLineA (KERNEL32.@)
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.
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.
130 * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
132 * References: MS KB article q102762.txt (special Win32s handling)
134 LPSTR WINAPI GetCommandLineA(void)
136 static char *cmdlineA; /* ASCII command line */
138 if (!cmdlineA) /* make an ansi version if we don't have it */
140 ANSI_STRING ansi;
141 RtlAcquirePebLock();
143 cmdlineA = (RtlUnicodeStringToAnsiString( &ansi, &NtCurrentTeb()->Peb->ProcessParameters->CommandLine, TRUE) == STATUS_SUCCESS) ?
144 ansi.Buffer : NULL;
145 RtlReleasePebLock();
147 return cmdlineA;
150 /***********************************************************************
151 * GetCommandLineW (KERNEL32.@)
153 LPWSTR WINAPI GetCommandLineW(void)
155 return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
159 /***********************************************************************
160 * GetEnvironmentStrings (KERNEL32.@)
161 * GetEnvironmentStringsA (KERNEL32.@)
163 LPSTR WINAPI GetEnvironmentStringsA(void)
165 LPWSTR ptrW;
166 unsigned len, slen;
167 LPSTR ret, ptrA;
169 RtlAcquirePebLock();
171 len = 1;
173 ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
174 while (*ptrW)
176 slen = strlenW(ptrW) + 1;
177 len += WideCharToMultiByte( CP_ACP, 0, ptrW, slen, NULL, 0, NULL, NULL );
178 ptrW += slen;
181 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )) != NULL)
183 ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
184 ptrA = ret;
185 while (*ptrW)
187 slen = strlenW(ptrW) + 1;
188 WideCharToMultiByte( CP_ACP, 0, ptrW, slen, ptrA, len, NULL, NULL );
189 ptrW += slen;
190 ptrA += strlen(ptrA) + 1;
192 *ptrA = 0;
195 RtlReleasePebLock();
196 return ret;
200 /***********************************************************************
201 * GetEnvironmentStringsW (KERNEL32.@)
203 LPWSTR WINAPI GetEnvironmentStringsW(void)
205 return NtCurrentTeb()->Peb->ProcessParameters->Environment;
209 /***********************************************************************
210 * FreeEnvironmentStringsA (KERNEL32.@)
212 BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr )
214 return HeapFree( GetProcessHeap(), 0, ptr );
218 /***********************************************************************
219 * FreeEnvironmentStringsW (KERNEL32.@)
221 BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr )
223 return TRUE;
227 /***********************************************************************
228 * GetEnvironmentVariableA (KERNEL32.@)
230 DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
232 UNICODE_STRING us_name;
233 PWSTR valueW;
234 DWORD ret;
236 if (!name || !*name)
238 SetLastError(ERROR_ENVVAR_NOT_FOUND);
239 return 0;
242 if (!(valueW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
243 return 0;
245 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
246 SetLastError(0);
247 ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size);
248 if (ret && ret < size)
250 WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL );
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)
256 if (ret == 0 && size && GetLastError() == 0)
257 value[0] = '\0';
259 RtlFreeUnicodeString( &us_name );
260 HeapFree(GetProcessHeap(), 0, valueW);
262 return ret;
266 /***********************************************************************
267 * GetEnvironmentVariableW (KERNEL32.@)
269 DWORD WINAPI GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
271 UNICODE_STRING us_name;
272 UNICODE_STRING us_value;
273 NTSTATUS status;
274 unsigned len;
276 TRACE("(%s %p %lu)\n", debugstr_w(name), val, size);
278 if (!name || !*name)
280 SetLastError(ERROR_ENVVAR_NOT_FOUND);
281 return 0;
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;
289 status = RtlQueryEnvironmentVariable_U(NULL, &us_name, &us_value);
290 len = us_value.Length / sizeof(WCHAR);
291 if (status != STATUS_SUCCESS)
293 SetLastError( RtlNtStatusToDosError(status) );
294 return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0;
296 if (size) val[len] = '\0';
298 return us_value.Length / sizeof(WCHAR);
302 /***********************************************************************
303 * SetEnvironmentVariableA (KERNEL32.@)
305 BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
307 UNICODE_STRING us_name;
308 BOOL ret;
310 if (!name)
312 SetLastError(ERROR_ENVVAR_NOT_FOUND);
313 return 0;
316 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
317 if (value)
319 UNICODE_STRING us_value;
321 RtlCreateUnicodeStringFromAsciiz( &us_value, value );
322 ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
323 RtlFreeUnicodeString( &us_value );
325 else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
327 RtlFreeUnicodeString( &us_name );
329 return ret;
333 /***********************************************************************
334 * SetEnvironmentVariableW (KERNEL32.@)
336 BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
338 UNICODE_STRING us_name;
339 NTSTATUS status;
341 TRACE("(%s %s)\n", debugstr_w(name), debugstr_w(value));
343 if (!name)
345 SetLastError(ERROR_ENVVAR_NOT_FOUND);
346 return 0;
349 RtlInitUnicodeString(&us_name, name);
350 if (value)
352 UNICODE_STRING us_value;
354 RtlInitUnicodeString(&us_value, value);
355 status = RtlSetEnvironmentVariable(NULL, &us_name, &us_value);
357 else status = RtlSetEnvironmentVariable(NULL, &us_name, NULL);
359 if (status != STATUS_SUCCESS)
361 SetLastError( RtlNtStatusToDosError(status) );
362 return FALSE;
365 /* FIXME: see comments in generate_env_block16 */
366 if (env_sel) generate_env_block16();
367 return TRUE;
371 /***********************************************************************
372 * ExpandEnvironmentStringsA (KERNEL32.@)
374 * Note: overlapping buffers are not supported; this is how it should be.
375 * FIXME: return value is wrong for MBCS
377 DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
379 UNICODE_STRING us_src;
380 PWSTR dstW = NULL;
381 DWORD ret;
383 RtlCreateUnicodeStringFromAsciiz( &us_src, src );
384 if (count)
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 );
392 else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0);
394 RtlFreeUnicodeString( &us_src );
395 if (dstW) HeapFree(GetProcessHeap(), 0, dstW);
397 return ret;
401 /***********************************************************************
402 * ExpandEnvironmentStringsW (KERNEL32.@)
404 DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
406 UNICODE_STRING us_src;
407 UNICODE_STRING us_dst;
408 NTSTATUS status;
409 DWORD res;
411 TRACE("(%s %p %lu)\n", debugstr_w(src), dst, len);
413 RtlInitUnicodeString(&us_src, src);
414 us_dst.Length = 0;
415 us_dst.MaximumLength = len * sizeof(WCHAR);
416 us_dst.Buffer = dst;
418 res = 0;
419 status = RtlExpandEnvironmentStrings_U(NULL, &us_src, &us_dst, &res);
420 res /= sizeof(WCHAR);
421 if (status != STATUS_SUCCESS)
423 SetLastError( RtlNtStatusToDosError(status) );
424 if (status != STATUS_BUFFER_TOO_SMALL) return 0;
425 if (len && dst) dst[len - 1] = '\0';
428 return res;
432 /***********************************************************************
433 * GetDOSEnvironment (KERNEL.131)
435 SEGPTR WINAPI GetDOSEnvironment16(void)
437 return generate_env_block16();
441 /***********************************************************************
442 * GetStdHandle (KERNEL32.@)
444 HANDLE WINAPI GetStdHandle( DWORD std_handle )
446 switch (std_handle)
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;
452 SetLastError( ERROR_INVALID_PARAMETER );
453 return INVALID_HANDLE_VALUE;
457 /***********************************************************************
458 * SetStdHandle (KERNEL32.@)
460 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
462 switch (std_handle)
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;
468 SetLastError( ERROR_INVALID_PARAMETER );
469 return FALSE;
472 /***********************************************************************
473 * GetStartupInfoA (KERNEL32.@)
475 VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
477 assert(startup_infoA.cb);
478 memcpy(info, &startup_infoA, sizeof(startup_infoA));
482 /***********************************************************************
483 * GetStartupInfoW (KERNEL32.@)
485 VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
487 assert(startup_infoW.cb);
488 memcpy(info, &startup_infoW, sizeof(startup_infoW));
491 /******************************************************************
492 * ENV_CopyStartupInformation (internal)
494 * Creates the STARTUPINFO information from the ntdll information
496 void ENV_CopyStartupInformation(void)
498 RTL_USER_PROCESS_PARAMETERS* rupp;
499 ANSI_STRING ansi;
501 RtlAcquirePebLock();
503 rupp = NtCurrentTeb()->Peb->ProcessParameters;
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;
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;
547 RtlReleasePebLock();