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"
39 #include "wine/server.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 WORD user
= LoadLibrary16( "USER.EXE" );
182 WORD gdi
= LoadLibrary16( "GDI.EXE" );
183 pHeapInfo
->wUserFreePercent
= (int)LOCAL_CountFree(user
) * 100 / LOCAL_HeapSize(user
);
184 pHeapInfo
->wGDIFreePercent
= (int)LOCAL_CountFree(gdi
) * 100 / LOCAL_HeapSize(gdi
);
185 pHeapInfo
->hUserSegment
= user
;
186 pHeapInfo
->hGDISegment
= gdi
;
187 FreeLibrary16( user
);
188 FreeLibrary16( gdi
);
193 /***********************************************************************
194 * ToolHelpHook (KERNEL.341)
195 * see "Undocumented Windows"
197 FARPROC16 WINAPI
ToolHelpHook16(FARPROC16 lpfnNotifyHandler
)
201 FIXME("(%p), stub.\n", lpfnNotifyHandler
);
203 HookNotify
= lpfnNotifyHandler
;
204 /* just return previously installed notification function */
209 /***********************************************************************
210 * CreateToolhelp32Snapshot (KERNEL32.@)
212 HANDLE WINAPI
CreateToolhelp32Snapshot( DWORD flags
, DWORD process
)
216 TRACE("%lx,%lx\n", flags
, process
);
217 if (!(flags
& (TH32CS_SNAPPROCESS
|TH32CS_SNAPTHREAD
|TH32CS_SNAPMODULE
)))
219 FIXME("flags %lx not implemented\n", flags
);
220 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
221 return INVALID_HANDLE_VALUE
;
224 /* Now do the snapshot */
225 SERVER_START_REQ( create_snapshot
)
228 if (flags
& TH32CS_SNAPMODULE
) req
->flags
|= SNAP_MODULE
;
229 if (flags
& TH32CS_SNAPPROCESS
) req
->flags
|= SNAP_PROCESS
;
230 if (flags
& TH32CS_SNAPTHREAD
) req
->flags
|= SNAP_THREAD
;
232 req
->inherit
= (flags
& TH32CS_INHERIT
) != 0;
234 wine_server_call_err( req
);
238 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
243 /***********************************************************************
244 * TOOLHELP_Thread32Next
246 * Implementation of Thread32First/Next
248 static BOOL
TOOLHELP_Thread32Next( HANDLE handle
, LPTHREADENTRY32 lpte
, BOOL first
)
252 if (lpte
->dwSize
< sizeof(THREADENTRY32
))
254 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
255 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(THREADENTRY32
), lpte
->dwSize
);
258 SERVER_START_REQ( next_thread
)
260 req
->handle
= handle
;
262 if ((ret
= !wine_server_call_err( req
)))
264 lpte
->cntUsage
= reply
->count
;
265 lpte
->th32ThreadID
= (DWORD
)reply
->tid
;
266 lpte
->th32OwnerProcessID
= (DWORD
)reply
->pid
;
267 lpte
->tpBasePri
= reply
->base_pri
;
268 lpte
->tpDeltaPri
= reply
->delta_pri
;
269 lpte
->dwFlags
= 0; /* SDK: "reserved; do not use" */
276 /***********************************************************************
277 * Thread32First (KERNEL32.@)
279 * Return info about the first thread in a toolhelp32 snapshot
281 BOOL WINAPI
Thread32First(HANDLE hSnapshot
, LPTHREADENTRY32 lpte
)
283 return TOOLHELP_Thread32Next(hSnapshot
, lpte
, TRUE
);
286 /***********************************************************************
287 * Thread32Next (KERNEL32.@)
289 * Return info about the "next" thread in a toolhelp32 snapshot
291 BOOL WINAPI
Thread32Next(HANDLE hSnapshot
, LPTHREADENTRY32 lpte
)
293 return TOOLHELP_Thread32Next(hSnapshot
, lpte
, FALSE
);
296 /***********************************************************************
297 * TOOLHELP_Process32Next
299 * Implementation of Process32First/Next. Note that the ANSI / Unicode
300 * version check is a bit of a hack as it relies on the fact that only
301 * the last field is actually different.
303 static BOOL
TOOLHELP_Process32Next( HANDLE handle
, LPPROCESSENTRY32W lppe
, BOOL first
, BOOL unicode
)
306 WCHAR exe
[MAX_PATH
-1];
311 if (lppe
->dwSize
< sizeof(PROCESSENTRY32W
))
313 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
314 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(PROCESSENTRY32W
), lppe
->dwSize
);
320 if (lppe
->dwSize
< sizeof(PROCESSENTRY32
))
322 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
323 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(PROCESSENTRY32
), lppe
->dwSize
);
327 SERVER_START_REQ( next_process
)
329 req
->handle
= handle
;
331 wine_server_set_reply( req
, exe
, sizeof(exe
) );
332 if ((ret
= !wine_server_call_err( req
)))
334 lppe
->cntUsage
= reply
->count
;
335 lppe
->th32ProcessID
= reply
->pid
;
336 lppe
->th32DefaultHeapID
= (DWORD
)reply
->heap
;
337 lppe
->th32ModuleID
= (DWORD
)reply
->module
;
338 lppe
->cntThreads
= reply
->threads
;
339 lppe
->th32ParentProcessID
= reply
->ppid
;
340 lppe
->pcPriClassBase
= reply
->priority
;
341 lppe
->dwFlags
= -1; /* FIXME */
344 len
= wine_server_reply_size(reply
) / sizeof(WCHAR
);
345 memcpy(lppe
->szExeFile
, reply
, wine_server_reply_size(reply
));
346 lppe
->szExeFile
[len
] = 0;
350 LPPROCESSENTRY32 lppe_a
= (LPPROCESSENTRY32
) lppe
;
352 len
= WideCharToMultiByte( CP_ACP
, 0, exe
, wine_server_reply_size(reply
) / sizeof(WCHAR
),
353 lppe_a
->szExeFile
, sizeof(lppe_a
->szExeFile
)-1, NULL
, NULL
);
354 lppe_a
->szExeFile
[len
] = 0;
363 /***********************************************************************
364 * Process32First (KERNEL32.@)
366 * Return info about the first process in a toolhelp32 snapshot
368 BOOL WINAPI
Process32First(HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
370 return TOOLHELP_Process32Next( hSnapshot
, (LPPROCESSENTRY32W
) lppe
, TRUE
, FALSE
/* ANSI */ );
373 /***********************************************************************
374 * Process32Next (KERNEL32.@)
376 * Return info about the "next" process in a toolhelp32 snapshot
378 BOOL WINAPI
Process32Next(HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
380 return TOOLHELP_Process32Next( hSnapshot
, (LPPROCESSENTRY32W
) lppe
, FALSE
, FALSE
/* ANSI */ );
383 /***********************************************************************
384 * Process32FirstW (KERNEL32.@)
386 * Return info about the first process in a toolhelp32 snapshot
388 BOOL WINAPI
Process32FirstW(HANDLE hSnapshot
, LPPROCESSENTRY32W lppe
)
390 return TOOLHELP_Process32Next( hSnapshot
, lppe
, TRUE
, TRUE
/* Unicode */ );
393 /***********************************************************************
394 * Process32NextW (KERNEL32.@)
396 * Return info about the "next" process in a toolhelp32 snapshot
398 BOOL WINAPI
Process32NextW(HANDLE hSnapshot
, LPPROCESSENTRY32W lppe
)
400 return TOOLHELP_Process32Next( hSnapshot
, lppe
, FALSE
, TRUE
/* Unicode */ );
404 /***********************************************************************
405 * TOOLHELP_Module32Next
407 * Implementation of Module32First/Next
409 static BOOL
TOOLHELP_Module32Next( HANDLE handle
, LPMODULEENTRY32 lpme
, BOOL first
)
415 if (lpme
->dwSize
< sizeof (MODULEENTRY32
))
417 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
418 ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32
), lpme
->dwSize
);
421 SERVER_START_REQ( next_module
)
423 req
->handle
= handle
;
425 wine_server_set_reply( req
, exe
, sizeof(exe
) );
426 if ((ret
= !wine_server_call_err( req
)))
429 lpme
->th32ModuleID
= 1; /* toolhelp internal id, never used */
430 lpme
->th32ProcessID
= reply
->pid
;
431 lpme
->GlblcntUsage
= 0xFFFF; /* FIXME */
432 lpme
->ProccntUsage
= 0xFFFF; /* FIXME */
433 lpme
->modBaseAddr
= reply
->base
;
434 lpme
->modBaseSize
= reply
->size
;
435 lpme
->hModule
= reply
->base
;
436 len
= WideCharToMultiByte( CP_ACP
, 0, exe
, wine_server_reply_size(reply
) / sizeof(WCHAR
),
437 lpme
->szExePath
, sizeof(lpme
->szExePath
) - 1, NULL
, NULL
);
438 lpme
->szExePath
[len
] = 0;
439 if ((ptr
= strrchr(lpme
->szExePath
, '\\'))) ptr
++;
440 else ptr
= lpme
->szExePath
;
441 lstrcpynA( lpme
->szModule
, ptr
, sizeof(lpme
->szModule
) );
448 /***********************************************************************
449 * Module32First (KERNEL32.@)
451 * Return info about the "first" module in a toolhelp32 snapshot
453 BOOL WINAPI
Module32First(HANDLE hSnapshot
, LPMODULEENTRY32 lpme
)
455 return TOOLHELP_Module32Next( hSnapshot
, lpme
, TRUE
);
458 /***********************************************************************
459 * Module32Next (KERNEL32.@)
461 * Return info about the "next" module in a toolhelp32 snapshot
463 BOOL WINAPI
Module32Next(HANDLE hSnapshot
, LPMODULEENTRY32 lpme
)
465 return TOOLHELP_Module32Next( hSnapshot
, lpme
, FALSE
);
468 /************************************************************************
469 * GlobalMasterHandle (KERNEL.28)
472 * Should return selector and handle of the information structure for
473 * the global heap. selector and handle are stored in the THHOOK as
474 * pGlobalHeap and hGlobalHeap.
475 * As Wine doesn't have this structure, we return both values as zero
476 * Applications should interpret this as "No Global Heap"
478 DWORD WINAPI
GlobalMasterHandle16(void)
484 /************************************************************************
485 * Heap32ListFirst (KERNEL.@)
488 BOOL WINAPI
Heap32ListFirst(HANDLE hSnapshot
, LPHEAPLIST32 lphl
)
494 /******************************************************************
495 * Toolhelp32ReadProcessMemory (KERNEL.@)
499 BOOL WINAPI
Toolhelp32ReadProcessMemory(DWORD pid
, const void* base
,
500 void* buf
, SIZE_T len
, SIZE_T
* r
)
505 h
= (pid
) ? OpenProcess(PROCESS_VM_READ
, FALSE
, pid
) : GetCurrentProcess();
508 ret
= ReadProcessMemory(h
, base
, buf
, len
, r
);
509 if (pid
) CloseHandle(h
);