4 The environment block starts with variables of the form
5 =C:=C:\Windows\System32 which we ignore.
7 TCHAR *useful_environment(TCHAR *rawenv) {
11 while (*env == _T('=')) {
20 /* Expand an environment variable. Must call HeapFree() on the result. */
21 TCHAR *expand_environment_string(TCHAR *string) {
24 len = ExpandEnvironmentStrings(string, 0, 0);
26 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_EXPANDENVIRONMENTSTRINGS_FAILED, string, error_string(GetLastError()), 0);
30 TCHAR *ret = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR));
32 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("ExpandEnvironmentStrings()"), _T("expand_environment_string"), 0);
36 if (! ExpandEnvironmentStrings(string, ret, len)) {
37 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_EXPANDENVIRONMENTSTRINGS_FAILED, string, error_string(GetLastError()), 0);
38 HeapFree(GetProcessHeap(), 0, ret);
46 Set all the environment variables from an environment block in the current
47 environment or remove all the variables in the block from the current
50 static int set_environment_block(TCHAR *env, bool set) {
54 for (s = env; *s; s++) {
55 for (t = s; *t && *t != _T('='); t++);
59 TCHAR *expanded = expand_environment_string(++t);
61 if (! SetEnvironmentVariable(s, expanded)) ret++;
62 HeapFree(GetProcessHeap(), 0, expanded);
65 if (! SetEnvironmentVariable(s, t)) ret++;
69 if (! SetEnvironmentVariable(s, NULL)) ret++;
79 int set_environment_block(TCHAR *env) {
80 return set_environment_block(env, true);
83 static int unset_environment_block(TCHAR *env) {
84 return set_environment_block(env, false);
87 /* Remove all variables from the process environment. */
88 int clear_environment() {
89 TCHAR *rawenv = GetEnvironmentStrings();
90 TCHAR *env = useful_environment(rawenv);
92 int ret = unset_environment_block(env);
94 if (rawenv) FreeEnvironmentStrings(rawenv);
99 /* Set the current environment to exactly duplicate an environment block. */
100 int duplicate_environment(TCHAR *rawenv) {
101 int ret = clear_environment();
102 TCHAR *env = useful_environment(rawenv);
103 ret += set_environment_block(env);
107 /* Replace NULL with CRLF. Leave NULL NULL as the end marker. */
108 int format_environment(TCHAR *env, unsigned long envlen, TCHAR **formatted, unsigned long *newlen) {
117 for (i = 0; i < envlen; i++) if (! env[i] && env[i + 1]) ++*newlen;
119 *formatted = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *newlen * sizeof(TCHAR));
125 for (i = 0, j = 0; i < envlen; i++) {
126 (*formatted)[j] = env[i];
129 (*formatted)[j] = _T('\r');
130 (*formatted)[++j] = _T('\n');
139 /* Strip CR and replace LF with NULL. */
140 int unformat_environment(TCHAR *env, unsigned long envlen, TCHAR **unformatted, unsigned long *newlen) {
149 for (i = 0; i < envlen; i++) if (env[i] != _T('\r')) ++*newlen;
150 /* Must end with two NULLs. */
153 *unformatted = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *newlen * sizeof(TCHAR));
154 if (! *unformatted) return 1;
156 for (i = 0, j = 0; i < envlen; i++) {
157 if (env[i] == _T('\r')) continue;
158 if (env[i] == _T('\n')) (*unformatted)[j] = _T('\0');
159 else (*unformatted)[j] = env[i];
167 Verify an environment block.
168 Returns: 1 if environment is invalid.
169 0 if environment is OK.
172 int test_environment(TCHAR *env) {
173 TCHAR path[PATH_LENGTH];
174 GetModuleFileName(0, path, _countof(path));
176 ZeroMemory(&si, sizeof(si));
178 PROCESS_INFORMATION pi;
179 ZeroMemory(&pi, sizeof(pi));
180 unsigned long flags = CREATE_SUSPENDED;
182 flags |= CREATE_UNICODE_ENVIRONMENT;
186 Try to relaunch ourselves but with the candidate environment set.
187 Assuming no solar flare activity, the only reason this would fail is if
188 the environment were invalid.
190 if (CreateProcess(0, path, 0, 0, 0, flags, env, 0, &si, &pi)) {
191 TerminateProcess(pi.hProcess, 0);
194 unsigned long error = GetLastError();
195 if (error == ERROR_INVALID_PARAMETER) return 1;