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