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
31static const char* rgchPathDelim = "\\";
32
33
34int
35mkAbsoluteFilename( 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
62int __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
232cleanup:
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
253cleanup2:
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