environ.c 14.6 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
 *
 * Note: overlapping buffers are not supported; this is how it should be.
309
 * FIXME: return value is wrong for MBCS
Alexandre Julliard's avatar
Alexandre Julliard committed
310
 */
311
DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
Alexandre Julliard's avatar
Alexandre Julliard committed
312
{
313 314 315
    UNICODE_STRING      us_src;
    PWSTR               dstW = NULL;
    DWORD               ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
316

317 318
    RtlCreateUnicodeStringFromAsciiz( &us_src, src );
    if (count)
Alexandre Julliard's avatar
Alexandre Julliard committed
319
    {
320 321 322 323 324
        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
325
    }
326
    else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
327

328
    RtlFreeUnicodeString( &us_src );
329
    HeapFree(GetProcessHeap(), 0, dstW);
330 331

    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
332 333 334 335
}


/***********************************************************************
336
 *           ExpandEnvironmentStringsW   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
337
 */
338
DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
Alexandre Julliard's avatar
Alexandre Julliard committed
339
{
340 341 342 343 344
    UNICODE_STRING      us_src;
    UNICODE_STRING      us_dst;
    NTSTATUS            status;
    DWORD               res;

345
    TRACE("(%s %p %u)\n", debugstr_w(src), dst, len);
346 347

    RtlInitUnicodeString(&us_src, src);
348 349 350 351 352

    /* make sure we don't overflow maximum UNICODE_STRING size */
    if (len > 0x7fff)
        len = 0x7fff;

353 354 355 356 357 358 359 360
    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
361
    {
362 363 364
        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
365
    }
366 367

    return res;
Alexandre Julliard's avatar
Alexandre Julliard committed
368 369
}

370 371

/***********************************************************************
372
 *           GetStdHandle    (KERNEL32.@)
373 374 375
 */
HANDLE WINAPI GetStdHandle( DWORD std_handle )
{
376
    switch (std_handle)
377
    {
378 379 380
        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;
381 382 383 384 385 386 387
    }
    SetLastError( ERROR_INVALID_PARAMETER );
    return INVALID_HANDLE_VALUE;
}


/***********************************************************************
388
 *           SetStdHandle    (KERNEL32.@)
389 390 391
 */
BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
{
392
    switch (std_handle)
393
    {
394 395 396
        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;
397 398 399 400 401 402
    }
    SetLastError( ERROR_INVALID_PARAMETER );
    return FALSE;
}

/***********************************************************************
403
 *              GetStartupInfoA         (KERNEL32.@)
404 405 406
 */
VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
{
407
    memcpy(info, &startup_infoA, sizeof(startup_infoA));
408 409 410 411
}


/***********************************************************************
412
 *              GetStartupInfoW         (KERNEL32.@)
413 414 415
 */
VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
{
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
    memcpy(info, &startup_infoW, sizeof(startup_infoW));
}

/******************************************************************
 *		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;
446 447
    startup_infoW.cbReserved2          = rupp->RuntimeInfo.MaximumLength;
    startup_infoW.lpReserved2          = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
448 449 450 451
    startup_infoW.hStdInput            = rupp->hStdInput;
    startup_infoW.hStdOutput           = rupp->hStdOutput;
    startup_infoW.hStdError            = rupp->hStdError;

452
    startup_infoA.cb                   = sizeof(startup_infoA);
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
    startup_infoA.lpReserved           = NULL;
    startup_infoA.lpDesktop = (rupp->Desktop.Length &&
                               RtlUnicodeStringToAnsiString( &ansi, &rupp->Desktop, TRUE) == STATUS_SUCCESS) ?
        ansi.Buffer : NULL;
    startup_infoA.lpTitle = (rupp->WindowTitle.Length &&
                             RtlUnicodeStringToAnsiString( &ansi, &rupp->WindowTitle, TRUE) == STATUS_SUCCESS) ?
        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;
469 470
    startup_infoA.cbReserved2          = rupp->RuntimeInfo.MaximumLength;
    startup_infoA.lpReserved2          = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
471 472 473 474 475
    startup_infoA.hStdInput            = rupp->hStdInput;
    startup_infoA.hStdOutput           = rupp->hStdOutput;
    startup_infoA.hStdError            = rupp->hStdError;

    RtlReleasePebLock();
476
}