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
37 #include "wine/winbase16.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp
);
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 */
57 #define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */
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 */
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 */
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)))
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 */
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 */
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 */
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
178 FARPROC16 lpfnCallback
;
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 ));
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;
217 /***********************************************************************
218 * GlobalFirst (TOOLHELP.51)
220 BOOL16 WINAPI
GlobalFirst16( GLOBALENTRY
*pGlobal
, WORD wFlags
)
222 if (wFlags
== GLOBAL_LRU
) return FALSE
;
224 return GlobalNext16( pGlobal
, wFlags
);
228 /***********************************************************************
229 * GlobalNext (TOOLHELP.52)
231 BOOL16 WINAPI
GlobalNext16( GLOBALENTRY
*pGlobal
, WORD wFlags
)
233 GLOBALARENA
*pGlobalArena
= get_global_arena();
236 if (pGlobal
->dwNext
>= GLOBAL_MAX_COUNT
) return FALSE
;
237 pArena
= pGlobalArena
+ pGlobal
->dwNext
;
238 if (wFlags
== GLOBAL_FREE
) /* only free blocks */
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
;
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
;
262 /***********************************************************************
263 * GlobalInfo (TOOLHELP.53)
265 BOOL16 WINAPI
GlobalInfo16( GLOBALINFO
*pInfo
)
267 GLOBALARENA
*pGlobalArena
= get_global_arena();
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
++;
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
;
303 /***********************************************************************
304 * GlobalEntryModule (TOOLHELP.55)
306 BOOL16 WINAPI
GlobalEntryModule16( GLOBALENTRY
*pGlobal
, HMODULE16 hModule
,
309 FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal
, hModule
, wSeg
);
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
;
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
;
349 /***********************************************************************
350 * LocalNext (TOOLHELP.58)
352 BOOL16 WINAPI
LocalNext16( LOCALENTRY
*pLocalEntry
)
354 WORD ds
= GlobalHandleToSel16( pLocalEntry
->hHeap
);
355 char *ptr
= MapSL( MAKESEGPTR( ds
, 0 ) );
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
;
370 pLocalEntry
->wNext
= 0;
371 pLocalEntry
->wSize
= pLocalEntry
->wNext
- pLocalEntry
->hHandle
;
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
)
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
;
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
)
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 !) */
452 pTask
= GlobalLock16( lpte
->hNext
);
453 if (!pTask
|| pTask
->magic
!= TDB_MAGIC
) return FALSE
;
454 if (pTask
->hInstance
)
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
;
477 /***********************************************************************
478 * TaskFindHandle (TOOLHELP.65)
480 BOOL16 WINAPI
TaskFindHandle16( TASKENTRY
*lpte
, HTASK16 hTask
)
483 return TaskNext16( lpte
);
487 /***********************************************************************
488 * MemManInfo (TOOLHELP.72)
490 BOOL16 WINAPI
MemManInfo16( MEMMANINFO
*info
)
492 SYSTEM_BASIC_INFORMATION sbi
;
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
;
516 /***********************************************************************
517 * NotifyRegister (TOOLHELP.73)
519 BOOL16 WINAPI
NotifyRegister16( HTASK16 htask
, FARPROC16 lpfnCallback
,
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
)
530 if (i
==nrofnotifys
) {
532 notifys
=HeapAlloc( GetProcessHeap(), 0,
533 sizeof(struct notify
) );
535 notifys
=HeapReAlloc( GetProcessHeap(), 0, notifys
,
536 sizeof(struct notify
)*(nrofnotifys
+1));
537 if (!notifys
) return FALSE
;
540 notifys
[i
].htask
=htask
;
541 notifys
[i
].lpfnCallback
=lpfnCallback
;
542 notifys
[i
].wFlags
=wFlags
;
546 /***********************************************************************
547 * NotifyUnregister (TOOLHELP.74)
549 BOOL16 WINAPI
NotifyUnregister16( HTASK16 htask
)
553 FIXME("(%x), semi-stub.\n", htask
);
554 if (!htask
) htask
= GetCurrentTask();
555 for (i
=nrofnotifys
;i
--;)
556 if (notifys
[i
].htask
==htask
)
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
));
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
);
576 /***********************************************************************
577 * StackTraceFirst (TOOLHELP.66)
579 BOOL16 WINAPI
StackTraceFirst16(STACKTRACEENTRY
*ste
, HTASK16 Task
)
581 FIXME("(%p, %04x), stub.\n", ste
, Task
);
585 /***********************************************************************
586 * StackTraceNext (TOOLHELP.68)
588 BOOL16 WINAPI
StackTraceNext16(STACKTRACEENTRY
*ste
)
590 FIXME("(%p), stub.\n", ste
);
594 /***********************************************************************
595 * InterruptRegister (TOOLHELP.75)
597 BOOL16 WINAPI
InterruptRegister16( HTASK16 task
, FARPROC callback
)
599 FIXME("(%04x, %p), stub.\n", task
, callback
);
603 /***********************************************************************
604 * InterruptUnRegister (TOOLHELP.76)
606 BOOL16 WINAPI
InterruptUnRegister16( HTASK16 task
)
608 FIXME("(%04x), stub.\n", task
);
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
);
626 /* check undocumented flag */
627 if (!(wFlags
& 0x8000))
628 TASK_CallTaskSignalProc( USIG16_TERMINATION
, hTask
);
631 /* UndocWin says to call int 0x21/0x4c exit=0xff here,
632 but let's just call ExitThread */
636 /***********************************************************************
637 * MemoryRead (TOOLHELP.78)
639 DWORD WINAPI
MemoryRead16( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
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
);
654 /***********************************************************************
655 * MemoryWrite (TOOLHELP.79)
657 DWORD WINAPI
MemoryWrite16( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
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
);
671 /***********************************************************************
672 * TimerCount (TOOLHELP.80)
674 BOOL16 WINAPI
TimerCount16( TIMERINFO
*pTimerInfo
)
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();
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" );
701 pHeapInfo
->wUserFreePercent
= (int)LocalCountFree16() * 100 / LocalHeapSize16();
703 pHeapInfo
->wGDIFreePercent
= (int)LocalCountFree16() * 100 / LocalHeapSize16();
705 pHeapInfo
->hUserSegment
= user
;
706 pHeapInfo
->hGDISegment
= gdi
;
707 FreeLibrary16( user
);
708 FreeLibrary16( gdi
);
712 /***********************************************************************
713 * Local32Info (TOOLHELP.84)
715 BOOL16 WINAPI
Local32Info16( LOCAL32INFO
*pLocal32Info
, HGLOBAL16 handle
)
717 FIXME( "Call Local32Info16 in kernel\n" );
721 /***********************************************************************
722 * Local32First (TOOLHELP.85)
724 BOOL16 WINAPI
Local32First16( LOCAL32ENTRY
*pLocal32Entry
, HGLOBAL16 handle
)
726 FIXME( "Call Local32First16 in kernel\n" );
730 /***********************************************************************
731 * Local32Next (TOOLHELP.86)
733 BOOL16 WINAPI
Local32Next16( LOCAL32ENTRY
*pLocal32Entry
)
735 FIXME( "Call Local32Next16 in kernel\n" );