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