server: Distinguish between a directory and a file changing in
[wine] / dlls / kernel / toolhelp.c
1 /*
2  * Misc Toolhelp functions
3  *
4  * Copyright 1996 Marcus Meissner
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <ctype.h>
30 #include <assert.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34 #include "tlhelp32.h"
35 #include "wine/server.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp);
40
41
42 /***********************************************************************
43  *           CreateToolhelp32Snapshot                   (KERNEL32.@)
44  */
45 HANDLE WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process )
46 {
47     HANDLE ret;
48
49     TRACE("%lx,%lx\n", flags, process );
50     if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE)))
51     {
52         FIXME("flags %lx not implemented\n", flags );
53         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
54         return INVALID_HANDLE_VALUE;
55     }
56
57     /* Now do the snapshot */
58     SERVER_START_REQ( create_snapshot )
59     {
60         req->flags = 0;
61         if (flags & TH32CS_SNAPMODULE)   req->flags |= SNAP_MODULE;
62         if (flags & TH32CS_SNAPPROCESS)  req->flags |= SNAP_PROCESS;
63         if (flags & TH32CS_SNAPTHREAD)   req->flags |= SNAP_THREAD;
64         req->attributes = (flags & TH32CS_INHERIT) ? OBJ_INHERIT : 0;
65         req->pid        = process;
66         wine_server_call_err( req );
67         ret = reply->handle;
68     }
69     SERVER_END_REQ;
70     if (!ret) ret = INVALID_HANDLE_VALUE;
71     return ret;
72 }
73
74
75 /***********************************************************************
76  *              TOOLHELP_Thread32Next
77  *
78  * Implementation of Thread32First/Next
79  */
80 static BOOL TOOLHELP_Thread32Next( HANDLE handle, LPTHREADENTRY32 lpte, BOOL first )
81 {
82     BOOL ret;
83
84     if (lpte->dwSize < sizeof(THREADENTRY32))
85     {
86         SetLastError( ERROR_INSUFFICIENT_BUFFER );
87         ERR("Result buffer too small (%ld)\n", lpte->dwSize);
88         return FALSE;
89     }
90     SERVER_START_REQ( next_thread )
91     {
92         req->handle = handle;
93         req->reset = first;
94         if ((ret = !wine_server_call_err( req )))
95         {
96             lpte->cntUsage           = reply->count;
97             lpte->th32ThreadID       = (DWORD)reply->tid;
98             lpte->th32OwnerProcessID = (DWORD)reply->pid;
99             lpte->tpBasePri          = reply->base_pri;
100             lpte->tpDeltaPri         = reply->delta_pri;
101             lpte->dwFlags            = 0;  /* SDK: "reserved; do not use" */
102         }
103     }
104     SERVER_END_REQ;
105     return ret;
106 }
107
108 /***********************************************************************
109  *              Thread32First    (KERNEL32.@)
110  *
111  * Return info about the first thread in a toolhelp32 snapshot
112  */
113 BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
114 {
115     return TOOLHELP_Thread32Next(hSnapshot, lpte, TRUE);
116 }
117
118 /***********************************************************************
119  *              Thread32Next   (KERNEL32.@)
120  *
121  * Return info about the "next" thread in a toolhelp32 snapshot
122  */
123 BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
124 {
125     return TOOLHELP_Thread32Next(hSnapshot, lpte, FALSE);
126 }
127
128 /***********************************************************************
129  *              TOOLHELP_Process32Next
130  *
131  * Implementation of Process32First/Next. Note that the ANSI / Unicode
132  * version check is a bit of a hack as it relies on the fact that only
133  * the last field is actually different.
134  */
135 static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY32W lppe, BOOL first, BOOL unicode )
136 {
137     BOOL ret;
138     WCHAR exe[MAX_PATH-1];
139     DWORD len, sz;
140
141     sz = unicode ? sizeof(PROCESSENTRY32W) : sizeof(PROCESSENTRY32);
142     if (lppe->dwSize < sz)
143     {
144         SetLastError( ERROR_INSUFFICIENT_BUFFER );
145         ERR("Result buffer too small (req: %ld, was: %ld)\n", sz, lppe->dwSize);
146         return FALSE;
147     }
148
149     SERVER_START_REQ( next_process )
150     {
151         req->handle = handle;
152         req->reset = first;
153         wine_server_set_reply( req, exe, sizeof(exe) );
154         if ((ret = !wine_server_call_err( req )))
155         {
156             lppe->cntUsage            = reply->count;
157             lppe->th32ProcessID       = reply->pid;
158             lppe->th32DefaultHeapID   = (DWORD)reply->heap;
159             lppe->th32ModuleID        = (DWORD)reply->module;
160             lppe->cntThreads          = reply->threads;
161             lppe->th32ParentProcessID = reply->ppid;
162             switch (reply->priority)
163             {
164             case PROCESS_PRIOCLASS_IDLE:
165                 lppe->pcPriClassBase = IDLE_PRIORITY_CLASS; break;
166             case PROCESS_PRIOCLASS_BELOW_NORMAL:
167                 lppe->pcPriClassBase = BELOW_NORMAL_PRIORITY_CLASS; break;
168             case PROCESS_PRIOCLASS_NORMAL:
169                 lppe->pcPriClassBase = NORMAL_PRIORITY_CLASS; break;
170             case PROCESS_PRIOCLASS_ABOVE_NORMAL:
171                 lppe->pcPriClassBase = ABOVE_NORMAL_PRIORITY_CLASS; break;
172             case PROCESS_PRIOCLASS_HIGH:
173                 lppe->pcPriClassBase = HIGH_PRIORITY_CLASS; break;
174             case PROCESS_PRIOCLASS_REALTIME:
175                 lppe->pcPriClassBase = REALTIME_PRIORITY_CLASS; break;
176             default:
177                 FIXME("Unknown NT priority class %d, setting to normal\n", reply->priority);
178                 lppe->pcPriClassBase = NORMAL_PRIORITY_CLASS;
179                 break;
180             }
181             lppe->dwFlags             = -1; /* FIXME */
182             if (unicode)
183             {
184                 len = wine_server_reply_size(reply) / sizeof(WCHAR);
185                 memcpy(lppe->szExeFile, reply, wine_server_reply_size(reply));
186                 lppe->szExeFile[len] = 0;
187             }
188             else
189             {
190                 LPPROCESSENTRY32 lppe_a = (LPPROCESSENTRY32) lppe;
191
192                 len = WideCharToMultiByte( CP_ACP, 0, exe, wine_server_reply_size(reply) / sizeof(WCHAR),
193                                            lppe_a->szExeFile, sizeof(lppe_a->szExeFile)-1, NULL, NULL );
194                 lppe_a->szExeFile[len] = 0;
195             }
196         }
197     }
198     SERVER_END_REQ;
199     return ret;
200 }
201
202
203 /***********************************************************************
204  *              Process32First    (KERNEL32.@)
205  *
206  * Return info about the first process in a toolhelp32 snapshot
207  */
208 BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
209 {
210     return TOOLHELP_Process32Next( hSnapshot, (LPPROCESSENTRY32W) lppe, TRUE, FALSE /* ANSI */ );
211 }
212
213 /***********************************************************************
214  *              Process32Next   (KERNEL32.@)
215  *
216  * Return info about the "next" process in a toolhelp32 snapshot
217  */
218 BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
219 {
220     return TOOLHELP_Process32Next( hSnapshot, (LPPROCESSENTRY32W) lppe, FALSE, FALSE /* ANSI */ );
221 }
222
223 /***********************************************************************
224  *              Process32FirstW    (KERNEL32.@)
225  *
226  * Return info about the first process in a toolhelp32 snapshot
227  */
228 BOOL WINAPI Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
229 {
230     return TOOLHELP_Process32Next( hSnapshot, lppe, TRUE, TRUE /* Unicode */ );
231 }
232
233 /***********************************************************************
234  *              Process32NextW   (KERNEL32.@)
235  *
236  * Return info about the "next" process in a toolhelp32 snapshot
237  */
238 BOOL WINAPI Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
239 {
240     return TOOLHELP_Process32Next( hSnapshot, lppe, FALSE, TRUE /* Unicode */ );
241 }
242
243
244 /***********************************************************************
245  *              TOOLHELP_Module32NextW
246  *
247  * Implementation of Module32First/Next
248  */
249 static BOOL TOOLHELP_Module32NextW( HANDLE handle, LPMODULEENTRY32W lpme, BOOL first )
250 {
251     BOOL ret;
252     WCHAR exe[MAX_PATH];
253     DWORD len;
254
255     if (lpme->dwSize < sizeof (MODULEENTRY32W))
256     {
257         SetLastError( ERROR_INSUFFICIENT_BUFFER );
258         ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32W), lpme->dwSize);
259         return FALSE;
260     }
261     SERVER_START_REQ( next_module )
262     {
263         req->handle = handle;
264         req->reset = first;
265         wine_server_set_reply( req, exe, sizeof(exe) );
266         if ((ret = !wine_server_call_err( req )))
267         {
268             const WCHAR* ptr;
269             lpme->th32ModuleID   = 1; /* toolhelp internal id, never used */
270             lpme->th32ProcessID  = reply->pid;
271             lpme->GlblcntUsage   = 0xFFFF; /* FIXME */
272             lpme->ProccntUsage   = 0xFFFF; /* FIXME */
273             lpme->modBaseAddr    = reply->base;
274             lpme->modBaseSize    = reply->size;
275             lpme->hModule        = reply->base;
276             len = wine_server_reply_size(reply) / sizeof(WCHAR);
277             memcpy(lpme->szExePath, exe, wine_server_reply_size(reply));
278             lpme->szExePath[len] = 0;
279             if ((ptr = strrchrW(lpme->szExePath, '\\'))) ptr++;
280             else ptr = lpme->szExePath;
281             lstrcpynW( lpme->szModule, ptr, sizeof(lpme->szModule)/sizeof(lpme->szModule[0]));
282         }
283     }
284     SERVER_END_REQ;
285     return ret;
286 }
287
288 /***********************************************************************
289  *              TOOLHELP_Module32NextA
290  *
291  * Implementation of Module32First/Next
292  */
293 static BOOL TOOLHELP_Module32NextA( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first )
294 {
295     BOOL ret;
296     MODULEENTRY32W mew;
297     
298     if (lpme->dwSize < sizeof (MODULEENTRY32))
299     {
300         SetLastError( ERROR_INSUFFICIENT_BUFFER );
301         ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32), lpme->dwSize);
302         return FALSE;
303     }
304     
305     mew.dwSize = sizeof(mew);
306     if ((ret = TOOLHELP_Module32NextW( handle, &mew, first )))
307     {
308         lpme->th32ModuleID  = mew.th32ModuleID;
309         lpme->th32ProcessID = mew.th32ProcessID;
310         lpme->GlblcntUsage  = mew.GlblcntUsage;
311         lpme->ProccntUsage  = mew.ProccntUsage;
312         lpme->modBaseAddr   = mew.modBaseAddr;
313         lpme->hModule       = mew.hModule;
314         WideCharToMultiByte( CP_ACP, 0, mew.szModule, -1, lpme->szModule, sizeof(lpme->szModule), NULL, NULL );
315         WideCharToMultiByte( CP_ACP, 0, mew.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), NULL, NULL );
316     }
317     return ret;
318 }
319
320 /***********************************************************************
321  *              Module32FirstW   (KERNEL32.@)
322  *
323  * Return info about the "first" module in a toolhelp32 snapshot
324  */
325 BOOL WINAPI Module32FirstW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
326 {
327     return TOOLHELP_Module32NextW( hSnapshot, lpme, TRUE );
328 }
329
330 /***********************************************************************
331  *              Module32First   (KERNEL32.@)
332  *
333  * Return info about the "first" module in a toolhelp32 snapshot
334  */
335 BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
336 {
337     return TOOLHELP_Module32NextA( hSnapshot, lpme, TRUE );
338 }
339
340 /***********************************************************************
341  *              Module32NextW   (KERNEL32.@)
342  *
343  * Return info about the "next" module in a toolhelp32 snapshot
344  */
345 BOOL WINAPI Module32NextW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
346 {
347     return TOOLHELP_Module32NextW( hSnapshot, lpme, FALSE );
348 }
349
350 /***********************************************************************
351  *              Module32Next   (KERNEL32.@)
352  *
353  * Return info about the "next" module in a toolhelp32 snapshot
354  */
355 BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
356 {
357     return TOOLHELP_Module32NextA( hSnapshot, lpme, FALSE );
358 }
359
360 /************************************************************************
361  *              Heap32ListFirst (KERNEL32.@)
362  *
363  */
364 BOOL WINAPI Heap32ListFirst(HANDLE hSnapshot, LPHEAPLIST32 lphl)
365 {
366     FIXME(": stub\n");
367     return FALSE;
368 }
369
370 /******************************************************************
371  *              Toolhelp32ReadProcessMemory (KERNEL32.@)
372  *
373  *
374  */
375 BOOL WINAPI Toolhelp32ReadProcessMemory(DWORD pid, const void* base,
376                                         void* buf, SIZE_T len, SIZE_T* r)
377 {
378     HANDLE h;
379     BOOL   ret = FALSE;
380
381     h = (pid) ? OpenProcess(PROCESS_VM_READ, FALSE, pid) : GetCurrentProcess();
382     if (h != NULL)
383     {
384         ret = ReadProcessMemory(h, base, buf, len, r);
385         if (pid) CloseHandle(h);
386     }
387     return ret;
388 }