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: test2.c
8**
9** Purpose: Test to ensure ExitThread() called from the last thread of
10** a process shuts down that process and returns the proper
11** exit code as specified in the ExitThread() call.
12**
13** Dependencies: PAL_Initialize
14** PAL_Terminate
15** Fail
16** ZeroMemory
17** GetCurrentDirectoryW
18** CreateProcessW
19** WaitForSingleObject
20** GetLastError
21** strlen
22** strncpy
23**
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 dwExpected = TEST_EXIT_CODE;
76
77 char rgchDirName[_MAX_DIR];
78 char absPathBuf[_MAX_PATH];
79 char* rgchAbsPathName;
80
81 /* initialize the PAL */
82 if( PAL_Initialize(argc, argv) != 0 )
83 {
84 return( FAIL );
85 }
86
87 /* zero our process and startup info structures */
88 ZeroMemory( &si, sizeof(si) );
89 si.cb = sizeof( si );
90 ZeroMemory( &pi, sizeof(pi) );
91
92 /* build the absolute path to the child process */
93 rgchAbsPathName = &absPathBuf[0];
94 dwFileLength = strlen( rgchChildFile );
95
96 dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName );
97 if( dwDirLength == 0 )
98 {
99 dwError = GetLastError();
100 Fail( "GetCurrentDirectory call failed with error code %d\n",
101 dwError );
102 }
103
104 dwSize = mkAbsoluteFilename( rgchDirName,
105 dwDirLength,
106 rgchChildFile,
107 dwFileLength,
108 rgchAbsPathName );
109 if( dwSize == 0 )
110 {
111 Fail( "Palsuite Code: mkAbsoluteFilename() call failed. Could ",
112 "not build absolute path name to file\n. Exiting.\n" );
113 }
114
115 /* launch the child process */
116 if( !CreateProcess( NULL, /* module name to execute */
117 rgchAbsPathName, /* command line */
118 NULL, /* process handle not */
119 /* inheritable */
120 NULL, /* thread handle not */
121 /* inheritable */
122 FALSE, /* handle inheritance */
123 CREATE_NEW_CONSOLE, /* dwCreationFlags */
124 NULL, /* use parent's environment */
125 NULL, /* use parent's starting */
126 /* directory */
127 &si, /* startup info struct */
128 &pi ) /* process info struct */
129 )
130 {
131 dwError = GetLastError();
132 Fail( "CreateProcess call failed with error code %d\n",
133 dwError );
134 }
135
136 /* wait for the child process to complete */
137 WaitForSingleObject ( pi.hProcess, INFINITE );
138
139 /* check the exit code from the process */
140 if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
141 {
142 dwError = GetLastError();
143 CloseHandle ( pi.hProcess );
144 CloseHandle ( pi.hThread );
145 Fail( "GetExitCodeProcess call failed with error code %d\n",
146 dwError );
147 }
148
149 /* close process and thread handle */
150 CloseHandle ( pi.hProcess );
151 CloseHandle ( pi.hThread );
152
153 /* check for the expected exit code */
154 /* exit code for some systems is as small as a char, so that's all */
155 /* we'll compare for checking success */
156 if( LOBYTE(LOWORD(dwExitCode)) != LOBYTE(LOWORD(dwExpected)) )
157 {
158 Fail( "GetExitCodeProcess returned an incorrect exit code %d, "
159 "expected value is %d\n",
160 LOWORD(dwExitCode), dwExpected );
161 }
162
163 /* terminate the PAL */
164 PAL_Terminate();
165
166 /* return success */
167 return PASS;
168}
169