ntdll: Rename local variables in heap_reallocate.
[wine.git] / dlls / toolhelp.dll16 / toolhelp.c
blob1bec37c505ec0e458938d0bca2f85743d524363e
1 /*
2 * Toolhelp functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 2009 Alexandre Julliard
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.
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.
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
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <assert.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winternl.h"
30 #include "wownt32.h"
32 #include "wine/winbase16.h"
33 #include "toolhelp.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp);
38 #include "pshpack1.h"
40 typedef struct
42 void *base; /* Base address (0 if discarded) */
43 DWORD size; /* Size in bytes (0 indicates a free block) */
44 HGLOBAL16 handle; /* Handle for this block */
45 HGLOBAL16 hOwner; /* Owner of this block */
46 BYTE lockCount; /* Count of GlobalFix() calls */
47 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
48 BYTE flags; /* Allocation flags */
49 BYTE selCount; /* Number of selectors allocated for this block */
50 } GLOBALARENA;
52 #define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */
54 typedef struct
56 WORD check; /* 00 Heap checking flag */
57 WORD freeze; /* 02 Heap frozen flag */
58 WORD items; /* 04 Count of items on the heap */
59 WORD first; /* 06 First item of the heap */
60 WORD pad1; /* 08 Always 0 */
61 WORD last; /* 0a Last item of the heap */
62 WORD pad2; /* 0c Always 0 */
63 BYTE ncompact; /* 0e Compactions counter */
64 BYTE dislevel; /* 0f Discard level */
65 DWORD distotal; /* 10 Total bytes discarded */
66 WORD htable; /* 14 Pointer to handle table */
67 WORD hfree; /* 16 Pointer to free handle table */
68 WORD hdelta; /* 18 Delta to expand the handle table */
69 WORD expand; /* 1a Pointer to expand function (unused) */
70 WORD pstat; /* 1c Pointer to status structure (unused) */
71 FARPROC16 notify; /* 1e Pointer to LocalNotify() function */
72 WORD lock; /* 22 Lock count for the heap */
73 WORD extra; /* 24 Extra bytes to allocate when expanding */
74 WORD minsize; /* 26 Minimum size of the heap */
75 WORD magic; /* 28 Magic number */
76 } LOCALHEAPINFO;
78 typedef struct
80 /* Arena header */
81 WORD prev; /* Previous arena | arena type */
82 WORD next; /* Next arena */
83 /* Start of the memory block or free-list info */
84 WORD size; /* Size of the free block */
85 WORD free_prev; /* Previous free block */
86 WORD free_next; /* Next free block */
87 } LOCALARENA;
89 #define LOCAL_ARENA_HEADER_SIZE 4
90 #define LOCAL_ARENA_HEADER( handle) ((handle) - LOCAL_ARENA_HEADER_SIZE)
91 #define LOCAL_ARENA_PTR(ptr,arena) ((LOCALARENA *)((char *)(ptr)+(arena)))
93 #define MOVEABLE_PREFIX sizeof(HLOCAL16)
95 /* Layout of a handle entry table
97 * WORD count of entries
98 * LOCALHANDLEENTRY[count] entries
99 * WORD near ptr to next table
101 typedef struct
103 WORD addr; /* Address of the MOVEABLE block */
104 BYTE flags; /* Flags for this block */
105 BYTE lock; /* Lock count */
106 } LOCALHANDLEENTRY;
109 typedef struct
111 WORD null; /* Always 0 */
112 DWORD old_ss_sp; /* Stack pointer; used by SwitchTaskTo() */
113 WORD heap; /* Pointer to the local heap information (if any) */
114 WORD atomtable; /* Pointer to the local atom table (if any) */
115 WORD stacktop; /* Top of the stack */
116 WORD stackmin; /* Lowest stack address used so far */
117 WORD stackbottom; /* Bottom of the stack */
118 } INSTANCEDATA;
120 typedef struct _THHOOK
122 HANDLE16 hGlobalHeap; /* 00 (handle BURGERMASTER) */
123 WORD pGlobalHeap; /* 02 (selector BURGERMASTER) */
124 HMODULE16 hExeHead; /* 04 hFirstModule */
125 HMODULE16 hExeSweep; /* 06 (unused) */
126 HANDLE16 TopPDB; /* 08 (handle of KERNEL PDB) */
127 HANDLE16 HeadPDB; /* 0A (first PDB in list) */
128 HANDLE16 TopSizePDB; /* 0C (unused) */
129 HTASK16 HeadTDB; /* 0E hFirstTask */
130 HTASK16 CurTDB; /* 10 hCurrentTask */
131 HTASK16 LoadTDB; /* 12 (unused) */
132 HTASK16 LockTDB; /* 14 hLockedTask */
133 } THHOOK;
135 typedef struct _NE_MODULE
137 WORD ne_magic; /* 00 'NE' signature */
138 WORD count; /* 02 Usage count (ne_ver/ne_rev on disk) */
139 WORD ne_enttab; /* 04 Near ptr to entry table */
140 HMODULE16 next; /* 06 Selector to next module (ne_cbenttab on disk) */
141 WORD dgroup_entry; /* 08 Near ptr to segment entry for DGROUP (ne_crc on disk) */
142 WORD fileinfo; /* 0a Near ptr to file info (OFSTRUCT) (ne_crc on disk) */
143 WORD ne_flags; /* 0c Module flags */
144 WORD ne_autodata; /* 0e Logical segment for DGROUP */
145 WORD ne_heap; /* 10 Initial heap size */
146 WORD ne_stack; /* 12 Initial stack size */
147 DWORD ne_csip; /* 14 Initial cs:ip */
148 DWORD ne_sssp; /* 18 Initial ss:sp */
149 WORD ne_cseg; /* 1c Number of segments in segment table */
150 WORD ne_cmod; /* 1e Number of module references */
151 WORD ne_cbnrestab; /* 20 Size of non-resident names table */
152 WORD ne_segtab; /* 22 Near ptr to segment table */
153 WORD ne_rsrctab; /* 24 Near ptr to resource table */
154 WORD ne_restab; /* 26 Near ptr to resident names table */
155 WORD ne_modtab; /* 28 Near ptr to module reference table */
156 WORD ne_imptab; /* 2a Near ptr to imported names table */
157 DWORD ne_nrestab; /* 2c File offset of non-resident names table */
158 WORD ne_cmovent; /* 30 Number of moveable entries in entry table*/
159 WORD ne_align; /* 32 Alignment shift count */
160 WORD ne_cres; /* 34 # of resource segments */
161 BYTE ne_exetyp; /* 36 Operating system flags */
162 BYTE ne_flagsothers; /* 37 Misc. flags */
163 HANDLE16 dlls_to_init; /* 38 List of DLLs to initialize (ne_pretthunks on disk) */
164 HANDLE16 nrname_handle; /* 3a Handle to non-resident name table (ne_psegrefbytes on disk) */
165 WORD ne_swaparea; /* 3c Min. swap area size */
166 WORD ne_expver; /* 3e Expected Windows version */
167 /* From here, these are extra fields not present in normal Windows */
168 HMODULE module32; /* PE module handle for Win32 modules */
169 HMODULE owner32; /* PE module containing this one for 16-bit builtins */
170 HMODULE16 self; /* Handle for this module */
171 WORD self_loading_sel; /* Selector used for self-loading apps. */
172 LPVOID rsrc32_map; /* HRSRC 16->32 map (for 32-bit modules) */
173 LPCVOID mapping; /* mapping of the binary file */
174 SIZE_T mapping_size; /* size of the file mapping */
175 } NE_MODULE;
177 #include "poppack.h"
179 #define TDB_MAGIC ('T' | ('D' << 8))
181 /* FIXME: to make this work, we have to call back all these registered
182 * functions from all over the WINE code. Someone with more knowledge than
183 * me please do that. -Marcus
186 static struct notify
188 HTASK16 htask;
189 FARPROC16 lpfnCallback;
190 WORD wFlags;
191 } *notifys = NULL;
193 static int nrofnotifys = 0;
195 static THHOOK *get_thhook(void)
197 static THHOOK *thhook;
199 if (!thhook) thhook = MapSL( (SEGPTR)GetProcAddress16( GetModuleHandle16("KERNEL"), (LPCSTR)332 ));
200 return thhook;
203 static GLOBALARENA *get_global_arena(void)
205 return *(GLOBALARENA **)get_thhook();
208 static LOCALHEAPINFO *get_local_heap( HANDLE16 ds )
210 INSTANCEDATA *ptr = MapSL( MAKESEGPTR( ds, 0 ));
212 if (!ptr || !ptr->heap) return NULL;
213 return (LOCALHEAPINFO*)((char*)ptr + ptr->heap);
217 /***********************************************************************
218 * GlobalHandleToSel (TOOLHELP.50)
220 WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle )
222 if (!handle) return 0;
223 if (!(handle & 7)) return handle - 1;
224 return handle | 7;
228 /***********************************************************************
229 * GlobalFirst (TOOLHELP.51)
231 BOOL16 WINAPI GlobalFirst16( GLOBALENTRY *pGlobal, WORD wFlags )
233 if (wFlags == GLOBAL_LRU) return FALSE;
234 pGlobal->dwNext = 0;
235 return GlobalNext16( pGlobal, wFlags );
239 /***********************************************************************
240 * GlobalNext (TOOLHELP.52)
242 BOOL16 WINAPI GlobalNext16( GLOBALENTRY *pGlobal, WORD wFlags)
244 GLOBALARENA *pGlobalArena = get_global_arena();
245 GLOBALARENA *pArena;
247 if (pGlobal->dwNext >= GLOBAL_MAX_COUNT) return FALSE;
248 pArena = pGlobalArena + pGlobal->dwNext;
249 if (wFlags == GLOBAL_FREE) /* only free blocks */
251 int i;
252 for (i = pGlobal->dwNext; i < GLOBAL_MAX_COUNT; i++, pArena++)
253 if (pArena->size == 0) break; /* block is free */
254 if (i >= GLOBAL_MAX_COUNT) return FALSE;
255 pGlobal->dwNext = i;
258 pGlobal->dwAddress = (DWORD_PTR)pArena->base;
259 pGlobal->dwBlockSize = pArena->size;
260 pGlobal->hBlock = pArena->handle;
261 pGlobal->wcLock = pArena->lockCount;
262 pGlobal->wcPageLock = pArena->pageLockCount;
263 pGlobal->wFlags = (GetCurrentPDB16() == pArena->hOwner);
264 pGlobal->wHeapPresent = FALSE;
265 pGlobal->hOwner = pArena->hOwner;
266 pGlobal->wType = GT_UNKNOWN;
267 pGlobal->wData = 0;
268 pGlobal->dwNext++;
269 return TRUE;
273 /***********************************************************************
274 * GlobalInfo (TOOLHELP.53)
276 BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo )
278 GLOBALARENA *pGlobalArena = get_global_arena();
279 GLOBALARENA *pArena;
280 int i;
282 pInfo->wcItems = GLOBAL_MAX_COUNT;
283 pInfo->wcItemsFree = 0;
284 pInfo->wcItemsLRU = 0;
285 for (i = 0, pArena = pGlobalArena; i < GLOBAL_MAX_COUNT; i++, pArena++)
286 if (pArena->size == 0) pInfo->wcItemsFree++;
287 return TRUE;
291 /***********************************************************************
292 * GlobalEntryHandle (TOOLHELP.54)
294 BOOL16 WINAPI GlobalEntryHandle16( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
296 GLOBALARENA *pGlobalArena = get_global_arena();
297 GLOBALARENA *pArena = pGlobalArena + (hItem >> __AHSHIFT);
299 pGlobal->dwAddress = (DWORD_PTR)pArena->base;
300 pGlobal->dwBlockSize = pArena->size;
301 pGlobal->hBlock = pArena->handle;
302 pGlobal->wcLock = pArena->lockCount;
303 pGlobal->wcPageLock = pArena->pageLockCount;
304 pGlobal->wFlags = (GetCurrentPDB16() == pArena->hOwner);
305 pGlobal->wHeapPresent = FALSE;
306 pGlobal->hOwner = pArena->hOwner;
307 pGlobal->wType = GT_UNKNOWN;
308 pGlobal->wData = 0;
309 pGlobal->dwNext++;
310 return TRUE;
314 /***********************************************************************
315 * GlobalEntryModule (TOOLHELP.55)
317 BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule,
318 WORD wSeg )
320 FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg);
321 return FALSE;
325 /***********************************************************************
326 * LocalInfo (TOOLHELP.56)
328 BOOL16 WINAPI LocalInfo16( LOCALINFO *pLocalInfo, HGLOBAL16 handle )
330 LOCALHEAPINFO *pInfo = get_local_heap( SELECTOROF(WOWGlobalLock16(handle)) );
331 if (!pInfo) return FALSE;
332 pLocalInfo->wcItems = pInfo->items;
333 return TRUE;
337 /***********************************************************************
338 * LocalFirst (TOOLHELP.57)
340 BOOL16 WINAPI LocalFirst16( LOCALENTRY *pLocalEntry, HGLOBAL16 handle )
342 WORD ds = GlobalHandleToSel16( handle );
343 char *ptr = MapSL( MAKESEGPTR( ds, 0 ) );
344 LOCALHEAPINFO *pInfo = get_local_heap( ds );
345 if (!pInfo) return FALSE;
347 pLocalEntry->hHandle = pInfo->first + LOCAL_ARENA_HEADER_SIZE;
348 pLocalEntry->wAddress = pLocalEntry->hHandle;
349 pLocalEntry->wFlags = LF_FIXED;
350 pLocalEntry->wcLock = 0;
351 pLocalEntry->wType = LT_NORMAL;
352 pLocalEntry->hHeap = handle;
353 pLocalEntry->wHeapType = NORMAL_HEAP;
354 pLocalEntry->wNext = LOCAL_ARENA_PTR(ptr,pInfo->first)->next;
355 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
356 return TRUE;
360 /***********************************************************************
361 * LocalNext (TOOLHELP.58)
363 BOOL16 WINAPI LocalNext16( LOCALENTRY *pLocalEntry )
365 WORD ds = GlobalHandleToSel16( pLocalEntry->hHeap );
366 char *ptr = MapSL( MAKESEGPTR( ds, 0 ) );
367 LOCALARENA *pArena;
368 WORD table, lhandle;
369 LOCALHEAPINFO *pInfo = get_local_heap( ds );
371 if (!pInfo) return FALSE;
372 if (!pLocalEntry->wNext) return FALSE;
373 table = pInfo->htable;
374 pArena = LOCAL_ARENA_PTR( ptr, pLocalEntry->wNext );
375 pLocalEntry->wAddress = pLocalEntry->wNext + LOCAL_ARENA_HEADER_SIZE;
376 pLocalEntry->wFlags = (pArena->prev & 3) + 1;
377 pLocalEntry->wcLock = 0;
378 /* Find the address in the entry tables */
379 lhandle = pLocalEntry->wAddress;
380 while (table)
382 WORD count = *(WORD *)(ptr + table);
383 LOCALHANDLEENTRY *pEntry = (LOCALHANDLEENTRY*)(ptr+table+sizeof(WORD));
384 for (; count > 0; count--, pEntry++)
385 if (pEntry->addr == lhandle + MOVEABLE_PREFIX)
387 lhandle = (HLOCAL16)((char *)pEntry - ptr);
388 table = 0;
389 pLocalEntry->wAddress = pEntry->addr;
390 pLocalEntry->wFlags = pEntry->flags;
391 pLocalEntry->wcLock = pEntry->lock;
392 break;
394 if (table) table = *(WORD *)pEntry;
396 pLocalEntry->hHandle = lhandle;
397 pLocalEntry->wType = LT_NORMAL;
398 if (pArena->next != pLocalEntry->wNext) /* last one? */
399 pLocalEntry->wNext = pArena->next;
400 else
401 pLocalEntry->wNext = 0;
402 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
403 return TRUE;
407 /**********************************************************************
408 * ModuleFirst (TOOLHELP.59)
410 BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme )
412 lpme->wNext = get_thhook()->hExeHead;
413 return ModuleNext16( lpme );
417 /**********************************************************************
418 * ModuleNext (TOOLHELP.60)
420 BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme )
422 NE_MODULE *pModule;
423 char *name;
425 if (!lpme->wNext) return FALSE;
426 if (!(pModule = GlobalLock16( GetExePtr(lpme->wNext) ))) return FALSE;
427 name = (char *)pModule + pModule->ne_restab;
428 memcpy( lpme->szModule, name + 1, min(*name, MAX_MODULE_NAME) );
429 lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0';
430 lpme->hModule = lpme->wNext;
431 lpme->wcUsage = pModule->count;
432 name = ((OFSTRUCT *)((char*)pModule + pModule->fileinfo))->szPathName;
433 lstrcpynA( lpme->szExePath, name, sizeof(lpme->szExePath) );
434 lpme->wNext = pModule->next;
435 return TRUE;
439 /**********************************************************************
440 * ModuleFindName (TOOLHELP.61)
442 BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name )
444 lpme->wNext = GetModuleHandle16( name );
445 return ModuleNext16( lpme );
449 /**********************************************************************
450 * ModuleFindHandle (TOOLHELP.62)
452 BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule )
454 hModule = GetExePtr( hModule );
455 lpme->wNext = hModule;
456 return ModuleNext16( lpme );
460 /***********************************************************************
461 * TaskFirst (TOOLHELP.63)
463 BOOL16 WINAPI TaskFirst16( TASKENTRY *lpte )
465 lpte->hNext = get_thhook()->HeadTDB;
466 return TaskNext16( lpte );
470 /***********************************************************************
471 * TaskNext (TOOLHELP.64)
473 BOOL16 WINAPI TaskNext16( TASKENTRY *lpte )
475 TDB *pTask;
476 INSTANCEDATA *pInstData;
478 TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext );
479 if (!lpte->hNext) return FALSE;
481 /* make sure that task and hInstance are valid (skip initial Wine task !) */
482 while (1) {
483 pTask = GlobalLock16( lpte->hNext );
484 if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
485 if (pTask->hInstance)
486 break;
487 lpte->hNext = pTask->hNext;
489 pInstData = MapSL( MAKESEGPTR( GlobalHandleToSel16(pTask->hInstance), 0 ) );
490 lpte->hTask = lpte->hNext;
491 lpte->hTaskParent = pTask->hParent;
492 lpte->hInst = pTask->hInstance;
493 lpte->hModule = pTask->hModule;
494 lpte->wSS = SELECTOROF( pTask->teb->SystemReserved1[0] );
495 lpte->wSP = OFFSETOF( pTask->teb->SystemReserved1[0] );
496 lpte->wStackTop = pInstData->stacktop;
497 lpte->wStackMinimum = pInstData->stackmin;
498 lpte->wStackBottom = pInstData->stackbottom;
499 lpte->wcEvents = pTask->nEvents;
500 lpte->hQueue = pTask->hQueue;
501 lstrcpynA( lpte->szModule, pTask->module_name, sizeof(lpte->szModule) );
502 lpte->wPSPOffset = 0x100; /*??*/
503 lpte->hNext = pTask->hNext;
504 return TRUE;
508 /***********************************************************************
509 * TaskFindHandle (TOOLHELP.65)
511 BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask )
513 lpte->hNext = hTask;
514 return TaskNext16( lpte );
518 /***********************************************************************
519 * MemManInfo (TOOLHELP.72)
521 BOOL16 WINAPI MemManInfo16( MEMMANINFO *info )
523 SYSTEM_BASIC_INFORMATION sbi;
524 MEMORYSTATUS status;
527 * Not unsurprisingly although the documentation says you
528 * _must_ provide the size in the dwSize field, this function
529 * (under Windows) always fills the structure and returns true.
531 NtQuerySystemInformation( SystemBasicInformation, &sbi, sizeof(sbi), NULL );
532 GlobalMemoryStatus( &status );
533 info->wPageSize = sbi.PageSize;
534 info->dwLargestFreeBlock = status.dwAvailVirtual;
535 info->dwMaxPagesAvailable = info->dwLargestFreeBlock / info->wPageSize;
536 info->dwMaxPagesLockable = info->dwMaxPagesAvailable;
537 info->dwTotalLinearSpace = status.dwTotalVirtual / info->wPageSize;
538 info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
539 info->dwFreePages = info->dwMaxPagesAvailable;
540 info->dwTotalPages = info->dwTotalLinearSpace;
541 info->dwFreeLinearSpace = info->dwMaxPagesAvailable;
542 info->dwSwapFilePages = status.dwTotalPageFile / info->wPageSize;
543 return TRUE;
547 /***********************************************************************
548 * NotifyRegister (TOOLHELP.73)
550 BOOL16 WINAPI NotifyRegister16( HTASK16 htask, FARPROC16 lpfnCallback,
551 WORD wFlags )
553 int i;
555 FIXME("(%x,%lx,%x), semi-stub.\n",
556 htask, (DWORD)lpfnCallback, wFlags );
557 if (!htask) htask = GetCurrentTask();
558 for (i=0;i<nrofnotifys;i++)
559 if (notifys[i].htask==htask)
560 break;
561 if (i==nrofnotifys) {
562 if (notifys==NULL)
563 notifys=HeapAlloc( GetProcessHeap(), 0,
564 sizeof(struct notify) );
565 else
566 notifys=HeapReAlloc( GetProcessHeap(), 0, notifys,
567 sizeof(struct notify)*(nrofnotifys+1));
568 if (!notifys) return FALSE;
569 nrofnotifys++;
571 notifys[i].htask=htask;
572 notifys[i].lpfnCallback=lpfnCallback;
573 notifys[i].wFlags=wFlags;
574 return TRUE;
577 /***********************************************************************
578 * NotifyUnregister (TOOLHELP.74)
580 BOOL16 WINAPI NotifyUnregister16( HTASK16 htask )
582 int i;
584 FIXME("(%x), semi-stub.\n", htask );
585 if (!htask) htask = GetCurrentTask();
586 for (i=nrofnotifys;i--;)
587 if (notifys[i].htask==htask)
588 break;
589 if (i==-1)
590 return FALSE;
591 memcpy(notifys+i,notifys+(i+1),sizeof(struct notify)*(nrofnotifys-i-1));
592 notifys=HeapReAlloc( GetProcessHeap(), 0, notifys,
593 (nrofnotifys-1)*sizeof(struct notify));
594 nrofnotifys--;
595 return TRUE;
598 /***********************************************************************
599 * StackTraceCSIPFirst (TOOLHELP.67)
601 BOOL16 WINAPI StackTraceCSIPFirst16(STACKTRACEENTRY *ste, WORD wSS, WORD wCS, WORD wIP, WORD wBP)
603 FIXME("(%p, ss %04x, cs %04x, ip %04x, bp %04x): stub.\n", ste, wSS, wCS, wIP, wBP);
604 return TRUE;
607 /***********************************************************************
608 * StackTraceFirst (TOOLHELP.66)
610 BOOL16 WINAPI StackTraceFirst16(STACKTRACEENTRY *ste, HTASK16 Task)
612 FIXME("(%p, %04x), stub.\n", ste, Task);
613 return TRUE;
616 /***********************************************************************
617 * StackTraceNext (TOOLHELP.68)
619 BOOL16 WINAPI StackTraceNext16(STACKTRACEENTRY *ste)
621 FIXME("(%p), stub.\n", ste);
622 return TRUE;
625 /***********************************************************************
626 * InterruptRegister (TOOLHELP.75)
628 BOOL16 WINAPI InterruptRegister16( HTASK16 task, FARPROC callback )
630 FIXME("(%04x, %p), stub.\n", task, callback);
631 return TRUE;
634 /***********************************************************************
635 * InterruptUnRegister (TOOLHELP.76)
637 BOOL16 WINAPI InterruptUnRegister16( HTASK16 task )
639 FIXME("(%04x), stub.\n", task);
640 return TRUE;
643 /***********************************************************************
644 * TerminateApp (TOOLHELP.77)
646 * See "Undocumented Windows".
648 void WINAPI TerminateApp16(HTASK16 hTask, WORD wFlags)
650 if (hTask && hTask != GetCurrentTask())
652 FIXME("cannot terminate task %x\n", hTask);
653 return;
656 #if 0 /* FIXME */
657 /* check undocumented flag */
658 if (!(wFlags & 0x8000))
659 TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
660 #endif
662 /* UndocWin says to call int 0x21/0x4c exit=0xff here,
663 but let's just call ExitThread */
664 ExitThread(0xff);
667 /***********************************************************************
668 * MemoryRead (TOOLHELP.78)
670 DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count )
672 char *base = (char *)GetSelectorBase( sel );
673 DWORD limit = GetSelectorLimit16( sel );
675 if (offset > limit) return 0;
676 if (offset + count > limit + 1) count = limit + 1 - offset;
677 memcpy( buffer, base + offset, count );
678 return count;
682 /***********************************************************************
683 * MemoryWrite (TOOLHELP.79)
685 DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
687 char *base = (char *)GetSelectorBase( sel );
688 DWORD limit = GetSelectorLimit16( sel );
690 if (offset > limit) return 0;
691 if (offset + count > limit) count = limit + 1 - offset;
692 memcpy( base + offset, buffer, count );
693 return count;
696 /***********************************************************************
697 * TimerCount (TOOLHELP.80)
699 BOOL16 WINAPI TimerCount16( TIMERINFO *pTimerInfo )
701 /* FIXME
702 * In standard mode, dwmsSinceStart = dwmsThisVM
704 * I tested this, under Windows in enhanced mode, and
705 * if you never switch VM (ie start/stop DOS) these
706 * values should be the same as well.
708 * Also, Wine should adjust for the hardware timer
709 * to reduce the amount of error to ~1ms.
710 * I can't be bothered, can you?
712 pTimerInfo->dwmsSinceStart = pTimerInfo->dwmsThisVM = GetTickCount();
713 return TRUE;
716 /***********************************************************************
717 * SystemHeapInfo (TOOLHELP.71)
719 BOOL16 WINAPI SystemHeapInfo16( SYSHEAPINFO *pHeapInfo )
721 HANDLE16 oldDS = CURRENT_DS;
722 WORD user = LoadLibrary16( "USER.EXE" );
723 WORD gdi = LoadLibrary16( "GDI.EXE" );
725 CURRENT_DS = user;
726 pHeapInfo->wUserFreePercent = (int)LocalCountFree16() * 100 / LocalHeapSize16();
727 CURRENT_DS = gdi;
728 pHeapInfo->wGDIFreePercent = (int)LocalCountFree16() * 100 / LocalHeapSize16();
729 CURRENT_DS = oldDS;
730 pHeapInfo->hUserSegment = user;
731 pHeapInfo->hGDISegment = gdi;
732 FreeLibrary16( user );
733 FreeLibrary16( gdi );
734 return TRUE;
737 /***********************************************************************
738 * Local32Info (TOOLHELP.84)
740 BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
742 FIXME( "Call Local32Info16 in kernel\n" );
743 return FALSE;
746 /***********************************************************************
747 * Local32First (TOOLHELP.85)
749 BOOL16 WINAPI Local32First16( LOCAL32ENTRY *pLocal32Entry, HGLOBAL16 handle )
751 FIXME( "Call Local32First16 in kernel\n" );
752 return FALSE;
755 /***********************************************************************
756 * Local32Next (TOOLHELP.86)
758 BOOL16 WINAPI Local32Next16( LOCAL32ENTRY *pLocal32Entry )
760 FIXME( "Call Local32Next16 in kernel\n" );
761 return FALSE;