@@ -45,12 +45,13 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result)
4545 }
4646}
4747
48- const char * ffProcessAppendOutput ( FFstrbuf * buffer , char * const argv [], bool useStdErr )
48+ const char * ffProcessSpawn ( char * const argv [], bool useStdErr , FFProcessHandle * outHandle )
4949{
50- int timeout = instance .config .general .processingTimeout ;
50+ const int32_t timeout = instance .config .general .processingTimeout ;
5151
5252 wchar_t pipeName [32 ];
53- swprintf (pipeName , ARRAY_SIZE (pipeName ), L"\\\\.\\pipe\\FASTFETCH-%u" , GetCurrentProcessId ());
53+ static unsigned pidCounter = 0 ;
54+ swprintf (pipeName , ARRAY_SIZE (pipeName ), L"\\\\.\\pipe\\FASTFETCH-%u-%u" , GetCurrentProcessId (), ++ pidCounter );
5455
5556 FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = CreateNamedPipeW (
5657 pipeName ,
@@ -82,52 +83,67 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
8283 return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed" ;
8384
8485 PROCESS_INFORMATION piProcInfo = {};
85-
86- BOOL success ;
87-
86+ STARTUPINFOA siStartInfo = {
87+ .cb = sizeof (siStartInfo ),
88+ .dwFlags = STARTF_USESTDHANDLES ,
89+ };
90+ if (useStdErr )
8891 {
89- STARTUPINFOA siStartInfo = {
90- .cb = sizeof (siStartInfo ),
91- .dwFlags = STARTF_USESTDHANDLES ,
92- };
93- if (useStdErr )
94- {
95- siStartInfo .hStdOutput = ffGetNullFD ();
96- siStartInfo .hStdError = hChildPipeWrite ;
97- }
98- else
99- {
100- siStartInfo .hStdOutput = hChildPipeWrite ;
101- siStartInfo .hStdError = ffGetNullFD ();
102- }
103-
104- FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate ();
105- argvToCmdline (argv , & cmdline );
106-
107- success = CreateProcessA (
108- NULL , // application name
109- cmdline .chars , // command line
110- NULL , // process security attributes
111- NULL , // primary thread security attributes
112- TRUE, // handles are inherited
113- 0 , // creation flags
114- NULL , // use parent's environment
115- NULL , // use parent's current directory
116- & siStartInfo , // STARTUPINFO pointer
117- & piProcInfo // receives PROCESS_INFORMATION
118- );
92+ siStartInfo .hStdOutput = ffGetNullFD ();
93+ siStartInfo .hStdError = hChildPipeWrite ;
94+ }
95+ else
96+ {
97+ siStartInfo .hStdOutput = hChildPipeWrite ;
98+ siStartInfo .hStdError = ffGetNullFD ();
11999 }
120100
101+ FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate ();
102+ argvToCmdline (argv , & cmdline );
103+
104+ BOOL success = CreateProcessA (
105+ NULL , // application name
106+ cmdline .chars , // command line
107+ NULL , // process security attributes
108+ NULL , // primary thread security attributes
109+ TRUE, // handles are inherited
110+ 0 , // creation flags
111+ NULL , // use parent's environment
112+ NULL , // use parent's current directory
113+ & siStartInfo , // STARTUPINFO pointer
114+ & piProcInfo // receives PROCESS_INFORMATION
115+ );
116+
121117 CloseHandle (hChildPipeWrite );
122118 if (!success )
119+ {
120+ if (GetLastError () == ERROR_FILE_NOT_FOUND )
121+ return "command not found" ;
123122 return "CreateProcessA() failed" ;
123+ }
124+
125+ CloseHandle (piProcInfo .hThread ); // we don't need the thread handle
126+ outHandle -> pid = piProcInfo .hProcess ;
127+ outHandle -> pipeRead = hChildPipeRead ;
128+ hChildPipeRead = INVALID_HANDLE_VALUE ; // ownership transferred, don't close it
124129
125- FF_AUTO_CLOSE_FD HANDLE hProcess = piProcInfo .hProcess ;
126- FF_MAYBE_UNUSED FF_AUTO_CLOSE_FD HANDLE hThread = piProcInfo .hThread ;
130+ return NULL ;
131+ }
132+
133+ const char * ffProcessReadOutput (FFProcessHandle * handle , FFstrbuf * buffer )
134+ {
135+ assert (handle -> pipeRead != INVALID_HANDLE_VALUE );
136+ assert (handle -> pid != INVALID_HANDLE_VALUE );
137+
138+ int32_t timeout = instance .config .general .processingTimeout ;
139+ FF_AUTO_CLOSE_FD HANDLE hProcess = handle -> pid ;
140+ FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = handle -> pipeRead ;
141+ handle -> pid = INVALID_HANDLE_VALUE ;
142+ handle -> pipeRead = INVALID_HANDLE_VALUE ;
127143
128144 char str [FF_PIPE_BUFSIZ ];
129145 DWORD nRead = 0 ;
130- OVERLAPPED overlapped = { };
146+ OVERLAPPED overlapped = {};
131147 // ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED
132148 do
133149 {
@@ -164,7 +180,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
164180 break ;
165181
166182 case ERROR_BROKEN_PIPE :
167- return NULL ;
183+ goto exit ;
168184
169185 default :
170186 CancelIo (hChildPipeRead );
@@ -175,6 +191,13 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
175191 ffStrbufAppendNS (buffer , nRead , str );
176192 } while (nRead > 0 );
177193
194+ exit :
195+ {
196+ DWORD exitCode = 0 ;
197+ if (GetExitCodeProcess (hProcess , & exitCode ) && exitCode != STILL_ACTIVE && exitCode != 0 )
198+ return "Child process exited with an error" ;
199+ }
200+
178201 return NULL ;
179202}
180203
0 commit comments