Fix Windows Unicode handling of environment variables

This commit is contained in:
Marc-André Moreau
2021-05-25 13:48:50 -04:00
committed by akallabeth
parent be5ace1123
commit 55be5f8bb0
3 changed files with 92 additions and 8 deletions

View File

@@ -134,6 +134,9 @@ extern "C"
WINPR_API char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock);
WINPR_API DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize);
WINPR_API char* GetEnvAlloc(LPCSTR lpName);
#ifdef __cplusplus
}
#endif

View File

@@ -643,3 +643,77 @@ char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
return envp;
}
#ifdef _WIN32
// https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
#define WINPR_MAX_ENVIRONMENT_LENGTH 2048
DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
{
int status;
DWORD result = 0;
DWORD nSizeW = 0;
LPWSTR lpNameW = NULL;
LPWSTR lpBufferW = NULL;
LPSTR lpBufferA = lpBuffer;
if (ConvertToUnicode(CP_UTF8, 0, lpName, -1, &lpNameW, 0) < 1)
goto cleanup;
if (!lpBuffer)
{
char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH];
WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH];
// calling GetEnvironmentVariableX with a NULL buffer should return the expected size
// TODO: dynamically allocate the buffer, or use the theoretical limit of 32,768 characters
lpBufferA = lpBufferMaxA;
lpBufferW = lpBufferMaxW;
nSizeW = sizeof(lpBufferMaxW) / 2;
result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
status = ConvertFromUnicode(CP_UTF8, 0, lpBufferW, -1, &lpBufferA, sizeof(lpBufferMaxA),
NULL, NULL);
if (status > 0)
result = (DWORD)status;
return result;
}
else
{
nSizeW = nSize + 1;
lpBufferW = calloc(nSizeW, 2);
if (!lpBufferW)
goto cleanup;
result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
if (result == 0)
goto cleanup;
status = ConvertFromUnicode(CP_UTF8, 0, lpBufferW, -1, &lpBufferA, nSize, NULL, NULL);
if (status > 0)
result = (DWORD)(status - 1);
}
cleanup:
free(lpBufferW);
free(lpNameW);
return result;
}
#else
DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
{
return GetEnvironmentVariableA(lpName, lpBuffer, nSize);
}
#endif

View File

@@ -59,20 +59,24 @@ static char* GetPath_XDG_RUNTIME_DIR(void);
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*/
static char* GetEnvAlloc(LPCSTR lpName)
char* GetEnvAlloc(LPCSTR lpName)
{
DWORD length;
DWORD nSize;
DWORD nStatus;
char* env = NULL;
length = GetEnvironmentVariableA(lpName, NULL, 0);
if (length > 0)
nSize = GetEnvironmentVariableX(lpName, NULL, 0);
if (nSize > 0)
{
env = malloc(length);
env = malloc(nSize);
if (!env)
return NULL;
if (GetEnvironmentVariableA(lpName, env, length) != length - 1)
nStatus = GetEnvironmentVariableX(lpName, env, nSize);
if (nStatus != (nSize - 1))
{
free(env);
return NULL;
@@ -376,7 +380,8 @@ char* GetEnvironmentPath(char* name)
{
char* env = NULL;
DWORD nSize;
nSize = GetEnvironmentVariableA(name, NULL, 0);
DWORD nStatus;
nSize = GetEnvironmentVariableX(name, NULL, 0);
if (nSize)
{
@@ -385,7 +390,9 @@ char* GetEnvironmentPath(char* name)
if (!env)
return NULL;
if (GetEnvironmentVariableA(name, env, nSize) != nSize - 1)
nStatus = GetEnvironmentVariableX(name, env, nSize);
if (nStatus != (nSize - 1))
{
free(env);
return NULL;