1*04e0dc4aSTimo Kreuzer //
2*04e0dc4aSTimo Kreuzer // get_environment_from_os.cpp
3*04e0dc4aSTimo Kreuzer //
4*04e0dc4aSTimo Kreuzer // Copyright (c) Microsoft Corporation. All rights reserved.
5*04e0dc4aSTimo Kreuzer //
6*04e0dc4aSTimo Kreuzer // Defines a pair of functions to get the environment strings from the operating
7*04e0dc4aSTimo Kreuzer // system. These functions copy the environment strings into a CRT-allocated
8*04e0dc4aSTimo Kreuzer // buffer and return a pointer to that buffer. The caller is responsible for
9*04e0dc4aSTimo Kreuzer // freeing the returned buffer (via _crt_free).
10*04e0dc4aSTimo Kreuzer //
11*04e0dc4aSTimo Kreuzer #include <corecrt_internal.h>
12*04e0dc4aSTimo Kreuzer #include <corecrt_internal_traits.h>
13*04e0dc4aSTimo Kreuzer #include <stdlib.h>
14*04e0dc4aSTimo Kreuzer
15*04e0dc4aSTimo Kreuzer
16*04e0dc4aSTimo Kreuzer
17*04e0dc4aSTimo Kreuzer namespace
18*04e0dc4aSTimo Kreuzer {
19*04e0dc4aSTimo Kreuzer struct environment_strings_traits
20*04e0dc4aSTimo Kreuzer {
21*04e0dc4aSTimo Kreuzer typedef wchar_t* type;
22*04e0dc4aSTimo Kreuzer
close__anon1ca68d940111::environment_strings_traits23*04e0dc4aSTimo Kreuzer static bool close(_In_ type p) throw()
24*04e0dc4aSTimo Kreuzer {
25*04e0dc4aSTimo Kreuzer FreeEnvironmentStringsW(p);
26*04e0dc4aSTimo Kreuzer return true;
27*04e0dc4aSTimo Kreuzer }
28*04e0dc4aSTimo Kreuzer
get_invalid_value__anon1ca68d940111::environment_strings_traits29*04e0dc4aSTimo Kreuzer static type get_invalid_value() throw()
30*04e0dc4aSTimo Kreuzer {
31*04e0dc4aSTimo Kreuzer return nullptr;
32*04e0dc4aSTimo Kreuzer }
33*04e0dc4aSTimo Kreuzer };
34*04e0dc4aSTimo Kreuzer
35*04e0dc4aSTimo Kreuzer typedef __crt_unique_handle_t<environment_strings_traits> environment_strings_handle;
36*04e0dc4aSTimo Kreuzer }
37*04e0dc4aSTimo Kreuzer
38*04e0dc4aSTimo Kreuzer
39*04e0dc4aSTimo Kreuzer
find_end_of_double_null_terminated_sequence(wchar_t const * const first)40*04e0dc4aSTimo Kreuzer static wchar_t const* __cdecl find_end_of_double_null_terminated_sequence(wchar_t const* const first) throw()
41*04e0dc4aSTimo Kreuzer {
42*04e0dc4aSTimo Kreuzer wchar_t const* last = first;
43*04e0dc4aSTimo Kreuzer for (; *last != '\0'; last += wcslen(last) + 1)
44*04e0dc4aSTimo Kreuzer {
45*04e0dc4aSTimo Kreuzer }
46*04e0dc4aSTimo Kreuzer
47*04e0dc4aSTimo Kreuzer return last + 1; // Return the pointer one-past-the-end of the double null terminator
48*04e0dc4aSTimo Kreuzer }
49*04e0dc4aSTimo Kreuzer
50*04e0dc4aSTimo Kreuzer
51*04e0dc4aSTimo Kreuzer
__dcrt_get_wide_environment_from_os()52*04e0dc4aSTimo Kreuzer extern "C" wchar_t* __cdecl __dcrt_get_wide_environment_from_os() throw()
53*04e0dc4aSTimo Kreuzer {
54*04e0dc4aSTimo Kreuzer environment_strings_handle const environment(GetEnvironmentStringsW());
55*04e0dc4aSTimo Kreuzer if (!environment)
56*04e0dc4aSTimo Kreuzer return nullptr;
57*04e0dc4aSTimo Kreuzer
58*04e0dc4aSTimo Kreuzer // Find the
59*04e0dc4aSTimo Kreuzer wchar_t const* const first = environment.get();
60*04e0dc4aSTimo Kreuzer wchar_t const* const last = find_end_of_double_null_terminated_sequence(first);
61*04e0dc4aSTimo Kreuzer
62*04e0dc4aSTimo Kreuzer size_t const required_count = last - first;
63*04e0dc4aSTimo Kreuzer
64*04e0dc4aSTimo Kreuzer __crt_unique_heap_ptr<wchar_t> buffer(_malloc_crt_t(wchar_t, required_count));
65*04e0dc4aSTimo Kreuzer if (!buffer)
66*04e0dc4aSTimo Kreuzer return nullptr;
67*04e0dc4aSTimo Kreuzer
68*04e0dc4aSTimo Kreuzer // Note that the multiplication here cannot overflow:
69*04e0dc4aSTimo Kreuzer memcpy(buffer.get(), environment.get(), required_count * sizeof(wchar_t));
70*04e0dc4aSTimo Kreuzer return buffer.detach();
71*04e0dc4aSTimo Kreuzer }
72*04e0dc4aSTimo Kreuzer
73*04e0dc4aSTimo Kreuzer
74*04e0dc4aSTimo Kreuzer
__dcrt_get_narrow_environment_from_os()75*04e0dc4aSTimo Kreuzer extern "C" char* __cdecl __dcrt_get_narrow_environment_from_os() throw()
76*04e0dc4aSTimo Kreuzer {
77*04e0dc4aSTimo Kreuzer // Note that we call GetEnvironmentStringsW and convert to multibyte. The
78*04e0dc4aSTimo Kreuzer // GetEnvironmentStringsA function returns the environment in the OEM code
79*04e0dc4aSTimo Kreuzer // page, but we need the strings in ANSI.
80*04e0dc4aSTimo Kreuzer environment_strings_handle const environment(GetEnvironmentStringsW());
81*04e0dc4aSTimo Kreuzer if (!environment.is_valid())
82*04e0dc4aSTimo Kreuzer return nullptr;
83*04e0dc4aSTimo Kreuzer
84*04e0dc4aSTimo Kreuzer wchar_t const* const first = environment.get();
85*04e0dc4aSTimo Kreuzer wchar_t const* const last = find_end_of_double_null_terminated_sequence(first);
86*04e0dc4aSTimo Kreuzer
87*04e0dc4aSTimo Kreuzer size_t const required_wide_count = last - first;
88*04e0dc4aSTimo Kreuzer #pragma warning(suppress:__WARNING_W2A_BEST_FIT) // 38021 Prefast recommends WC_NO_BEST_FIT_CHARS.
89*04e0dc4aSTimo Kreuzer size_t const required_narrow_count = static_cast<size_t>(__acrt_WideCharToMultiByte(
90*04e0dc4aSTimo Kreuzer CP_ACP,
91*04e0dc4aSTimo Kreuzer 0,
92*04e0dc4aSTimo Kreuzer environment.get(),
93*04e0dc4aSTimo Kreuzer static_cast<int>(required_wide_count),
94*04e0dc4aSTimo Kreuzer nullptr,
95*04e0dc4aSTimo Kreuzer 0,
96*04e0dc4aSTimo Kreuzer nullptr,
97*04e0dc4aSTimo Kreuzer nullptr));
98*04e0dc4aSTimo Kreuzer
99*04e0dc4aSTimo Kreuzer if (required_narrow_count == 0)
100*04e0dc4aSTimo Kreuzer return nullptr;
101*04e0dc4aSTimo Kreuzer
102*04e0dc4aSTimo Kreuzer __crt_unique_heap_ptr<char> buffer(_malloc_crt_t(char, required_narrow_count));
103*04e0dc4aSTimo Kreuzer if (!buffer)
104*04e0dc4aSTimo Kreuzer return nullptr;
105*04e0dc4aSTimo Kreuzer
106*04e0dc4aSTimo Kreuzer #pragma warning(suppress:__WARNING_W2A_BEST_FIT) // 38021 Prefast recommends WC_NO_BEST_FIT_CHARS.
107*04e0dc4aSTimo Kreuzer int const conversion_result = __acrt_WideCharToMultiByte(
108*04e0dc4aSTimo Kreuzer CP_ACP,
109*04e0dc4aSTimo Kreuzer 0,
110*04e0dc4aSTimo Kreuzer environment.get(),
111*04e0dc4aSTimo Kreuzer static_cast<int>(required_wide_count),
112*04e0dc4aSTimo Kreuzer buffer.get(),
113*04e0dc4aSTimo Kreuzer static_cast<int>(required_narrow_count),
114*04e0dc4aSTimo Kreuzer nullptr,
115*04e0dc4aSTimo Kreuzer nullptr);
116*04e0dc4aSTimo Kreuzer
117*04e0dc4aSTimo Kreuzer if (conversion_result == 0)
118*04e0dc4aSTimo Kreuzer return nullptr;
119*04e0dc4aSTimo Kreuzer
120*04e0dc4aSTimo Kreuzer return buffer.detach();
121*04e0dc4aSTimo Kreuzer }
122