msvcp90: Return last index in string::find_last_not_of_cstr_substr if input is empty.
[wine/multimedia.git] / dlls / toolhelp.dll16 / toolhelp.c
blob4fa1500e5ec5e6914d905ba2024dbc95157597a3
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 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 #include <ctype.h>
33 #include <assert.h>
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winternl.h"
37 #include "wownt32.h"
39 #include "wine/winbase16.h"
40 #include "toolhelp.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp);
45 #include "pshpack1.h"
47 typedef struct
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 */
57 } GLOBALARENA;
59 #define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */
61 typedef struct
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 */
83 } LOCALHEAPINFO;
85 typedef struct
87 /* Arena header */
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 */
94 } LOCALARENA;
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)))
100 typedef struct
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 */
109 } INSTANCEDATA;
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 */
124 } THHOOK;
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 */
166 } NE_MODULE;
168 #include "poppack.h"
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
177 static struct notify
179 HTASK16 htask;
180 FARPROC16 lpfnCallback;
181 WORD wFlags;
182 } *notifys = NULL;
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 ));
191 return thhook;
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;
215 return handle | 7;
219 /***********************************************************************
220 * GlobalFirst (TOOLHELP.51)
222 BOOL16 WINAPI GlobalFirst16( GLOBALENTRY *pGlobal, WORD wFlags )
224 if (wFlags == GLOBAL_LRU) return FALSE;
225 pGlobal->dwNext = 0;
226 return GlobalNext16( pGlobal, wFlags );
230 /***********************************************************************
231 * GlobalNext (TOOLHELP.52)
233 BOOL16 WINAPI GlobalNext16( GLOBALENTRY *pGlobal, WORD wFlags)
235 GLOBALARENA *pGlobalArena = get_global_arena();
236 GLOBALARENA *pArena;
238 if (pGlobal->dwNext >= GLOBAL_MAX_COUNT) return FALSE;
239 pArena = pGlobalArena + pGlobal->dwNext;
240 if (wFlags == GLOBAL_FREE) /* only free blocks */
242 int i;
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;
246 pGlobal->dwNext = i;
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;
258 pGlobal->wData = 0;
259 pGlobal->dwNext++;
260 return TRUE;
264 /***********************************************************************
265 * GlobalInfo (TOOLHELP.53)
267 BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo )
269 GLOBALARENA *pGlobalArena = get_global_arena();
270 GLOBALARENA *pArena;
271 int i;
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++;
278 return TRUE;
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;
299 pGlobal->wData = 0;
300 pGlobal->dwNext++;
301 return TRUE;
305 /***********************************************************************
306 * GlobalEntryModule (TOOLHELP.55)
308 BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule,
309 WORD wSeg )
311 FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg);
312 return FALSE;
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;
324 return TRUE;
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;
347 return TRUE;
351 /***********************************************************************
352 * LocalNext (TOOLHELP.58)
354 BOOL16 WINAPI LocalNext16( LOCALENTRY *pLocalEntry )
356 WORD ds = GlobalHandleToSel16( pLocalEntry->hHeap );
357 char *ptr = MapSL( MAKESEGPTR( ds, 0 ) );
358 LOCALARENA *pArena;
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;
371 else
372 pLocalEntry->wNext = 0;
373 pLocalEntry->wSize = pLocalEntry->wNext - pLocalEntry->hHandle;
374 return TRUE;
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 )
393 NE_MODULE *pModule;
394 char *name;
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;
406 return TRUE;
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 )
446 TDB *pTask;
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 !) */
453 while (1) {
454 pTask = GlobalLock16( lpte->hNext );
455 if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
456 if (pTask->hInstance)
457 break;
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;
475 return TRUE;
479 /***********************************************************************
480 * TaskFindHandle (TOOLHELP.65)
482 BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask )
484 lpte->hNext = hTask;
485 return TaskNext16( lpte );
489 /***********************************************************************
490 * MemManInfo (TOOLHELP.72)
492 BOOL16 WINAPI MemManInfo16( MEMMANINFO *info )
494 SYSTEM_BASIC_INFORMATION sbi;
495 MEMORYSTATUS status;
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;
514 return TRUE;
518 /***********************************************************************
519 * NotifyRegister (TOOLHELP.73)
521 BOOL16 WINAPI NotifyRegister16( HTASK16 htask, FARPROC16 lpfnCallback,
522 WORD wFlags )
524 int i;
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)
531 break;
532 if (i==nrofnotifys) {
533 if (notifys==NULL)
534 notifys=HeapAlloc( GetProcessHeap(), 0,
535 sizeof(struct notify) );
536 else
537 notifys=HeapReAlloc( GetProcessHeap(), 0, notifys,
538 sizeof(struct notify)*(nrofnotifys+1));
539 if (!notifys) return FALSE;
540 nrofnotifys++;
542 notifys[i].htask=htask;
543 notifys[i].lpfnCallback=lpfnCallback;
544 notifys[i].wFlags=wFlags;
545 return TRUE;
548 /***********************************************************************
549 * NotifyUnregister (TOOLHELP.74)
551 BOOL16 WINAPI NotifyUnregister16( HTASK16 htask )
553 int i;
555 FIXME("(%x), semi-stub.\n", htask );
556 if (!htask) htask = GetCurrentTask();
557 for (i=nrofnotifys;i--;)
558 if (notifys[i].htask==htask)
559 break;
560 if (i==-1)
561 return FALSE;
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));
565 nrofnotifys--;
566 return TRUE;
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);
575 return TRUE;
578 /***********************************************************************
579 * StackTraceFirst (TOOLHELP.66)
581 BOOL16 WINAPI StackTraceFirst16(STACKTRACEENTRY *ste, HTASK16 Task)
583 FIXME("(%p, %04x), stub.\n", ste, Task);
584 return TRUE;
587 /***********************************************************************
588 * StackTraceNext (TOOLHELP.68)
590 BOOL16 WINAPI StackTraceNext16(STACKTRACEENTRY *ste)
592 FIXME("(%p), stub.\n", ste);
593 return TRUE;
596 /***********************************************************************
597 * InterruptRegister (TOOLHELP.75)
599 BOOL16 WINAPI InterruptRegister16( HTASK16 task, FARPROC callback )
601 FIXME("(%04x, %p), stub.\n", task, callback);
602 return TRUE;
605 /***********************************************************************
606 * InterruptUnRegister (TOOLHELP.76)
608 BOOL16 WINAPI InterruptUnRegister16( HTASK16 task )
610 FIXME("(%04x), stub.\n", task);
611 return TRUE;
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);
624 return;
627 #if 0 /* FIXME */
628 /* check undocumented flag */
629 if (!(wFlags & 0x8000))
630 TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask );
631 #endif
633 /* UndocWin says to call int 0x21/0x4c exit=0xff here,
634 but let's just call ExitThread */
635 ExitThread(0xff);
638 /***********************************************************************
639 * MemoryRead (TOOLHELP.78)
641 DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count )
643 LDT_ENTRY entry;
644 DWORD limit;
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 );
652 return count;
656 /***********************************************************************
657 * MemoryWrite (TOOLHELP.79)
659 DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count )
661 LDT_ENTRY entry;
662 DWORD limit;
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 );
670 return count;
673 /***********************************************************************
674 * TimerCount (TOOLHELP.80)
676 BOOL16 WINAPI TimerCount16( TIMERINFO *pTimerInfo )
678 /* FIXME
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();
690 return TRUE;
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" );
702 stack16->ds = user;
703 pHeapInfo->wUserFreePercent = (int)LocalCountFree16() * 100 / LocalHeapSize16();
704 stack16->ds = gdi;
705 pHeapInfo->wGDIFreePercent = (int)LocalCountFree16() * 100 / LocalHeapSize16();
706 stack16->ds = oldDS;
707 pHeapInfo->hUserSegment = user;
708 pHeapInfo->hGDISegment = gdi;
709 FreeLibrary16( user );
710 FreeLibrary16( gdi );
711 return TRUE;
714 /***********************************************************************
715 * Local32Info (TOOLHELP.84)
717 BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
719 FIXME( "Call Local32Info16 in kernel\n" );
720 return FALSE;
723 /***********************************************************************
724 * Local32First (TOOLHELP.85)
726 BOOL16 WINAPI Local32First16( LOCAL32ENTRY *pLocal32Entry, HGLOBAL16 handle )
728 FIXME( "Call Local32First16 in kernel\n" );
729 return FALSE;
732 /***********************************************************************
733 * Local32Next (TOOLHELP.86)
735 BOOL16 WINAPI Local32Next16( LOCAL32ENTRY *pLocal32Entry )
737 FIXME( "Call Local32Next16 in kernel\n" );
738 return FALSE;