1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*============================================================
6**
7** Source: createprocessw/test2/parentprocess.c
8**
9** Purpose: Test the following features of CreateProcessW:
10** - Check to see if hProcess & hThread are set in
11** return PROCESS_INFORMATION structure
12** - Check to see if stdin, stdout, & stderr handles
13** are used when STARTF_USESTDHANDLES is specified
14** in STARUPINFO flags and bInheritHandles = TRUE
15** - Check to see that proper arguments are passed to
16** child process
17**
18** Dependencies: CreatePipe
19** strcpy, strlen, strncmp, memset
20** WaitForSingleObject
21** WriteFile, ReadFile
22** GetExitCodeProcess
23**
24
25**
26**=========================================================*/
27
28#define UNICODE
29#include <palsuite.h>
30#include "test2.h"
31
32
33
34int __cdecl main( int argc, char **argv )
35{
36
37 /*******************************************
38 * Declarations
39 *******************************************/
40 STARTUPINFO si;
41 PROCESS_INFORMATION pi;
42
43 HANDLE hTestStdInR = NULL;
44 HANDLE hTestStdInW = NULL;
45 HANDLE hTestStdOutR = NULL;
46 HANDLE hTestStdOutW = NULL;
47 HANDLE hTestStdErrR = NULL;
48 HANDLE hTestStdErrW = NULL;
49
50 BOOL bRetVal = FALSE;
51 DWORD dwBytesWritten = 0;
52 DWORD dwBytesRead = 0;
53 DWORD dwExitCode = 0;
54
55 SECURITY_ATTRIBUTES pipeAttributes;
56
57 char szStdOutBuf[BUF_LEN];
58 char szStdErrBuf[BUF_LEN];
59 WCHAR szFullPathNameW[_MAX_PATH];
60
61
62 /*******************************************
63 * Initialization
64 *******************************************/
65
66 if(0 != (PAL_Initialize(argc, argv)))
67 {
68 return ( FAIL );
69 }
70
71 /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
72 pipeAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
73 pipeAttributes.lpSecurityDescriptor = NULL;
74 pipeAttributes.bInheritHandle = TRUE;
75
76
77 /*Create a StdIn pipe for child*/
78 bRetVal = CreatePipe(&hTestStdInR, /* read handle*/
79 &hTestStdInW, /* write handle */
80 &pipeAttributes, /* security attributes*/
81 1024); /* pipe size*/
82
83 if (bRetVal == FALSE)
84 {
85 Fail("ERROR: %ld :Unable to create stdin pipe\n", GetLastError());
86 }
87
88
89 /*Create a StdOut pipe for child*/
90 bRetVal = CreatePipe(&hTestStdOutR, /* read handle*/
91 &hTestStdOutW, /* write handle */
92 &pipeAttributes, /* security attributes*/
93 0); /* pipe size*/
94
95 if (bRetVal == FALSE)
96 {
97 Fail("ERROR: %ld :Unable to create stdout pipe\n", GetLastError());
98 }
99
100
101 /*Create a StdErr pipe for child*/
102 bRetVal = CreatePipe(&hTestStdErrR, /* read handle*/
103 &hTestStdErrW, /* write handle */
104 &pipeAttributes, /* security attributes*/
105 0); /* pipe size*/
106
107 if (bRetVal == FALSE)
108 {
109 Fail("ERROR: %ld :Unable to create stderr pipe\n", GetLastError());
110 }
111
112 /* Zero the data structure space */
113 ZeroMemory ( &pi, sizeof(pi) );
114 ZeroMemory ( &si, sizeof(si) );
115
116 /* Set the process flags and standard io handles */
117 si.cb = sizeof(si);
118 si.dwFlags = STARTF_USESTDHANDLES;
119 si.hStdInput = hTestStdInR;
120 si.hStdOutput = hTestStdOutW;
121 si.hStdError = hTestStdErrW;
122
123 wcscpy(szFullPathNameW, szChildFileW);
124 wcscat(szFullPathNameW, szArgs);
125
126 /*******************************************
127 * Start Testing
128 *******************************************/
129
130 /* Launch the child */
131 if ( !CreateProcess (NULL, szFullPathNameW, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
132 {
133 Fail("ERROR: CreateProcess call failed. GetLastError returned %d\n",
134 GetLastError() );
135 }
136
137 /* Check the returned process information for validity */
138 if (pi.hProcess == 0 || pi.hThread == 0)
139 {
140 Fail("ERROR: CreateProcess Error: Process Handle = %u, Thread Handle = %u\n",
141 pi.hProcess, pi.hThread);
142 }
143
144
145 /* Write the Constructed string to stdin pipe for the child process */
146 if (WriteFile(hTestStdInW, szTestString, strlen(szTestString), &dwBytesWritten, NULL) == FALSE
147 || WriteFile(hTestStdInW, "\n", strlen("\n"), &dwBytesWritten, NULL) == FALSE)
148 {
149 Fail("ERROR: %ld :unable to write to write pipe handle "
150 "hTestStdInW=0x%lx\n", GetLastError(), hTestStdInW);
151 }
152
153 /* Wait for the child to finish, Max 20 seconds */
154 dwExitCode = WaitForSingleObject(pi.hProcess, 20000);
155
156 /* If the child failed then whole thing fails */
157 if (dwExitCode != WAIT_OBJECT_0)
158 {
159 TerminateProcess(pi.hProcess, 0);
160 Fail("ERROR: The child failed to run properly.\n");
161 }
162
163 /* Check for problems in the child process */
164 if (GetExitCodeProcess(pi.hProcess, &dwExitCode) == FALSE)
165 {
166 Fail("ERROR: Call to GetExitCodeProcess failed.\n");
167 }
168 else if (dwExitCode == EXIT_ERR_CODE1)
169 {
170 Fail("ERROR: The Child process could not reead the string "
171 "written to the stdin pipe.\n");
172 }
173 else if (dwExitCode == EXIT_ERR_CODE2)
174 {
175 Fail("ERROR: The Child process could not write the string "
176 "the stdout pipe or stderr pipe.\n");
177 }
178 else if (dwExitCode == EXIT_ERR_CODE3)
179 {
180 Fail("ERROR: The Child received the wrong number of "
181 "command line arguments.\n");
182 }
183 else if (dwExitCode == EXIT_ERR_CODE4)
184 {
185 Fail("ERROR: The Child received the wrong "
186 "command line arguments.\n");
187 }
188 else if (dwExitCode != EXIT_OK_CODE)
189 {
190 Fail("ERROR: Unexpected exit code returned: %u. Child process "
191 "did not complete its part of the test.\n", dwExitCode);
192 }
193
194
195 /* The child ran ok, so check to see if we received the proper */
196 /* strings through the pipes. */
197
198 /* clear our buffers */
199 memset(szStdOutBuf, 0, BUF_LEN);
200 memset(szStdErrBuf, 0, BUF_LEN);
201
202 /* Read the data back from the child process stdout */
203 bRetVal = ReadFile(hTestStdOutR, /* handle to read pipe*/
204 szStdOutBuf, /* buffer to write to*/
205 BUF_LEN, /* number of bytes to read*/
206 &dwBytesRead, /* number of bytes read*/
207 NULL); /* overlapped buffer*/
208
209 /*Read the data back from the child process stderr */
210 bRetVal = ReadFile(hTestStdErrR, /* handle to read pipe*/
211 szStdErrBuf, /* buffer to write to*/
212 BUF_LEN, /* number of bytes to read*/
213 &dwBytesRead, /* number of bytes read*/
214 NULL); /* overlapped buffer*/
215
216
217 /* Confirm that we recieved the same string that we originally */
218 /* wrote to the child and was received on both stdout & stderr.*/
219 if (strncmp(szTestString, szStdOutBuf, strlen(szTestString)) != 0
220 || strncmp(szTestString, szStdErrBuf, strlen(szTestString)) != 0)
221 {
222 Fail("ERROR: The data read back from child does not match "
223 "what was written. STDOUT: %s STDERR: %s\n",
224 szStdOutBuf, szStdErrBuf);
225 }
226
227
228 /*******************************************
229 * Clean Up
230 *******************************************/
231
232 /* Close process and thread handle */
233 CloseHandle ( pi.hProcess );
234 CloseHandle ( pi.hThread );
235
236 CloseHandle(hTestStdInR);
237 CloseHandle(hTestStdInW);
238 CloseHandle(hTestStdOutR);
239 CloseHandle(hTestStdOutW);
240 CloseHandle(hTestStdErrR);
241 CloseHandle(hTestStdErrW);
242
243 PAL_Terminate();
244 return ( PASS );
245}
246