New set of macros for server calls; makes requests without variable
[wine] / dlls / kernel / toolhelp.c
1 /*
2  * Misc Toolhelp functions
3  *
4  * Copyright 1996 Marcus Meissner
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <ctype.h>
11 #include <assert.h>
12 #include "winbase.h"
13 #include "wine/winbase16.h"
14 #include "winerror.h"
15 #include "local.h"
16 #include "tlhelp32.h"
17 #include "toolhelp.h"
18 #include "heap.h"
19 #include "server.h"
20 #include "debugtools.h"
21
22 DEFAULT_DEBUG_CHANNEL(toolhelp);
23
24
25 /* FIXME: to make this working, we have to callback all these registered 
26  * functions from all over the WINE code. Someone with more knowledge than
27  * me please do that. -Marcus
28  */
29 static struct notify
30 {
31     HTASK16   htask;
32     FARPROC16 lpfnCallback;
33     WORD     wFlags;
34 } *notifys = NULL;
35
36 static int nrofnotifys = 0;
37
38 static FARPROC16 HookNotify = NULL;
39
40 /***********************************************************************
41  *              NotifyRegister16 (TOOLHELP.73)
42  */
43 BOOL16 WINAPI NotifyRegister16( HTASK16 htask, FARPROC16 lpfnCallback,
44                               WORD wFlags )
45 {
46     int i;
47
48     FIXME("(%x,%lx,%x), semi-stub.\n",
49                       htask, (DWORD)lpfnCallback, wFlags );
50     if (!htask) htask = GetCurrentTask();
51     for (i=0;i<nrofnotifys;i++)
52         if (notifys[i].htask==htask)
53             break;
54     if (i==nrofnotifys) {
55         if (notifys==NULL)
56             notifys=(struct notify*)HeapAlloc( GetProcessHeap(), 0,
57                                                sizeof(struct notify) );
58         else
59             notifys=(struct notify*)HeapReAlloc( GetProcessHeap(), 0, notifys,
60                                         sizeof(struct notify)*(nrofnotifys+1));
61         if (!notifys) return FALSE;
62         nrofnotifys++;
63     }
64     notifys[i].htask=htask;
65     notifys[i].lpfnCallback=lpfnCallback;
66     notifys[i].wFlags=wFlags;
67     return TRUE;
68 }
69
70 /***********************************************************************
71  *              NotifyUnregister16 (TOOLHELP.74)
72  */
73 BOOL16 WINAPI NotifyUnregister16( HTASK16 htask )
74 {
75     int i;
76     
77     FIXME("(%x), semi-stub.\n", htask );
78     if (!htask) htask = GetCurrentTask();
79     for (i=nrofnotifys;i--;)
80         if (notifys[i].htask==htask)
81             break;
82     if (i==-1)
83         return FALSE;
84     memcpy(notifys+i,notifys+(i+1),sizeof(struct notify)*(nrofnotifys-i-1));
85     notifys=(struct notify*)HeapReAlloc( GetProcessHeap(), 0, notifys,
86                                         (nrofnotifys-1)*sizeof(struct notify));
87     nrofnotifys--;
88     return TRUE;
89 }
90
91 /***********************************************************************
92  *              StackTraceCSIPFirst (TOOLHELP.67)
93  */
94 BOOL16 WINAPI StackTraceCSIPFirst16(STACKTRACEENTRY *ste, WORD wSS, WORD wCS, WORD wIP, WORD wBP)
95 {
96     FIXME("(%p, ss %04x, cs %04x, ip %04x, bp %04x): stub.\n", ste, wSS, wCS, wIP, wBP);
97     return TRUE;
98 }
99
100 /***********************************************************************
101  *              StackTraceFirst (TOOLHELP.66)
102  */
103 BOOL16 WINAPI StackTraceFirst16(STACKTRACEENTRY *ste, HTASK16 Task)
104 {
105     FIXME("(%p, %04x), stub.\n", ste, Task);
106     return TRUE;
107 }
108
109 /***********************************************************************
110  *              StackTraceNext (TOOLHELP.68)
111  */
112 BOOL16 WINAPI StackTraceNext16(STACKTRACEENTRY *ste)
113 {
114     FIXME("(%p), stub.\n", ste);
115     return TRUE;
116 }
117
118 /***********************************************************************
119  *              InterruptRegister (TOOLHELP.75)
120  */
121 BOOL16 WINAPI InterruptRegister16( HTASK16 task, FARPROC callback )
122 {
123     FIXME("(%04x, %p), stub.\n", task, callback);
124     return TRUE;
125 }
126
127 /***********************************************************************
128  *              InterruptUnRegister (TOOLHELP.76)
129  */
130 BOOL16 WINAPI InterruptUnRegister16( HTASK16 task )
131 {
132     FIXME("(%04x), stub.\n", task);
133     return TRUE;
134 }
135
136 /***********************************************************************
137  *           TimerCount   (TOOLHELP.80)
138  */
139 BOOL16 WINAPI TimerCount16( TIMERINFO *pTimerInfo )
140 {
141     /* FIXME
142      * In standard mode, dwmsSinceStart = dwmsThisVM 
143      *
144      * I tested this, under Windows in enhanced mode, and
145      * if you never switch VM (ie start/stop DOS) these
146      * values should be the same as well. 
147      *
148      * Also, Wine should adjust for the hardware timer
149      * to reduce the amount of error to ~1ms. 
150      * I can't be bothered, can you?
151      */
152     pTimerInfo->dwmsSinceStart = pTimerInfo->dwmsThisVM = GetTickCount();
153     return TRUE;
154 }
155
156 /***********************************************************************
157  *           SystemHeapInfo   (TOOLHELP.71)
158  */
159 BOOL16 WINAPI SystemHeapInfo16( SYSHEAPINFO *pHeapInfo )
160 {
161     WORD user = LoadLibrary16( "USER.EXE" );
162     WORD gdi = LoadLibrary16( "GDI.EXE" );
163     pHeapInfo->wUserFreePercent = (int)LOCAL_CountFree(user) * 100 / LOCAL_HeapSize(user);
164     pHeapInfo->wGDIFreePercent  = (int)LOCAL_CountFree(gdi) * 100 / LOCAL_HeapSize(gdi);
165     pHeapInfo->hUserSegment = user;
166     pHeapInfo->hGDISegment  = gdi;
167     FreeLibrary16( user );
168     FreeLibrary16( gdi );
169     return TRUE;
170 }
171
172
173 /***********************************************************************
174  *           ToolHelpHook                             (KERNEL.341)
175  *      see "Undocumented Windows"
176  */
177 FARPROC16 WINAPI ToolHelpHook16(FARPROC16 lpfnNotifyHandler)
178 {
179         FARPROC16 tmp;
180
181         FIXME("(%p), stub.\n", lpfnNotifyHandler);
182         tmp = HookNotify;
183         HookNotify = lpfnNotifyHandler;
184         /* just return previously installed notification function */
185         return tmp;
186 }
187
188
189 /***********************************************************************
190  *           CreateToolhelp32Snapshot                   (KERNEL32.179)
191  */
192 HANDLE WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process ) 
193 {
194     HANDLE ret;
195
196     TRACE("%lx,%lx\n", flags, process );
197     if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE)))
198     {
199         FIXME("flags %lx not implemented\n", flags );
200         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
201         return INVALID_HANDLE_VALUE;
202     }
203
204     /* Now do the snapshot */
205     SERVER_START_REQ( create_snapshot )
206     {
207         req->flags   = flags & ~TH32CS_INHERIT;
208         req->inherit = (flags & TH32CS_INHERIT) != 0;
209         req->pid     = (void *)process;
210         SERVER_CALL_ERR();
211         ret = req->handle;
212     }
213     SERVER_END_REQ;
214     if (!ret) ret = INVALID_HANDLE_VALUE;
215     return ret;
216 }
217
218
219 /***********************************************************************
220  *              TOOLHELP_Thread32Next
221  *
222  * Implementation of Thread32First/Next
223  */
224 static BOOL TOOLHELP_Thread32Next( HANDLE handle, LPTHREADENTRY32 lpte, BOOL first )
225 {
226     BOOL ret;
227
228     if (lpte->dwSize < sizeof(THREADENTRY32))
229     {
230         SetLastError( ERROR_INSUFFICIENT_BUFFER );
231         ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(THREADENTRY32), lpte->dwSize);
232         return FALSE;
233     }
234     SERVER_START_REQ( next_thread )
235     {
236         req->handle = handle;
237         req->reset = first;
238         if ((ret = !SERVER_CALL_ERR()))
239         {
240             lpte->cntUsage           = req->count;
241             lpte->th32ThreadID       = (DWORD)req->tid;
242             lpte->th32OwnerProcessID = (DWORD)req->pid;
243             lpte->tpBasePri          = req->base_pri;
244             lpte->tpDeltaPri         = req->delta_pri;
245             lpte->dwFlags            = 0;  /* SDK: "reserved; do not use" */
246         }
247     }
248     SERVER_END_REQ;
249     return ret;
250 }
251
252 /***********************************************************************
253  *              Thread32First    (KERNEL32.686)
254  *
255  * Return info about the first thread in a toolhelp32 snapshot
256  */
257 BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
258 {
259     return TOOLHELP_Thread32Next(hSnapshot, lpte, TRUE);
260 }
261
262 /***********************************************************************
263  *              Thread32Next   (KERNEL32.687)
264  *
265  * Return info about the "next" thread in a toolhelp32 snapshot
266  */
267 BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
268 {
269     return TOOLHELP_Thread32Next(hSnapshot, lpte, FALSE);
270 }
271
272 /***********************************************************************
273  *              TOOLHELP_Process32Next
274  *
275  * Implementation of Process32First/Next
276  */
277 static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY32 lppe, BOOL first )
278 {
279     BOOL ret;
280
281     if (lppe->dwSize < sizeof(PROCESSENTRY32))
282     {
283         SetLastError( ERROR_INSUFFICIENT_BUFFER );
284         ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(PROCESSENTRY32), lppe->dwSize);
285         return FALSE;
286     }
287     SERVER_START_REQ( next_process )
288     {
289         req->handle = handle;
290         req->reset = first;
291         if ((ret = !SERVER_CALL_ERR()))
292         {
293             lppe->cntUsage            = req->count;
294             lppe->th32ProcessID       = (DWORD)req->pid;
295             lppe->th32DefaultHeapID   = 0;  /* FIXME */
296             lppe->th32ModuleID        = 0;  /* FIXME */
297             lppe->cntThreads          = req->threads;
298             lppe->th32ParentProcessID = 0;  /* FIXME */
299             lppe->pcPriClassBase      = req->priority;
300             lppe->dwFlags             = -1; /* FIXME */
301             lppe->szExeFile[0]        = 0;  /* FIXME */
302         }
303     }
304     SERVER_END_REQ;
305     return ret;
306 }
307
308
309 /***********************************************************************
310  *              Process32First    (KERNEL32.555)
311  *
312  * Return info about the first process in a toolhelp32 snapshot
313  */
314 BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
315 {
316     return TOOLHELP_Process32Next( hSnapshot, lppe, TRUE );
317 }
318
319 /***********************************************************************
320  *              Process32Next   (KERNEL32.556)
321  *
322  * Return info about the "next" process in a toolhelp32 snapshot
323  */
324 BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
325 {
326     return TOOLHELP_Process32Next( hSnapshot, lppe, FALSE );
327 }
328
329
330 /***********************************************************************
331  *              TOOLHELP_Module32Next
332  *
333  * Implementation of Module32First/Next
334  */
335 static BOOL TOOLHELP_Module32Next( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first )
336 {
337     BOOL ret;
338
339     if (lpme->dwSize < sizeof (MODULEENTRY32))
340     {
341         SetLastError( ERROR_INSUFFICIENT_BUFFER );
342         ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32), lpme->dwSize);
343         return FALSE;
344     }
345     SERVER_START_REQ( next_module )
346     {
347         req->handle = handle;
348         req->reset = first;
349         if ((ret = !SERVER_CALL_ERR()))
350         {
351             lpme->th32ModuleID   = 0;  /* toolhelp internal id, never used */
352             lpme->th32ProcessID  = (DWORD)req->pid;
353             lpme->GlblcntUsage   = 0; /* FIXME */
354             lpme->ProccntUsage   = 0; /* FIXME */ 
355             lpme->modBaseAddr    = req->base;
356             lpme->modBaseSize    = 0; /* FIXME */
357             lpme->hModule        = (DWORD)req->base;
358             lpme->szModule[0]    = 0;  /* FIXME */
359             lpme->szExePath[0]   = 0;  /* FIXME */
360         }
361     }
362     SERVER_END_REQ;
363     return ret;
364 }
365
366 /***********************************************************************
367  *              Module32First   (KERNEL32.527)
368  *
369  * Return info about the "first" module in a toolhelp32 snapshot
370  */
371 BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
372 {
373     return TOOLHELP_Module32Next( hSnapshot, lpme, TRUE );
374 }
375
376 /***********************************************************************
377  *              Module32Next   (KERNEL32.528)
378  *
379  * Return info about the "next" module in a toolhelp32 snapshot
380  */
381 BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
382 {
383     return TOOLHELP_Module32Next( hSnapshot, lpme, FALSE );
384 }
385
386 /************************************************************************
387  *              GlobalMasterHandle16 (KERNEL.28)
388  *
389  *
390  * Should return selector and handle of the information structure for 
391  * the global heap. selector and handle are stored in the THHOOK as
392  * pGlobalHeap and hGlobalHeap.
393  * As Wine doesn't have this structure, we return both values as zero
394  * Applications should interpret this as "No Global Heap"
395  */
396 DWORD WINAPI GlobalMasterHandle16(void)
397 {
398     FIXME(": stub\n");
399     return 0;
400 }