Commit | Line | Data |
---|---|---|
c1dbeade AJ |
1 | /* |
2 | * Toolhelp functions | |
3 | * | |
4 | * Copyright 1996 Marcus Meissner | |
5 | * Copyright 2009 Alexandre Julliard | |
6 | * | |
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. | |
11 | * | |
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. | |
16 | * | |
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 | |
20 | */ | |
21 | ||
22 | #include "config.h" | |
23 | ||
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" | |
38 | ||
39 | #include "wine/winbase16.h" | |
40 | #include "toolhelp.h" | |
41 | #include "wine/debug.h" | |
42 | ||
43 | WINE_DEFAULT_DEBUG_CHANNEL(toolhelp); | |
44 | ||
45 | #include "pshpack1.h" | |
46 | ||
47 | typedef struct | |
48 | { | |
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; | |
58 | ||
59 | #define GLOBAL_MAX_COUNT 8192 /* Max number of allocated blocks */ | |
60 | ||
61 | typedef struct | |
62 | { | |
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; | |
84 | ||
85 | typedef struct | |
86 | { | |
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; | |
95 | ||
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))) | |
99 | ||
100 | typedef struct | |
101 | { | |
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; | |
110 | ||
111 | typedef struct _THHOOK | |
112 | { | |
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; | |
125 | ||
126 | typedef struct _NE_MODULE | |
127 | { | |
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; | |
167 | ||
168 | #include "poppack.h" | |
169 | ||
170 | #define TDB_MAGIC ('T' | ('D' << 8)) | |
171 | ||
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 | |
175 | */ | |
176 | ||
177 | static struct notify | |
178 | { | |
179 | HTASK16 htask; | |
180 | FARPROC16 lpfnCallback; | |
181 | WORD wFlags; | |
182 | } *notifys = NULL; | |
183 | ||
184 | static int nrofnotifys = 0; | |
185 | ||
186 | static THHOOK *get_thhook(void) | |
187 | { | |
188 | static THHOOK *thhook; | |
189 | ||
190 | if (!thhook) thhook = MapSL( (SEGPTR)GetProcAddress16( GetModuleHandle16("KERNEL"), (LPCSTR)332 )); | |
191 | return thhook; | |
192 | } | |
193 | ||
194 | static GLOBALARENA *get_global_arena(void) | |
195 | { | |
196 | return *(GLOBALARENA **)get_thhook(); | |
197 | } | |
198 | ||
199 | static LOCALHEAPINFO *get_local_heap( HANDLE16 ds ) | |
200 | { | |
201 | INSTANCEDATA *ptr = MapSL( MAKESEGPTR( ds, 0 )); | |
202 | ||
203 | if (!ptr || !ptr->heap) return NULL; | |
204 | return (LOCALHEAPINFO*)((char*)ptr + ptr->heap); | |
205 | } | |
206 | ||
207 | ||
208 | /*********************************************************************** | |
209 | * GlobalHandleToSel (TOOLHELP.50) | |
210 | */ | |
211 | WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle ) | |
212 | { | |
213 | if (!handle) return 0; | |
214 | if (!(handle & 7)) return handle - 1; | |
215 | return handle | 7; | |
216 | } | |
217 | ||
218 | ||
219 | /*********************************************************************** | |
220 | * GlobalFirst (TOOLHELP.51) | |
221 | */ | |
222 | BOOL16 WINAPI GlobalFirst16( GLOBALENTRY *pGlobal, WORD wFlags ) | |
223 | { | |
224 | if (wFlags == GLOBAL_LRU) return FALSE; | |
225 | pGlobal->dwNext = 0; | |
226 | return GlobalNext16( pGlobal, wFlags ); | |
227 | } | |
228 | ||
229 | ||
230 | /*********************************************************************** | |
231 | * GlobalNext (TOOLHELP.52) | |
232 | */ | |
233 | BOOL16 WINAPI GlobalNext16( GLOBALENTRY *pGlobal, WORD wFlags) | |
234 | { | |
235 | GLOBALARENA *pGlobalArena = get_global_arena(); | |
236 | GLOBALARENA *pArena; | |
237 | ||
238 | if (pGlobal->dwNext >= GLOBAL_MAX_COUNT) return FALSE; | |
239 | pArena = pGlobalArena + pGlobal->dwNext; | |
240 | if (wFlags == GLOBAL_FREE) /* only free blocks */ | |
241 | { | |
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; | |
247 | } | |
248 | ||
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; | |
261 | } | |
262 | ||
263 | ||
264 | /*********************************************************************** | |
265 | * GlobalInfo (TOOLHELP.53) | |
266 | */ | |
267 | BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo ) | |
268 | { | |
269 | GLOBALARENA *pGlobalArena = get_global_arena(); | |
270 | GLOBALARENA *pArena; | |
271 | int i; | |
272 | ||
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; | |
279 | } | |
280 | ||
281 | ||
282 | /*********************************************************************** | |
283 | * GlobalEntryHandle (TOOLHELP.54) | |
284 | */ | |
285 | BOOL16 WINAPI GlobalEntryHandle16( GLOBALENTRY *pGlobal, HGLOBAL16 hItem ) | |
286 | { | |
287 | GLOBALARENA *pGlobalArena = get_global_arena(); | |
288 | GLOBALARENA *pArena = pGlobalArena + (hItem >> __AHSHIFT); | |
289 | ||
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; | |
302 | } | |
303 | ||
304 | ||
305 | /*********************************************************************** | |
306 | * GlobalEntryModule (TOOLHELP.55) | |
307 | */ | |
308 | BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule, | |
309 | WORD wSeg ) | |
310 | { | |
311 | FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg); | |
312 | return FALSE; | |
313 | } | |
314 | ||
315 | ||
316 | /*********************************************************************** | |
317 | * LocalInfo (TOOLHELP.56) | |
318 | */ | |
319 | BOOL16 WINAPI LocalInfo16( LOCALINFO *pLocalInfo, HGLOBAL16 handle ) | |
320 | { | |
321 | LOCALHEAPINFO *pInfo = get_local_heap( SELECTOROF(WOWGlobalLock16(handle)) ); | |
322 | if (!pInfo) return FALSE; | |
323 | pLocalInfo->wcItems = pInfo->items; | |
324 | return TRUE; | |
325 | } | |
326 | ||
327 | ||
328 | /*********************************************************************** | |
329 | * LocalFirst (TOOLHELP.57) | |
330 | */ | |
331 | BOOL16 WINAPI LocalFirst16( LOCALENTRY *pLocalEntry, HGLOBAL16 handle ) | |
332 | { | |
333 | WORD ds = GlobalHandleToSel16( handle ); | |
334 | char *ptr = MapSL( MAKESEGPTR( ds, 0 ) ); | |
335 | LOCALHEAPINFO *pInfo = get_local_heap( ds ); | |
336 | if (!pInfo) return FALSE; | |
337 | ||
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; | |
348 | } | |
349 | ||
350 | ||
351 | /*********************************************************************** | |
352 | * LocalNext (TOOLHELP.58) | |
353 | */ | |
354 | BOOL16 WINAPI LocalNext16( LOCALENTRY *pLocalEntry ) | |
355 | { | |
356 | WORD ds = GlobalHandleToSel16( pLocalEntry->hHeap ); | |
357 | char *ptr = MapSL( MAKESEGPTR( ds, 0 ) ); | |
358 | LOCALARENA *pArena; | |
359 | ||
360 | if (!get_local_heap( ds )) return FALSE; | |
361 | if (!pLocalEntry->wNext) return FALSE; | |
362 | pArena = LOCAL_ARENA_PTR( ptr, pLocalEntry->wNext ); | |
363 | ||
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; | |
375 | } | |
376 | ||
377 | ||
378 | /********************************************************************** | |
379 | * ModuleFirst (TOOLHELP.59) | |
380 | */ | |
381 | BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme ) | |
382 | { | |
383 | lpme->wNext = get_thhook()->hExeHead; | |
384 | return ModuleNext16( lpme ); | |
385 | } | |
386 | ||
387 | ||
388 | /********************************************************************** | |
389 | * ModuleNext (TOOLHELP.60) | |
390 | */ | |
391 | BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme ) | |
392 | { | |
393 | NE_MODULE *pModule; | |
394 | char *name; | |
395 | ||
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; | |
407 | } | |
408 | ||
409 | ||
410 | /********************************************************************** | |
411 | * ModuleFindName (TOOLHELP.61) | |
412 | */ | |
413 | BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name ) | |
414 | { | |
415 | lpme->wNext = GetModuleHandle16( name ); | |
416 | return ModuleNext16( lpme ); | |
417 | } | |
418 | ||
419 | ||
420 | /********************************************************************** | |
421 | * ModuleFindHandle (TOOLHELP.62) | |
422 | */ | |
423 | BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule ) | |
424 | { | |
425 | hModule = GetExePtr( hModule ); | |
426 | lpme->wNext = hModule; | |
427 | return ModuleNext16( lpme ); | |
428 | } | |
429 | ||
430 | ||
431 | /*********************************************************************** | |
432 | * TaskFirst (TOOLHELP.63) | |
433 | */ | |
434 | BOOL16 WINAPI TaskFirst16( TASKENTRY *lpte ) | |
435 | { | |
436 | lpte->hNext = get_thhook()->HeadTDB; | |
437 | return TaskNext16( lpte ); | |
438 | } | |
439 | ||
440 | ||
441 | /*********************************************************************** | |
442 | * TaskNext (TOOLHELP.64) | |
443 | */ | |
444 | BOOL16 WINAPI TaskNext16( TASKENTRY *lpte ) | |
445 | { | |
446 | TDB *pTask; | |
447 | INSTANCEDATA *pInstData; | |
448 | ||
449 | TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext ); | |
450 | if (!lpte->hNext) return FALSE; | |
451 | ||
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; | |
459 | } | |
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; | |
476 | } | |
477 | ||
478 | ||
479 | /*********************************************************************** | |
480 | * TaskFindHandle (TOOLHELP.65) | |
481 | */ | |
482 | BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask ) | |
483 | { | |
484 | lpte->hNext = hTask; | |
485 | return TaskNext16( lpte ); | |
486 | } | |
487 | ||
488 | ||
489 | /*********************************************************************** | |
490 | * MemManInfo (TOOLHELP.72) | |
491 | */ | |
492 | BOOL16 WINAPI MemManInfo16( MEMMANINFO *info ) | |
493 | { | |
494 | MEMORYSTATUS status; | |
495 | ||
496 | /* | |
497 | * Not unsurprisingly although the documentation says you | |
498 | * _must_ provide the size in the dwSize field, this function | |
499 | * (under Windows) always fills the structure and returns true. | |
500 | */ | |
501 | GlobalMemoryStatus( &status ); | |
502 | info->wPageSize = getpagesize(); | |
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; | |
513 | } | |
514 | ||
515 | ||
516 | /*********************************************************************** | |
517 | * NotifyRegister (TOOLHELP.73) | |
518 | */ | |
519 | BOOL16 WINAPI NotifyRegister16( HTASK16 htask, FARPROC16 lpfnCallback, | |
520 | WORD wFlags ) | |
521 | { | |
522 | int i; | |
523 | ||
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++; | |
539 | } | |
540 | notifys[i].htask=htask; | |
541 | notifys[i].lpfnCallback=lpfnCallback; | |
542 | notifys[i].wFlags=wFlags; | |
543 | return TRUE; | |
544 | } | |
545 | ||
546 | /*********************************************************************** | |
547 | * NotifyUnregister (TOOLHELP.74) | |
548 | */ | |
549 | BOOL16 WINAPI NotifyUnregister16( HTASK16 htask ) | |
550 | { | |
551 | int i; | |
552 | ||
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; | |
565 | } | |
566 | ||
567 | /*********************************************************************** | |
568 | * StackTraceCSIPFirst (TOOLHELP.67) | |
569 | */ | |
570 | BOOL16 WINAPI StackTraceCSIPFirst16(STACKTRACEENTRY *ste, WORD wSS, WORD wCS, WORD wIP, WORD wBP) | |
571 | { | |
572 | FIXME("(%p, ss %04x, cs %04x, ip %04x, bp %04x): stub.\n", ste, wSS, wCS, wIP, wBP); | |
573 | return TRUE; | |
574 | } | |
575 | ||
576 | /*********************************************************************** | |
577 | * StackTraceFirst (TOOLHELP.66) | |
578 | */ | |
579 | BOOL16 WINAPI StackTraceFirst16(STACKTRACEENTRY *ste, HTASK16 Task) | |
580 | { | |
581 | FIXME("(%p, %04x), stub.\n", ste, Task); | |
582 | return TRUE; | |
583 | } | |
584 | ||
585 | /*********************************************************************** | |
586 | * StackTraceNext (TOOLHELP.68) | |
587 | */ | |
588 | BOOL16 WINAPI StackTraceNext16(STACKTRACEENTRY *ste) | |
589 | { | |
590 | FIXME("(%p), stub.\n", ste); | |
591 | return TRUE; | |
592 | } | |
593 | ||
594 | /*********************************************************************** | |
595 | * InterruptRegister (TOOLHELP.75) | |
596 | */ | |
597 | BOOL16 WINAPI InterruptRegister16( HTASK16 task, FARPROC callback ) | |
598 | { | |
599 | FIXME("(%04x, %p), stub.\n", task, callback); | |
600 | return TRUE; | |
601 | } | |
602 | ||
603 | /*********************************************************************** | |
604 | * InterruptUnRegister (TOOLHELP.76) | |
605 | */ | |
606 | BOOL16 WINAPI InterruptUnRegister16( HTASK16 task ) | |
607 | { | |
608 | FIXME("(%04x), stub.\n", task); | |
609 | return TRUE; | |
610 | } | |
611 | ||
612 | /*********************************************************************** | |
613 | * TerminateApp (TOOLHELP.77) | |
614 | * | |
615 | * See "Undocumented Windows". | |
616 | */ | |
617 | void WINAPI TerminateApp16(HTASK16 hTask, WORD wFlags) | |
618 | { | |
619 | if (hTask && hTask != GetCurrentTask()) | |
620 | { | |
621 | FIXME("cannot terminate task %x\n", hTask); | |
622 | return; | |
623 | } | |
624 | ||
625 | #if 0 /* FIXME */ | |
626 | /* check undocumented flag */ | |
627 | if (!(wFlags & 0x8000)) | |
628 | TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask ); | |
629 | #endif | |
630 | ||
631 | /* UndocWin says to call int 0x21/0x4c exit=0xff here, | |
632 | but let's just call ExitThread */ | |
633 | ExitThread(0xff); | |
634 | } | |
635 | ||
636 | /*********************************************************************** | |
637 | * MemoryRead (TOOLHELP.78) | |
638 | */ | |
639 | DWORD WINAPI MemoryRead16( WORD sel, DWORD offset, void *buffer, DWORD count ) | |
640 | { | |
641 | LDT_ENTRY entry; | |
642 | DWORD limit; | |
643 | ||
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; | |
651 | } | |
652 | ||
653 | ||
654 | /*********************************************************************** | |
655 | * MemoryWrite (TOOLHELP.79) | |
656 | */ | |
657 | DWORD WINAPI MemoryWrite16( WORD sel, DWORD offset, void *buffer, DWORD count ) | |
658 | { | |
659 | LDT_ENTRY entry; | |
660 | DWORD limit; | |
661 | ||
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; | |
669 | } | |
670 | ||
671 | /*********************************************************************** | |
672 | * TimerCount (TOOLHELP.80) | |
673 | */ | |
674 | BOOL16 WINAPI TimerCount16( TIMERINFO *pTimerInfo ) | |
675 | { | |
676 | /* FIXME | |
677 | * In standard mode, dwmsSinceStart = dwmsThisVM | |
678 | * | |
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. | |
682 | * | |
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? | |
686 | */ | |
687 | pTimerInfo->dwmsSinceStart = pTimerInfo->dwmsThisVM = GetTickCount(); | |
688 | return TRUE; | |
689 | } | |
690 | ||
691 | /*********************************************************************** | |
692 | * SystemHeapInfo (TOOLHELP.71) | |
693 | */ | |
694 | BOOL16 WINAPI SystemHeapInfo16( SYSHEAPINFO *pHeapInfo ) | |
695 | { | |
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; | |
710 | } | |
711 | ||
712 | /*********************************************************************** | |
713 | * Local32Info (TOOLHELP.84) | |
714 | */ | |
715 | BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle ) | |
716 | { | |
717 | FIXME( "Call Local32Info16 in kernel\n" ); | |
718 | return FALSE; | |
719 | } | |
720 | ||
721 | /*********************************************************************** | |
722 | * Local32First (TOOLHELP.85) | |
723 | */ | |
724 | BOOL16 WINAPI Local32First16( LOCAL32ENTRY *pLocal32Entry, HGLOBAL16 handle ) | |
725 | { | |
726 | FIXME( "Call Local32First16 in kernel\n" ); | |
727 | return FALSE; | |
728 | } | |
729 | ||
730 | /*********************************************************************** | |
731 | * Local32Next (TOOLHELP.86) | |
732 | */ | |
733 | BOOL16 WINAPI Local32Next16( LOCAL32ENTRY *pLocal32Entry ) | |
734 | { | |
735 | FIXME( "Call Local32Next16 in kernel\n" ); | |
736 | return FALSE; | |
737 | } |