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: test1.c |
8 | ** |
9 | ** Purpose: Test to ensure OpenProcess works properly. |
10 | ** |
11 | ** Dependencies: PAL_Initialize |
12 | ** PAL_Terminate |
13 | ** Fail |
14 | ** ZeroMemory |
15 | ** GetCurrentDirectoryW |
16 | ** CreateProcessW |
17 | ** WaitForSingleObject |
18 | ** CreateMutexW |
19 | ** ReleaseMutex |
20 | ** CloseHandle |
21 | ** GetLastError |
22 | ** strlen |
23 | ** strncpy |
24 | ** |
25 | ** |
26 | **===========================================================================*/ |
27 | #include <palsuite.h> |
28 | #include "myexitcode.h" |
29 | |
30 | |
31 | static const char* rgchPathDelim = "\\" ; |
32 | |
33 | |
34 | int |
35 | mkAbsoluteFilename( LPSTR dirName, |
36 | DWORD dwDirLength, |
37 | LPCSTR fileName, |
38 | DWORD dwFileLength, |
39 | LPSTR absPathName ) |
40 | { |
41 | DWORD sizeDN, sizeFN, sizeAPN; |
42 | |
43 | sizeDN = strlen( dirName ); |
44 | sizeFN = strlen( fileName ); |
45 | sizeAPN = (sizeDN + 1 + sizeFN + 1); |
46 | |
47 | /* ensure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */ |
48 | if( sizeAPN > _MAX_PATH ) |
49 | { |
50 | return ( 0 ); |
51 | } |
52 | |
53 | strncpy( absPathName, dirName, dwDirLength +1 ); |
54 | strncpy( absPathName, rgchPathDelim, 2 ); |
55 | strncpy( absPathName, fileName, dwFileLength +1 ); |
56 | |
57 | return (sizeAPN); |
58 | |
59 | } |
60 | |
61 | |
62 | int __cdecl main( int argc, char **argv ) |
63 | |
64 | { |
65 | const char* rgchChildFile = "childprocess" ; |
66 | |
67 | STARTUPINFO si; |
68 | PROCESS_INFORMATION pi; |
69 | |
70 | DWORD dwError; |
71 | DWORD dwExitCode; |
72 | DWORD dwFileLength; |
73 | DWORD dwDirLength; |
74 | DWORD dwSize; |
75 | DWORD dwRet; |
76 | |
77 | HANDLE hMutex; |
78 | HANDLE hChildProcess; |
79 | |
80 | char rgchDirName[_MAX_DIR]; |
81 | char absPathBuf[_MAX_PATH]; |
82 | char* rgchAbsPathName; |
83 | |
84 | BOOL ret = FAIL; |
85 | BOOL bChildDone = FALSE; |
86 | WCHAR wszMutexName[] = { 'T','E','S','T','1','\0' }; |
87 | |
88 | /* initialize the PAL */ |
89 | if( PAL_Initialize(argc, argv) != 0 ) |
90 | { |
91 | return( FAIL ); |
92 | } |
93 | |
94 | /* create a mutex to synchronize with the child process */ |
95 | hMutex = CreateMutexW( NULL, TRUE, wszMutexName ); |
96 | if( hMutex == NULL ) |
97 | { |
98 | Fail( "ERROR:%lu:CreateMutex() call failed\r\n" , GetLastError() ); |
99 | } |
100 | |
101 | /* zero our process and startup info structures */ |
102 | ZeroMemory( &si, sizeof(si) ); |
103 | si.cb = sizeof( si ); |
104 | ZeroMemory( &pi, sizeof(pi) ); |
105 | |
106 | /* build the absolute path to the child process */ |
107 | rgchAbsPathName = &absPathBuf[0]; |
108 | dwFileLength = strlen( rgchChildFile ); |
109 | |
110 | dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName ); |
111 | if( dwDirLength == 0 ) |
112 | { |
113 | dwError = GetLastError(); |
114 | if( ReleaseMutex( hMutex ) == 0 ) |
115 | { |
116 | Trace( "ERROR:%lu:ReleaseMutex() call failed\n" , GetLastError() ); |
117 | } |
118 | if( CloseHandle( hMutex ) == 0 ) |
119 | { |
120 | Trace( "ERROR:%lu:CloseHandle() call failed\n" , GetLastError() ); |
121 | } |
122 | Fail( "GetCurrentDirectory call failed with error code %d\n" , |
123 | dwError ); |
124 | } |
125 | |
126 | dwSize = mkAbsoluteFilename( rgchDirName, |
127 | dwDirLength, |
128 | rgchChildFile, |
129 | dwFileLength, |
130 | rgchAbsPathName ); |
131 | if( dwSize == 0 ) |
132 | { |
133 | if( ReleaseMutex( hMutex ) == 0 ) |
134 | { |
135 | Trace( "ERROR:%lu:ReleaseMutex() call failed\n" , GetLastError() ); |
136 | } |
137 | if( CloseHandle( hMutex ) == 0 ) |
138 | { |
139 | Trace( "ERROR:%lu:CloseHandle() call failed\n" , GetLastError() ); |
140 | } |
141 | Fail( "Palsuite Code: mkAbsoluteFilename() call failed. Could " , |
142 | "not build absolute path name to file\n. Exiting.\n" ); |
143 | } |
144 | |
145 | /* launch the child process */ |
146 | if( !CreateProcess( NULL, /* module name to execute */ |
147 | rgchAbsPathName, /* command line */ |
148 | NULL, /* process handle not */ |
149 | /* inheritable */ |
150 | NULL, /* thread handle not */ |
151 | /*inheritable */ |
152 | FALSE, /* handle inheritance */ |
153 | CREATE_NEW_CONSOLE, /* dwCreationFlags */ |
154 | NULL, /* use parent's environment */ |
155 | NULL, /* use parent's starting */ |
156 | /* directory */ |
157 | &si, /* startup info struct */ |
158 | &pi ) /* process info struct */ |
159 | ) |
160 | { |
161 | dwError = GetLastError(); |
162 | if( ReleaseMutex( hMutex ) == 0 ) |
163 | { |
164 | Trace( "ERROR:%lu:ReleaseMutex() call failed\n" , GetLastError() ); |
165 | } |
166 | if( CloseHandle( hMutex ) == 0 ) |
167 | { |
168 | Trace( "ERROR:%lu:CloseHandle() call failed\n" , GetLastError() ); |
169 | } |
170 | Fail( "CreateProcess call failed with error code %d\n" , |
171 | dwError ); |
172 | } |
173 | |
174 | /* open another handle to the child process */ |
175 | hChildProcess = OpenProcess( PROCESS_ALL_ACCESS, /* access */ |
176 | FALSE, /* inheritable */ |
177 | pi.dwProcessId /* process id */ |
178 | ); |
179 | if( hChildProcess == NULL ) |
180 | { |
181 | dwError = GetLastError(); |
182 | if( ReleaseMutex( hMutex ) == 0 ) |
183 | { |
184 | Trace( "ERROR:%lu:ReleaseMutex() call failed\n" , GetLastError() ); |
185 | } |
186 | Trace( "ERROR:%lu:OpenProcess call failed\n" , dwError ); |
187 | goto cleanup2; |
188 | } |
189 | |
190 | /* release the mutex so the child can proceed */ |
191 | if( ReleaseMutex( hMutex ) == 0 ) |
192 | { |
193 | Trace( "ERROR:%lu:ReleaseMutex() call failed\n" , GetLastError() ); |
194 | goto cleanup; |
195 | } |
196 | |
197 | /* wait for the child process to complete, using the new handle */ |
198 | dwRet = WaitForSingleObject( hChildProcess, 10000 ); |
199 | if( dwRet != WAIT_OBJECT_0 ) |
200 | { |
201 | Trace( "ERROR:WaitForSingleObject call returned %lu, " |
202 | "expected WAIT_OBJECT_0" , |
203 | dwRet ); |
204 | goto cleanup; |
205 | } |
206 | |
207 | /* remember that we waited until the child was finished */ |
208 | bChildDone = TRUE; |
209 | |
210 | /* check the exit code from the process -- this is a bit of an */ |
211 | /* extra verification that we opened the correct process handle */ |
212 | if( ! GetExitCodeProcess( hChildProcess, &dwExitCode ) ) |
213 | { |
214 | Trace( "ERROR:%lu:GetExitCodeProcess call failed\n" , GetLastError() ); |
215 | goto cleanup; |
216 | } |
217 | |
218 | /* verification */ |
219 | if( (dwExitCode & 0xFF) != (TEST_EXIT_CODE & 0xFF) ) |
220 | { |
221 | Trace( "GetExitCodeProcess returned an incorrect exit code %d, " |
222 | "expected value is %d\n" , |
223 | (dwExitCode & 0xFF), |
224 | (TEST_EXIT_CODE & 0xFF)); |
225 | goto cleanup; |
226 | } |
227 | |
228 | /* success if we get here */ |
229 | ret = PASS; |
230 | |
231 | |
232 | cleanup: |
233 | /* wait on the child process to complete if necessary */ |
234 | if( ! bChildDone ) |
235 | { |
236 | dwRet = WaitForSingleObject( hChildProcess, 10000 ); |
237 | if( dwRet != WAIT_OBJECT_0 ) |
238 | { |
239 | Trace( "ERROR:WaitForSingleObject call returned %lu, " |
240 | "expected WAIT_OBJECT_0" , |
241 | dwRet ); |
242 | ret = FAIL; |
243 | } |
244 | } |
245 | |
246 | /* close all our handles */ |
247 | if( CloseHandle ( hChildProcess ) == 0 ) |
248 | { |
249 | Trace( "ERROR:%lu:CloseHandle() call failed\n" , GetLastError() ); |
250 | ret = FAIL; |
251 | } |
252 | |
253 | cleanup2: |
254 | if( CloseHandle ( pi.hProcess ) == 0 ) |
255 | { |
256 | Trace( "ERROR:%lu:CloseHandle() call failed\n" , GetLastError() ); |
257 | ret = FAIL; |
258 | } |
259 | if( CloseHandle ( pi.hThread ) == 0 ) |
260 | { |
261 | Trace( "ERROR:%lu:CloseHandle() call failed\n" , GetLastError() ); |
262 | ret = FAIL; |
263 | } |
264 | if( CloseHandle( hMutex ) == 0 ) |
265 | { |
266 | Trace( "ERROR:%lu:CloseHandle() call failed\n" , GetLastError() ); |
267 | ret = FAIL; |
268 | } |
269 | |
270 | if( ret == FAIL ) |
271 | { |
272 | Fail( "test failed\n" ); |
273 | } |
274 | |
275 | |
276 | |
277 | /* terminate the PAL */ |
278 | PAL_Terminate(); |
279 | |
280 | /* return success */ |
281 | return PASS; |
282 | } |
283 | |