annotate foosdk/sdk/foobar2000/helpers/ProcessUtils.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
1 #pragma once
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
2
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
3 #ifdef FOOBAR2000_DESKTOP_WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
4
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
5 #include <libPPUI/win32_op.h>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
6
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
7 namespace ProcessUtils {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
8 class PipeIO : public stream_reader, public stream_writer {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
9 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
10 PFC_DECLARE_EXCEPTION(timeout, exception_io, "Timeout");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
11 PipeIO(HANDLE handle, HANDLE hEvent, bool processMessages, DWORD timeOut = INFINITE) : m_handle(handle), m_event(hEvent), m_processMessages(processMessages), m_timeOut(timeOut) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
12 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
13 ~PipeIO() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
14 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
15
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
16 void write(const void * p_buffer,size_t p_bytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
17 if (p_bytes == 0) return;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
18 OVERLAPPED ol = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
19 ol.hEvent = m_event;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
20 ResetEvent(m_event);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
21 DWORD bytesWritten;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
22 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
23 if (WriteFile( m_handle, p_buffer, pfc::downcast_guarded<DWORD>(p_bytes), &bytesWritten, &ol)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
24 // succeeded already?
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
25 if (bytesWritten != p_bytes) throw exception_io();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
26 return;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
27 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
28
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
29 {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
30 const DWORD code = GetLastError();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
31 if (code != ERROR_IO_PENDING) exception_io_from_win32(code);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
32 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
33 const HANDLE handles[] = {m_event, abort.get_abort_event()};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
34 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
35 DWORD state = myWait(_countof(handles), handles);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
36 if (state == WAIT_OBJECT_0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
37 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
38 WIN32_IO_OP( GetOverlappedResult(m_handle,&ol,&bytesWritten,TRUE) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
39 } catch(...) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
40 _cancel(ol);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
41 throw;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
42 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
43 if (bytesWritten != p_bytes) throw exception_io();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
44 return;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
45 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
46 _cancel(ol);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
47 abort.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
48 throw timeout();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
49 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
50 size_t read(void * p_buffer,size_t p_bytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
51 uint8_t * ptr = (uint8_t*) p_buffer;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
52 size_t done = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
53 while(done < p_bytes) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
54 abort.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
55 size_t delta = readPass(ptr + done, p_bytes - done, abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
56 if (delta == 0) break;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
57 done += delta;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
58 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
59 return done;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
60 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
61 size_t readPass(void * p_buffer,size_t p_bytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
62 if (p_bytes == 0) return 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
63 OVERLAPPED ol = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
64 ol.hEvent = m_event;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
65 ResetEvent(m_event);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
66 DWORD bytesDone;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
67 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
68 if (ReadFile( m_handle, p_buffer, pfc::downcast_guarded<DWORD>(p_bytes), &bytesDone, &ol)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
69 // succeeded already?
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
70 return bytesDone;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
71 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
72
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
73 {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
74 const DWORD code = GetLastError();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
75 switch(code) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
76 case ERROR_HANDLE_EOF:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
77 return 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
78 case ERROR_IO_PENDING:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
79 break; // continue
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
80 default:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
81 exception_io_from_win32(code);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
82 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
83 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
84
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
85 const HANDLE handles[] = {m_event, abort.get_abort_event()};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
86 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
87 DWORD state = myWait(_countof(handles), handles);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
88 if (state == WAIT_OBJECT_0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
89 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
90 if (!GetOverlappedResult(m_handle,&ol,&bytesDone,TRUE)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
91 const DWORD code = GetLastError();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
92 if (code == ERROR_HANDLE_EOF) bytesDone = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
93 else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
94 _cancel(ol);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
95 exception_io_from_win32(code);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
96 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
97 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
98 return bytesDone;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
99 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
100 _cancel(ol);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
101 abort.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
102 throw timeout();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
103 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
104 private:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
105 DWORD myWait(DWORD count, const HANDLE * handles) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
106 if (m_processMessages) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
107 for(;;) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
108 DWORD state = MsgWaitForMultipleObjects(count, handles, FALSE, m_timeOut, QS_ALLINPUT);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
109 if (state == WAIT_OBJECT_0 + count) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
110 ProcessPendingMessages();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
111 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
112 return state;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
113 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
114 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
115 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
116 return WaitForMultipleObjects(count, handles, FALSE, m_timeOut);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
117 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
118 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
119 void _cancel(OVERLAPPED & ol) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
120 #if _WIN32_WINNT >= 0x600
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
121 CancelIoEx(m_handle,&ol);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
122 #else
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
123 CancelIo(m_handle);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
124 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
125 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
126 static void ProcessPendingMessages() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
127 MSG msg = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
128 while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
129 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
130
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
131 HANDLE m_handle;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
132 HANDLE m_event;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
133 const DWORD m_timeOut;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
134 const bool m_processMessages;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
135 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
136
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
137 class SubProcess : public stream_reader, public stream_writer {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
138 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
139 PFC_DECLARE_EXCEPTION(failure, std::exception, "Unexpected failure");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
140
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
141 SubProcess(const char * exePath, DWORD timeOutMS = 60*1000) : ExePath(exePath), hStdIn(), hStdOut(), hProcess(), ProcessMessages(false), TimeOutMS(timeOutMS) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
142 HANDLE ev;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
143 WIN32_OP( (ev = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
144 hEventRead = ev;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
145 WIN32_OP( (ev = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
146 hEventWrite = ev;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
147 Restart();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
148 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
149 void Restart() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
150 CleanUp();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
151 STARTUPINFO si = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
152 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
153 si.cb = sizeof(si);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
154 si.dwFlags = STARTF_USESTDHANDLES | STARTF_FORCEOFFFEEDBACK;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
155 //si.wShowWindow = SW_HIDE;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
156
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
157 myCreatePipeOut(si.hStdInput, hStdIn);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
158 myCreatePipeIn(hStdOut, si.hStdOutput);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
159 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
160
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
161 PROCESS_INFORMATION pi = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
162 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
163 WIN32_OP( CreateProcess(pfc::stringcvt::string_os_from_utf8(ExePath), NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
164 } catch(std::exception const & e) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
165 throw failure(PFC_string_formatter() << "Could not start the worker process - " << e);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
166 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
167 hProcess = pi.hProcess; _Close(pi.hThread);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
168 } catch(...) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
169 _Close(si.hStdInput);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
170 _Close(si.hStdOutput);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
171 CleanUp(); throw;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
172 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
173 _Close(si.hStdInput);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
174 _Close(si.hStdOutput);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
175 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
176 ~SubProcess() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
177 CleanUp();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
178 CloseHandle(hEventRead);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
179 CloseHandle(hEventWrite);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
180 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
181
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
182 bool IsRunning() const {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
183 return hProcess != NULL;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
184 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
185 void Detach() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
186 CleanUp(true);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
187 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
188 bool ProcessMessages;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
189 DWORD TimeOutMS;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
190
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
191
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
192 void write(const void * p_buffer,size_t p_bytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
193 PipeIO writer(hStdIn, hEventWrite, ProcessMessages, TimeOutMS);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
194 writer.write(p_buffer, p_bytes, abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
195 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
196 size_t read(void * p_buffer,size_t p_bytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
197 PipeIO reader(hStdOut, hEventRead, ProcessMessages, TimeOutMS);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
198 return reader.read(p_buffer, p_bytes, abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
199 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
200 void SetPriority(DWORD val) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
201 SetPriorityClass(hProcess, val);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
202 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
203 protected:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
204 HANDLE hStdIn, hStdOut, hProcess, hEventRead, hEventWrite;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
205 const pfc::string8 ExePath;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
206
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
207 void CleanUp(bool bDetach = false) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
208 _Close(hStdIn); _Close(hStdOut);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
209 if (hProcess != NULL) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
210 if (!bDetach) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
211 if (WaitForSingleObject(hProcess, TimeOutMS) != WAIT_OBJECT_0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
212 //PFC_ASSERT( !"Should not get here - worker stuck" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
213 FB2K_console_formatter() << pfc::string_filename_ext(ExePath) << " unresponsive - terminating";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
214 TerminateProcess(hProcess, -1);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
215 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
216 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
217 _Close(hProcess);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
218 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
219 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
220 private:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
221 static void _Close(HANDLE & h) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
222 if (h != NULL) {CloseHandle(h); h = NULL;}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
223 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
224
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
225 static void myCreatePipe(HANDLE & in, HANDLE & out) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
226 SECURITY_ATTRIBUTES Attributes = { sizeof(SECURITY_ATTRIBUTES), 0, true };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
227 WIN32_OP( CreatePipe( &in, &out, &Attributes, 0 ) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
228 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
229
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
230 static pfc::string_formatter makePipeName() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
231 GUID id;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
232 CoCreateGuid (&id);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
233 return pfc::format( "\\\\.\\pipe\\", pfc::print_guid(id));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
234 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
235
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
236 static void myCreatePipeOut(HANDLE & in, HANDLE & out) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
237 SECURITY_ATTRIBUTES Attributes = { sizeof(SECURITY_ATTRIBUTES), 0, true };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
238 const pfc::stringcvt::string_os_from_utf8 pipeName( makePipeName() );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
239 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
240 HANDLE pipe = CreateNamedPipe(
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
241 pipeName,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
242 FILE_FLAG_FIRST_PIPE_INSTANCE | PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
243 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
244 1,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
245 1024*64,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
246 1024*64,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
247 NMPWAIT_USE_DEFAULT_WAIT,&Attributes);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
248 if (pipe == INVALID_HANDLE_VALUE) throw exception_win32(GetLastError());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
249
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
250 in = CreateFile(pipeName,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,&Attributes,OPEN_EXISTING,0,NULL);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
251 DuplicateHandle ( GetCurrentProcess(), pipe, GetCurrentProcess(), &out, 0, FALSE, DUPLICATE_SAME_ACCESS );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
252 CloseHandle(pipe);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
253 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
254
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
255 static void myCreatePipeIn(HANDLE & in, HANDLE & out) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
256 SECURITY_ATTRIBUTES Attributes = { sizeof(SECURITY_ATTRIBUTES), 0, true };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
257 const pfc::stringcvt::string_os_from_utf8 pipeName( makePipeName() );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
258 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
259 HANDLE pipe = CreateNamedPipe(
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
260 pipeName,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
261 FILE_FLAG_FIRST_PIPE_INSTANCE | PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
262 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
263 1,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
264 1024*64,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
265 1024*64,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
266 NMPWAIT_USE_DEFAULT_WAIT,&Attributes);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
267 if (pipe == INVALID_HANDLE_VALUE) throw exception_win32(GetLastError());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
268
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
269 out = CreateFile(pipeName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,&Attributes,OPEN_EXISTING,0,NULL);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
270 DuplicateHandle ( GetCurrentProcess(), pipe, GetCurrentProcess(), &in, 0, FALSE, DUPLICATE_SAME_ACCESS );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
271 CloseHandle(pipe);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
272 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
273
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
274 PFC_CLASS_NOT_COPYABLE_EX(SubProcess)
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
275 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
276 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
277
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
278 #endif // FOOBAR2000_DESKTOP_WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
279