Repository: microsoft/terminal
File: src/types/Environment.cpp (C++)

Code before:
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "precomp.h"
#include "inc/Environment.hpp"

using namespace ::Microsoft::Console::Utils;

// We cannot use spand or not_null because we're dealing with \0\0-terminated buffers of unknown length
#pragma warning(disable : 26481 26429)

// Function Description:
// - Updates an EnvironmentVariableMapW with the current process's unicode
//   environment variables ignoring ones already set in the provided map.
// Arguments:
// - map: The map to populate with the current processes's environment variables.
// Return Value:
// - S_OK if we succeeded, or an appropriate HRESULT for failing
HRESULT Microsoft::Console::Utils::UpdateEnvironmentMapW(EnvironmentVariableMapW& map) noexcept
try
{
    LPWCH currentEnvVars{};
    auto freeCurrentEnv = wil::scope_exit([&] {
        if (currentEnvVars)
        {
            FreeEnvironmentStringsW(currentEnvVars);
            currentEnvVars = nullptr;
        }
    });

    currentEnvVars = ::GetEnvironmentStringsW();
    RETURN_HR_IF_NULL(E_OUTOFMEMORY, currentEnvVars);

    // Each entry is NULL-terminated; block is guaranteed to be double-NULL terminated at a minimum.
    for (wchar_t const* lastCh{ currentEnvVars }; *lastCh != '\0'; ++lastCh)
    {
        // Copy current entry into temporary map.
        const size_t cchEntry{ ::wcslen(lastCh) };
        const std::wstring_view entry{ lastCh, cchEntry };

        // Every entry is of the form "name=value\0".
        const auto pos = entry.find_first_of(L"=", 0, 1);

Review comment (refactor):
@nathpete can you test what happens if you replace `GetCurrentProcessToken` with..


```c++
auto processToken{ wil::open_current_access_token() };
CreateEnv(...processToken.get()...)
```

If that doesn't restore `USERNAME`, can you try passing `TOKEN_QUERY|TOKEN_DUPLICATE` as the first arg to open_current_acc?

Code after:
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "precomp.h"
#include "inc/Environment.hpp"

using namespace ::Microsoft::Console::Utils;

// We cannot use spand or not_null because we're dealing with \0\0-terminated buffers of unknown length
#pragma warning(disable : 26481 26429)

// Function Description:
// - Wraps win32's CreateEnvironmentBlock to return a smart pointer.
EnvironmentBlockPtr Microsoft::Console::Utils::CreateEnvironmentBlock()
{
    void* newEnvironmentBlock{ nullptr };
    if (!::CreateEnvironmentBlock(&newEnvironmentBlock, GetCurrentProcessToken(), FALSE))
    {
        return nullptr;
    }
    return EnvironmentBlockPtr{ newEnvironmentBlock };
}

// Function Description:
// - Updates an EnvironmentVariableMapW with the current process's unicode
//   environment variables ignoring ones already set in the provided map.
// Arguments:
// - map: The map to populate with the current processes's environment variables.
// - environmentBlock: Optional environment block to use when filling map. If omitted,
//   defaults to the current environment.
// Return Value:
// - S_OK if we succeeded, or an appropriate HRESULT for failing
HRESULT Microsoft::Console::Utils::UpdateEnvironmentMapW(EnvironmentVariableMapW& map, void* environmentBlock) noexcept
try
{
    wchar_t const* activeEnvironmentBlock{ static_cast<wchar_t const*>(environmentBlock) };

    wil::unique_environstrings_ptr currentEnvVars;
    if (!activeEnvironmentBlock)
    {
        currentEnvVars.reset(::GetEnvironmentStringsW());
        RETURN_HR_IF_NULL(E_OUTOFMEMORY, currentEnvVars);