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