ReactOS  0.4.13-dev-563-g0561610
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 
31 static char selfname[MAX_PATH];
32 
33 /* Some functions are only in later versions of kernel32.dll */
34 static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
35 static BOOL (WINAPI *pModule32First)(HANDLE, LPMODULEENTRY32);
36 static BOOL (WINAPI *pModule32Next)(HANDLE, LPMODULEENTRY32);
37 static BOOL (WINAPI *pProcess32First)(HANDLE, LPPROCESSENTRY32);
38 static BOOL (WINAPI *pProcess32Next)(HANDLE, LPPROCESSENTRY32);
39 static BOOL (WINAPI *pThread32First)(HANDLE, LPTHREADENTRY32);
40 static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32);
41 
42 /* 1 minute should be more than enough */
43 #define WAIT_TIME (60 * 1000)
44 
45 static 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  */
61 static 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]);
78  ev3 = CreateEventW(NULL, FALSE, FALSE, NULL);
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 */
89  if (w != WAIT_OBJECT_0) ExitProcess(w);
90  /* signal sub-thread to terminate */
91  SetEvent(ev3);
93  if (w != WAIT_OBJECT_0) ExitProcess(w);
95  ExitProcess(w);
96  default:
97  return -1;
98  }
99 }
100 
101 static void test_process(DWORD curr_pid, DWORD sub_pcs_pid)
102 {
103  HANDLE hSnapshot;
104  PROCESSENTRY32 pe;
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 
153 static 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 
205 static const char* curr_expected_modules[] =
206 {
207  "kernel32_test.exe",
208  "kernel32.dll",
209  "ntdll.dll"
210 };
211 
212 static 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 
222 static void test_module(DWORD pid, const char* expected[], unsigned num_expected)
223 {
224  HANDLE hSnapshot;
225  PROCESSENTRY32 pe;
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 
284 START_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);
327  startup.dwFlags = STARTF_USESHOWWINDOW;
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++;
340  sub_expected_modules[0] = p;
341 
342  test_process(pid, info.dwProcessId);
343  test_thread(pid, info.dwProcessId);
346 
347  SetEvent(ev2);
348  winetest_wait_child_process( info.hProcess );
349 }
static DWORD WINAPI sub_thread(void *pmt)
Definition: toolhelp.c:45
static int argc
Definition: ServiceArgs.c:12
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3835
#define trace(...)
Definition: kmt_test.h:217
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
HMODULE module
Definition: main.cpp:47
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
#define WAIT_ABANDONED
Definition: winbase.h:393
int WINAPI lstrcmpiA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:42
static const char * sub_expected_modules[]
Definition: toolhelp.c:212
static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid)
Definition: toolhelp.c:153
char szExePath[MAX_PATH]
Definition: tlhelp32.h:103
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
BYTE * modBaseAddr
Definition: tlhelp32.h:99
static char selfname[MAX_PATH]
Definition: toolhelp.c:31
CHAR szExeFile[MAX_PATH]
Definition: tlhelp32.h:70
static HINSTANCE hkernel32
Definition: process.c:66
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1517
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
START_TEST(toolhelp)
Definition: toolhelp.c:284
GLuint buffer
Definition: glext.h:5915
int startup(int argc, const char *argv[])
Definition: startup.c:430
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
#define TH32CS_SNAPMODULE
Definition: tlhelp32.h:28
int32_t INT_PTR
Definition: typedefs.h:62
#define argv
Definition: mplay32.c:18
static BOOL(WINAPI *pModule32First)(HANDLE
int winetest_debug
DWORD WINAPI GetModuleFileNameA(HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
Definition: loader.c:546
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:597
struct _test_info info[]
Definition: SetCursorPos.c:19
char szModule[MAX_MODULE_NAME32+1]
Definition: tlhelp32.h:102
static int init(void)
Definition: toolhelp.c:61
#define sprintf(buf, format,...)
Definition: sprintf.c:55
BOOL WINAPI GetExitCodeThread(IN HANDLE hThread, OUT LPDWORD lpExitCode)
Definition: thread.c:502
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
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
#define NUM_OF(x)
Definition: toolhelp.c:220
DWORD th32ThreadID
Definition: tlhelp32.h:75
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR lpLibFileName)
Definition: loader.c:111
static LPPROCESSENTRY32
Definition: toolhelp.c:37
static const char * curr_expected_modules[]
Definition: toolhelp.c:205
#define ok(value,...)
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:111
smooth NULL
Definition: ftsmooth.c:416
#define STARTF_USESHOWWINDOW
Definition: winbase.h:472
#define WAIT_OBJECT_0
Definition: winbase.h:387
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:4772
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
static HANDLE(WINAPI *pCreateToolhelp32Snapshot)(DWORD
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint num
Definition: glext.h:9618
int winetest_get_mainargs(char ***pargv)
DWORD th32ProcessID
Definition: tlhelp32.h:63
DWORD th32OwnerProcessID
Definition: tlhelp32.h:76
static void test_process(DWORD curr_pid, DWORD sub_pcs_pid)
Definition: toolhelp.c:101
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:819
uint32_t DWORD_PTR
Definition: typedefs.h:63
static DWORD
Definition: toolhelp.c:34
void winetest_wait_child_process(HANDLE process)
#define SW_SHOWNORMAL
Definition: winuser.h:764
#define TH32CS_SNAPTHREAD
Definition: tlhelp32.h:27
#define TH32CS_SNAPPROCESS
Definition: tlhelp32.h:26
HANDLE hThread
Definition: wizard.c:27
#define WAIT_TIME
Definition: toolhelp.c:43
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
static LPMODULEENTRY32
Definition: toolhelp.c:35
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define GetProcAddress(x, y)
Definition: compat.h:410
static void test_module(DWORD pid, const char *expected[], unsigned num_expected)
Definition: toolhelp.c:222
GLfloat GLfloat p
Definition: glext.h:8902
#define memset(x, y, z)
Definition: compat.h:39
#define win_skip
Definition: test.h:141
static TfClientId tid
static struct sockaddr_in sa
Definition: adnsresfilter.c:69
BOOL expected
Definition: store.c:2063
DWORD th32ProcessID
Definition: tlhelp32.h:96
DWORD WINAPI GetCurrentProcessId(VOID)
Definition: proc.c:1188
static LPTHREADENTRY32
Definition: toolhelp.c:39
DWORD modBaseSize
Definition: tlhelp32.h:100