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