crypt32: Fixed day/month mismatch in time encoding routines.
[wine] / dlls / kernel / tests / toolhelp.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <windef.h>
25 #include <winbase.h>
26
27 #include "tlhelp32.h"
28 #include "wine/test.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32
33 static char     selfname[MAX_PATH];
34
35 /* 1 minute should be more than enough */
36 #define WAIT_TIME       (60 * 1000)
37
38 static DWORD WINAPI sub_thread(void* pmt)
39 {
40     DWORD w = WaitForSingleObject((HANDLE)pmt, WAIT_TIME);
41     return w;
42 }
43
44 /******************************************************************
45  *              init
46  *
47  * generates basic information like:
48  *      selfname:       the way to reinvoke ourselves
49  * returns:
50  *      -1      on error
51  *      0       if parent
52  *      doesn't return if child
53  */
54 static int     init(void)
55 {
56     int                 argc;
57     char**              argv;
58     HANDLE              ev1, ev2, ev3, hThread;
59     DWORD               w;
60
61     argc = winetest_get_mainargs( &argv );
62     strcpy(selfname, argv[0]);
63
64     switch (argc)
65     {
66     case 2: /* the test program */
67         return 0;
68     case 4: /* the sub-process */
69         ev1 = (HANDLE)atoi(argv[2]);
70         ev2 = (HANDLE)atoi(argv[3]);
71         ev3 = CreateEvent(NULL, FALSE, FALSE, NULL);
72
73         if (ev3 == NULL) ExitProcess(WAIT_ABANDONED);
74         hThread = CreateThread(NULL, 0, sub_thread, ev3, 0, NULL);
75         if (hThread == NULL) ExitProcess(WAIT_ABANDONED);
76         if (!LoadLibraryA("shell32.dll")) ExitProcess(WAIT_ABANDONED);
77     
78         /* signal init of sub-process is done */
79         SetEvent(ev1);
80         /* wait for parent to have done all its queries */
81         w = WaitForSingleObject(ev2, WAIT_TIME);
82         if (w != WAIT_OBJECT_0) ExitProcess(w);
83         /* signal sub-thread to terminate */
84         SetEvent(ev3);
85         w = WaitForSingleObject(hThread, WAIT_TIME);
86         if (w != WAIT_OBJECT_0) ExitProcess(w);
87         GetExitCodeThread(hThread, &w);
88         ExitProcess(w);
89     default:
90         return -1;
91     }
92 }
93
94 static void test_process(DWORD curr_pid, DWORD sub_pcs_pid)
95 {
96     HANDLE              hSnapshot;
97     PROCESSENTRY32      pe;
98     THREADENTRY32       te;
99     MODULEENTRY32       me;
100     unsigned            found = 0;
101     int                 num = 0;
102
103     hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
104     ok(hSnapshot != NULL, "Cannot create snapshot\n");
105
106     /* check that this current process is enumerated */
107     pe.dwSize = sizeof(pe);
108     if (Process32First( hSnapshot, &pe ))
109     {
110         do
111         {
112             if (pe.th32ProcessID == curr_pid) found++;
113             if (pe.th32ProcessID == sub_pcs_pid) found++;
114             trace("PID=%lx %s\n", pe.th32ProcessID, pe.szExeFile);
115             num++;
116         } while (Process32Next( hSnapshot, &pe ));
117     }
118     ok(found == 2, "couldn't find self and/or sub-process in process list\n");
119
120     /* check that first really resets the enumeration */
121     found = 0;
122     if (Process32First( hSnapshot, &pe ))
123     {
124         do
125         {
126             if (pe.th32ProcessID == curr_pid) found++;
127             if (pe.th32ProcessID == sub_pcs_pid) found++;
128             trace("PID=%lx %s\n", pe.th32ProcessID, pe.szExeFile);
129             num--;
130         } while (Process32Next( hSnapshot, &pe ));
131     }
132     ok(found == 2, "couldn't find self and/or sub-process in process list\n");
133     ok(!num, "mismatch in counting\n");
134
135     te.dwSize = sizeof(te);
136     ok(!Thread32First( hSnapshot, &te ), "shouldn't return a thread\n");
137
138     me.dwSize = sizeof(me);
139     ok(!Module32First( hSnapshot, &me ), "shouldn't return a module\n");
140
141     CloseHandle(hSnapshot);
142     ok(!Process32First( hSnapshot, &pe ), "shouldn't return a process\n");
143 }
144
145 static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid)
146 {
147     HANDLE              hSnapshot;
148     PROCESSENTRY32      pe;
149     THREADENTRY32       te;
150     MODULEENTRY32       me;
151     int                 num = 0;
152     unsigned            curr_found = 0;
153     unsigned            sub_found = 0;
154     
155     hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
156     ok(hSnapshot != NULL, "Cannot create snapshot\n");
157
158     /* check that this current process is enumerated */
159     te.dwSize = sizeof(te);
160     if (Thread32First( hSnapshot, &te ))
161     {
162         do
163         {
164             if (te.th32OwnerProcessID == curr_pid) curr_found++;
165             if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++;
166             trace("PID=%lx TID=%lx %ld\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri);
167             num++;
168         } while (Thread32Next( hSnapshot, &te ));
169     }
170     ok(curr_found == 1, "couldn't find self in thread list\n");
171     ok(sub_found == 2, "couldn't find sub-process thread's in thread list\n");
172
173     /* check that first really resets enumeration */
174     curr_found = 0;
175     sub_found = 0;
176     if (Thread32First( hSnapshot, &te ))
177     {
178         do
179         {
180             if (te.th32OwnerProcessID == curr_pid) curr_found++;
181             if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++;
182             trace("PID=%lx TID=%lx %ld\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri);
183             num--;
184         } while (Thread32Next( hSnapshot, &te ));
185     }
186     ok(curr_found == 1, "couldn't find self in thread list\n");
187     ok(sub_found == 2, "couldn't find sub-process thread's in thread list\n");
188
189     pe.dwSize = sizeof(pe);
190     ok(!Process32First( hSnapshot, &pe ), "shouldn't return a process\n");
191
192     me.dwSize = sizeof(me);
193     ok(!Module32First( hSnapshot, &me ), "shouldn't return a module\n");
194
195     CloseHandle(hSnapshot);
196     ok(!Thread32First( hSnapshot, &te ), "shouldn't return a thread\n");
197 }
198
199 static const char* curr_expected_modules[] =
200 {
201     "kernel32.dll",
202     "kernel32_test.exe"
203     /* FIXME: could test for ntdll on NT and Wine */
204 };
205 static const char* sub_expected_modules[] =
206 {
207     "kernel32.dll",
208     "kernel32_test.exe",
209     "shell32.dll"
210     /* FIXME: could test for ntdll on NT and Wine */
211 };
212 #define NUM_OF(x) (sizeof(x) / sizeof(x[0]))
213
214 static void test_module(DWORD pid, const char* expected[], unsigned num_expected)
215 {
216     HANDLE              hSnapshot;
217     PROCESSENTRY32      pe;
218     THREADENTRY32       te;
219     MODULEENTRY32       me;
220     unsigned            found[32];
221     int                 i, num = 0;
222
223     ok(NUM_OF(found) >= num_expected, "Internal: bump found[] size\n");
224
225     hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid );
226     ok(hSnapshot != NULL, "Cannot create snapshot\n");
227
228     for (i = 0; i < num_expected; i++) found[i] = 0;
229     me.dwSize = sizeof(me);
230     if (Module32First( hSnapshot, &me ))
231     {
232         do
233         {
234             trace("PID=%lx base=%p size=%lx %s %s\n",
235                   me.th32ProcessID, me.modBaseAddr, me.modBaseSize, me.szExePath, me.szModule);
236             ok(me.th32ProcessID == pid, "wrong returned process id");
237             for (i = 0; i < num_expected; i++)
238                 if (!strcmp(expected[i], me.szModule)) found[i]++;
239             num++;
240         } while (Module32Next( hSnapshot, &me ));
241     }
242     for (i = 0; i < num_expected; i++)
243         ok(found[i] == 1, "Module %s is %s\n",
244            expected[i], found[i] ? "listed more than once" : "not listed");
245
246     /* check that first really resets the enumeration */
247     for (i = 0; i < num_expected; i++) found[i] = 0;
248     me.dwSize = sizeof(me);
249     if (Module32First( hSnapshot, &me ))
250     {
251         do
252         {
253             trace("PID=%lx base=%p size=%lx %s %s\n",
254                   me.th32ProcessID, me.modBaseAddr, me.modBaseSize, me.szExePath, me.szModule);
255             for (i = 0; i < num_expected; i++)
256                 if (!strcmp(expected[i], me.szModule)) found[i]++;
257             num--;
258         } while (Module32Next( hSnapshot, &me ));
259     }
260     for (i = 0; i < num_expected; i++)
261         ok(found[i] == 1, "Module %s is %s\n",
262            expected[i], found[i] ? "listed more than once" : "not listed");
263     ok(!num, "mismatch in counting\n");
264
265     pe.dwSize = sizeof(pe);
266     ok(!Process32First( hSnapshot, &pe ), "shouldn't return a process\n");
267
268     me.dwSize = sizeof(me);
269     ok(!Thread32First( hSnapshot, &te ), "shouldn't return a thread\n");
270
271     CloseHandle(hSnapshot);
272     ok(!Module32First( hSnapshot, &me ), "shouldn't return a module\n");
273 }
274
275 START_TEST(toolhelp)
276 {
277     DWORD               pid = GetCurrentProcessId();
278     int                 r;
279     char                buffer[MAX_PATH];
280     SECURITY_ATTRIBUTES sa;
281     PROCESS_INFORMATION info;
282     STARTUPINFOA        startup;
283     HANDLE              ev1, ev2;
284     DWORD               w;
285
286     r = init();
287     ok(r == 0, "Basic init of sub-process test\n");
288     if (r != 0) return;
289
290     sa.nLength = sizeof(sa);
291     sa.lpSecurityDescriptor = NULL;
292     sa.bInheritHandle = TRUE;
293
294     ev1 = CreateEvent(&sa, FALSE, FALSE, NULL);
295     ev2 = CreateEvent(&sa, FALSE, FALSE, NULL);
296     ok (ev1 != NULL && ev2 != NULL, "Couldn't create events\n");
297     memset(&startup, 0, sizeof(startup));
298     startup.cb = sizeof(startup);
299     startup.dwFlags = STARTF_USESHOWWINDOW;
300     startup.wShowWindow = SW_SHOWNORMAL;
301
302     sprintf(buffer, "%s tests/toolhelp.c %lu %lu", selfname, (DWORD)ev1, (DWORD)ev2);
303     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
304     /* wait for child to be initialized */
305     w = WaitForSingleObject(ev1, WAIT_TIME);
306     ok(w == WAIT_OBJECT_0, "Failed to wait on sub-process startup\n");
307
308     test_process(pid, info.dwProcessId);
309     test_thread(pid, info.dwProcessId);
310     test_module(pid, curr_expected_modules, NUM_OF(curr_expected_modules));
311     test_module(info.dwProcessId, sub_expected_modules, NUM_OF(sub_expected_modules));
312
313     SetEvent(ev2);
314     w = WaitForSingleObject(info.hProcess, WAIT_TIME);
315     ok(w == WAIT_OBJECT_0, "Failed to wait on sub-process termination\n");
316     ok(GetExitCodeProcess(info.hProcess, &w), "couldn't get process exit code\n");
317     ok(w == WAIT_OBJECT_0, "Sub-Process failed to terminate properly\n");
318 }