1 /*-------------------------------------------------------------------------
4 * putenv(), setenv(), and unsetenv() for win32.
6 * These functions update both the process environment and caches in
7 * (potentially multiple) C run-time library (CRT) versions.
9 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
16 *-------------------------------------------------------------------------
23 * Note that unlike POSIX putenv(), this doesn't use the passed-in string
24 * as permanent storage.
27 pgwin32_putenv(const char *envval
)
31 typedef int (_cdecl
* PUTENVPROC
) (const char *);
32 static const char *const modulenames
[] = {
33 "msvcrt", /* Visual Studio 6.0 / MinGW */
35 "msvcr70", /* Visual Studio 2002 */
37 "msvcr71", /* Visual Studio 2003 */
39 "msvcr80", /* Visual Studio 2005 */
41 "msvcr90", /* Visual Studio 2008 */
43 "msvcr100", /* Visual Studio 2010 */
45 "msvcr110", /* Visual Studio 2012 */
47 "msvcr120", /* Visual Studio 2013 */
49 "ucrtbase", /* Visual Studio 2015 and later */
56 * Update process environment, making this change visible to child
57 * processes and to CRTs initializing in the future. Do this before the
58 * _putenv() loop, for the benefit of any CRT that initializes during this
59 * pgwin32_putenv() execution, after the loop checks that CRT.
61 * Need a copy of the string so we can modify it.
63 envcpy
= strdup(envval
);
66 cp
= strchr(envcpy
, '=');
77 * Only call SetEnvironmentVariable() when we are adding a variable,
78 * not when removing it. Calling it on both crashes on at least
79 * certain versions of MinGW.
81 if (!SetEnvironmentVariable(envcpy
, cp
))
90 * Each CRT has its own _putenv() symbol and copy of the environment.
91 * Update the environment in each CRT module currently loaded, so every
92 * third-party library sees this change regardless of the CRT it links
93 * against. Addresses within these modules may become invalid the moment
94 * we call FreeLibrary(), so don't cache them.
96 for (i
= 0; modulenames
[i
]; i
++)
98 HMODULE hmodule
= NULL
;
99 BOOL res
= GetModuleHandleEx(0, modulenames
[i
], &hmodule
);
101 if (res
!= 0 && hmodule
!= NULL
)
103 PUTENVPROC putenvFunc
;
105 putenvFunc
= (PUTENVPROC
) (pg_funcptr_t
) GetProcAddress(hmodule
, "_putenv");
108 FreeLibrary(hmodule
);
113 * Finally, update our "own" cache. This is redundant with the loop
114 * above, except when PostgreSQL itself links to a CRT not listed above.
115 * Ideally, the loop does visit all possible CRTs, making this redundant.
117 return _putenv(envval
);
121 pgwin32_setenv(const char *name
, const char *value
, int overwrite
)
126 /* Error conditions, per POSIX */
127 if (name
== NULL
|| name
[0] == '\0' || strchr(name
, '=') != NULL
||
134 /* No work if variable exists and we're not to replace it */
135 if (overwrite
== 0 && getenv(name
) != NULL
)
138 envstr
= (char *) malloc(strlen(name
) + strlen(value
) + 2);
139 if (!envstr
) /* not much we can do if no memory */
142 sprintf(envstr
, "%s=%s", name
, value
);
144 res
= pgwin32_putenv(envstr
);
150 pgwin32_unsetenv(const char *name
)
155 envbuf
= (char *) malloc(strlen(name
) + 2);
159 sprintf(envbuf
, "%s=", name
);
160 res
= pgwin32_putenv(envbuf
);