Skip to content

Commit 897c7ad

Browse files
author
Iain Patterson
committed
Support starting processes with a console on Windows 10.
By default we let the application inherit NSSM's console. On Windows 10 Creators Update an application inheriting a console would fail to start with error STATUS_DLL_INIT_FAILED. Now we close our own console and call CreateProcess() with the CREATE_NEW_CONSOLE flag if the application needs a console. Unfortunately the ASCII art logo has to be sacrificed in the name of progress...
1 parent 140e503 commit 897c7ad

File tree

3 files changed

+11
-165
lines changed

3 files changed

+11
-165
lines changed

console.cpp

-148
Original file line numberDiff line numberDiff line change
@@ -21,156 +21,8 @@ bool check_console() {
2121
return false;
2222
}
2323

24-
/* Helpers for drawing the banner. */
25-
static inline void block(unsigned int a, short x, short y, unsigned long n) {
26-
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
27-
TCHAR s = _T(' ');
28-
29-
unsigned long out;
30-
COORD c = { x, y };
31-
FillConsoleOutputAttribute(h, a, n, c, &out);
32-
FillConsoleOutputCharacter(h, s, n, c, &out);
33-
}
34-
35-
static inline void R(short x, short y, unsigned long n) {
36-
block(BACKGROUND_RED | BACKGROUND_INTENSITY, x, y, n);
37-
}
38-
39-
static inline void r(short x, short y, unsigned long n) {
40-
block(BACKGROUND_RED, x, y, n);
41-
}
42-
43-
static inline void b(short x, short y, unsigned long n) {
44-
block(0, x, y, n);
45-
}
46-
4724
void alloc_console(nssm_service_t *service) {
4825
if (service->no_console) return;
4926

5027
AllocConsole();
51-
52-
/* Disable accidental closure. */
53-
HWND window = GetConsoleWindow();
54-
HMENU menu = GetSystemMenu(window, false);
55-
EnableMenuItem(menu, SC_CLOSE, MF_GRAYED);
56-
57-
/* Set a title like "[NSSM] Jenkins" */
58-
TCHAR displayname[SERVICE_NAME_LENGTH];
59-
unsigned long len = _countof(displayname);
60-
SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT);
61-
if (services) {
62-
if (! GetServiceDisplayName(services, service->name, displayname, &len)) ZeroMemory(displayname, sizeof(displayname));
63-
CloseServiceHandle(services);
64-
}
65-
if (! displayname[0]) _sntprintf_s(displayname, _countof(displayname), _TRUNCATE, _T("%s"), service->name);
66-
67-
TCHAR title[65535];
68-
_sntprintf_s(title, _countof(title), _TRUNCATE, _T("[%s] %s"), NSSM, displayname);
69-
SetConsoleTitle(title);
70-
71-
/* Draw the NSSM logo on the console window. */
72-
short y = 0;
73-
74-
b(0, y, 80);
75-
y++;
76-
77-
b(0, y, 80);
78-
y++;
79-
80-
b(0, y, 80);
81-
y++;
82-
83-
b(0, y, 80);
84-
y++;
85-
86-
b(0, y, 80);
87-
r(18, y, 5); r(28, y, 4); r(41, y, 4); r(68, y, 1);
88-
R(6, y, 5); R(19, y, 4); R(29, y, 1); R(32, y, 3); R(42, y, 1); R(45, y, 3); R(52, y, 5); R(69, y, 4);
89-
y++;
90-
91-
b(0, y, 80);
92-
r(8, y, 4); r(20, y, 1); r(28, y, 1); r(33, y, 3); r(41, y, 1); r(46, y, 3); r (57, y, 1);
93-
R(9, y, 2); R(21, y, 1); R(27, y, 1); R(34, y, 1); R(40, y, 1); R(47, y, 1); R(54, y, 3); R(68, y, 3);
94-
y++;
95-
96-
b(0, y, 80);
97-
r(12, y, 1); r(20, y, 1); r(26, y, 1); r(34, y, 2); r(39, y, 1); r(47, y, 2); r(67, y, 2);
98-
R(9, y, 3); R(21, y, 1); R(27, y, 1); R(40, y, 1); R(54, y, 1); R(56, y, 2); R(67, y, 1); R(69, y, 2);
99-
y++;
100-
101-
b(0, y, 80);
102-
r(9, y, 1); r(20, y, 1); r(26, y, 1); r (35, y, 1); r(39, y, 1); r(48, y, 1); r(58, y, 1);
103-
R(10, y, 3); R(21, y, 1); R(27, y, 1); R(40, y, 1); R(54, y, 1); R(56, y, 2); R(67, y, 1); R(69, y, 2);
104-
y++;
105-
106-
b(0, y, 80);
107-
r(9, y, 1); r(56, y, 1); r(66, y, 2);
108-
R(11, y, 3); R(21, y, 1); R(26, y, 2); R(39, y, 2); R(54, y, 1); R(57, y, 2); R(69, y, 2);
109-
y++;
110-
111-
b(0, y, 80);
112-
r(9, y, 1); r(26, y, 1); r(39, y, 1); r(59, y, 1);
113-
R(12, y, 3); R(21, y, 1); R(27, y, 2); R(40, y, 2); R(54, y, 1); R(57, y, 2); R(66, y, 1); R(69, y, 2);
114-
y++;
115-
116-
b(0, y, 80);
117-
r(9, y, 1); r(12, y, 4); r(30, y, 1); r(43, y, 1); r(57, y, 1); r(65, y, 2);
118-
R(13, y, 2); R(21, y, 1); R(27, y, 3); R(40, y, 3); R(54, y, 1); R(58, y, 2); R(69, y, 2);
119-
y++;
120-
121-
b(0, y, 80);
122-
r(9, y, 1); r(13, y, 4); r(27, y, 7); r(40, y, 7);
123-
R(14, y, 2); R(21, y, 1); R(28, y, 5); R(41, y, 5); R(54, y, 1); R(58, y, 2); R(65, y, 1); R(69, y, 2);
124-
y++;
125-
126-
b(0, y, 80);
127-
r(9, y, 1); r(60, y, 1); r(65, y, 1);
128-
R(14, y, 3); R(21, y, 1); R(29, y, 6); R(42, y, 6); R(54, y, 1); R(58, y, 2); R(69, y, 2);
129-
y++;
130-
131-
b(0, y, 80);
132-
r(9, y, 1); r(31, y, 1); r(44, y, 1); r(58, y, 1); r(64, y, 1);
133-
R(15, y, 3); R(21, y, 1); R(32, y, 4); R(45, y, 4); R(54, y, 1); R(59, y, 2); R(69, y, 2);
134-
y++;
135-
136-
b(0, y, 80);
137-
r(9, y, 1); r(33, y, 1); r(46, y, 1); r(61, y, 1); r(64, y, 1);
138-
R(16, y, 3); R(21, y, 1); R(34, y, 2); R(47, y, 2); R(54, y, 1); R(59, y, 2); R(69, y, 2);
139-
y++;
140-
141-
b(0, y, 80);
142-
r(9, y, 1); r(16, y, 4); r(36, y, 1); r(49, y, 1); r(59, y, 1); r(63, y, 1);
143-
R(17, y, 2); R(21, y, 1); R(34, y, 2); R(47, y, 2); R(54, y, 1); R(60, y, 2); R(69, y, 2);
144-
y++;
145-
146-
b(0, y, 80);
147-
r(9, y, 1); r(17, y, 4); r(26, y, 1); r(36, y, 1); r(39, y, 1); r(49, y, 1);
148-
R(18, y, 2); R(21, y, 1); R(35, y, 1); R(48, y, 1); R(54, y, 1); R(60, y, 2); R(63, y, 1); R(69, y, 2);
149-
y++;
150-
151-
b(0, y, 80);
152-
r(26, y, 2); r(39, y, 2); r(63, y, 1);
153-
R(9, y, 1); R(18, y, 4); R(35, y, 1); R(48, y, 1); R(54, y, 1); R(60, y, 3); R(69, y, 2);
154-
y++;
155-
156-
b(0, y, 80);
157-
r(34, y, 1); r(47, y, 1); r(60, y, 1);
158-
R(9, y, 1); R(19, y, 3); R(26, y, 2); R(35, y, 1); R(39, y, 2); R(48, y, 1); R(54, y, 1); R(61, y, 2); R(69, y, 2);
159-
y++;
160-
161-
b(0, y, 80);
162-
r(8, y, 1); r(35, y, 1); r(48, y, 1); r(62, y, 1); r(71, y, 1);
163-
R(9, y, 1); R(20, y, 2); R(26, y, 3); R(34, y, 1); R(39, y, 3); R(47, y, 1); R(54, y, 1); R(61, y, 1); R(69, y, 2);
164-
y++;
165-
166-
b(0, y, 80);
167-
r(11, y, 1); r(26, y, 1); r(28, y, 5); r(39, y, 1); r(41, y, 5); r(51, y, 7); r(61, y, 1); r(66, y, 8);
168-
R(7, y, 4); R(21, y, 1); R(29, y, 1); R(33, y, 1); R(42, y, 1); R(46, y, 1); R(52, y, 5); R(67, y, 7);
169-
y++;
170-
171-
b(0, y, 80);
172-
y++;
173-
174-
b(0, y, 80);
175-
y++;
17628
}

io.cpp

+8-14
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsign
305305

306306
int get_output_handles(nssm_service_t *service, STARTUPINFO *si) {
307307
if (! si) return 1;
308+
bool inherit_handles = false;
308309

309310
/* Allocate a new console so we get a fresh stdin, stdout and stderr. */
310311
alloc_console(service);
@@ -316,6 +317,8 @@ int get_output_handles(nssm_service_t *service, STARTUPINFO *si) {
316317
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);
317318
return 2;
318319
}
320+
321+
inherit_handles = true;
319322
}
320323

321324
/* stdout */
@@ -341,6 +344,8 @@ int get_output_handles(nssm_service_t *service, STARTUPINFO *si) {
341344
}
342345

343346
if (dup_handle(service->stdout_si, &si->hStdOutput, _T("stdout_si"), _T("stdout"))) close_handle(&service->stdout_thread);
347+
348+
inherit_handles = true;
344349
}
345350

346351
/* stderr */
@@ -379,26 +384,15 @@ int get_output_handles(nssm_service_t *service, STARTUPINFO *si) {
379384
}
380385

381386
if (dup_handle(service->stderr_si, &si->hStdError, _T("stderr_si"), _T("stderr"))) close_handle(&service->stderr_thread);
387+
388+
inherit_handles = true;
382389
}
383390

384391
/*
385392
We need to set the startup_info flags to make the new handles
386393
inheritable by the new process.
387394
*/
388-
si->dwFlags |= STARTF_USESTDHANDLES;
389-
390-
if (service->no_console) return 0;
391-
392-
/* Redirect other handles. */
393-
if (! si->hStdInput) {
394-
if (dup_handle(GetStdHandle(STD_INPUT_HANDLE), &si->hStdInput, _T("STD_INPUT_HANDLE"), _T("stdin"))) return 8;
395-
}
396-
if (! si->hStdOutput) {
397-
if (dup_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si->hStdOutput, _T("STD_OUTPUT_HANDLE"), _T("stdout"))) return 9;
398-
}
399-
if (! si->hStdError) {
400-
if (dup_handle(GetStdHandle(STD_ERROR_HANDLE), &si->hStdError, _T("STD_ERROR_HANDLE"), _T("stderr"))) return 10;
401-
}
395+
if (inherit_handles) si->dwFlags |= STARTF_USESTDHANDLES;
402396

403397
return 0;
404398
}

service.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1875,11 +1875,12 @@ int start_service(nssm_service_t *service) {
18751875
/* Set up I/O redirection. */
18761876
if (get_output_handles(service, &si)) {
18771877
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_OUTPUT_HANDLES_FAILED, service->name, 0);
1878-
if (! service->no_console) FreeConsole();
1878+
FreeConsole();
18791879
close_output_handles(&si);
18801880
unset_service_environment(service);
18811881
return stop_service(service, 4, true, true);
18821882
}
1883+
FreeConsole();
18831884

18841885
/* Pre-start hook. May need I/O to have been redirected already. */
18851886
if (nssm_hook(&hook_threads, service, NSSM_HOOK_EVENT_START, NSSM_HOOK_ACTION_PRE, &control, NSSM_SERVICE_STATUS_DEADLINE, false) == NSSM_HOOK_STATUS_ABORT) {
@@ -1897,6 +1898,7 @@ int start_service(nssm_service_t *service) {
18971898
if (si.dwFlags & STARTF_USESTDHANDLES) inherit_handles = true;
18981899
unsigned long flags = service->priority & priority_mask();
18991900
if (service->affinity) flags |= CREATE_SUSPENDED;
1901+
if (! service->no_console) flags |= CREATE_NEW_CONSOLE;
19001902
if (! CreateProcess(0, cmd, 0, 0, inherit_handles, flags, 0, service->dir, &si, &pi)) {
19011903
unsigned long exitcode = 3;
19021904
unsigned long error = GetLastError();
@@ -1913,8 +1915,6 @@ int start_service(nssm_service_t *service) {
19131915

19141916
close_output_handles(&si);
19151917

1916-
if (! service->no_console) FreeConsole();
1917-
19181918
if (service->affinity) {
19191919
/*
19201920
We are explicitly storing service->affinity as a 64-bit unsigned integer

0 commit comments

Comments
 (0)