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
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
39 #include "wine/winbase16.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp
);
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 */
59 #define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */
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 */
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 */
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)))
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 */
111 typedef struct _THHOOK
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 */
126 typedef struct _NE_MODULE
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 */
170 #define TDB_MAGIC ('T' | ('D' << 8))
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
180 FARPROC16 lpfnCallback
;
184 static int nrofnotifys
= 0;
186 static THHOOK
*get_thhook(void)
188 static THHOOK
*thhook
;
190 if (!thhook
) thhook
= MapSL( (SEGPTR
)GetProcAddress16( GetModuleHandle16("KERNEL"), (LPCSTR
)332 ));
194 static GLOBALARENA
*get_global_arena(void)
196 return *(GLOBALARENA
**)get_thhook();
199 static LOCALHEAPINFO
*get_local_heap( HANDLE16 ds
)
201 INSTANCEDATA
*ptr
= MapSL( MAKESEGPTR( ds
, 0 ));
203 if (!ptr
|| !ptr
->heap
) return NULL
;
204 return (LOCALHEAPINFO
*)((char*)ptr
+ ptr
->heap
);
208 /***********************************************************************
209 * GlobalHandleToSel (TOOLHELP.50)
211 WORD WINAPI
GlobalHandleToSel16( HGLOBAL16 handle
)
213 if (!handle
) return 0;
214 if (!(handle
& 7)) return handle
- 1;
219 /***********************************************************************
220 * GlobalFirst (TOOLHELP.51)
222 BOOL16 WINAPI
GlobalFirst16( GLOBALENTRY
*pGlobal
, WORD wFlags
)
224 if (wFlags
== GLOBAL_LRU
) return FALSE
;
226 return GlobalNext16( pGlobal
, wFlags
);
230 /***********************************************************************
231 * GlobalNext (TOOLHELP.52)
233 BOOL16 WINAPI
GlobalNext16( GLOBALENTRY
*pGlobal
, WORD wFlags
)
235 GLOBALARENA
*pGlobalArena
= get_global_arena();
238 if (pGlobal
->dwNext
>= GLOBAL_MAX_COUNT
) return FALSE
;
239 pArena
= pGlobalArena
+ pGlobal
->dwNext
;
240 if (wFlags
== GLOBAL_FREE
) /* only free blocks */
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
;
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
;
264 /***********************************************************************
265 * GlobalInfo (TOOLHELP.53)
267 BOOL16 WINAPI
GlobalInfo16( GLOBALINFO
*pInfo
)
269 GLOBALARENA
*pGlobalArena
= get_global_arena();
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
++;
282 /***********************************************************************
283 * GlobalEntryHandle (TOOLHELP.54)
285 BOOL16 WINAPI
GlobalEntryHandle16( GLOBALENTRY
*pGlobal
, HGLOBAL16 hItem
)
287 GLOBALARENA
*pGlobalArena
= get_global_arena();
288 GLOBALARENA
*pArena
= pGlobalArena
+ (hItem
>> __AHSHIFT
);
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
;
305 /***********************************************************************
306 * GlobalEntryModule (TOOLHELP.55)
308 BOOL16 WINAPI
GlobalEntryModule16( GLOBALENTRY
*pGlobal
, HMODULE16 hModule
,
311 FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal
, hModule
, wSeg
);
316 /***********************************************************************
317 * LocalInfo (TOOLHELP.56)
319 BOOL16 WINAPI
LocalInfo16( LOCALINFO
*pLocalInfo
, HGLOBAL16 handle
)
321 LOCALHEAPINFO
*pInfo
= get_local_heap( SELECTOROF(WOWGlobalLock16(handle
)) );
322 if (!pInfo
) return FALSE
;
323 pLocalInfo
->wcItems
= pInfo
->items
;
328 /***********************************************************************
329 * LocalFirst (TOOLHELP.57)
331 BOOL16 WINAPI
LocalFirst16( LOCALENTRY
*pLocalEntry
, HGLOBAL16 handle
)
333 WORD ds
= GlobalHandleToSel16( handle
);
334 char *ptr
= MapSL( MAKESEGPTR( ds
, 0 ) );
335 LOCALHEAPINFO
*pInfo
= get_local_heap( ds
);
336 if (!pInfo
) return FALSE
;
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
;
351 /***********************************************************************
352 * LocalNext (TOOLHELP.58)
354 BOOL16 WINAPI
LocalNext16( LOCALENTRY
*pLocalEntry
)
356 WORD ds
= GlobalHandleToSel16( pLocalEntry
->hHeap
);
357 char *ptr
= MapSL( MAKESEGPTR( ds
, 0 ) );
360 if (!get_local_heap( ds
)) return FALSE
;
361 if (!pLocalEntry
->wNext
) return FALSE
;
362 pArena
= LOCAL_ARENA_PTR( ptr
, pLocalEntry
->wNext
);
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
;
372 pLocalEntry
->wNext
= 0;
373 pLocalEntry
->wSize
= pLocalEntry
->wNext
- pLocalEntry
->hHandle
;
378 /**********************************************************************
379 * ModuleFirst (TOOLHELP.59)
381 BOOL16 WINAPI
ModuleFirst16( MODULEENTRY
*lpme
)
383 lpme
->wNext
= get_thhook()->hExeHead
;
384 return ModuleNext16( lpme
);
388 /**********************************************************************
389 * ModuleNext (TOOLHELP.60)
391 BOOL16 WINAPI
ModuleNext16( MODULEENTRY
*lpme
)
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
;
410 /**********************************************************************
411 * ModuleFindName (TOOLHELP.61)
413 BOOL16 WINAPI
ModuleFindName16( MODULEENTRY
*lpme
, LPCSTR name
)
415 lpme
->wNext
= GetModuleHandle16( name
);
416 return ModuleNext16( lpme
);
420 /**********************************************************************
421 * ModuleFindHandle (TOOLHELP.62)
423 BOOL16 WINAPI
ModuleFindHandle16( MODULEENTRY
*lpme
, HMODULE16 hModule
)
425 hModule
= GetExePtr( hModule
);
426 lpme
->wNext
= hModule
;
427 return ModuleNext16( lpme
);
431 /***********************************************************************
432 * TaskFirst (TOOLHELP.63)
434 BOOL16 WINAPI
TaskFirst16( TASKENTRY
*lpte
)
436 lpte
->hNext
= get_thhook()->HeadTDB
;
437 return TaskNext16( lpte
);
441 /***********************************************************************
442 * TaskNext (TOOLHELP.64)
444 BOOL16 WINAPI
TaskNext16( TASKENTRY
*lpte
)
447 INSTANCEDATA
*pInstData
;
449 TRACE_(toolhelp
)("(%p): task=%04x\n", lpte
, lpte
->hNext
);
450 if (!lpte
->hNext
) return FALSE
;
452 /* make sure that task and hInstance are valid (skip initial Wine task !) */
454 pTask
= GlobalLock16( lpte
->hNext
);
455 if (!pTask
|| pTask
->magic
!= TDB_MAGIC
) return FALSE
;
456 if (pTask
->hInstance
)
458 lpte
->hNext
= pTask
->hNext
;
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
;
479 /***********************************************************************
480 * TaskFindHandle (TOOLHELP.65)
482 BOOL16 WINAPI
TaskFindHandle16( TASKENTRY
*lpte
, HTASK16 hTask
)
485 return TaskNext16( lpte
);
489 /***********************************************************************
490 * MemManInfo (TOOLHELP.72)
492 BOOL16 WINAPI
MemManInfo16( MEMMANINFO
*info
)
494 SYSTEM_BASIC_INFORMATION sbi
;
498 * Not unsurprisingly although the documentation says you
499 * _must_ provide the size in the dwSize field, this function
500 * (under Windows) always fills the structure and returns true.
502 NtQuerySystemInformation( SystemBasicInformation
, &sbi
, sizeof(sbi
), NULL
);
503 GlobalMemoryStatus( &status
);
504 info
->wPageSize
= sbi
.PageSize
;
505 info
->dwLargestFreeBlock
= status
.dwAvailVirtual
;
506 info
->dwMaxPagesAvailable
= info
->dwLargestFreeBlock
/ info
->wPageSize
;
507 info
->dwMaxPagesLockable
= info
->dwMaxPagesAvailable
;
508 info
->dwTotalLinearSpace
= status
.dwTotalVirtual
/ info
->wPageSize
;
509 info
->dwTotalUnlockedPages
= info
->dwTotalLinearSpace
;
510 info
->dwFreePages
= info
->dwMaxPagesAvailable
;
511 info
->dwTotalPages
= info
->dwTotalLinearSpace
;
512 info
->dwFreeLinearSpace
= info
->dwMaxPagesAvailable
;
513 info
->dwSwapFilePages
= status
.dwTotalPageFile
/ info
->wPageSize
;
518 /***********************************************************************
519 * NotifyRegister (TOOLHELP.73)
521 BOOL16 WINAPI
NotifyRegister16( HTASK16 htask
, FARPROC16 lpfnCallback
,
526 FIXME("(%x,%x,%x), semi-stub.\n",
527 htask
, (DWORD
)lpfnCallback
, wFlags
);
528 if (!htask
) htask
= GetCurrentTask();
529 for (i
=0;i
<nrofnotifys
;i
++)
530 if (notifys
[i
].htask
==htask
)
532 if (i
==nrofnotifys
) {
534 notifys
=HeapAlloc( GetProcessHeap(), 0,
535 sizeof(struct notify
) );
537 notifys
=HeapReAlloc( GetProcessHeap(), 0, notifys
,
538 sizeof(struct notify
)*(nrofnotifys
+1));
539 if (!notifys
) return FALSE
;
542 notifys
[i
].htask
=htask
;
543 notifys
[i
].lpfnCallback
=lpfnCallback
;
544 notifys
[i
].wFlags
=wFlags
;
548 /***********************************************************************
549 * NotifyUnregister (TOOLHELP.74)
551 BOOL16 WINAPI
NotifyUnregister16( HTASK16 htask
)
555 FIXME("(%x), semi-stub.\n", htask
);
556 if (!htask
) htask
= GetCurrentTask();
557 for (i
=nrofnotifys
;i
--;)
558 if (notifys
[i
].htask
==htask
)
562 memcpy(notifys
+i
,notifys
+(i
+1),sizeof(struct notify
)*(nrofnotifys
-i
-1));
563 notifys
=HeapReAlloc( GetProcessHeap(), 0, notifys
,
564 (nrofnotifys
-1)*sizeof(struct notify
));
569 /***********************************************************************
570 * StackTraceCSIPFirst (TOOLHELP.67)
572 BOOL16 WINAPI
StackTraceCSIPFirst16(STACKTRACEENTRY
*ste
, WORD wSS
, WORD wCS
, WORD wIP
, WORD wBP
)
574 FIXME("(%p, ss %04x, cs %04x, ip %04x, bp %04x): stub.\n", ste
, wSS
, wCS
, wIP
, wBP
);
578 /***********************************************************************
579 * StackTraceFirst (TOOLHELP.66)
581 BOOL16 WINAPI
StackTraceFirst16(STACKTRACEENTRY
*ste
, HTASK16 Task
)
583 FIXME("(%p, %04x), stub.\n", ste
, Task
);
587 /***********************************************************************
588 * StackTraceNext (TOOLHELP.68)
590 BOOL16 WINAPI
StackTraceNext16(STACKTRACEENTRY
*ste
)
592 FIXME("(%p), stub.\n", ste
);
596 /***********************************************************************
597 * InterruptRegister (TOOLHELP.75)
599 BOOL16 WINAPI
InterruptRegister16( HTASK16 task
, FARPROC callback
)
601 FIXME("(%04x, %p), stub.\n", task
, callback
);
605 /***********************************************************************
606 * InterruptUnRegister (TOOLHELP.76)
608 BOOL16 WINAPI
InterruptUnRegister16( HTASK16 task
)
610 FIXME("(%04x), stub.\n", task
);
614 /***********************************************************************
615 * TerminateApp (TOOLHELP.77)
617 * See "Undocumented Windows".
619 void WINAPI
TerminateApp16(HTASK16 hTask
, WORD wFlags
)
621 if (hTask
&& hTask
!= GetCurrentTask())
623 FIXME("cannot terminate task %x\n", hTask
);
628 /* check undocumented flag */
629 if (!(wFlags
& 0x8000))
630 TASK_CallTaskSignalProc( USIG16_TERMINATION
, hTask
);
633 /* UndocWin says to call int 0x21/0x4c exit=0xff here,
634 but let's just call ExitThread */
638 /***********************************************************************
639 * MemoryRead (TOOLHELP.78)
641 DWORD WINAPI
MemoryRead16( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
646 wine_ldt_get_entry( sel
, &entry
);
647 if (wine_ldt_is_empty( &entry
)) return 0;
648 limit
= wine_ldt_get_limit( &entry
);
649 if (offset
> limit
) return 0;
650 if (offset
+ count
> limit
+ 1) count
= limit
+ 1 - offset
;
651 memcpy( buffer
, (char *)wine_ldt_get_base(&entry
) + offset
, count
);
656 /***********************************************************************
657 * MemoryWrite (TOOLHELP.79)
659 DWORD WINAPI
MemoryWrite16( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
664 wine_ldt_get_entry( sel
, &entry
);
665 if (wine_ldt_is_empty( &entry
)) return 0;
666 limit
= wine_ldt_get_limit( &entry
);
667 if (offset
> limit
) return 0;
668 if (offset
+ count
> limit
) count
= limit
+ 1 - offset
;
669 memcpy( (char *)wine_ldt_get_base(&entry
) + offset
, buffer
, count
);
673 /***********************************************************************
674 * TimerCount (TOOLHELP.80)
676 BOOL16 WINAPI
TimerCount16( TIMERINFO
*pTimerInfo
)
679 * In standard mode, dwmsSinceStart = dwmsThisVM
681 * I tested this, under Windows in enhanced mode, and
682 * if you never switch VM (ie start/stop DOS) these
683 * values should be the same as well.
685 * Also, Wine should adjust for the hardware timer
686 * to reduce the amount of error to ~1ms.
687 * I can't be bothered, can you?
689 pTimerInfo
->dwmsSinceStart
= pTimerInfo
->dwmsThisVM
= GetTickCount();
693 /***********************************************************************
694 * SystemHeapInfo (TOOLHELP.71)
696 BOOL16 WINAPI
SystemHeapInfo16( SYSHEAPINFO
*pHeapInfo
)
698 STACK16FRAME
* stack16
= MapSL((SEGPTR
)NtCurrentTeb()->WOW32Reserved
);
699 HANDLE16 oldDS
= stack16
->ds
;
700 WORD user
= LoadLibrary16( "USER.EXE" );
701 WORD gdi
= LoadLibrary16( "GDI.EXE" );
703 pHeapInfo
->wUserFreePercent
= (int)LocalCountFree16() * 100 / LocalHeapSize16();
705 pHeapInfo
->wGDIFreePercent
= (int)LocalCountFree16() * 100 / LocalHeapSize16();
707 pHeapInfo
->hUserSegment
= user
;
708 pHeapInfo
->hGDISegment
= gdi
;
709 FreeLibrary16( user
);
710 FreeLibrary16( gdi
);
714 /***********************************************************************
715 * Local32Info (TOOLHELP.84)
717 BOOL16 WINAPI
Local32Info16( LOCAL32INFO
*pLocal32Info
, HGLOBAL16 handle
)
719 FIXME( "Call Local32Info16 in kernel\n" );
723 /***********************************************************************
724 * Local32First (TOOLHELP.85)
726 BOOL16 WINAPI
Local32First16( LOCAL32ENTRY
*pLocal32Entry
, HGLOBAL16 handle
)
728 FIXME( "Call Local32First16 in kernel\n" );
732 /***********************************************************************
733 * Local32Next (TOOLHELP.86)
735 BOOL16 WINAPI
Local32Next16( LOCAL32ENTRY
*pLocal32Entry
)
737 FIXME( "Call Local32Next16 in kernel\n" );