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
32 #include "wine/winbase16.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp
);
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 */
52 #define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */
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 */
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 */
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
103 WORD addr
; /* Address of the MOVEABLE block */
104 BYTE flags
; /* Flags for this block */
105 BYTE lock
; /* Lock count */
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 */
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 */
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 */
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
189 FARPROC16 lpfnCallback
;
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 ));
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;
228 /***********************************************************************
229 * GlobalFirst (TOOLHELP.51)
231 BOOL16 WINAPI
GlobalFirst16( GLOBALENTRY
*pGlobal
, WORD wFlags
)
233 if (wFlags
== GLOBAL_LRU
) return FALSE
;
235 return GlobalNext16( pGlobal
, wFlags
);
239 /***********************************************************************
240 * GlobalNext (TOOLHELP.52)
242 BOOL16 WINAPI
GlobalNext16( GLOBALENTRY
*pGlobal
, WORD wFlags
)
244 GLOBALARENA
*pGlobalArena
= get_global_arena();
247 if (pGlobal
->dwNext
>= GLOBAL_MAX_COUNT
) return FALSE
;
248 pArena
= pGlobalArena
+ pGlobal
->dwNext
;
249 if (wFlags
== GLOBAL_FREE
) /* only free blocks */
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
;
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
;
273 /***********************************************************************
274 * GlobalInfo (TOOLHELP.53)
276 BOOL16 WINAPI
GlobalInfo16( GLOBALINFO
*pInfo
)
278 GLOBALARENA
*pGlobalArena
= get_global_arena();
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
++;
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
;
314 /***********************************************************************
315 * GlobalEntryModule (TOOLHELP.55)
317 BOOL16 WINAPI
GlobalEntryModule16( GLOBALENTRY
*pGlobal
, HMODULE16 hModule
,
320 FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal
, hModule
, wSeg
);
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
;
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
;
360 /***********************************************************************
361 * LocalNext (TOOLHELP.58)
363 BOOL16 WINAPI
LocalNext16( LOCALENTRY
*pLocalEntry
)
365 WORD ds
= GlobalHandleToSel16( pLocalEntry
->hHeap
);
366 char *ptr
= MapSL( MAKESEGPTR( ds
, 0 ) );
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
;
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
);
389 pLocalEntry
->wAddress
= pEntry
->addr
;
390 pLocalEntry
->wFlags
= pEntry
->flags
;
391 pLocalEntry
->wcLock
= pEntry
->lock
;
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
;
401 pLocalEntry
->wNext
= 0;
402 pLocalEntry
->wSize
= pLocalEntry
->wNext
- pLocalEntry
->hHandle
;
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
)
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
;
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
)
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 !) */
483 pTask
= GlobalLock16( lpte
->hNext
);
484 if (!pTask
|| pTask
->magic
!= TDB_MAGIC
) return FALSE
;
485 if (pTask
->hInstance
)
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
;
508 /***********************************************************************
509 * TaskFindHandle (TOOLHELP.65)
511 BOOL16 WINAPI
TaskFindHandle16( TASKENTRY
*lpte
, HTASK16 hTask
)
514 return TaskNext16( lpte
);
518 /***********************************************************************
519 * MemManInfo (TOOLHELP.72)
521 BOOL16 WINAPI
MemManInfo16( MEMMANINFO
*info
)
523 SYSTEM_BASIC_INFORMATION sbi
;
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
;
547 /***********************************************************************
548 * NotifyRegister (TOOLHELP.73)
550 BOOL16 WINAPI
NotifyRegister16( HTASK16 htask
, FARPROC16 lpfnCallback
,
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
)
561 if (i
==nrofnotifys
) {
563 notifys
=HeapAlloc( GetProcessHeap(), 0,
564 sizeof(struct notify
) );
566 notifys
=HeapReAlloc( GetProcessHeap(), 0, notifys
,
567 sizeof(struct notify
)*(nrofnotifys
+1));
568 if (!notifys
) return FALSE
;
571 notifys
[i
].htask
=htask
;
572 notifys
[i
].lpfnCallback
=lpfnCallback
;
573 notifys
[i
].wFlags
=wFlags
;
577 /***********************************************************************
578 * NotifyUnregister (TOOLHELP.74)
580 BOOL16 WINAPI
NotifyUnregister16( HTASK16 htask
)
584 FIXME("(%x), semi-stub.\n", htask
);
585 if (!htask
) htask
= GetCurrentTask();
586 for (i
=nrofnotifys
;i
--;)
587 if (notifys
[i
].htask
==htask
)
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
));
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
);
607 /***********************************************************************
608 * StackTraceFirst (TOOLHELP.66)
610 BOOL16 WINAPI
StackTraceFirst16(STACKTRACEENTRY
*ste
, HTASK16 Task
)
612 FIXME("(%p, %04x), stub.\n", ste
, Task
);
616 /***********************************************************************
617 * StackTraceNext (TOOLHELP.68)
619 BOOL16 WINAPI
StackTraceNext16(STACKTRACEENTRY
*ste
)
621 FIXME("(%p), stub.\n", ste
);
625 /***********************************************************************
626 * InterruptRegister (TOOLHELP.75)
628 BOOL16 WINAPI
InterruptRegister16( HTASK16 task
, FARPROC callback
)
630 FIXME("(%04x, %p), stub.\n", task
, callback
);
634 /***********************************************************************
635 * InterruptUnRegister (TOOLHELP.76)
637 BOOL16 WINAPI
InterruptUnRegister16( HTASK16 task
)
639 FIXME("(%04x), stub.\n", task
);
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
);
657 /* check undocumented flag */
658 if (!(wFlags
& 0x8000))
659 TASK_CallTaskSignalProc( USIG16_TERMINATION
, hTask
);
662 /* UndocWin says to call int 0x21/0x4c exit=0xff here,
663 but let's just call ExitThread */
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
);
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
);
696 /***********************************************************************
697 * TimerCount (TOOLHELP.80)
699 BOOL16 WINAPI
TimerCount16( TIMERINFO
*pTimerInfo
)
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();
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" );
726 pHeapInfo
->wUserFreePercent
= (int)LocalCountFree16() * 100 / LocalHeapSize16();
728 pHeapInfo
->wGDIFreePercent
= (int)LocalCountFree16() * 100 / LocalHeapSize16();
730 pHeapInfo
->hUserSegment
= user
;
731 pHeapInfo
->hGDISegment
= gdi
;
732 FreeLibrary16( user
);
733 FreeLibrary16( gdi
);
737 /***********************************************************************
738 * Local32Info (TOOLHELP.84)
740 BOOL16 WINAPI
Local32Info16( LOCAL32INFO
*pLocal32Info
, HGLOBAL16 handle
)
742 FIXME( "Call Local32Info16 in kernel\n" );
746 /***********************************************************************
747 * Local32First (TOOLHELP.85)
749 BOOL16 WINAPI
Local32First16( LOCAL32ENTRY
*pLocal32Entry
, HGLOBAL16 handle
)
751 FIXME( "Call Local32First16 in kernel\n" );
755 /***********************************************************************
756 * Local32Next (TOOLHELP.86)
758 BOOL16 WINAPI
Local32Next16( LOCAL32ENTRY
*pLocal32Entry
)
760 FIXME( "Call Local32Next16 in kernel\n" );