2 * Misc Toolhelp functions
4 * Copyright 1996 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "wine/winbase16.h"
38 #include "wine/server.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp
);
45 /* FIXME: to make this work, we have to call back all these registered
46 * functions from all over the WINE code. Someone with more knowledge than
47 * me please do that. -Marcus
52 FARPROC16 lpfnCallback
;
56 static int nrofnotifys
= 0;
58 static FARPROC16 HookNotify
= NULL
;
60 /***********************************************************************
61 * NotifyRegister (TOOLHELP.73)
63 BOOL16 WINAPI
NotifyRegister16( HTASK16 htask
, FARPROC16 lpfnCallback
,
68 FIXME("(%x,%lx,%x), semi-stub.\n",
69 htask
, (DWORD
)lpfnCallback
, wFlags
);
70 if (!htask
) htask
= GetCurrentTask();
71 for (i
=0;i
<nrofnotifys
;i
++)
72 if (notifys
[i
].htask
==htask
)
76 notifys
=HeapAlloc( GetProcessHeap(), 0,
77 sizeof(struct notify
) );
79 notifys
=HeapReAlloc( GetProcessHeap(), 0, notifys
,
80 sizeof(struct notify
)*(nrofnotifys
+1));
81 if (!notifys
) return FALSE
;
84 notifys
[i
].htask
=htask
;
85 notifys
[i
].lpfnCallback
=lpfnCallback
;
86 notifys
[i
].wFlags
=wFlags
;
90 /***********************************************************************
91 * NotifyUnregister (TOOLHELP.74)
93 BOOL16 WINAPI
NotifyUnregister16( HTASK16 htask
)
97 FIXME("(%x), semi-stub.\n", htask
);
98 if (!htask
) htask
= GetCurrentTask();
99 for (i
=nrofnotifys
;i
--;)
100 if (notifys
[i
].htask
==htask
)
104 memcpy(notifys
+i
,notifys
+(i
+1),sizeof(struct notify
)*(nrofnotifys
-i
-1));
105 notifys
=HeapReAlloc( GetProcessHeap(), 0, notifys
,
106 (nrofnotifys
-1)*sizeof(struct notify
));
111 /***********************************************************************
112 * StackTraceCSIPFirst (TOOLHELP.67)
114 BOOL16 WINAPI
StackTraceCSIPFirst16(STACKTRACEENTRY
*ste
, WORD wSS
, WORD wCS
, WORD wIP
, WORD wBP
)
116 FIXME("(%p, ss %04x, cs %04x, ip %04x, bp %04x): stub.\n", ste
, wSS
, wCS
, wIP
, wBP
);
120 /***********************************************************************
121 * StackTraceFirst (TOOLHELP.66)
123 BOOL16 WINAPI
StackTraceFirst16(STACKTRACEENTRY
*ste
, HTASK16 Task
)
125 FIXME("(%p, %04x), stub.\n", ste
, Task
);
129 /***********************************************************************
130 * StackTraceNext (TOOLHELP.68)
132 BOOL16 WINAPI
StackTraceNext16(STACKTRACEENTRY
*ste
)
134 FIXME("(%p), stub.\n", ste
);
138 /***********************************************************************
139 * InterruptRegister (TOOLHELP.75)
141 BOOL16 WINAPI
InterruptRegister16( HTASK16 task
, FARPROC callback
)
143 FIXME("(%04x, %p), stub.\n", task
, callback
);
147 /***********************************************************************
148 * InterruptUnRegister (TOOLHELP.76)
150 BOOL16 WINAPI
InterruptUnRegister16( HTASK16 task
)
152 FIXME("(%04x), stub.\n", task
);
156 /***********************************************************************
157 * TimerCount (TOOLHELP.80)
159 BOOL16 WINAPI
TimerCount16( TIMERINFO
*pTimerInfo
)
162 * In standard mode, dwmsSinceStart = dwmsThisVM
164 * I tested this, under Windows in enhanced mode, and
165 * if you never switch VM (ie start/stop DOS) these
166 * values should be the same as well.
168 * Also, Wine should adjust for the hardware timer
169 * to reduce the amount of error to ~1ms.
170 * I can't be bothered, can you?
172 pTimerInfo
->dwmsSinceStart
= pTimerInfo
->dwmsThisVM
= GetTickCount();
176 /***********************************************************************
177 * SystemHeapInfo (TOOLHELP.71)
179 BOOL16 WINAPI
SystemHeapInfo16( SYSHEAPINFO
*pHeapInfo
)
181 STACK16FRAME
* stack16
= MapSL((SEGPTR
)NtCurrentTeb()->WOW32Reserved
);
182 HANDLE16 oldDS
= stack16
->ds
;
183 WORD user
= LoadLibrary16( "USER.EXE" );
184 WORD gdi
= LoadLibrary16( "GDI.EXE" );
186 pHeapInfo
->wUserFreePercent
= (int)LocalCountFree16() * 100 / LocalHeapSize16();
188 pHeapInfo
->wGDIFreePercent
= (int)LocalCountFree16() * 100 / LocalHeapSize16();
190 pHeapInfo
->hUserSegment
= user
;
191 pHeapInfo
->hGDISegment
= gdi
;
192 FreeLibrary16( user
);
193 FreeLibrary16( gdi
);
198 /***********************************************************************
199 * ToolHelpHook (KERNEL.341)
200 * see "Undocumented Windows"
202 FARPROC16 WINAPI
ToolHelpHook16(FARPROC16 lpfnNotifyHandler
)
206 FIXME("(%p), stub.\n", lpfnNotifyHandler
);
208 HookNotify
= lpfnNotifyHandler
;
209 /* just return previously installed notification function */
214 /***********************************************************************
215 * CreateToolhelp32Snapshot (KERNEL32.@)
217 HANDLE WINAPI
CreateToolhelp32Snapshot( DWORD flags
, DWORD process
)
221 TRACE("%lx,%lx\n", flags
, process
);
222 if (!(flags
& (TH32CS_SNAPPROCESS
|TH32CS_SNAPTHREAD
|TH32CS_SNAPMODULE
)))
224 FIXME("flags %lx not implemented\n", flags
);
225 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
226 return INVALID_HANDLE_VALUE
;
229 /* Now do the snapshot */
230 SERVER_START_REQ( create_snapshot
)
233 if (flags
& TH32CS_SNAPMODULE
) req
->flags
|= SNAP_MODULE
;
234 if (flags
& TH32CS_SNAPPROCESS
) req
->flags
|= SNAP_PROCESS
;
235 if (flags
& TH32CS_SNAPTHREAD
) req
->flags
|= SNAP_THREAD
;
237 req
->inherit
= (flags
& TH32CS_INHERIT
) != 0;
239 wine_server_call_err( req
);
243 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
248 /***********************************************************************
249 * TOOLHELP_Thread32Next
251 * Implementation of Thread32First/Next
253 static BOOL
TOOLHELP_Thread32Next( HANDLE handle
, LPTHREADENTRY32 lpte
, BOOL first
)
257 if (lpte
->dwSize
< sizeof(THREADENTRY32
))
259 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
260 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(THREADENTRY32
), lpte
->dwSize
);
263 SERVER_START_REQ( next_thread
)
265 req
->handle
= handle
;
267 if ((ret
= !wine_server_call_err( req
)))
269 lpte
->cntUsage
= reply
->count
;
270 lpte
->th32ThreadID
= (DWORD
)reply
->tid
;
271 lpte
->th32OwnerProcessID
= (DWORD
)reply
->pid
;
272 lpte
->tpBasePri
= reply
->base_pri
;
273 lpte
->tpDeltaPri
= reply
->delta_pri
;
274 lpte
->dwFlags
= 0; /* SDK: "reserved; do not use" */
281 /***********************************************************************
282 * Thread32First (KERNEL32.@)
284 * Return info about the first thread in a toolhelp32 snapshot
286 BOOL WINAPI
Thread32First(HANDLE hSnapshot
, LPTHREADENTRY32 lpte
)
288 return TOOLHELP_Thread32Next(hSnapshot
, lpte
, TRUE
);
291 /***********************************************************************
292 * Thread32Next (KERNEL32.@)
294 * Return info about the "next" thread in a toolhelp32 snapshot
296 BOOL WINAPI
Thread32Next(HANDLE hSnapshot
, LPTHREADENTRY32 lpte
)
298 return TOOLHELP_Thread32Next(hSnapshot
, lpte
, FALSE
);
301 /***********************************************************************
302 * TOOLHELP_Process32Next
304 * Implementation of Process32First/Next. Note that the ANSI / Unicode
305 * version check is a bit of a hack as it relies on the fact that only
306 * the last field is actually different.
308 static BOOL
TOOLHELP_Process32Next( HANDLE handle
, LPPROCESSENTRY32W lppe
, BOOL first
, BOOL unicode
)
311 WCHAR exe
[MAX_PATH
-1];
316 if (lppe
->dwSize
< sizeof(PROCESSENTRY32W
))
318 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
319 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(PROCESSENTRY32W
), lppe
->dwSize
);
325 if (lppe
->dwSize
< sizeof(PROCESSENTRY32
))
327 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
328 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(PROCESSENTRY32
), lppe
->dwSize
);
332 SERVER_START_REQ( next_process
)
334 req
->handle
= handle
;
336 wine_server_set_reply( req
, exe
, sizeof(exe
) );
337 if ((ret
= !wine_server_call_err( req
)))
339 lppe
->cntUsage
= reply
->count
;
340 lppe
->th32ProcessID
= reply
->pid
;
341 lppe
->th32DefaultHeapID
= (DWORD
)reply
->heap
;
342 lppe
->th32ModuleID
= (DWORD
)reply
->module
;
343 lppe
->cntThreads
= reply
->threads
;
344 lppe
->th32ParentProcessID
= reply
->ppid
;
345 lppe
->pcPriClassBase
= reply
->priority
;
346 lppe
->dwFlags
= -1; /* FIXME */
349 len
= wine_server_reply_size(reply
) / sizeof(WCHAR
);
350 memcpy(lppe
->szExeFile
, reply
, wine_server_reply_size(reply
));
351 lppe
->szExeFile
[len
] = 0;
355 LPPROCESSENTRY32 lppe_a
= (LPPROCESSENTRY32
) lppe
;
357 len
= WideCharToMultiByte( CP_ACP
, 0, exe
, wine_server_reply_size(reply
) / sizeof(WCHAR
),
358 lppe_a
->szExeFile
, sizeof(lppe_a
->szExeFile
)-1, NULL
, NULL
);
359 lppe_a
->szExeFile
[len
] = 0;
368 /***********************************************************************
369 * Process32First (KERNEL32.@)
371 * Return info about the first process in a toolhelp32 snapshot
373 BOOL WINAPI
Process32First(HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
375 return TOOLHELP_Process32Next( hSnapshot
, (LPPROCESSENTRY32W
) lppe
, TRUE
, FALSE
/* ANSI */ );
378 /***********************************************************************
379 * Process32Next (KERNEL32.@)
381 * Return info about the "next" process in a toolhelp32 snapshot
383 BOOL WINAPI
Process32Next(HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
385 return TOOLHELP_Process32Next( hSnapshot
, (LPPROCESSENTRY32W
) lppe
, FALSE
, FALSE
/* ANSI */ );
388 /***********************************************************************
389 * Process32FirstW (KERNEL32.@)
391 * Return info about the first process in a toolhelp32 snapshot
393 BOOL WINAPI
Process32FirstW(HANDLE hSnapshot
, LPPROCESSENTRY32W lppe
)
395 return TOOLHELP_Process32Next( hSnapshot
, lppe
, TRUE
, TRUE
/* Unicode */ );
398 /***********************************************************************
399 * Process32NextW (KERNEL32.@)
401 * Return info about the "next" process in a toolhelp32 snapshot
403 BOOL WINAPI
Process32NextW(HANDLE hSnapshot
, LPPROCESSENTRY32W lppe
)
405 return TOOLHELP_Process32Next( hSnapshot
, lppe
, FALSE
, TRUE
/* Unicode */ );
409 /***********************************************************************
410 * TOOLHELP_Module32NextW
412 * Implementation of Module32First/Next
414 static BOOL
TOOLHELP_Module32NextW( HANDLE handle
, LPMODULEENTRY32W lpme
, BOOL first
)
420 if (lpme
->dwSize
< sizeof (MODULEENTRY32W
))
422 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
423 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32W
), lpme
->dwSize
);
426 SERVER_START_REQ( next_module
)
428 req
->handle
= handle
;
430 wine_server_set_reply( req
, exe
, sizeof(exe
) );
431 if ((ret
= !wine_server_call_err( req
)))
434 lpme
->th32ModuleID
= 1; /* toolhelp internal id, never used */
435 lpme
->th32ProcessID
= reply
->pid
;
436 lpme
->GlblcntUsage
= 0xFFFF; /* FIXME */
437 lpme
->ProccntUsage
= 0xFFFF; /* FIXME */
438 lpme
->modBaseAddr
= reply
->base
;
439 lpme
->modBaseSize
= reply
->size
;
440 lpme
->hModule
= reply
->base
;
441 len
= wine_server_reply_size(reply
) / sizeof(WCHAR
);
442 memcpy(lpme
->szExePath
, exe
, wine_server_reply_size(reply
));
443 lpme
->szExePath
[len
] = 0;
444 if ((ptr
= strrchrW(lpme
->szExePath
, '\\'))) ptr
++;
445 else ptr
= lpme
->szExePath
;
446 lstrcpynW( lpme
->szModule
, ptr
, sizeof(lpme
->szModule
)/sizeof(lpme
->szModule
[0]));
453 /***********************************************************************
454 * TOOLHELP_Module32NextA
456 * Implementation of Module32First/Next
458 static BOOL
TOOLHELP_Module32NextA( HANDLE handle
, LPMODULEENTRY32 lpme
, BOOL first
)
463 if (lpme
->dwSize
< sizeof (MODULEENTRY32
))
465 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
466 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32
), lpme
->dwSize
);
470 mew
.dwSize
= sizeof(mew
);
471 if ((ret
= TOOLHELP_Module32NextW( handle
, &mew
, first
)))
473 lpme
->th32ModuleID
= mew
.th32ModuleID
;
474 lpme
->th32ProcessID
= mew
.th32ProcessID
;
475 lpme
->GlblcntUsage
= mew
.GlblcntUsage
;
476 lpme
->ProccntUsage
= mew
.ProccntUsage
;
477 lpme
->modBaseAddr
= mew
.modBaseAddr
;
478 lpme
->hModule
= mew
.hModule
;
479 WideCharToMultiByte( CP_ACP
, 0, mew
.szModule
, -1, lpme
->szModule
, sizeof(lpme
->szModule
), NULL
, NULL
);
480 WideCharToMultiByte( CP_ACP
, 0, mew
.szExePath
, -1, lpme
->szExePath
, sizeof(lpme
->szExePath
), NULL
, NULL
);
485 /***********************************************************************
486 * Module32FirstW (KERNEL32.@)
488 * Return info about the "first" module in a toolhelp32 snapshot
490 BOOL WINAPI
Module32FirstW(HANDLE hSnapshot
, LPMODULEENTRY32W lpme
)
492 return TOOLHELP_Module32NextW( hSnapshot
, lpme
, TRUE
);
495 /***********************************************************************
496 * Module32First (KERNEL32.@)
498 * Return info about the "first" module in a toolhelp32 snapshot
500 BOOL WINAPI
Module32First(HANDLE hSnapshot
, LPMODULEENTRY32 lpme
)
502 return TOOLHELP_Module32NextA( hSnapshot
, lpme
, TRUE
);
505 /***********************************************************************
506 * Module32NextW (KERNEL32.@)
508 * Return info about the "next" module in a toolhelp32 snapshot
510 BOOL WINAPI
Module32NextW(HANDLE hSnapshot
, LPMODULEENTRY32W lpme
)
512 return TOOLHELP_Module32NextW( hSnapshot
, lpme
, FALSE
);
515 /***********************************************************************
516 * Module32Next (KERNEL32.@)
518 * Return info about the "next" module in a toolhelp32 snapshot
520 BOOL WINAPI
Module32Next(HANDLE hSnapshot
, LPMODULEENTRY32 lpme
)
522 return TOOLHELP_Module32NextA( hSnapshot
, lpme
, FALSE
);
525 /************************************************************************
526 * GlobalMasterHandle (KERNEL.28)
529 * Should return selector and handle of the information structure for
530 * the global heap. selector and handle are stored in the THHOOK as
531 * pGlobalHeap and hGlobalHeap.
532 * As Wine doesn't have this structure, we return both values as zero
533 * Applications should interpret this as "No Global Heap"
535 DWORD WINAPI
GlobalMasterHandle16(void)
541 /************************************************************************
542 * Heap32ListFirst (KERNEL.@)
545 BOOL WINAPI
Heap32ListFirst(HANDLE hSnapshot
, LPHEAPLIST32 lphl
)
551 /******************************************************************
552 * Toolhelp32ReadProcessMemory (KERNEL.@)
556 BOOL WINAPI
Toolhelp32ReadProcessMemory(DWORD pid
, const void* base
,
557 void* buf
, SIZE_T len
, SIZE_T
* r
)
562 h
= (pid
) ? OpenProcess(PROCESS_VM_READ
, FALSE
, pid
) : GetCurrentProcess();
565 ret
= ReadProcessMemory(h
, base
, buf
, len
, r
);
566 if (pid
) CloseHandle(h
);