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