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