crypt32/tests: Add a trailing '\n' to ok() calls.
[wine.git] / dlls / toolhelp.dll16 / toolhelp.c
blobcf5e6ef778ca81378c2aac4457fb3b1eddd926b7
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 "config.h"
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <ctype.h>
31 #include <assert.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winternl.h"
35 #include "wownt32.h"
37 #include "wine/winbase16.h"
38 #include "toolhelp.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp);
43 #include "pshpack1.h"
45 typedef struct
47 void *base; /* Base address (0 if discarded) */
48 DWORD size; /* Size in bytes (0 indicates a free block) */
49 HGLOBAL16 handle; /* Handle for this block */
50 HGLOBAL16 hOwner; /* Owner of this block */
51 BYTE lockCount; /* Count of GlobalFix() calls */
52 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
53 BYTE flags; /* Allocation flags */
54 BYTE selCount; /* Number of selectors allocated for this block */
55 } GLOBALARENA;
57 #define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */
59 typedef struct
61 WORD check; /* 00 Heap checking flag */
62 WORD freeze; /* 02 Heap frozen flag */
63 WORD items; /* 04 Count of items on the heap */
64 WORD first; /* 06 First item of the heap */
65 WORD pad1; /* 08 Always 0 */
66 WORD last; /* 0a Last item of the heap */
67 WORD pad2; /* 0c Always 0 */
68 BYTE ncompact; /* 0e Compactions counter */
69 BYTE dislevel; /* 0f Discard level */
70 DWORD distotal; /* 10 Total bytes discarded */
71 WORD htable; /* 14 Pointer to handle table */
72 WORD hfree; /* 16 Pointer to free handle table */
73 WORD hdelta; /* 18 Delta to expand the handle table */
74 WORD expand; /* 1a Pointer to expand function (unused) */
75 WORD pstat; /* 1c Pointer to status structure (unused) */
76 FARPROC16 notify; /* 1e Pointer to LocalNotify() function */
77 WORD lock; /* 22 Lock count for the heap */
78 WORD extra; /* 24 Extra bytes to allocate when expanding */
79 WORD minsize; /* 26 Minimum size of the heap */
80 WORD magic; /* 28 Magic number */
81 } LOCALHEAPINFO;
83 typedef struct
85 /* Arena header */
86 WORD prev; /* Previous arena | arena type */
87 WORD next; /* Next arena */
88 /* Start of the memory block or free-list info */
89 WORD size; /* Size of the free block */
90 WORD free_prev; /* Previous free block */
91 WORD free_next; /* Next free block */
92 } LOCALARENA;
94 #define LOCAL_ARENA_HEADER_SIZE 4
95 #define LOCAL_ARENA_HEADER( handle) ((handle) - LOCAL_ARENA_HEADER_SIZE)
96 #define LOCAL_ARENA_PTR(ptr,arena) ((LOCALARENA *)((char *)(ptr)+(arena)))
98 typedef struct
100 WORD null; /* Always 0 */
101 DWORD old_ss_sp; /* Stack pointer; used by SwitchTaskTo() */
102 WORD heap; /* Pointer to the local heap information (if any) */
103 WORD atomtable; /* Pointer to the local atom table (if any) */
104 WORD stacktop; /* Top of the stack */
105 WORD stackmin; /* Lowest stack address used so far */
106 WORD stackbottom; /* Bottom of the stack */
107 } INSTANCEDATA;
109 typedef struct _THHOOK
111 HANDLE16 hGlobalHeap; /* 00 (handle BURGERMASTER) */
112 WORD pGlobalHeap; /* 02 (selector BURGERMASTER) */
113 HMODULE16 hExeHead; /* 04 hFirstModule */
114 HMODULE16 hExeSweep; /* 06 (unused) */
115 HANDLE16 TopPDB; /* 08 (handle of KERNEL PDB) */
116 HANDLE16 HeadPDB; /* 0A (first PDB in list) */
117 HANDLE16 TopSizePDB; /* 0C (unused) */
118 HTASK16 HeadTDB; /* 0E hFirstTask */
119 HTASK16 CurTDB; /* 10 hCurrentTask */
120 HTASK16 LoadTDB; /* 12 (unused) */
121 HTASK16 LockTDB; /* 14 hLockedTask */
122 } THHOOK;
124 typedef struct _NE_MODULE
126 WORD ne_magic; /* 00 'NE' signature */
127 WORD count; /* 02 Usage count (ne_ver/ne_rev on disk) */
128 WORD ne_enttab; /* 04 Near ptr to entry table */
129 HMODULE16 next; /* 06 Selector to next module (ne_cbenttab on disk) */
130 WORD dgroup_entry; /* 08 Near ptr to segment entry for DGROUP (ne_crc on disk) */
131 WORD fileinfo; /* 0a Near ptr to file info (OFSTRUCT) (ne_crc on disk) */
132 WORD ne_flags; /* 0c Module flags */
133 WORD ne_autodata; /* 0e Logical segment for DGROUP */
134 WORD ne_heap; /* 10 Initial heap size */
135 WORD ne_stack; /* 12 Initial stack size */
136 DWORD ne_csip; /* 14 Initial cs:ip */
137 DWORD ne_sssp; /* 18 Initial ss:sp */
138 WORD ne_cseg; /* 1c Number of segments in segment table */
139 WORD ne_cmod; /* 1e Number of module references */
140 WORD ne_cbnrestab; /* 20 Size of non-resident names table */
141 WORD ne_segtab; /* 22 Near ptr to segment table */
142 WORD ne_rsrctab; /* 24 Near ptr to resource table */
143 WORD ne_restab; /* 26 Near ptr to resident names table */
144 WORD ne_modtab; /* 28 Near ptr to module reference table */
145 WORD ne_imptab; /* 2a Near ptr to imported names table */
146 DWORD ne_nrestab; /* 2c File offset of non-resident names table */
147 WORD ne_cmovent; /* 30 Number of moveable entries in entry table*/
148 WORD ne_align; /* 32 Alignment shift count */
149 WORD ne_cres; /* 34 # of resource segments */
150 BYTE ne_exetyp; /* 36 Operating system flags */
151 BYTE ne_flagsothers; /* 37 Misc. flags */
152 HANDLE16 dlls_to_init; /* 38 List of DLLs to initialize (ne_pretthunks on disk) */
153 HANDLE16 nrname_handle; /* 3a Handle to non-resident name table (ne_psegrefbytes on disk) */
154 WORD ne_swaparea; /* 3c Min. swap area size */
155 WORD ne_expver; /* 3e Expected Windows version */
156 /* From here, these are extra fields not present in normal Windows */
157 HMODULE module32; /* PE module handle for Win32 modules */
158 HMODULE owner32; /* PE module containing this one for 16-bit builtins */
159 HMODULE16 self; /* Handle for this module */
160 WORD self_loading_sel; /* Selector used for self-loading apps. */
161 LPVOID rsrc32_map; /* HRSRC 16->32 map (for 32-bit modules) */
162 LPCVOID mapping; /* mapping of the binary file */
163 SIZE_T mapping_size; /* size of the file mapping */
164 } NE_MODULE;
166 #include "poppack.h"
168 #define TDB_MAGIC ('T' | ('D' << 8))
170 /* FIXME: to make this work, we have to call back all these registered
171 * functions from all over the WINE code. Someone with more knowledge than
172 * me please do that. -Marcus
175 static struct notify
177 HTASK16 htask;
178 FARPROC16 lpfnCallback;
179 WORD wFlags;
180 } *notifys = NULL;
182 static int nrofnotifys = 0;
184 static THHOOK *get_thhook(void)
186 static THHOOK *thhook;
188 if (!thhook) thhook = MapSL( (SEGPTR)GetProcAddress16( GetModuleHandle16("KERNEL"), (LPCSTR)332 ));
189 return thhook;
192 static GLOBALARENA *get_global_arena(void)
194 return *(GLOBALARENA **)get_thhook();
197 static LOCALHEAPINFO *get_local_heap( HANDLE16 ds )
199 INSTANCEDATA *ptr = MapSL( MAKESEGPTR( ds, 0 ));
201 if (!ptr || !ptr->heap) return NULL;
202 return (LOCALHEAPINFO*)((char*)ptr + ptr->heap);
206 /***********************************************************************
207 * GlobalHandleToSel (TOOLHELP.50)
209 WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle )
211 if (!handle) return 0;
212 if (!(handle & 7)) return handle - 1;
213 return handle | 7;
217 /***********************************************************************
218 * GlobalFirst (TOOLHELP.51)
220 BOOL16 WINAPI GlobalFirst16( GLOBALENTRY *pGlobal, WORD wFlags )
222 if (wFlags == GLOBAL_LRU) return FALSE;
223 pGlobal->dwNext = 0;
224 return GlobalNext16( pGlobal, wFlags );
228 /***********************************************************************
229 * GlobalNext (TOOLHELP.52)
231 BOOL16 WINAPI GlobalNext16( GLOBALENTRY *pGlobal, WORD wFlags)
233 GLOBALARENA *pGlobalArena = get_global_arena();
234 GLOBALARENA *pArena;
236 if (pGlobal->dwNext >= GLOBAL_MAX_COUNT) return FALSE;
237 pArena = pGlobalArena + pGlobal->dwNext;
238 if (wFlags == GLOBAL_FREE) /* only free blocks */
240 int i;
241 for (i = pGlobal->dwNext; i < GLOBAL_MAX_COUNT; i++, pArena++)
242 if (pArena->size == 0) break; /* block is free */
243 if (i >= GLOBAL_MAX_COUNT) return FALSE;
244 pGlobal->dwNext = i;
247 pGlobal->dwAddress = (DWORD_PTR)pArena->base;
248 pGlobal->dwBlockSize = pArena->size;
249 pGlobal->hBlock = pArena->handle;
250 pGlobal->wcLock = pArena->lockCount;
251 pGlobal->wcPageLock = pArena->pageLockCount;
252 pGlobal->wFlags = (GetCurrentPDB16() == pArena->hOwner);
253 pGlobal->wHeapPresent = FALSE;
254 pGlobal->hOwner = pArena->hOwner;
255 pGlobal->wType = GT_UNKNOWN;
256 pGlobal->wData = 0;
257 pGlobal->dwNext++;
258 return TRUE;
262 /***********************************************************************
263 * GlobalInfo (TOOLHELP.53)
265 BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo )
267 GLOBALARENA *pGlobalArena = get_global_arena();
268 GLOBALARENA *pArena;
269 int i;
271 pInfo->wcItems = GLOBAL_MAX_COUNT;
272 pInfo->wcItemsFree = 0;
273 pInfo->wcItemsLRU = 0;
274 for (i = 0, pArena = pGlobalArena; i < GLOBAL_MAX_COUNT; i++, pArena++)
275 if (pArena->size == 0) pInfo->wcItemsFree++;
276 return TRUE;
280 /***********************************************************************
281 * GlobalEntryHandle (TOOLHELP.54)
283 BOOL16 WINAPI GlobalEntryHandle16( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
285 GLOBALARENA *pGlobalArena = get_global_arena();
286 GLOBALARENA *pArena = pGlobalArena + (hItem >> __AHSHIFT);
288 pGlobal->dwAddress = (DWORD_PTR)pArena->base;
289 pGlobal->dwBlockSize = pArena->size;
290 pGlobal->hBlock = pArena->handle;
291 pGlobal->wcLock = pArena->lockCount;
292 pGlobal->wcPageLock = pArena->pageLockCount;
293 pGlobal->wFlags = (GetCurrentPDB16() == pArena->hOwner);
294 pGlobal->wHeapPresent = FALSE;
295 pGlobal->hOwner = pArena->hOwner;
296 pGlobal->wType = GT_UNKNOWN;
297 pGlobal->wData = 0;
298 pGlobal->dwNext++;
299 return TRUE;
303 /***********************************************************************
304 * GlobalEntryModule (TOOLHELP.55)
306 BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule,
307 WORD wSeg )
309 FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg);
310 return FALSE;
314 /***********************************************************************
315 * LocalInfo (TOOLHELP.56)
317 BOOL16 WINAPI LocalInfo16( LOCALINFO *pLocalInfo, HGLOBAL16 handle )
319 LOCALHEAPINFO *pInfo = get_local_heap( SELECTOROF(WOWGlobalLock16(handle)) );
320 if (!pInfo) return FALSE;
321 pLocalInfo->wcItems = pInfo->items;
322 return TRUE;
326 /***********************************************************************
327 * LocalFirst (TOOLHELP.57)
329 BOOL16 WINAPI LocalFirst16( LOCALENTRY *pLocalEntry, HGLOBAL16 handle )
331 WORD ds = GlobalHandleToSel16( handle );
332 char *ptr = MapSL( MAKESEGPTR( ds, 0 ) );
333 LOCALHEAPINFO *pInfo = get_local_heap( ds );
334 if (!pInfo) return FALSE;
336 pLocalEntry->hHandle = pInfo->first + LOCAL_ARENA_HEADER_SIZE;
337 pLocalEntry->wAddress = pLocalEntry->hHandle;
338 pLocalEntry->wFlags = LF_FIXED;
339 pLocalEntry->wcLock = 0;
340 pLocalEntry->wType = LT_NORMAL;
341 pLocalEntry->hHeap = handle;
342 pLocalEntry->wHeapType = NORMAL_HEAP;
343 pLocalEntry->wNext = LOCAL_ARENA_PTR(ptr,pInfo->first)->next;
344 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
345 return TRUE;
349 /***********************************************************************
350 * LocalNext (TOOLHELP.58)
352 BOOL16 WINAPI LocalNext16( LOCALENTRY *pLocalEntry )
354 WORD ds = GlobalHandleToSel16( pLocalEntry->hHeap );
355 char *ptr = MapSL( MAKESEGPTR( ds, 0 ) );
356 LOCALARENA *pArena;
358 if (!get_local_heap( ds )) return FALSE;
359 if (!pLocalEntry->wNext) return FALSE;
360 pArena = LOCAL_ARENA_PTR( ptr, pLocalEntry->wNext );
362 pLocalEntry->hHandle = pLocalEntry->wNext + LOCAL_ARENA_HEADER_SIZE;
363 pLocalEntry->wAddress = pLocalEntry->hHandle;
364 pLocalEntry->wFlags = (pArena->prev & 3) + 1;
365 pLocalEntry->wcLock = 0;
366 pLocalEntry->wType = LT_NORMAL;
367 if (pArena->next != pLocalEntry->wNext) /* last one? */
368 pLocalEntry->wNext = pArena->next;
369 else
370 pLocalEntry->wNext = 0;
371 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
372 return TRUE;
376 /**********************************************************************
377 * ModuleFirst (TOOLHELP.59)
379 BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme )
381 lpme->wNext = get_thhook()->hExeHead;
382 return ModuleNext16( lpme );
386 /**********************************************************************
387 * ModuleNext (TOOLHELP.60)
389 BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme )
391 NE_MODULE *pModule;
392 char *name;
394 if (!lpme->wNext) return FALSE;
395 if (!(pModule = GlobalLock16( GetExePtr(lpme->wNext) ))) return FALSE;
396 name = (char *)pModule + pModule->ne_restab;
397 memcpy( lpme->szModule, name + 1, min(*name, MAX_MODULE_NAME) );
398 lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0';
399 lpme->hModule = lpme->wNext;
400 lpme->wcUsage = pModule->count;
401 name = ((OFSTRUCT *)((char*)pModule + pModule->fileinfo))->szPathName;
402 lstrcpynA( lpme->szExePath, name, sizeof(lpme->szExePath) );
403 lpme->wNext = pModule->next;
404 return TRUE;
408 /**********************************************************************
409 * ModuleFindName (TOOLHELP.61)
411 BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name )
413 lpme->wNext = GetModuleHandle16( name );
414 return ModuleNext16( lpme );
418 /**********************************************************************
419 * ModuleFindHandle (TOOLHELP.62)
421 BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule )
423 hModule = GetExePtr( hModule );
424 lpme->wNext = hModule;
425 return ModuleNext16( lpme );
429 /***********************************************************************
430 * TaskFirst (TOOLHELP.63)
432 BOOL16 WINAPI TaskFirst16( TASKENTRY *lpte )
434 lpte->hNext = get_thhook()->HeadTDB;
435 return TaskNext16( lpte );
439 /***********************************************************************
440 * TaskNext (TOOLHELP.64)
442 BOOL16 WINAPI TaskNext16( TASKENTRY *lpte )
444 TDB *pTask;
445 INSTANCEDATA *pInstData;
447 TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext );
448 if (!lpte->hNext) return FALSE;
450 /* make sure that task and hInstance are valid (skip initial Wine task !) */
451 while (1) {
452 pTask = GlobalLock16( lpte->hNext );
453 if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
454 if (pTask->hInstance)
455 break;
456 lpte->hNext = pTask->hNext;
458 pInstData = MapSL( MAKESEGPTR( GlobalHandleToSel16(pTask->hInstance), 0 ) );
459 lpte->hTask = lpte->hNext;
460 lpte->hTaskParent = pTask->hParent;
461 lpte->hInst = pTask->hInstance;
462 lpte->hModule = pTask->hModule;
463 lpte->wSS = SELECTOROF( pTask->teb->WOW32Reserved );
464 lpte->wSP = OFFSETOF( pTask->teb->WOW32Reserved );
465 lpte->wStackTop = pInstData->stacktop;
466 lpte->wStackMinimum = pInstData->stackmin;
467 lpte->wStackBottom = pInstData->stackbottom;
468 lpte->wcEvents = pTask->nEvents;
469 lpte->hQueue = pTask->hQueue;
470 lstrcpynA( lpte->szModule, pTask->module_name, sizeof(lpte->szModule) );
471 lpte->wPSPOffset = 0x100; /*??*/
472 lpte->hNext = pTask->hNext;
473 return TRUE;
477 /***********************************************************************
478 * TaskFindHandle (TOOLHELP.65)
480 BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask )
482 lpte->hNext = hTask;
483 return TaskNext16( lpte );
487 /***********************************************************************
488 * MemManInfo (TOOLHELP.72)
490 BOOL16 WINAPI MemManInfo16( MEMMANINFO *info )
492 SYSTEM_BASIC_INFORMATION sbi;
493 MEMORYSTATUS status;
496 * Not unsurprisingly although the documentation says you
497 * _must_ provide the size in the dwSize field, this function
498 * (under Windows) always fills the structure and returns true.
500 NtQuerySystemInformation( SystemBasicInformation, &sbi, sizeof(sbi), NULL );
501 GlobalMemoryStatus( &status );
502 info->wPageSize = sbi.PageSize;
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;
516 /***********************************************************************
517 * NotifyRegister (TOOLHELP.73)
519 BOOL16 WINAPI NotifyRegister16( HTASK16 htask, FARPROC16 lpfnCallback,
520 WORD wFlags )
522 int i;
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++;
540 notifys[i].htask=htask;
541 notifys[i].lpfnCallback=lpfnCallback;
542 notifys[i].wFlags=wFlags;
543 return TRUE;
546 /***********************************************************************
547 * NotifyUnregister (TOOLHELP.74)
549 BOOL16 WINAPI NotifyUnregister16( HTASK16 htask )
551 int i;
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;
567 /***********************************************************************
568 * StackTraceCSIPFirst (TOOLHELP.67)
570 BOOL16 WINAPI StackTraceCSIPFirst16(STACKTRACEENTRY *ste, WORD wSS, WORD wCS, WORD wIP, WORD wBP)
572 FIXME("(%p, ss %04x, cs %04x, ip %04x, bp %04x): stub.\n", ste, wSS, wCS, wIP, wBP);
573 return TRUE;
576 /***********************************************************************
577 * StackTraceFirst (TOOLHELP.66)
579 BOOL16 WINAPI StackTraceFirst16(STACKTRACEENTRY *ste, HTASK16 Task)
581 FIXME("(%p, %04x), stub.\n", ste, Task);
582 return TRUE;
585 /***********************************************************************
586 * StackTraceNext (TOOLHELP.68)
588 BOOL16 WINAPI StackTraceNext16(STACKTRACEENTRY *ste)
590 FIXME("(%p), stub.\n", ste);
591 return TRUE;
594 /***********************************************************************
595 * InterruptRegister (TOOLHELP.75)
597 BOOL16 WINAPI InterruptRegister16( HTASK16 task, FARPROC callback )
599 FIXME("(%04x, %p), stub.\n", task, callback);
600 return TRUE;
603 /***********************************************************************
604 * InterruptUnRegister (TOOLHELP.76)
606 BOOL16 WINAPI InterruptUnRegister16( HTASK16 task )
608 FIXME("(%04x), stub.\n", task);
609 return TRUE;
612 /***********************************************************************
613 * TerminateApp (TOOLHELP.77)
615 * See "Undocumented Windows".
617 void WINAPI TerminateApp16(HTASK16 hTask, WORD wFlags)
619 if (hTask && hTask != GetCurrentTask())
621 FIXME("cannot terminate task %x\n", hTask);
622 return;
625 #if 0 /* FIXME */
626 /* check undocumented flag */
627 if (!(wFlags & 0x8000))
628 TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
629 #endif
631 /* UndocWin says to call int 0x21/0x4c exit=0xff here,
632 but let's just call ExitThread */
633 ExitThread(0xff);
636 /***********************************************************************
637 * MemoryRead (TOOLHELP.78)
639 DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count )
641 LDT_ENTRY entry;
642 DWORD limit;
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;
654 /***********************************************************************
655 * MemoryWrite (TOOLHELP.79)
657 DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
659 LDT_ENTRY entry;
660 DWORD limit;
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;
671 /***********************************************************************
672 * TimerCount (TOOLHELP.80)
674 BOOL16 WINAPI TimerCount16( TIMERINFO *pTimerInfo )
676 /* FIXME
677 * In standard mode, dwmsSinceStart = dwmsThisVM
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.
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?
687 pTimerInfo->dwmsSinceStart = pTimerInfo->dwmsThisVM = GetTickCount();
688 return TRUE;
691 /***********************************************************************
692 * SystemHeapInfo (TOOLHELP.71)
694 BOOL16 WINAPI SystemHeapInfo16( SYSHEAPINFO *pHeapInfo )
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;
712 /***********************************************************************
713 * Local32Info (TOOLHELP.84)
715 BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
717 FIXME( "Call Local32Info16 in kernel\n" );
718 return FALSE;
721 /***********************************************************************
722 * Local32First (TOOLHELP.85)
724 BOOL16 WINAPI Local32First16( LOCAL32ENTRY *pLocal32Entry, HGLOBAL16 handle )
726 FIXME( "Call Local32First16 in kernel\n" );
727 return FALSE;
730 /***********************************************************************
731 * Local32Next (TOOLHELP.86)
733 BOOL16 WINAPI Local32Next16( LOCAL32ENTRY *pLocal32Entry )
735 FIXME( "Call Local32Next16 in kernel\n" );
736 return FALSE;