ReactOS 0.4.15-dev-8339-g4028de8
toolhelp.c
Go to the documentation of this file.
1/*
2 * Toolhelp
3 *
4 * Copyright 2005 Eric Pouech
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include <stdarg.h>
22#include <stdlib.h>
23#include <stdio.h>
24
25#include "windef.h"
26#include "winbase.h"
27#include "tlhelp32.h"
28#include "wine/test.h"
29#include "winuser.h"
30
31static char selfname[MAX_PATH];
32
33/* Some functions are only in later versions of kernel32.dll */
34static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
35static BOOL (WINAPI *pModule32First)(HANDLE, LPMODULEENTRY32);
36static BOOL (WINAPI *pModule32Next)(HANDLE, LPMODULEENTRY32);
37static BOOL (WINAPI *pProcess32First)(HANDLE, LPPROCESSENTRY32);
38static BOOL (WINAPI *pProcess32Next)(HANDLE, LPPROCESSENTRY32);
39static BOOL (WINAPI *pThread32First)(HANDLE, LPTHREADENTRY32);
40static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32);
41
42/* 1 minute should be more than enough */
43#define WAIT_TIME (60 * 1000)
44
45static DWORD WINAPI sub_thread(void* pmt)
46{
48 return w;
49}
50
51/******************************************************************
52 * init
53 *
54 * generates basic information like:
55 * selfname: the way to reinvoke ourselves
56 * returns:
57 * -1 on error
58 * 0 if parent
59 * doesn't return if child
60 */
61static int init(void)
62{
63 int argc;
64 char** argv;
65 HANDLE ev1, ev2, ev3, hThread;
66 DWORD w, tid;
67
69 strcpy(selfname, argv[0]);
70
71 switch (argc)
72 {
73 case 2: /* the test program */
74 return 0;
75 case 4: /* the sub-process */
76 ev1 = (HANDLE)(INT_PTR)atoi(argv[2]);
77 ev2 = (HANDLE)(INT_PTR)atoi(argv[3]);
79
80 if (ev3 == NULL) ExitProcess(WAIT_ABANDONED);
81 hThread = CreateThread(NULL, 0, sub_thread, ev3, 0, &tid);
83 if (!LoadLibraryA("shell32.dll")) ExitProcess(WAIT_ABANDONED);
84
85 /* signal init of sub-process is done */
86 SetEvent(ev1);
87 /* wait for parent to have done all its queries */
90 /* signal sub-thread to terminate */
91 SetEvent(ev3);
96 default:
97 return -1;
98 }
99}
100
101static void test_process(DWORD curr_pid, DWORD sub_pcs_pid)
102{
103 HANDLE hSnapshot;
105 MODULEENTRY32 me;
106 unsigned found = 0;
107 int num = 0;
108 int childpos = -1;
109
110 hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
111 ok(hSnapshot != NULL, "Cannot create snapshot\n");
112
113 /* check that this current process is enumerated */
114 pe.dwSize = sizeof(pe);
115 if (pProcess32First( hSnapshot, &pe ))
116 {
117 do
118 {
119 if (pe.th32ProcessID == curr_pid) found++;
120 if (pe.th32ProcessID == sub_pcs_pid) { childpos = num; found++; }
121 trace("PID=%x %s\n", pe.th32ProcessID, pe.szExeFile);
122 num++;
123 } while (pProcess32Next( hSnapshot, &pe ));
124 }
125 ok(found == 2, "couldn't find self and/or sub-process in process list\n");
126
127 /* check that first really resets the enumeration */
128 found = 0;
129 if (pProcess32First( hSnapshot, &pe ))
130 {
131 do
132 {
133 if (pe.th32ProcessID == curr_pid) found++;
134 if (pe.th32ProcessID == sub_pcs_pid) found++;
135 trace("PID=%x %s\n", pe.th32ProcessID, pe.szExeFile);
136 num--;
137 } while (pProcess32Next( hSnapshot, &pe ));
138 }
139 ok(found == 2, "couldn't find self and/or sub-process in process list\n");
140 ok(!num, "mismatch in counting\n");
141
142 /* one broken program does Process32First() and does not expect anything
143 * interesting to be there, especially not the just forked off child */
144 ok (childpos !=0, "child is not expected to be at position 0.\n");
145
146 me.dwSize = sizeof(me);
147 ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n");
148
149 CloseHandle(hSnapshot);
150 ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n");
151}
152
153static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid)
154{
155 HANDLE hSnapshot;
156 THREADENTRY32 te;
157 MODULEENTRY32 me;
158 int num = 0;
159 unsigned curr_found = 0;
160 unsigned sub_found = 0;
161
162 hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
163 ok(hSnapshot != NULL, "Cannot create snapshot\n");
164
165 /* check that this current process is enumerated */
166 te.dwSize = sizeof(te);
167 if (pThread32First( hSnapshot, &te ))
168 {
169 do
170 {
171 if (te.th32OwnerProcessID == curr_pid) curr_found++;
172 if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++;
173 if (winetest_debug > 1)
174 trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri);
175 num++;
176 } while (pThread32Next( hSnapshot, &te ));
177 }
178 ok(curr_found, "couldn't find self in thread list\n");
179 ok(sub_found >= 2, "couldn't find sub-process threads in thread list\n");
180
181 /* check that first really resets enumeration */
182 curr_found = 0;
183 sub_found = 0;
184 if (pThread32First( hSnapshot, &te ))
185 {
186 do
187 {
188 if (te.th32OwnerProcessID == curr_pid) curr_found++;
189 if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++;
190 if (winetest_debug > 1)
191 trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri);
192 num--;
193 } while (pThread32Next( hSnapshot, &te ));
194 }
195 ok(curr_found, "couldn't find self in thread list\n");
196 ok(sub_found >= 2, "couldn't find sub-process threads in thread list\n");
197
198 me.dwSize = sizeof(me);
199 ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n");
200
201 CloseHandle(hSnapshot);
202 ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n");
203}
204
205static const char* curr_expected_modules[] =
206{
207 "kernel32_test.exe",
208 "kernel32.dll",
209 "ntdll.dll"
210};
211
212static const char* sub_expected_modules[] =
213{
214 "kernel32_test.exe",
215 "kernel32.dll",
216 "shell32.dll",
217 "ntdll.dll"
218};
219
220#define NUM_OF(x) (sizeof(x) / sizeof(x[0]))
221
222static void test_module(DWORD pid, const char* expected[], unsigned num_expected)
223{
224 HANDLE hSnapshot;
226 THREADENTRY32 te;
227 MODULEENTRY32 me;
228 unsigned found[32];
229 unsigned i;
230 int num = 0;
231
232 ok(NUM_OF(found) >= num_expected, "Internal: bump found[] size\n");
233
234 hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid );
235 ok(hSnapshot != NULL, "Cannot create snapshot\n");
236
237 for (i = 0; i < num_expected; i++) found[i] = 0;
238 me.dwSize = sizeof(me);
239 if (pModule32First( hSnapshot, &me ))
240 {
241 do
242 {
243 trace("PID=%x base=%p size=%x %s %s\n",
245 ok(me.th32ProcessID == pid, "wrong returned process id\n");
246 for (i = 0; i < num_expected; i++)
247 if (!lstrcmpiA(expected[i], me.szModule)) found[i]++;
248 num++;
249 } while (pModule32Next( hSnapshot, &me ));
250 }
251 for (i = 0; i < num_expected; i++)
252 ok(found[i] == 1, "Module %s is %s\n",
253 expected[i], found[i] ? "listed more than once" : "not listed");
254
255 /* check that first really resets the enumeration */
256 for (i = 0; i < num_expected; i++) found[i] = 0;
257 me.dwSize = sizeof(me);
258 if (pModule32First( hSnapshot, &me ))
259 {
260 do
261 {
262 trace("PID=%x base=%p size=%x %s %s\n",
264 for (i = 0; i < num_expected; i++)
265 if (!lstrcmpiA(expected[i], me.szModule)) found[i]++;
266 num--;
267 } while (pModule32Next( hSnapshot, &me ));
268 }
269 for (i = 0; i < num_expected; i++)
270 ok(found[i] == 1, "Module %s is %s\n",
271 expected[i], found[i] ? "listed more than once" : "not listed");
272 ok(!num, "mismatch in counting\n");
273
274 pe.dwSize = sizeof(pe);
275 ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n");
276
277 te.dwSize = sizeof(te);
278 ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n");
279
280 CloseHandle(hSnapshot);
281 ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n");
282}
283
284START_TEST(toolhelp)
285{
287 int r;
288 char *p, module[MAX_PATH];
289 char buffer[MAX_PATH];
293 HANDLE ev1, ev2;
294 DWORD w;
295 HANDLE hkernel32 = GetModuleHandleA("kernel32");
296
297 pCreateToolhelp32Snapshot = (VOID *) GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
298 pModule32First = (VOID *) GetProcAddress(hkernel32, "Module32First");
299 pModule32Next = (VOID *) GetProcAddress(hkernel32, "Module32Next");
300 pProcess32First = (VOID *) GetProcAddress(hkernel32, "Process32First");
301 pProcess32Next = (VOID *) GetProcAddress(hkernel32, "Process32Next");
302 pThread32First = (VOID *) GetProcAddress(hkernel32, "Thread32First");
303 pThread32Next = (VOID *) GetProcAddress(hkernel32, "Thread32Next");
304
305 if (!pCreateToolhelp32Snapshot ||
306 !pModule32First || !pModule32Next ||
307 !pProcess32First || !pProcess32Next ||
308 !pThread32First || !pThread32Next)
309 {
310 win_skip("Needed functions are not available, most likely running on Windows NT\n");
311 return;
312 }
313
314 r = init();
315 ok(r == 0, "Basic init of sub-process test\n");
316 if (r != 0) return;
317
318 sa.nLength = sizeof(sa);
319 sa.lpSecurityDescriptor = NULL;
320 sa.bInheritHandle = TRUE;
321
322 ev1 = CreateEventW(&sa, FALSE, FALSE, NULL);
323 ev2 = CreateEventW(&sa, FALSE, FALSE, NULL);
324 ok (ev1 != NULL && ev2 != NULL, "Couldn't create events\n");
325 memset(&startup, 0, sizeof(startup));
326 startup.cb = sizeof(startup);
328 startup.wShowWindow = SW_SHOWNORMAL;
329
330 sprintf(buffer, "%s tests/toolhelp.c %lu %lu", selfname, (DWORD_PTR)ev1, (DWORD_PTR)ev2);
331 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
332 /* wait for child to be initialized */
334 ok(w == WAIT_OBJECT_0, "Failed to wait on sub-process startup\n");
335
336 GetModuleFileNameA( 0, module, sizeof(module) );
337 if (!(p = strrchr( module, '\\' ))) p = module;
338 else p++;
341
342 test_process(pid, info.dwProcessId);
343 test_thread(pid, info.dwProcessId);
346
347 SetEvent(ev2);
349}
static int argc
Definition: ServiceArgs.c:12
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
static void startup(void)
static struct sockaddr_in sa
Definition: adnsresfilter.c:69
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define START_TEST(x)
Definition: atltest.h:75
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
#define GetProcAddress(x, y)
Definition: compat.h:753
#define MAX_PATH
Definition: compat.h:34
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR lpLibFileName)
Definition: loader.c:111
DWORD WINAPI GetModuleFileNameA(HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
Definition: loader.c:539
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1487
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
Definition: proc.c:4741
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
BOOL WINAPI GetExitCodeThread(IN HANDLE hThread, OUT LPDWORD lpExitCode)
Definition: thread.c:541
int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4223
unsigned long DWORD
Definition: ntddk_ex.h:95
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLuint buffer
Definition: glext.h:5915
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLuint num
Definition: glext.h:9618
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define sprintf(buf, format,...)
Definition: sprintf.c:55
BOOL expected
Definition: store.c:2063
static HINSTANCE hkernel32
Definition: process.c:66
static LPMODULEENTRY32
Definition: toolhelp.c:35
static LPPROCESSENTRY32
Definition: toolhelp.c:37
static DWORD
Definition: toolhelp.c:34
static void test_module(DWORD pid, const char *expected[], unsigned num_expected)
Definition: toolhelp.c:222
static const char * curr_expected_modules[]
Definition: toolhelp.c:205
static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid)
Definition: toolhelp.c:153
static DWORD WINAPI sub_thread(void *pmt)
Definition: toolhelp.c:45
#define NUM_OF(x)
Definition: toolhelp.c:220
static void test_process(DWORD curr_pid, DWORD sub_pcs_pid)
Definition: toolhelp.c:101
static const char * sub_expected_modules[]
Definition: toolhelp.c:212
#define WAIT_TIME
Definition: toolhelp.c:43
static char selfname[MAX_PATH]
Definition: toolhelp.c:31
static int init(void)
Definition: toolhelp.c:61
static TfClientId tid
#define argv
Definition: mplay32.c:18
HANDLE hThread
Definition: wizard.c:28
#define BOOL
Definition: nt_native.h:43
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
int winetest_debug
#define win_skip
Definition: test.h:163
int winetest_get_mainargs(char ***pargv)
void winetest_wait_child_process(HANDLE process)
#define memset(x, y, z)
Definition: compat.h:39
BYTE * modBaseAddr
Definition: tlhelp32.h:99
char szModule[MAX_MODULE_NAME32+1]
Definition: tlhelp32.h:102
DWORD th32ProcessID
Definition: tlhelp32.h:96
DWORD modBaseSize
Definition: tlhelp32.h:100
char szExePath[MAX_PATH]
Definition: tlhelp32.h:103
CHAR szExeFile[MAX_PATH]
Definition: tlhelp32.h:70
DWORD th32ProcessID
Definition: tlhelp32.h:63
DWORD th32ThreadID
Definition: tlhelp32.h:75
DWORD th32OwnerProcessID
Definition: tlhelp32.h:76
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:651
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
#define TH32CS_SNAPPROCESS
Definition: tlhelp32.h:26
struct tagTHREADENTRY32 * LPTHREADENTRY32
Definition: toolhelp.c:40
#define TH32CS_SNAPTHREAD
Definition: tlhelp32.h:27
#define TH32CS_SNAPMODULE
Definition: tlhelp32.h:28
int32_t INT_PTR
Definition: typedefs.h:64
uint32_t DWORD_PTR
Definition: typedefs.h:65
PVOID HANDLE
Definition: typedefs.h:73
#define WAIT_ABANDONED
Definition: winbase.h:412
#define STARTF_USESHOWWINDOW
Definition: winbase.h:491
DWORD WINAPI GetCurrentProcessId(void)
Definition: proc.c:1158
#define WAIT_OBJECT_0
Definition: winbase.h:406
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3837
#define WINAPI
Definition: msvc.h:6
#define SW_SHOWNORMAL
Definition: winuser.h:770