environ.c 15.1 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Process environment management
 *
 * Copyright 1996, 1998 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21 22 23
#include "config.h"
#include "wine/port.h"

24
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25 26
#include <stdlib.h>
#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/library.h"
35
#include "winternl.h"
36 37
#include "wine/unicode.h"
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39 40
#include "kernel_private.h"

41
WINE_DEFAULT_DEBUG_CHANNEL(environ);
42

43
/* Notes:
Alexandre Julliard's avatar
Alexandre Julliard committed
44 45 46 47 48
 * - contrary to Microsoft docs, the environment strings do not appear
 *   to be sorted on Win95 (although they are on NT); so we don't bother
 *   to sort them either.
 */

49 50 51
static STARTUPINFOW startup_infoW;
static STARTUPINFOA startup_infoA;

Alexandre Julliard's avatar
Alexandre Julliard committed
52 53

/***********************************************************************
54
 *           GetCommandLineA      (KERNEL32.@)
55 56 57 58 59 60
 *
 * WARNING: there's a Windows incompatibility lurking here !
 * Win32s always includes the full path of the program file,
 * whereas Windows NT only returns the full file path plus arguments
 * in case the program has been started with a full path.
 * Win9x seems to have inherited NT behaviour.
61
 *
62 63 64 65 66 67
 * Note that both Start Menu Execute and Explorer start programs with
 * fully specified quoted app file paths, which is why probably the only case
 * where you'll see single file names is in case of direct launch
 * via CreateProcess or WinExec.
 *
 * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
68
 *
69
 * References: MS KB article q102762.txt (special Win32s handling)
Alexandre Julliard's avatar
Alexandre Julliard committed
70
 */
71
LPSTR WINAPI GetCommandLineA(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
72
{
73 74 75 76 77 78 79 80 81 82 83 84
    static char *cmdlineA;  /* ASCII command line */
    
    if (!cmdlineA) /* make an ansi version if we don't have it */
    {
        ANSI_STRING     ansi;
        RtlAcquirePebLock();

        cmdlineA = (RtlUnicodeStringToAnsiString( &ansi, &NtCurrentTeb()->Peb->ProcessParameters->CommandLine, TRUE) == STATUS_SUCCESS) ?
            ansi.Buffer : NULL;
        RtlReleasePebLock();
    }
    return cmdlineA;
Alexandre Julliard's avatar
Alexandre Julliard committed
85 86 87
}

/***********************************************************************
88
 *           GetCommandLineW      (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
89
 */
90
LPWSTR WINAPI GetCommandLineW(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
91
{
92
    return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
Alexandre Julliard's avatar
Alexandre Julliard committed
93 94 95 96
}


/***********************************************************************
97
 *           GetEnvironmentStringsA   (KERNEL32.@)
98
 *           GetEnvironmentStrings    (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
99
 */
100
LPSTR WINAPI GetEnvironmentStringsA(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
101
{
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    LPWSTR      ptrW;
    unsigned    len, slen;
    LPSTR       ret, ptrA;

    RtlAcquirePebLock();

    len = 1;

    ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
    while (*ptrW)
    {
        slen = strlenW(ptrW) + 1;
        len += WideCharToMultiByte( CP_ACP, 0, ptrW, slen, NULL, 0, NULL, NULL );
        ptrW += slen;
    }

    if ((ret = HeapAlloc( GetProcessHeap(), 0, len )) != NULL)
    {
        ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
        ptrA = ret;
        while (*ptrW)
        {
            slen = strlenW(ptrW) + 1;
            WideCharToMultiByte( CP_ACP, 0, ptrW, slen, ptrA, len, NULL, NULL );
            ptrW += slen;
            ptrA += strlen(ptrA) + 1;
        }
        *ptrA = 0;
    }

    RtlReleasePebLock();
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
134 135 136 137
}


/***********************************************************************
138
 *           GetEnvironmentStringsW   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
139
 */
140
LPWSTR WINAPI GetEnvironmentStringsW(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
141
{
142
    return NtCurrentTeb()->Peb->ProcessParameters->Environment;
Alexandre Julliard's avatar
Alexandre Julliard committed
143 144 145 146
}


/***********************************************************************
147
 *           FreeEnvironmentStringsA   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
148
 */
149
BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr )
Alexandre Julliard's avatar
Alexandre Julliard committed
150
{
151
    return HeapFree( GetProcessHeap(), 0, ptr );
Alexandre Julliard's avatar
Alexandre Julliard committed
152 153 154 155
}


/***********************************************************************
156
 *           FreeEnvironmentStringsW   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
157
 */
158
BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr )
Alexandre Julliard's avatar
Alexandre Julliard committed
159
{
160
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
161 162 163 164
}


/***********************************************************************
165
 *           GetEnvironmentVariableA   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
166
 */
167
DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
Alexandre Julliard's avatar
Alexandre Julliard committed
168
{
169 170 171
    UNICODE_STRING      us_name;
    PWSTR               valueW;
    DWORD               ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
172 173 174

    if (!name || !*name)
    {
175
        SetLastError(ERROR_ENVVAR_NOT_FOUND);
Alexandre Julliard's avatar
Alexandre Julliard committed
176 177
        return 0;
    }
178

179 180 181 182 183 184 185
    if (!(valueW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
        return 0;

    RtlCreateUnicodeStringFromAsciiz( &us_name, name );
    SetLastError(0);
    ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size);
    if (ret && ret < size)
Alexandre Julliard's avatar
Alexandre Julliard committed
186
    {
187
        WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
188
    }
189 190 191 192 193 194 195 196 197 198
    /* this is needed to tell, with 0 as a return value, the difference between:
     * - an error (GetLastError() != 0)
     * - returning an empty string (in this case, we need to update the buffer)
     */
    if (ret == 0 && size && GetLastError() == 0)
        value[0] = '\0';

    RtlFreeUnicodeString( &us_name );
    HeapFree(GetProcessHeap(), 0, valueW);

199
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
200 201 202 203
}


/***********************************************************************
204
 *           GetEnvironmentVariableW   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
205
 */
206
DWORD WINAPI GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
Alexandre Julliard's avatar
Alexandre Julliard committed
207
{
208 209 210 211
    UNICODE_STRING      us_name;
    UNICODE_STRING      us_value;
    NTSTATUS            status;
    unsigned            len;
212

213
    TRACE("(%s %p %u)\n", debugstr_w(name), val, size);
214 215

    if (!name || !*name)
216
    {
217
        SetLastError(ERROR_ENVVAR_NOT_FOUND);
218 219 220
        return 0;
    }

221 222 223 224 225 226 227 228
    RtlInitUnicodeString(&us_name, name);
    us_value.Length = 0;
    us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
    us_value.Buffer = val;

    status = RtlQueryEnvironmentVariable_U(NULL, &us_name, &us_value);
    len = us_value.Length / sizeof(WCHAR);
    if (status != STATUS_SUCCESS)
Alexandre Julliard's avatar
Alexandre Julliard committed
229
    {
230 231
        SetLastError( RtlNtStatusToDosError(status) );
        return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
232
    }
233 234 235
    if (size) val[len] = '\0';

    return us_value.Length / sizeof(WCHAR);
Alexandre Julliard's avatar
Alexandre Julliard committed
236 237 238 239
}


/***********************************************************************
240
 *           SetEnvironmentVariableA   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
241
 */
242
BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
Alexandre Julliard's avatar
Alexandre Julliard committed
243
{
244 245
    UNICODE_STRING      us_name;
    BOOL                ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
246

247
    if (!name)
248
    {
249 250
        SetLastError(ERROR_ENVVAR_NOT_FOUND);
        return 0;
251 252
    }

253 254
    RtlCreateUnicodeStringFromAsciiz( &us_name, name );
    if (value)
Alexandre Julliard's avatar
Alexandre Julliard committed
255
    {
256
        UNICODE_STRING      us_value;
Alexandre Julliard's avatar
Alexandre Julliard committed
257

258 259 260
        RtlCreateUnicodeStringFromAsciiz( &us_value, value );
        ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
        RtlFreeUnicodeString( &us_value );
Alexandre Julliard's avatar
Alexandre Julliard committed
261
    }
262
    else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
263

264
    RtlFreeUnicodeString( &us_name );
Alexandre Julliard's avatar
Alexandre Julliard committed
265 266 267 268 269 270

    return ret;
}


/***********************************************************************
271
 *           SetEnvironmentVariableW   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
272
 */
273
BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
Alexandre Julliard's avatar
Alexandre Julliard committed
274
{
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
    UNICODE_STRING      us_name;
    NTSTATUS            status;

    TRACE("(%s %s)\n", debugstr_w(name), debugstr_w(value));

    if (!name)
    {
        SetLastError(ERROR_ENVVAR_NOT_FOUND);
        return 0;
    }

    RtlInitUnicodeString(&us_name, name);
    if (value)
    {
        UNICODE_STRING      us_value;

        RtlInitUnicodeString(&us_value, value);
        status = RtlSetEnvironmentVariable(NULL, &us_name, &us_value);
    }
    else status = RtlSetEnvironmentVariable(NULL, &us_name, NULL);

    if (status != STATUS_SUCCESS)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return FALSE;
    }
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
302 303 304 305
}


/***********************************************************************
306
 *           ExpandEnvironmentStringsA   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
307
 *
308 309
 * See ExpandEnvironmentStringsW.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
310
 * Note: overlapping buffers are not supported; this is how it should be.
311
 * FIXME: return value is wrong for MBCS
Alexandre Julliard's avatar
Alexandre Julliard committed
312
 */
313
DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
Alexandre Julliard's avatar
Alexandre Julliard committed
314
{
315 316 317
    UNICODE_STRING      us_src;
    PWSTR               dstW = NULL;
    DWORD               ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
318

319 320
    RtlCreateUnicodeStringFromAsciiz( &us_src, src );
    if (count)
Alexandre Julliard's avatar
Alexandre Julliard committed
321
    {
322 323 324 325 326
        if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR))))
            return 0;
        ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count);
        if (ret)
            WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
327
    }
328
    else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
329

330
    RtlFreeUnicodeString( &us_src );
331
    HeapFree(GetProcessHeap(), 0, dstW);
332 333

    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
334 335 336 337
}


/***********************************************************************
338
 *           ExpandEnvironmentStringsW   (KERNEL32.@)
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
 *
 * Replaces references to environment variables of the form '%EnvVar%'
 * by their value. If the environment variable does not exist, then the
 * reference is left as is.
 *
 * PARAMS
 *  src       [I] The string to be expanded.
 *  dst       [O] The buffer in which to put the expanded string.
 *  len       [I] The buffer size, in characters.
 *
 * RETURNS
 *  The number of characters copied into the buffer. If the buffer is
 *  too small, then the required buffer size, in characters including the
 *  trailing '\0', is returned.
 *  If the function fails for some other reason, then it returns 0.
Alexandre Julliard's avatar
Alexandre Julliard committed
354
 */
355
DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
Alexandre Julliard's avatar
Alexandre Julliard committed
356
{
357 358 359 360 361
    UNICODE_STRING      us_src;
    UNICODE_STRING      us_dst;
    NTSTATUS            status;
    DWORD               res;

362
    TRACE("(%s %p %u)\n", debugstr_w(src), dst, len);
363 364

    RtlInitUnicodeString(&us_src, src);
365

366
    /* make sure we don't overflow the maximum UNICODE_STRING size */
367 368
    if (len > UNICODE_STRING_MAX_CHARS)
        len = UNICODE_STRING_MAX_CHARS;
369

370 371 372 373 374 375 376 377
    us_dst.Length = 0;
    us_dst.MaximumLength = len * sizeof(WCHAR);
    us_dst.Buffer = dst;

    res = 0;
    status = RtlExpandEnvironmentStrings_U(NULL, &us_src, &us_dst, &res);
    res /= sizeof(WCHAR);
    if (status != STATUS_SUCCESS)
Alexandre Julliard's avatar
Alexandre Julliard committed
378
    {
379 380 381
        SetLastError( RtlNtStatusToDosError(status) );
        if (status != STATUS_BUFFER_TOO_SMALL) return 0;
        if (len && dst) dst[len - 1] = '\0';
Alexandre Julliard's avatar
Alexandre Julliard committed
382
    }
383 384

    return res;
Alexandre Julliard's avatar
Alexandre Julliard committed
385 386
}

387 388

/***********************************************************************
389
 *           GetStdHandle    (KERNEL32.@)
390 391 392
 */
HANDLE WINAPI GetStdHandle( DWORD std_handle )
{
393
    switch (std_handle)
394
    {
395 396 397
        case STD_INPUT_HANDLE:  return NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
        case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
        case STD_ERROR_HANDLE:  return NtCurrentTeb()->Peb->ProcessParameters->hStdError;
398
    }
399
    SetLastError( ERROR_INVALID_HANDLE );
400 401 402 403 404
    return INVALID_HANDLE_VALUE;
}


/***********************************************************************
405
 *           SetStdHandle    (KERNEL32.@)
406 407 408
 */
BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
{
409
    switch (std_handle)
410
    {
411 412 413
        case STD_INPUT_HANDLE:  NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle;  return TRUE;
        case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE;
        case STD_ERROR_HANDLE:  NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle;  return TRUE;
414
    }
415
    SetLastError( ERROR_INVALID_HANDLE );
416 417 418 419
    return FALSE;
}

/***********************************************************************
420
 *              GetStartupInfoA         (KERNEL32.@)
421 422 423
 */
VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
{
424
    *info = startup_infoA;
425 426 427 428
}


/***********************************************************************
429
 *              GetStartupInfoW         (KERNEL32.@)
430 431 432
 */
VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
{
433
    *info = startup_infoW;
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
}

/******************************************************************
 *		ENV_CopyStartupInformation (internal)
 *
 * Creates the STARTUPINFO information from the ntdll information
 */
void ENV_CopyStartupInformation(void)
{
    RTL_USER_PROCESS_PARAMETERS* rupp;
    ANSI_STRING         ansi;

    RtlAcquirePebLock();
    
    rupp = NtCurrentTeb()->Peb->ProcessParameters;

    startup_infoW.cb                   = sizeof(startup_infoW);
    startup_infoW.lpReserved           = NULL;
    startup_infoW.lpDesktop            = rupp->Desktop.Buffer;
    startup_infoW.lpTitle              = rupp->WindowTitle.Buffer;
    startup_infoW.dwX                  = rupp->dwX;
    startup_infoW.dwY                  = rupp->dwY;
    startup_infoW.dwXSize              = rupp->dwXSize;
    startup_infoW.dwYSize              = rupp->dwYSize;
    startup_infoW.dwXCountChars        = rupp->dwXCountChars;
    startup_infoW.dwYCountChars        = rupp->dwYCountChars;
    startup_infoW.dwFillAttribute      = rupp->dwFillAttribute;
    startup_infoW.dwFlags              = rupp->dwFlags;
    startup_infoW.wShowWindow          = rupp->wShowWindow;
463 464
    startup_infoW.cbReserved2          = rupp->RuntimeInfo.MaximumLength;
    startup_infoW.lpReserved2          = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
465 466 467 468
    startup_infoW.hStdInput            = rupp->hStdInput;
    startup_infoW.hStdOutput           = rupp->hStdOutput;
    startup_infoW.hStdError            = rupp->hStdError;

469
    startup_infoA.cb                   = sizeof(startup_infoA);
470
    startup_infoA.lpReserved           = NULL;
471
    startup_infoA.lpDesktop = RtlUnicodeStringToAnsiString( &ansi, &rupp->Desktop, TRUE ) == STATUS_SUCCESS ?
472
        ansi.Buffer : NULL;
473
    startup_infoA.lpTitle = RtlUnicodeStringToAnsiString( &ansi, &rupp->WindowTitle, TRUE ) == STATUS_SUCCESS ?
474 475 476 477 478 479 480 481 482 483
        ansi.Buffer : NULL;
    startup_infoA.dwX                  = rupp->dwX;
    startup_infoA.dwY                  = rupp->dwY;
    startup_infoA.dwXSize              = rupp->dwXSize;
    startup_infoA.dwYSize              = rupp->dwYSize;
    startup_infoA.dwXCountChars        = rupp->dwXCountChars;
    startup_infoA.dwYCountChars        = rupp->dwYCountChars;
    startup_infoA.dwFillAttribute      = rupp->dwFillAttribute;
    startup_infoA.dwFlags              = rupp->dwFlags;
    startup_infoA.wShowWindow          = rupp->wShowWindow;
484 485
    startup_infoA.cbReserved2          = rupp->RuntimeInfo.MaximumLength;
    startup_infoA.lpReserved2          = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
486 487 488 489 490
    startup_infoA.hStdInput            = rupp->hStdInput;
    startup_infoA.hStdOutput           = rupp->hStdOutput;
    startup_infoA.hStdError            = rupp->hStdError;

    RtlReleasePebLock();
491
}