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 | |
33 | int __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 | |