ws2_32/tests: Properly destroy the async test window.
[wine] / dlls / toolhelp.dll16 / toolhelp.c
CommitLineData
c1dbeade
AJ
1/*
2 * Toolhelp functions
3 *
4 * Copyright 1996 Marcus Meissner
5 * Copyright 2009 Alexandre Julliard
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include "config.h"
23
24#define NONAMELESSUNION
25#define NONAMELESSSTRUCT
26#include <stdarg.h>
27#include <stdlib.h>
28#include <string.h>
29#ifdef HAVE_UNISTD_H
30# include <unistd.h>
31#endif
32#include <ctype.h>
33#include <assert.h>
34#include "windef.h"
35#include "winbase.h"
36#include "winternl.h"
37#include "wownt32.h"
38
39#include "wine/winbase16.h"
40#include "toolhelp.h"
41#include "wine/debug.h"
42
43WINE_DEFAULT_DEBUG_CHANNEL(toolhelp);
44
45#include "pshpack1.h"
46
47typedef struct
48{
49 void *base; /* Base address (0 if discarded) */
50 DWORD size; /* Size in bytes (0 indicates a free block) */
51 HGLOBAL16 handle; /* Handle for this block */
52 HGLOBAL16 hOwner; /* Owner of this block */
53 BYTE lockCount; /* Count of GlobalFix() calls */
54 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
55 BYTE flags; /* Allocation flags */
56 BYTE selCount; /* Number of selectors allocated for this block */
57} GLOBALARENA;
58
59#define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */
60
61typedef struct
62{
63 WORD check; /* 00 Heap checking flag */
64 WORD freeze; /* 02 Heap frozen flag */
65 WORD items; /* 04 Count of items on the heap */
66 WORD first; /* 06 First item of the heap */
67 WORD pad1; /* 08 Always 0 */
68 WORD last; /* 0a Last item of the heap */
69 WORD pad2; /* 0c Always 0 */
70 BYTE ncompact; /* 0e Compactions counter */
71 BYTE dislevel; /* 0f Discard level */
72 DWORD distotal; /* 10 Total bytes discarded */
73 WORD htable; /* 14 Pointer to handle table */
74 WORD hfree; /* 16 Pointer to free handle table */
75 WORD hdelta; /* 18 Delta to expand the handle table */
76 WORD expand; /* 1a Pointer to expand function (unused) */
77 WORD pstat; /* 1c Pointer to status structure (unused) */
78 FARPROC16 notify; /* 1e Pointer to LocalNotify() function */
79 WORD lock; /* 22 Lock count for the heap */
80 WORD extra; /* 24 Extra bytes to allocate when expanding */
81 WORD minsize; /* 26 Minimum size of the heap */
82 WORD magic; /* 28 Magic number */
83} LOCALHEAPINFO;
84
85typedef struct
86{
87/* Arena header */
88 WORD prev; /* Previous arena | arena type */
89 WORD next; /* Next arena */
90/* Start of the memory block or free-list info */
91 WORD size; /* Size of the free block */
92 WORD free_prev; /* Previous free block */
93 WORD free_next; /* Next free block */
94} LOCALARENA;
95
96#define LOCAL_ARENA_HEADER_SIZE 4
97#define LOCAL_ARENA_HEADER( handle) ((handle) - LOCAL_ARENA_HEADER_SIZE)
98#define LOCAL_ARENA_PTR(ptr,arena) ((LOCALARENA *)((char *)(ptr)+(arena)))
99
100typedef struct
101{
102 WORD null; /* Always 0 */
103 DWORD old_ss_sp; /* Stack pointer; used by SwitchTaskTo() */
104 WORD heap; /* Pointer to the local heap information (if any) */
105 WORD atomtable; /* Pointer to the local atom table (if any) */
106 WORD stacktop; /* Top of the stack */
107 WORD stackmin; /* Lowest stack address used so far */
108 WORD stackbottom; /* Bottom of the stack */
109} INSTANCEDATA;
110
111typedef struct _THHOOK
112{
113 HANDLE16 hGlobalHeap; /* 00 (handle BURGERMASTER) */
114 WORD pGlobalHeap; /* 02 (selector BURGERMASTER) */
115 HMODULE16 hExeHead; /* 04 hFirstModule */
116 HMODULE16 hExeSweep; /* 06 (unused) */
117 HANDLE16 TopPDB; /* 08 (handle of KERNEL PDB) */
118 HANDLE16 HeadPDB; /* 0A (first PDB in list) */
119 HANDLE16 TopSizePDB; /* 0C (unused) */
120 HTASK16 HeadTDB; /* 0E hFirstTask */
121 HTASK16 CurTDB; /* 10 hCurrentTask */
122 HTASK16 LoadTDB; /* 12 (unused) */
123 HTASK16 LockTDB; /* 14 hLockedTask */
124} THHOOK;
125
126typedef struct _NE_MODULE
127{
128 WORD ne_magic; /* 00 'NE' signature */
129 WORD count; /* 02 Usage count (ne_ver/ne_rev on disk) */
130 WORD ne_enttab; /* 04 Near ptr to entry table */
131 HMODULE16 next; /* 06 Selector to next module (ne_cbenttab on disk) */
132 WORD dgroup_entry; /* 08 Near ptr to segment entry for DGROUP (ne_crc on disk) */
133 WORD fileinfo; /* 0a Near ptr to file info (OFSTRUCT) (ne_crc on disk) */
134 WORD ne_flags; /* 0c Module flags */
135 WORD ne_autodata; /* 0e Logical segment for DGROUP */
136 WORD ne_heap; /* 10 Initial heap size */
137 WORD ne_stack; /* 12 Initial stack size */
138 DWORD ne_csip; /* 14 Initial cs:ip */
139 DWORD ne_sssp; /* 18 Initial ss:sp */
140 WORD ne_cseg; /* 1c Number of segments in segment table */
141 WORD ne_cmod; /* 1e Number of module references */
142 WORD ne_cbnrestab; /* 20 Size of non-resident names table */
143 WORD ne_segtab; /* 22 Near ptr to segment table */
144 WORD ne_rsrctab; /* 24 Near ptr to resource table */
145 WORD ne_restab; /* 26 Near ptr to resident names table */
146 WORD ne_modtab; /* 28 Near ptr to module reference table */
147 WORD ne_imptab; /* 2a Near ptr to imported names table */
148 DWORD ne_nrestab; /* 2c File offset of non-resident names table */
149 WORD ne_cmovent; /* 30 Number of moveable entries in entry table*/
150 WORD ne_align; /* 32 Alignment shift count */
151 WORD ne_cres; /* 34 # of resource segments */
152 BYTE ne_exetyp; /* 36 Operating system flags */
153 BYTE ne_flagsothers; /* 37 Misc. flags */
154 HANDLE16 dlls_to_init; /* 38 List of DLLs to initialize (ne_pretthunks on disk) */
155 HANDLE16 nrname_handle; /* 3a Handle to non-resident name table (ne_psegrefbytes on disk) */
156 WORD ne_swaparea; /* 3c Min. swap area size */
157 WORD ne_expver; /* 3e Expected Windows version */
158 /* From here, these are extra fields not present in normal Windows */
159 HMODULE module32; /* PE module handle for Win32 modules */
160 HMODULE owner32; /* PE module containing this one for 16-bit builtins */
161 HMODULE16 self; /* Handle for this module */
162 WORD self_loading_sel; /* Selector used for self-loading apps. */
163 LPVOID rsrc32_map; /* HRSRC 16->32 map (for 32-bit modules) */
164 LPCVOID mapping; /* mapping of the binary file */
165 SIZE_T mapping_size; /* size of the file mapping */
166} NE_MODULE;
167
168#include "poppack.h"
169
170#define TDB_MAGIC ('T' | ('D' << 8))
171
172/* FIXME: to make this work, we have to call back all these registered
173 * functions from all over the WINE code. Someone with more knowledge than
174 * me please do that. -Marcus
175 */
176
177static struct notify
178{
179 HTASK16 htask;
180 FARPROC16 lpfnCallback;
181 WORD wFlags;
182} *notifys = NULL;
183
184static int nrofnotifys = 0;
185
186static THHOOK *get_thhook(void)
187{
188 static THHOOK *thhook;
189
190 if (!thhook) thhook = MapSL( (SEGPTR)GetProcAddress16( GetModuleHandle16("KERNEL"), (LPCSTR)332 ));
191 return thhook;
192}
193
194static GLOBALARENA *get_global_arena(void)
195{
196 return *(GLOBALARENA **)get_thhook();
197}
198
199static LOCALHEAPINFO *get_local_heap( HANDLE16 ds )
200{
201 INSTANCEDATA *ptr = MapSL( MAKESEGPTR( ds, 0 ));
202
203 if (!ptr || !ptr->heap) return NULL;
204 return (LOCALHEAPINFO*)((char*)ptr + ptr->heap);
205}
206
207
208/***********************************************************************
209 * GlobalHandleToSel (TOOLHELP.50)
210 */
211WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle )
212{
213 if (!handle) return 0;
214 if (!(handle & 7)) return handle - 1;
215 return handle | 7;
216}
217
218
219/***********************************************************************
220 * GlobalFirst (TOOLHELP.51)
221 */
222BOOL16 WINAPI GlobalFirst16( GLOBALENTRY *pGlobal, WORD wFlags )
223{
224 if (wFlags == GLOBAL_LRU) return FALSE;
225 pGlobal->dwNext = 0;
226 return GlobalNext16( pGlobal, wFlags );
227}
228
229
230/***********************************************************************
231 * GlobalNext (TOOLHELP.52)
232 */
233BOOL16 WINAPI GlobalNext16( GLOBALENTRY *pGlobal, WORD wFlags)
234{
235 GLOBALARENA *pGlobalArena = get_global_arena();
236 GLOBALARENA *pArena;
237
238 if (pGlobal->dwNext >= GLOBAL_MAX_COUNT) return FALSE;
239 pArena = pGlobalArena + pGlobal->dwNext;
240 if (wFlags == GLOBAL_FREE) /* only free blocks */
241 {
242 int i;
243 for (i = pGlobal->dwNext; i < GLOBAL_MAX_COUNT; i++, pArena++)
244 if (pArena->size == 0) break; /* block is free */
245 if (i >= GLOBAL_MAX_COUNT) return FALSE;
246 pGlobal->dwNext = i;
247 }
248
249 pGlobal->dwAddress = (DWORD_PTR)pArena->base;
250 pGlobal->dwBlockSize = pArena->size;
251 pGlobal->hBlock = pArena->handle;
252 pGlobal->wcLock = pArena->lockCount;
253 pGlobal->wcPageLock = pArena->pageLockCount;
254 pGlobal->wFlags = (GetCurrentPDB16() == pArena->hOwner);
255 pGlobal->wHeapPresent = FALSE;
256 pGlobal->hOwner = pArena->hOwner;
257 pGlobal->wType = GT_UNKNOWN;
258 pGlobal->wData = 0;
259 pGlobal->dwNext++;
260 return TRUE;
261}
262
263
264/***********************************************************************
265 * GlobalInfo (TOOLHELP.53)
266 */
267BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo )
268{
269 GLOBALARENA *pGlobalArena = get_global_arena();
270 GLOBALARENA *pArena;
271 int i;
272
273 pInfo->wcItems = GLOBAL_MAX_COUNT;
274 pInfo->wcItemsFree = 0;
275 pInfo->wcItemsLRU = 0;
276 for (i = 0, pArena = pGlobalArena; i < GLOBAL_MAX_COUNT; i++, pArena++)
277 if (pArena->size == 0) pInfo->wcItemsFree++;
278 return TRUE;
279}
280
281
282/***********************************************************************
283 * GlobalEntryHandle (TOOLHELP.54)
284 */
285BOOL16 WINAPI GlobalEntryHandle16( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
286{
287 GLOBALARENA *pGlobalArena = get_global_arena();
288 GLOBALARENA *pArena = pGlobalArena + (hItem >> __AHSHIFT);
289
290 pGlobal->dwAddress = (DWORD_PTR)pArena->base;
291 pGlobal->dwBlockSize = pArena->size;
292 pGlobal->hBlock = pArena->handle;
293 pGlobal->wcLock = pArena->lockCount;
294 pGlobal->wcPageLock = pArena->pageLockCount;
295 pGlobal->wFlags = (GetCurrentPDB16() == pArena->hOwner);
296 pGlobal->wHeapPresent = FALSE;
297 pGlobal->hOwner = pArena->hOwner;
298 pGlobal->wType = GT_UNKNOWN;
299 pGlobal->wData = 0;
300 pGlobal->dwNext++;
301 return TRUE;
302}
303
304
305/***********************************************************************
306 * GlobalEntryModule (TOOLHELP.55)
307 */
308BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule,
309 WORD wSeg )
310{
311 FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg);
312 return FALSE;
313}
314
315
316/***********************************************************************
317 * LocalInfo (TOOLHELP.56)
318 */
319BOOL16 WINAPI LocalInfo16( LOCALINFO *pLocalInfo, HGLOBAL16 handle )
320{
321 LOCALHEAPINFO *pInfo = get_local_heap( SELECTOROF(WOWGlobalLock16(handle)) );
322 if (!pInfo) return FALSE;
323 pLocalInfo->wcItems = pInfo->items;
324 return TRUE;
325}
326
327
328/***********************************************************************
329 * LocalFirst (TOOLHELP.57)
330 */
331BOOL16 WINAPI LocalFirst16( LOCALENTRY *pLocalEntry, HGLOBAL16 handle )
332{
333 WORD ds = GlobalHandleToSel16( handle );
334 char *ptr = MapSL( MAKESEGPTR( ds, 0 ) );
335 LOCALHEAPINFO *pInfo = get_local_heap( ds );
336 if (!pInfo) return FALSE;
337
338 pLocalEntry->hHandle = pInfo->first + LOCAL_ARENA_HEADER_SIZE;
339 pLocalEntry->wAddress = pLocalEntry->hHandle;
340 pLocalEntry->wFlags = LF_FIXED;
341 pLocalEntry->wcLock = 0;
342 pLocalEntry->wType = LT_NORMAL;
343 pLocalEntry->hHeap = handle;
344 pLocalEntry->wHeapType = NORMAL_HEAP;
345 pLocalEntry->wNext = LOCAL_ARENA_PTR(ptr,pInfo->first)->next;
346 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
347 return TRUE;
348}
349
350
351/***********************************************************************
352 * LocalNext (TOOLHELP.58)
353 */
354BOOL16 WINAPI LocalNext16( LOCALENTRY *pLocalEntry )
355{
356 WORD ds = GlobalHandleToSel16( pLocalEntry->hHeap );
357 char *ptr = MapSL( MAKESEGPTR( ds, 0 ) );
358 LOCALARENA *pArena;
359
360 if (!get_local_heap( ds )) return FALSE;
361 if (!pLocalEntry->wNext) return FALSE;
362 pArena = LOCAL_ARENA_PTR( ptr, pLocalEntry->wNext );
363
364 pLocalEntry->hHandle = pLocalEntry->wNext + LOCAL_ARENA_HEADER_SIZE;
365 pLocalEntry->wAddress = pLocalEntry->hHandle;
366 pLocalEntry->wFlags = (pArena->prev & 3) + 1;
367 pLocalEntry->wcLock = 0;
368 pLocalEntry->wType = LT_NORMAL;
369 if (pArena->next != pLocalEntry->wNext) /* last one? */
370 pLocalEntry->wNext = pArena->next;
371 else
372 pLocalEntry->wNext = 0;
373 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
374 return TRUE;
375}
376
377
378/**********************************************************************
379 * ModuleFirst (TOOLHELP.59)
380 */
381BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme )
382{
383 lpme->wNext = get_thhook()->hExeHead;
384 return ModuleNext16( lpme );
385}
386
387
388/**********************************************************************
389 * ModuleNext (TOOLHELP.60)
390 */
391BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme )
392{
393 NE_MODULE *pModule;
394 char *name;
395
396 if (!lpme->wNext) return FALSE;
397 if (!(pModule = GlobalLock16( GetExePtr(lpme->wNext) ))) return FALSE;
398 name = (char *)pModule + pModule->ne_restab;
399 memcpy( lpme->szModule, name + 1, min(*name, MAX_MODULE_NAME) );
400 lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0';
401 lpme->hModule = lpme->wNext;
402 lpme->wcUsage = pModule->count;
403 name = ((OFSTRUCT *)((char*)pModule + pModule->fileinfo))->szPathName;
404 lstrcpynA( lpme->szExePath, name, sizeof(lpme->szExePath) );
405 lpme->wNext = pModule->next;
406 return TRUE;
407}
408
409
410/**********************************************************************
411 * ModuleFindName (TOOLHELP.61)
412 */
413BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name )
414{
415 lpme->wNext = GetModuleHandle16( name );
416 return ModuleNext16( lpme );
417}
418
419
420/**********************************************************************
421 * ModuleFindHandle (TOOLHELP.62)
422 */
423BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule )
424{
425 hModule = GetExePtr( hModule );
426 lpme->wNext = hModule;
427 return ModuleNext16( lpme );
428}
429
430
431/***********************************************************************
432 * TaskFirst (TOOLHELP.63)
433 */
434BOOL16 WINAPI TaskFirst16( TASKENTRY *lpte )
435{
436 lpte->hNext = get_thhook()->HeadTDB;
437 return TaskNext16( lpte );
438}
439
440
441/***********************************************************************
442 * TaskNext (TOOLHELP.64)
443 */
444BOOL16 WINAPI TaskNext16( TASKENTRY *lpte )
445{
446 TDB *pTask;
447 INSTANCEDATA *pInstData;
448
449 TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext );
450 if (!lpte->hNext) return FALSE;
451
452 /* make sure that task and hInstance are valid (skip initial Wine task !) */
453 while (1) {
454 pTask = GlobalLock16( lpte->hNext );
455 if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
456 if (pTask->hInstance)
457 break;
458 lpte->hNext = pTask->hNext;
459 }
460 pInstData = MapSL( MAKESEGPTR( GlobalHandleToSel16(pTask->hInstance), 0 ) );
461 lpte->hTask = lpte->hNext;
462 lpte->hTaskParent = pTask->hParent;
463 lpte->hInst = pTask->hInstance;
464 lpte->hModule = pTask->hModule;
465 lpte->wSS = SELECTOROF( pTask->teb->WOW32Reserved );
466 lpte->wSP = OFFSETOF( pTask->teb->WOW32Reserved );
467 lpte->wStackTop = pInstData->stacktop;
468 lpte->wStackMinimum = pInstData->stackmin;
469 lpte->wStackBottom = pInstData->stackbottom;
470 lpte->wcEvents = pTask->nEvents;
471 lpte->hQueue = pTask->hQueue;
472 lstrcpynA( lpte->szModule, pTask->module_name, sizeof(lpte->szModule) );
473 lpte->wPSPOffset = 0x100; /*??*/
474 lpte->hNext = pTask->hNext;
475 return TRUE;
476}
477
478
479/***********************************************************************
480 * TaskFindHandle (TOOLHELP.65)
481 */
482BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask )
483{
484 lpte->hNext = hTask;
485 return TaskNext16( lpte );
486}
487
488
489/***********************************************************************
490 * MemManInfo (TOOLHELP.72)
491 */
492BOOL16 WINAPI MemManInfo16( MEMMANINFO *info )
493{
494 MEMORYSTATUS status;
495
496 /*
497 * Not unsurprisingly although the documentation says you
498 * _must_ provide the size in the dwSize field, this function
499 * (under Windows) always fills the structure and returns true.
500 */
501 GlobalMemoryStatus( &status );
502 info->wPageSize = getpagesize();
503 info->dwLargestFreeBlock = status.dwAvailVirtual;
504 info->dwMaxPagesAvailable = info->dwLargestFreeBlock / info->wPageSize;
505 info->dwMaxPagesLockable = info->dwMaxPagesAvailable;
506 info->dwTotalLinearSpace = status.dwTotalVirtual / info->wPageSize;
507 info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
508 info->dwFreePages = info->dwMaxPagesAvailable;
509 info->dwTotalPages = info->dwTotalLinearSpace;
510 info->dwFreeLinearSpace = info->dwMaxPagesAvailable;
511 info->dwSwapFilePages = status.dwTotalPageFile / info->wPageSize;
512 return TRUE;
513}
514
515
516/***********************************************************************
517 * NotifyRegister (TOOLHELP.73)
518 */
519BOOL16 WINAPI NotifyRegister16( HTASK16 htask, FARPROC16 lpfnCallback,
520 WORD wFlags )
521{
522 int i;
523
524 FIXME("(%x,%x,%x), semi-stub.\n",
525 htask, (DWORD)lpfnCallback, wFlags );
526 if (!htask) htask = GetCurrentTask();
527 for (i=0;i<nrofnotifys;i++)
528 if (notifys[i].htask==htask)
529 break;
530 if (i==nrofnotifys) {
531 if (notifys==NULL)
532 notifys=HeapAlloc( GetProcessHeap(), 0,
533 sizeof(struct notify) );
534 else
535 notifys=HeapReAlloc( GetProcessHeap(), 0, notifys,
536 sizeof(struct notify)*(nrofnotifys+1));
537 if (!notifys) return FALSE;
538 nrofnotifys++;
539 }
540 notifys[i].htask=htask;
541 notifys[i].lpfnCallback=lpfnCallback;
542 notifys[i].wFlags=wFlags;
543 return TRUE;
544}
545
546/***********************************************************************
547 * NotifyUnregister (TOOLHELP.74)
548 */
549BOOL16 WINAPI NotifyUnregister16( HTASK16 htask )
550{
551 int i;
552
553 FIXME("(%x), semi-stub.\n", htask );
554 if (!htask) htask = GetCurrentTask();
555 for (i=nrofnotifys;i--;)
556 if (notifys[i].htask==htask)
557 break;
558 if (i==-1)
559 return FALSE;
560 memcpy(notifys+i,notifys+(i+1),sizeof(struct notify)*(nrofnotifys-i-1));
561 notifys=HeapReAlloc( GetProcessHeap(), 0, notifys,
562 (nrofnotifys-1)*sizeof(struct notify));
563 nrofnotifys--;
564 return TRUE;
565}
566
567/***********************************************************************
568 * StackTraceCSIPFirst (TOOLHELP.67)
569 */
570BOOL16 WINAPI StackTraceCSIPFirst16(STACKTRACEENTRY *ste, WORD wSS, WORD wCS, WORD wIP, WORD wBP)
571{
572 FIXME("(%p, ss %04x, cs %04x, ip %04x, bp %04x): stub.\n", ste, wSS, wCS, wIP, wBP);
573 return TRUE;
574}
575
576/***********************************************************************
577 * StackTraceFirst (TOOLHELP.66)
578 */
579BOOL16 WINAPI StackTraceFirst16(STACKTRACEENTRY *ste, HTASK16 Task)
580{
581 FIXME("(%p, %04x), stub.\n", ste, Task);
582 return TRUE;
583}
584
585/***********************************************************************
586 * StackTraceNext (TOOLHELP.68)
587 */
588BOOL16 WINAPI StackTraceNext16(STACKTRACEENTRY *ste)
589{
590 FIXME("(%p), stub.\n", ste);
591 return TRUE;
592}
593
594/***********************************************************************
595 * InterruptRegister (TOOLHELP.75)
596 */
597BOOL16 WINAPI InterruptRegister16( HTASK16 task, FARPROC callback )
598{
599 FIXME("(%04x, %p), stub.\n", task, callback);
600 return TRUE;
601}
602
603/***********************************************************************
604 * InterruptUnRegister (TOOLHELP.76)
605 */
606BOOL16 WINAPI InterruptUnRegister16( HTASK16 task )
607{
608 FIXME("(%04x), stub.\n", task);
609 return TRUE;
610}
611
612/***********************************************************************
613 * TerminateApp (TOOLHELP.77)
614 *
615 * See "Undocumented Windows".
616 */
617void WINAPI TerminateApp16(HTASK16 hTask, WORD wFlags)
618{
619 if (hTask && hTask != GetCurrentTask())
620 {
621 FIXME("cannot terminate task %x\n", hTask);
622 return;
623 }
624
625#if 0 /* FIXME */
626 /* check undocumented flag */
627 if (!(wFlags & 0x8000))
628 TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
629#endif
630
631 /* UndocWin says to call int 0x21/0x4c exit=0xff here,
632 but let's just call ExitThread */
633 ExitThread(0xff);
634}
635
636/***********************************************************************
637 * MemoryRead (TOOLHELP.78)
638 */
639DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count )
640{
641 LDT_ENTRY entry;
642 DWORD limit;
643
644 wine_ldt_get_entry( sel, &entry );
645 if (wine_ldt_is_empty( &entry )) return 0;
646 limit = wine_ldt_get_limit( &entry );
647 if (offset > limit) return 0;
648 if (offset + count > limit + 1) count = limit + 1 - offset;
649 memcpy( buffer, (char *)wine_ldt_get_base(&entry) + offset, count );
650 return count;
651}
652
653
654/***********************************************************************
655 * MemoryWrite (TOOLHELP.79)
656 */
657DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
658{
659 LDT_ENTRY entry;
660 DWORD limit;
661
662 wine_ldt_get_entry( sel, &entry );
663 if (wine_ldt_is_empty( &entry )) return 0;
664 limit = wine_ldt_get_limit( &entry );
665 if (offset > limit) return 0;
666 if (offset + count > limit) count = limit + 1 - offset;
667 memcpy( (char *)wine_ldt_get_base(&entry) + offset, buffer, count );
668 return count;
669}
670
671/***********************************************************************
672 * TimerCount (TOOLHELP.80)
673 */
674BOOL16 WINAPI TimerCount16( TIMERINFO *pTimerInfo )
675{
676 /* FIXME
677 * In standard mode, dwmsSinceStart = dwmsThisVM
678 *
679 * I tested this, under Windows in enhanced mode, and
680 * if you never switch VM (ie start/stop DOS) these
681 * values should be the same as well.
682 *
683 * Also, Wine should adjust for the hardware timer
684 * to reduce the amount of error to ~1ms.
685 * I can't be bothered, can you?
686 */
687 pTimerInfo->dwmsSinceStart = pTimerInfo->dwmsThisVM = GetTickCount();
688 return TRUE;
689}
690
691/***********************************************************************
692 * SystemHeapInfo (TOOLHELP.71)
693 */
694BOOL16 WINAPI SystemHeapInfo16( SYSHEAPINFO *pHeapInfo )
695{
696 STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
697 HANDLE16 oldDS = stack16->ds;
698 WORD user = LoadLibrary16( "USER.EXE" );
699 WORD gdi = LoadLibrary16( "GDI.EXE" );
700 stack16->ds = user;
701 pHeapInfo->wUserFreePercent = (int)LocalCountFree16() * 100 / LocalHeapSize16();
702 stack16->ds = gdi;
703 pHeapInfo->wGDIFreePercent = (int)LocalCountFree16() * 100 / LocalHeapSize16();
704 stack16->ds = oldDS;
705 pHeapInfo->hUserSegment = user;
706 pHeapInfo->hGDISegment = gdi;
707 FreeLibrary16( user );
708 FreeLibrary16( gdi );
709 return TRUE;
710}
711
712/***********************************************************************
713 * Local32Info (TOOLHELP.84)
714 */
715BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
716{
717 FIXME( "Call Local32Info16 in kernel\n" );
718 return FALSE;
719}
720
721/***********************************************************************
722 * Local32First (TOOLHELP.85)
723 */
724BOOL16 WINAPI Local32First16( LOCAL32ENTRY *pLocal32Entry, HGLOBAL16 handle )
725{
726 FIXME( "Call Local32First16 in kernel\n" );
727 return FALSE;
728}
729
730/***********************************************************************
731 * Local32Next (TOOLHELP.86)
732 */
733BOOL16 WINAPI Local32Next16( LOCAL32ENTRY *pLocal32Entry )
734{
735 FIXME( "Call Local32Next16 in kernel\n" );
736 return FALSE;
737}