xref: /AOO41X/main/desktop/win32/source/guistdio/guistdio.inc (revision e3a7b91b49e4d9ec2856213648b0df1853a72db8)
1707d5dc6SAndrew Rist/**************************************************************
2cdf0e10cSrcweir *
3707d5dc6SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4707d5dc6SAndrew Rist * or more contributor license agreements.  See the NOTICE file
5707d5dc6SAndrew Rist * distributed with this work for additional information
6707d5dc6SAndrew Rist * regarding copyright ownership.  The ASF licenses this file
7707d5dc6SAndrew Rist * to you under the Apache License, Version 2.0 (the
8707d5dc6SAndrew Rist * "License"); you may not use this file except in compliance
9707d5dc6SAndrew Rist * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir *
11707d5dc6SAndrew Rist *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir *
13707d5dc6SAndrew Rist * Unless required by applicable law or agreed to in writing,
14707d5dc6SAndrew Rist * software distributed under the License is distributed on an
15707d5dc6SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16707d5dc6SAndrew Rist * KIND, either express or implied.  See the License for the
17707d5dc6SAndrew Rist * specific language governing permissions and limitations
18707d5dc6SAndrew Rist * under the License.
19cdf0e10cSrcweir *
20707d5dc6SAndrew Rist *************************************************************/
21707d5dc6SAndrew Rist
22707d5dc6SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir#define UNICODE
25cdf0e10cSrcweir#define WIN32_LEAN_AND_MEAN
26cdf0e10cSrcweir#ifdef _MSC_VER
27cdf0e10cSrcweir#pragma warning(push,1) // disable warnings within system headers
28cdf0e10cSrcweir#endif
29cdf0e10cSrcweir#include <windows.h>
30cdf0e10cSrcweir#ifdef _MSC_VER
31cdf0e10cSrcweir#pragma warning(pop)
32cdf0e10cSrcweir#endif
33cdf0e10cSrcweir
34cdf0e10cSrcweir#define _UNICODE
35cdf0e10cSrcweir#include <tchar.h>
36cdf0e10cSrcweir
37cdf0e10cSrcweir#include <string.h>
38cdf0e10cSrcweir#include <stdlib.h>
39cdf0e10cSrcweir#include <systools/win32/uwinapi.h>
40cdf0e10cSrcweir
41cdf0e10cSrcweir#include <stdio.h>
42cdf0e10cSrcweir
43cdf0e10cSrcweir#ifdef UNOPKG
44cdf0e10cSrcweir
45cdf0e10cSrcweirDWORD passOutputToConsole(HANDLE readPipe, HANDLE console)
46cdf0e10cSrcweir{
47cdf0e10cSrcweir	BYTE aBuffer[1024];
48cdf0e10cSrcweir	DWORD dwRead = 0;
49cdf0e10cSrcweir	HANDLE hReadPipe = readPipe;
50cdf0e10cSrcweir	BOOL fSuccess;
51cdf0e10cSrcweir	DWORD dwWritten;
52cdf0e10cSrcweir
53cdf0e10cSrcweir	//Indicates that we read an odd number of bytes. That is, we only read half of the last
54cdf0e10cSrcweir	//wchar_t
55cdf0e10cSrcweir	bool bIncompleteWchar = false;
56cdf0e10cSrcweir	//fprintf, fwprintf will both send char data without the terminating zero.
57cdf0e10cSrcweir	//fwprintf converts the unicode string first.
58cdf0e10cSrcweir	//We expect here to receive unicode without the terminating zero.
59cdf0e10cSrcweir	//unopkg and the extension manager code MUST
60cdf0e10cSrcweir	//use dp_misc::writeConsole instead of using fprintf, etc.
61cdf0e10cSrcweir
62cdf0e10cSrcweir	DWORD dwToRead = sizeof(aBuffer);
63cdf0e10cSrcweir	BYTE * pBuffer = aBuffer;
64cdf0e10cSrcweir	while ( ReadFile( hReadPipe, pBuffer, dwToRead, &dwRead, NULL ) )
65cdf0e10cSrcweir	{
66cdf0e10cSrcweir		//If the previous ReadFile call read an odd number of bytes, then the last one was
67cdf0e10cSrcweir		//put at the front of the buffer. We increase the number of read bytes by one to reflect
68cdf0e10cSrcweir		//that one byte.
69cdf0e10cSrcweir		if (bIncompleteWchar)
70cdf0e10cSrcweir			dwRead++;
71*e3a7b91bSmseidel		//We must make sure that only complete wchar_t|s are written. WriteConsole takes
72cdf0e10cSrcweir		//the number of wchar_t|s as argument. ReadFile, however, reads bytes.
73cdf0e10cSrcweir		bIncompleteWchar = dwRead % 2 ? true : false;
74cdf0e10cSrcweir		if (bIncompleteWchar)
75cdf0e10cSrcweir		{
76cdf0e10cSrcweir			//To test this case, give aBuffer a small odd size, e.g. aBuffer[3]
77cdf0e10cSrcweir			//The last byte, which is the incomplete wchar_t (half of it), will not be written.
78cdf0e10cSrcweir			fSuccess = WriteConsoleW( console, aBuffer,
79cdf0e10cSrcweir				(dwRead - 1) / 2, &dwWritten, NULL );
80cdf0e10cSrcweir
81cdf0e10cSrcweir			//Move the last byte to the front of the buffer, so that it is the start of the
82cdf0e10cSrcweir			//next string
83cdf0e10cSrcweir			aBuffer[0] = aBuffer[dwRead - 1];
84cdf0e10cSrcweir
85cdf0e10cSrcweir			//Make sure that ReadFile does not overwrite the first byte the next time
86cdf0e10cSrcweir			dwToRead = sizeof(aBuffer) - 1;
87cdf0e10cSrcweir			pBuffer = aBuffer + 1;
88cdf0e10cSrcweir
89cdf0e10cSrcweir		}
90cdf0e10cSrcweir		else
91cdf0e10cSrcweir		{	//We have read an even number of bytes. Therefore, we do not put the last incomplete
92cdf0e10cSrcweir			//wchar_t at the front of the buffer. We will use the complete buffer the next time
93cdf0e10cSrcweir			//when ReadFile is called.
94cdf0e10cSrcweir			dwToRead = sizeof(aBuffer);
95cdf0e10cSrcweir			pBuffer = aBuffer;
96cdf0e10cSrcweir			fSuccess = WriteConsoleW( console,
97cdf0e10cSrcweir				aBuffer, dwRead / 2, &dwWritten, NULL );
98cdf0e10cSrcweir		}
99cdf0e10cSrcweir	}
100cdf0e10cSrcweir
101cdf0e10cSrcweir	return 0;
102cdf0e10cSrcweir}
103cdf0e10cSrcweir
104cdf0e10cSrcweir#endif
105cdf0e10cSrcweir
106cdf0e10cSrcweir#ifdef UNOPKG
107cdf0e10cSrcweirDWORD WINAPI OutputThread( LPVOID pParam )
108cdf0e10cSrcweir{
109cdf0e10cSrcweir	return passOutputToConsole((HANDLE)pParam, GetStdHandle( STD_OUTPUT_HANDLE ));
110cdf0e10cSrcweir}
111cdf0e10cSrcweir
112cdf0e10cSrcweir#else
113cdf0e10cSrcweirDWORD WINAPI OutputThread( LPVOID pParam )
114cdf0e10cSrcweir{
115cdf0e10cSrcweir	BYTE	aBuffer[256];
116cdf0e10cSrcweir	DWORD	dwRead = 0;
117cdf0e10cSrcweir	HANDLE	hReadPipe = (HANDLE)pParam;
118cdf0e10cSrcweir	while ( ReadFile( hReadPipe, &aBuffer, sizeof(aBuffer), &dwRead, NULL ) )
119cdf0e10cSrcweir	{
120cdf0e10cSrcweir		BOOL	fSuccess;
121cdf0e10cSrcweir		DWORD	dwWritten;
122cdf0e10cSrcweir
123cdf0e10cSrcweir		fSuccess = WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), aBuffer, dwRead, &dwWritten, NULL );
124cdf0e10cSrcweir	}
125cdf0e10cSrcweir
126cdf0e10cSrcweir	return 0;
127cdf0e10cSrcweir}
128cdf0e10cSrcweir#endif
129cdf0e10cSrcweir//---------------------------------------------------------------------------
130cdf0e10cSrcweir// Thread that reads from child process standard error pipe
131cdf0e10cSrcweir//---------------------------------------------------------------------------
132cdf0e10cSrcweir
133cdf0e10cSrcweir#ifdef UNOPKG
134cdf0e10cSrcweirDWORD WINAPI ErrorThread( LPVOID pParam )
135cdf0e10cSrcweir{
136cdf0e10cSrcweir	return passOutputToConsole((HANDLE)pParam, GetStdHandle( STD_ERROR_HANDLE ));
137cdf0e10cSrcweir}
138cdf0e10cSrcweir
139cdf0e10cSrcweir#else
140cdf0e10cSrcweirDWORD WINAPI ErrorThread( LPVOID pParam )
141cdf0e10cSrcweir{
142cdf0e10cSrcweir	BYTE	aBuffer[256];
143cdf0e10cSrcweir	DWORD	dwRead = 0;
144cdf0e10cSrcweir	HANDLE	hReadPipe = (HANDLE)pParam;
145cdf0e10cSrcweir
146cdf0e10cSrcweir	while ( ReadFile( hReadPipe, &aBuffer, sizeof(aBuffer), &dwRead, NULL ) )
147cdf0e10cSrcweir	{
148cdf0e10cSrcweir		BOOL	fSuccess;
149cdf0e10cSrcweir		DWORD	dwWritten;
150cdf0e10cSrcweir
151cdf0e10cSrcweir		fSuccess = WriteFile( GetStdHandle( STD_ERROR_HANDLE ), aBuffer, dwRead, &dwWritten, NULL );
152cdf0e10cSrcweir	}
153cdf0e10cSrcweir
154cdf0e10cSrcweir	return 0;
155cdf0e10cSrcweir}
156cdf0e10cSrcweir#endif
157cdf0e10cSrcweir//---------------------------------------------------------------------------
158cdf0e10cSrcweir// Thread that writes to child process standard input pipe
159cdf0e10cSrcweir//---------------------------------------------------------------------------
160cdf0e10cSrcweir#ifdef UNOPKG
161cdf0e10cSrcweir
162cdf0e10cSrcweirDWORD WINAPI InputThread( LPVOID pParam )
163cdf0e10cSrcweir{
164cdf0e10cSrcweir	DWORD	dwRead = 0;
165cdf0e10cSrcweir	HANDLE	hWritePipe = (HANDLE)pParam;
166cdf0e10cSrcweir
167cdf0e10cSrcweir    //We need to read in the complete input until we encounter a new line before
168cdf0e10cSrcweir    //converting to Unicode. This is necessary because the input string can use
169cdf0e10cSrcweir    //characters of one, two, and more bytes. If the last character is not
170cdf0e10cSrcweir    //complete, then it will not be converted properly.
171cdf0e10cSrcweir
172cdf0e10cSrcweir    //Find out how a new line (0xd 0xa) looks like with the used code page.
173cdf0e10cSrcweir    //Characters may have one or multiple bytes and different byte ordering
174cdf0e10cSrcweir    //can be used (little and big endian);
175cdf0e10cSrcweir    int cNewLine = WideCharToMultiByte(
176cdf0e10cSrcweir        GetConsoleCP(), 0, L"\r\n", 2, NULL, 0, NULL, NULL);
177cdf0e10cSrcweir    char * mbBuff = new char[cNewLine];
178cdf0e10cSrcweir    WideCharToMultiByte(
179cdf0e10cSrcweir        GetConsoleCP(), 0, L"\r\n", 2, mbBuff, cNewLine, NULL, NULL);
180cdf0e10cSrcweir
181cdf0e10cSrcweir    const size_t dwBufferSize = 256;
182cdf0e10cSrcweir    char* readBuf = (char*) malloc(dwBufferSize);
183cdf0e10cSrcweir    int readAll = 0;
184cdf0e10cSrcweir    size_t curBufSize = dwBufferSize;
185cdf0e10cSrcweir
186cdf0e10cSrcweir    while ( ReadFile( GetStdHandle( STD_INPUT_HANDLE ),
187cdf0e10cSrcweir                      readBuf + readAll,
188cdf0e10cSrcweir                      curBufSize - readAll, &dwRead, NULL ) )
189cdf0e10cSrcweir	{
190cdf0e10cSrcweir        readAll += dwRead;
191cdf0e10cSrcweir        int lastBufSize = curBufSize;
192cdf0e10cSrcweir        //Grow the buffer if necessary
193cdf0e10cSrcweir        if (readAll > curBufSize * 0.7)
194cdf0e10cSrcweir        {
195cdf0e10cSrcweir            curBufSize *= 2;
196cdf0e10cSrcweir            readBuf = (char *) realloc(readBuf, curBufSize);
197cdf0e10cSrcweir        }
198cdf0e10cSrcweir
199cdf0e10cSrcweir        //If the buffer was filled completely then
200cdf0e10cSrcweir        //there could be more input coming. But if we read from the console
201cdf0e10cSrcweir        //and the console input fits exactly in the buffer, then the next
202*e3a7b91bSmseidel        //ReadFile would block until the user presses return, etc.
203cdf0e10cSrcweir        //Therefor we check if last character is a new line.
204cdf0e10cSrcweir        //To test this, set dwBufferSize to 4 and enter "no". This should produce
205cdf0e10cSrcweir        //4 bytes with most code pages.
206cdf0e10cSrcweir        if ( readAll == lastBufSize
207cdf0e10cSrcweir             && memcmp(readBuf + lastBufSize - cNewLine, mbBuff, cNewLine) != 0)
208cdf0e10cSrcweir        {
209cdf0e10cSrcweir            //The buffer was completely filled and the last byte(s) are no
210cdf0e10cSrcweir            //new line, so there is more to come.
211cdf0e10cSrcweir            continue;
212cdf0e10cSrcweir        }
213cdf0e10cSrcweir        //Obtain the size of the buffer for the converted string.
214cdf0e10cSrcweir        int sizeWBuf = MultiByteToWideChar(
215cdf0e10cSrcweir            GetConsoleCP(), MB_PRECOMPOSED, readBuf, readAll, NULL, 0);
216cdf0e10cSrcweir
217cdf0e10cSrcweir        wchar_t * wideBuf = new wchar_t[sizeWBuf];
218cdf0e10cSrcweir
219cdf0e10cSrcweir        //Do the conversion.
220cdf0e10cSrcweir        MultiByteToWideChar(
221cdf0e10cSrcweir            GetConsoleCP(), MB_PRECOMPOSED, readBuf, readAll, wideBuf, sizeWBuf);
222cdf0e10cSrcweir
223cdf0e10cSrcweir        BOOL	fSuccess;
224cdf0e10cSrcweir		DWORD	dwWritten;
225cdf0e10cSrcweir        fSuccess = WriteFile( hWritePipe, wideBuf, sizeWBuf * 2, &dwWritten, NULL );
226cdf0e10cSrcweir        delete[] wideBuf;
227cdf0e10cSrcweir        readAll = 0;
228cdf0e10cSrcweir	}
229cdf0e10cSrcweir    delete[] mbBuff;
230cdf0e10cSrcweir    free(readBuf);
231cdf0e10cSrcweir	return 0;
232cdf0e10cSrcweir}
233cdf0e10cSrcweir#else
234cdf0e10cSrcweirDWORD WINAPI InputThread( LPVOID pParam )
235cdf0e10cSrcweir{
236cdf0e10cSrcweir	BYTE	aBuffer[256];
237cdf0e10cSrcweir	DWORD	dwRead = 0;
238cdf0e10cSrcweir	HANDLE	hWritePipe = (HANDLE)pParam;
239cdf0e10cSrcweir
240cdf0e10cSrcweir	while ( ReadFile( GetStdHandle( STD_INPUT_HANDLE ), &aBuffer, sizeof(aBuffer), &dwRead, NULL ) )
241cdf0e10cSrcweir	{
242cdf0e10cSrcweir		BOOL	fSuccess;
243cdf0e10cSrcweir		DWORD	dwWritten;
244cdf0e10cSrcweir
245cdf0e10cSrcweir		fSuccess = WriteFile( hWritePipe, aBuffer, dwRead, &dwWritten, NULL );
246cdf0e10cSrcweir	}
247cdf0e10cSrcweir
248cdf0e10cSrcweir	return 0;
249cdf0e10cSrcweir}
250cdf0e10cSrcweir#endif
251cdf0e10cSrcweir
252cdf0e10cSrcweir//---------------------------------------------------------------------------
253cdf0e10cSrcweir// Thread that waits until child process reached input idle
254cdf0e10cSrcweir//---------------------------------------------------------------------------
255cdf0e10cSrcweir
256cdf0e10cSrcweirDWORD WINAPI WaitForUIThread( LPVOID pParam )
257cdf0e10cSrcweir{
258cdf0e10cSrcweir	HANDLE	hProcess = (HANDLE)pParam;
259cdf0e10cSrcweir
260cdf0e10cSrcweir#ifndef UNOPKG
261cdf0e10cSrcweir	if ( !_tgetenv( TEXT("UNOPKG") ) )
262cdf0e10cSrcweir		WaitForInputIdle( hProcess, INFINITE );
263cdf0e10cSrcweir#endif
264cdf0e10cSrcweir
265cdf0e10cSrcweir	return 0;
266cdf0e10cSrcweir}
267cdf0e10cSrcweir
268cdf0e10cSrcweir
269cdf0e10cSrcweir//---------------------------------------------------------------------------
270cdf0e10cSrcweir// Ctrl-Break handler that terminates the child process if Ctrl-C was pressed
271cdf0e10cSrcweir//---------------------------------------------------------------------------
272cdf0e10cSrcweir
273cdf0e10cSrcweirHANDLE	hTargetProcess = INVALID_HANDLE_VALUE;
274cdf0e10cSrcweir
275cdf0e10cSrcweirBOOL WINAPI CtrlBreakHandler(
276cdf0e10cSrcweir  DWORD   // control signal type
277cdf0e10cSrcweir)
278cdf0e10cSrcweir{
279cdf0e10cSrcweir	TerminateProcess( hTargetProcess, 255 );
280cdf0e10cSrcweir	return TRUE;
281cdf0e10cSrcweir}
282cdf0e10cSrcweir
283cdf0e10cSrcweir
284cdf0e10cSrcweir//---------------------------------------------------------------------------
285cdf0e10cSrcweir
286cdf0e10cSrcweir//---------------------------------------------------------------------------
287cdf0e10cSrcweir
288cdf0e10cSrcweir#ifdef __MINGW32__
289cdf0e10cSrcweirint main( int, char ** )
290cdf0e10cSrcweir#else
291cdf0e10cSrcweirint _tmain( int, _TCHAR ** )
292cdf0e10cSrcweir#endif
293cdf0e10cSrcweir{
294cdf0e10cSrcweir	TCHAR				szTargetFileName[MAX_PATH] = TEXT("");
295cdf0e10cSrcweir	STARTUPINFO			aStartupInfo;
296cdf0e10cSrcweir	PROCESS_INFORMATION	aProcessInfo;
297cdf0e10cSrcweir
298cdf0e10cSrcweir	ZeroMemory( &aStartupInfo, sizeof(aStartupInfo) );
299cdf0e10cSrcweir	aStartupInfo.cb = sizeof(aStartupInfo);
300cdf0e10cSrcweir	aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
301cdf0e10cSrcweir
302cdf0e10cSrcweir	// Create an output pipe where the write end is inheritable
303cdf0e10cSrcweir
304cdf0e10cSrcweir	HANDLE	hOutputRead, hOutputWrite;
305cdf0e10cSrcweir
306cdf0e10cSrcweir	if ( CreatePipe( &hOutputRead, &hOutputWrite, NULL, 0 ) )
307cdf0e10cSrcweir	{
308cdf0e10cSrcweir		HANDLE	hTemp;
309cdf0e10cSrcweir
310cdf0e10cSrcweir		DuplicateHandle( GetCurrentProcess(), hOutputWrite, GetCurrentProcess(), &hTemp, 0, TRUE, DUPLICATE_SAME_ACCESS );
311cdf0e10cSrcweir		CloseHandle( hOutputWrite );
312cdf0e10cSrcweir		hOutputWrite = hTemp;
313cdf0e10cSrcweir
314cdf0e10cSrcweir		aStartupInfo.hStdOutput = hOutputWrite;
315cdf0e10cSrcweir	}
316cdf0e10cSrcweir
317cdf0e10cSrcweir	// Create an error pipe where the write end is inheritable
318cdf0e10cSrcweir
319cdf0e10cSrcweir	HANDLE	hErrorRead, hErrorWrite;
320cdf0e10cSrcweir
321cdf0e10cSrcweir	if ( CreatePipe( &hErrorRead, &hErrorWrite, NULL, 0 ) )
322cdf0e10cSrcweir	{
323cdf0e10cSrcweir		HANDLE	hTemp;
324cdf0e10cSrcweir
325cdf0e10cSrcweir		DuplicateHandle( GetCurrentProcess(), hErrorWrite, GetCurrentProcess(), &hTemp, 0, TRUE, DUPLICATE_SAME_ACCESS );
326cdf0e10cSrcweir		CloseHandle( hErrorWrite );
327cdf0e10cSrcweir		hErrorWrite = hTemp;
328cdf0e10cSrcweir
329cdf0e10cSrcweir		aStartupInfo.hStdError = hErrorWrite;
330cdf0e10cSrcweir	}
331cdf0e10cSrcweir
332cdf0e10cSrcweir	// Create an input pipe where the read end is inheritable
333cdf0e10cSrcweir
334cdf0e10cSrcweir	HANDLE	hInputRead, hInputWrite;
335cdf0e10cSrcweir
336cdf0e10cSrcweir	if ( CreatePipe( &hInputRead, &hInputWrite, NULL, 0 ) )
337cdf0e10cSrcweir	{
338cdf0e10cSrcweir		HANDLE	hTemp;
339cdf0e10cSrcweir
340cdf0e10cSrcweir		DuplicateHandle( GetCurrentProcess(), hInputRead, GetCurrentProcess(), &hTemp, 0, TRUE, DUPLICATE_SAME_ACCESS );
341cdf0e10cSrcweir		CloseHandle( hInputRead );
342cdf0e10cSrcweir		hInputRead = hTemp;
343cdf0e10cSrcweir
344cdf0e10cSrcweir		aStartupInfo.hStdInput = hInputRead;
345cdf0e10cSrcweir	}
346cdf0e10cSrcweir
347cdf0e10cSrcweir	// Get image path with same name but with .exe extension
348cdf0e10cSrcweir
349cdf0e10cSrcweir	TCHAR				szModuleFileName[MAX_PATH];
350cdf0e10cSrcweir
351cdf0e10cSrcweir	GetModuleFileName( NULL, szModuleFileName, MAX_PATH );
352cdf0e10cSrcweir	_TCHAR	*lpLastDot = _tcsrchr( szModuleFileName, '.' );
353cdf0e10cSrcweir	if ( lpLastDot && 0 == _tcsicmp( lpLastDot, _T(".COM") ) )
354cdf0e10cSrcweir	{
355cdf0e10cSrcweir		size_t len = lpLastDot - szModuleFileName;
356cdf0e10cSrcweir		_tcsncpy( szTargetFileName, szModuleFileName, len );
357cdf0e10cSrcweir		_tcsncpy( szTargetFileName + len, _T(".EXE"), sizeof(szTargetFileName)/sizeof(szTargetFileName[0]) - len );
358cdf0e10cSrcweir	}
359cdf0e10cSrcweir
360cdf0e10cSrcweir	// Create process with same command line, environment and stdio handles which
361cdf0e10cSrcweir	// are directed to the created pipes
362cdf0e10cSrcweir
363cdf0e10cSrcweir	BOOL	fSuccess = CreateProcess(
364cdf0e10cSrcweir		szTargetFileName,
365cdf0e10cSrcweir		GetCommandLine(),
366cdf0e10cSrcweir		NULL,
367cdf0e10cSrcweir		NULL,
368cdf0e10cSrcweir		TRUE,
369cdf0e10cSrcweir		0,
370cdf0e10cSrcweir		NULL,
371cdf0e10cSrcweir		NULL,
372cdf0e10cSrcweir		&aStartupInfo,
373cdf0e10cSrcweir		&aProcessInfo );
374cdf0e10cSrcweir
375cdf0e10cSrcweir	if ( fSuccess )
376cdf0e10cSrcweir	{
377cdf0e10cSrcweir		// These pipe ends are inherited by the child process and no longer used
378cdf0e10cSrcweir		CloseHandle( hOutputWrite );
379cdf0e10cSrcweir		CloseHandle( hErrorWrite );
380cdf0e10cSrcweir		CloseHandle( hInputRead );
381cdf0e10cSrcweir
382cdf0e10cSrcweir		// Set the Ctrl-Break handler
383cdf0e10cSrcweir		hTargetProcess = aProcessInfo.hProcess;
384cdf0e10cSrcweir		SetConsoleCtrlHandler( CtrlBreakHandler, TRUE );
385cdf0e10cSrcweir
386cdf0e10cSrcweir		// Create threads that redirect remote pipe io to current process's console stdio
387cdf0e10cSrcweir
388cdf0e10cSrcweir		DWORD	dwOutputThreadId, dwErrorThreadId, dwInputThreadId;
389cdf0e10cSrcweir
390cdf0e10cSrcweir		HANDLE	hOutputThread = CreateThread( NULL, 0, OutputThread, (LPVOID)hOutputRead, 0, &dwOutputThreadId );
391cdf0e10cSrcweir		HANDLE	hErrorThread = CreateThread( NULL, 0, OutputThread, (LPVOID)hErrorRead, 0, &dwErrorThreadId );
392cdf0e10cSrcweir		HANDLE	hInputThread = CreateThread( NULL, 0, InputThread, (LPVOID)hInputWrite, 0, &dwInputThreadId );
393cdf0e10cSrcweir
394cdf0e10cSrcweir		// Create thread that wait until child process entered input idle
395cdf0e10cSrcweir
396cdf0e10cSrcweir		DWORD	dwWaitForUIThreadId;
397cdf0e10cSrcweir		HANDLE	hWaitForUIThread = CreateThread( NULL, 0, WaitForUIThread, (LPVOID)aProcessInfo.hProcess, 0, &dwWaitForUIThreadId );
398cdf0e10cSrcweir
399cdf0e10cSrcweir		DWORD	dwWaitResult;
400cdf0e10cSrcweir		HANDLE	hObjects[] =
401cdf0e10cSrcweir			{
402cdf0e10cSrcweir				hTargetProcess,
403cdf0e10cSrcweir				hWaitForUIThread,
404cdf0e10cSrcweir				hOutputThread,
405cdf0e10cSrcweir				hErrorThread
406cdf0e10cSrcweir			};
407cdf0e10cSrcweir
408cdf0e10cSrcweir #ifdef UNOPKG
409cdf0e10cSrcweir		dwWaitResult = WaitForMultipleObjects( elementsof(hObjects), hObjects, TRUE, INFINITE );
410cdf0e10cSrcweir #else
411cdf0e10cSrcweir		bool	bDetach = false;
412cdf0e10cSrcweir		int		nOpenPipes = 2;
413cdf0e10cSrcweir		do
414cdf0e10cSrcweir		{
415cdf0e10cSrcweir			dwWaitResult = WaitForMultipleObjects( elementsof(hObjects), hObjects, FALSE, INFINITE );
416cdf0e10cSrcweir
417cdf0e10cSrcweir			switch ( dwWaitResult )
418cdf0e10cSrcweir			{
419cdf0e10cSrcweir			case WAIT_OBJECT_0:	// The child process has terminated
420cdf0e10cSrcweir			case WAIT_OBJECT_0 + 1: // The child process entered input idle
421cdf0e10cSrcweir				bDetach = true;
422cdf0e10cSrcweir				break;
423cdf0e10cSrcweir			case WAIT_OBJECT_0 + 2: // The remote end of stdout pipe was closed
424cdf0e10cSrcweir			case WAIT_OBJECT_0 + 3: // The remote end of stderr pipe was closed
425cdf0e10cSrcweir				bDetach = --nOpenPipes <= 0;
426cdf0e10cSrcweir				break;
427cdf0e10cSrcweir			default: // Something went wrong
428cdf0e10cSrcweir				bDetach = true;
429cdf0e10cSrcweir				break;
430cdf0e10cSrcweir			}
431cdf0e10cSrcweir		} while( !bDetach );
432cdf0e10cSrcweir
433cdf0e10cSrcweir#endif
434cdf0e10cSrcweir
435cdf0e10cSrcweir		CloseHandle( hOutputThread );
436cdf0e10cSrcweir		CloseHandle( hErrorThread );
437cdf0e10cSrcweir		CloseHandle( hInputThread );
438cdf0e10cSrcweir		CloseHandle( hWaitForUIThread );
439cdf0e10cSrcweir
440cdf0e10cSrcweir		DWORD	dwExitCode = 0;
441cdf0e10cSrcweir		GetExitCodeProcess( aProcessInfo.hProcess, &dwExitCode );
442cdf0e10cSrcweir		CloseHandle( aProcessInfo.hProcess );
443cdf0e10cSrcweir		CloseHandle( aProcessInfo.hThread );
444cdf0e10cSrcweir
445cdf0e10cSrcweir		return dwExitCode;
446cdf0e10cSrcweir	}
447cdf0e10cSrcweir
448cdf0e10cSrcweir	return -1;
449cdf0e10cSrcweir}
450