Implemented CreateToolhelp32Snapshot, including two of the routines
using snapshots, Process32First and Process32Next.
diff --git a/include/process.h b/include/process.h
index 46eb24a..51e6207 100644
--- a/include/process.h
+++ b/include/process.h
@@ -108,6 +108,8 @@
LCID locale; /* c4 Locale to be queried by GetThreadLocale (NT) */
/* The following are Wine-specific fields */
void *server_pid; /* Server id for this process */
+ struct _PDB32 *list_next; /* List reference - list of PDB's */
+ struct _PDB32 *list_prev; /* List reference - list of PDB's */
} PDB32;
/* Process flags */
@@ -157,5 +159,9 @@
PROCESS_INFORMATION *info );
extern void PROCESS_SuspendOtherThreads(void);
extern void PROCESS_ResumeOtherThreads(void);
+extern int PROCESS_PDBList_Getsize (void);
+extern PDB32* PROCESS_PDBList_Getfirst (void);
+extern PDB32* PROCESS_PDBList_Getnext (PDB32*);
#endif /* __WINE_PROCESS_H */
+
diff --git a/include/tlhelp32.h b/include/tlhelp32.h
new file mode 100644
index 0000000..b8b798a
--- /dev/null
+++ b/include/tlhelp32.h
@@ -0,0 +1,29 @@
+#ifndef __WINE_TLHELP32_H
+#define __WINE_TLHELP32_H
+
+#include "windows.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /*===================================================================
+ * Arguments for Toolhelp routines
+ */
+
+ /*
+ * CreateToolhelp32Snapshot
+ */
+
+#define TH32CS_SNAPHEAPLIST 0x00000001
+#define TH32CS_SNAPPROCESS 0x00000002
+#define TH32CS_SNAPTHREAD 0x00000004
+#define TH32CS_SNAPMODULE 0x00000008
+#define TH32CS_SNAPALL (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE)
+#define TH32CS_INHERIT 0x80000000
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#endif /* __WINE_TLHELP32_H */
diff --git a/include/toolhelp.h b/include/toolhelp.h
index bb0a572..f2b1629 100644
--- a/include/toolhelp.h
+++ b/include/toolhelp.h
@@ -2,10 +2,13 @@
#define __WINE_TOOLHELP_H
#include "windows.h"
+#include "tlhelp32.h"
#define MAX_DATA 11
#define MAX_MODULE_NAME 9
+#ifndef MAX_PATH
#define MAX_PATH 255
+#endif
#define MAX_CLASSNAME 255
#pragma pack(1)
diff --git a/misc/toolhelp.c b/misc/toolhelp.c
index c3cb60a..387727f 100644
--- a/misc/toolhelp.c
+++ b/misc/toolhelp.c
@@ -8,11 +8,54 @@
#include <string.h>
#include <unistd.h>
#include <ctype.h>
+#include <assert.h>
#include "windows.h"
#include "win.h"
+#include "winerror.h"
+#include "tlhelp32.h"
#include "toolhelp.h"
#include "debug.h"
#include "heap.h"
+#include "process.h"
+#include "k32obj.h"
+
+/*
+ * Support for toolhelp's snapshots. They
+ * are supposed to be Kernel32 Objects.
+ * Only the Destroy() method is implemented
+ */
+
+static void SNAPSHOT_Destroy( K32OBJ *obj );
+
+const K32OBJ_OPS SNAPSHOT_Ops =
+{
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ NULL, /* add_wait */
+ NULL, /* remove_wait */
+ NULL, /* read */
+ NULL, /* write */
+ SNAPSHOT_Destroy /* destroy */
+};
+
+/* The K32 snapshot object object */
+/* Process snapshot kernel32 object */
+typedef struct _Process32Snapshot
+{
+ K32OBJ header;
+
+ DWORD numProcs;
+ DWORD arrayCounter;
+ /*
+ * Store a reference to the PDB list.
+ * Insuure in the alloc and dealloc routines for this structure that
+ * I increment and decrement the pdb->head.refcount, so that the
+ * original pdb will stay around for as long as I use it, but it's
+ * not locked forver into memory.
+ */
+ PDB32 **processArray;
+}
+SNAPSHOT_OBJECT;
/* FIXME: to make this working, we have to callback all these registered
* functions from all over the WINE code. Someone with more knowledge than
@@ -103,10 +146,298 @@
}
/***********************************************************************
+ * SNAPSHOT_Destroy
+ *
+ * Deallocate K32 snapshot objects
+ */
+static void SNAPSHOT_Destroy (K32OBJ *obj)
+{
+ int i;
+ SNAPSHOT_OBJECT *snapshot = (SNAPSHOT_OBJECT *) obj;
+ assert (obj->type == K32OBJ_CHANGE);
+
+ if (snapshot->processArray)
+ {
+ for (i = 0; snapshot->processArray[i] && i <snapshot->numProcs; i++)
+ {
+ K32OBJ_DecCount (&snapshot->processArray[i]->header);
+ }
+ HeapFree (GetProcessHeap (), 0, snapshot->processArray);
+ snapshot->processArray = NULL;
+ }
+
+ obj->type = K32OBJ_UNKNOWN;
+ HeapFree (GetProcessHeap (), 0, snapshot);
+}
+
+/***********************************************************************
* CreateToolHelp32Snapshot (KERNEL32.179)
* see "Undocumented Windows"
*/
-HANDLE32 WINAPI CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID) {
- FIXME(toolhelp,"(0x%08lx,0x%08lx), stub!\n",dwFlags,th32ProcessID);
- return INVALID_HANDLE_VALUE32;
+HANDLE32 WINAPI CreateToolhelp32Snapshot(DWORD dwFlags, DWORD
+ th32ProcessID)
+{
+ HANDLE32 ssHandle;
+ SNAPSHOT_OBJECT *snapshot;
+ int numProcesses;
+ int i;
+ PDB32* pdb;
+
+ printf ("%x & TH32CS_INHERIT (%x) = %x %s\n", dwFlags,
+ TH32CS_INHERIT, TH32CS_INHERIT,
+ dwFlags & TH32CS_INHERIT,
+ dwFlags & TH32CS_INHERIT ? "TRUE" : "FALSE");
+ printf ("%x & TH32CS_SNAPHEAPLIST (%x) = %x %s\n", dwFlags,
+ TH32CS_SNAPHEAPLIST, TH32CS_SNAPHEAPLIST,
+ dwFlags & TH32CS_SNAPHEAPLIST,
+ dwFlags & TH32CS_SNAPHEAPLIST ? "TRUE" : "FALSE");
+ printf ("%x & TH32CS_SNAPMODULE (%x) = %x %s\n", dwFlags,
+ TH32CS_SNAPMODULE, TH32CS_SNAPMODULE,
+ dwFlags & TH32CS_SNAPMODULE,
+ dwFlags & TH32CS_SNAPMODULE ? "TRUE" : "FALSE");
+ printf ("%x & TH32CS_SNAPPROCESS (%x) = %x %s\n", dwFlags,
+ TH32CS_SNAPPROCESS, TH32CS_SNAPPROCESS,
+ dwFlags & TH32CS_SNAPPROCESS,
+ dwFlags & TH32CS_SNAPPROCESS ? "TRUE" : "FALSE");
+ printf ("%x & TH32CS_SNAPTHREAD (%x) = %x %s\n", dwFlags,
+ TH32CS_SNAPTHREAD, TH32CS_SNAPTHREAD,
+ dwFlags & TH32CS_SNAPTHREAD,
+ dwFlags & TH32CS_SNAPTHREAD ? "TRUE" : "FALSE");
+
+ /**** FIXME: Not implmented ***/
+ if (dwFlags & TH32CS_INHERIT)
+ {
+ FIXME(toolhelp,"(0x%08lx (TH32CS_INHERIT),0x%08lx), stub!\n",
+ dwFlags,th32ProcessID);
+
+ return INVALID_HANDLE_VALUE32;
+ }
+ if (dwFlags & TH32CS_SNAPHEAPLIST)
+ {
+ FIXME(toolhelp,"(0x%08lx (TH32CS_SNAPHEAPLIST),0x%08lx), stub!\n",
+ dwFlags,th32ProcessID);
+ return INVALID_HANDLE_VALUE32;
+ }
+ if (dwFlags & TH32CS_SNAPMODULE)
+ {
+ FIXME(toolhelp,"(0x%08lx (TH32CS_SNAPMODULE),0x%08lx), stub!\n",
+ dwFlags,th32ProcessID);
+ return INVALID_HANDLE_VALUE32;
+ }
+
+ if (dwFlags & TH32CS_SNAPPROCESS)
+ {
+ TRACE (toolhelp, "(0x%08lx (TH32CS_SNAPMODULE),0x%08lx)\n",
+ dwFlags,th32ProcessID);
+ snapshot = HeapAlloc (GetProcessHeap (), 0, sizeof
+ (SNAPSHOT_OBJECT));
+ if (!snapshot)
+ {
+ return INVALID_HANDLE_VALUE32;
+ }
+
+ snapshot->header.type = K32OBJ_TOOLHELP_SNAPSHOT;
+ snapshot->header.refcount = 1;
+ snapshot->arrayCounter = 0;
+
+ /*
+ * Lock here, to prevent processes from being created or
+ * destroyed while the snapshot is gathered
+ */
+
+ SYSTEM_LOCK ();
+ numProcesses = PROCESS_PDBList_Getsize ();
+
+ snapshot->processArray = (PDB32**)
+ HeapAlloc (GetProcessHeap (), 0, sizeof (PDB32*) * numProcesses);
+
+ if (!snapshot->processArray)
+ {
+ HeapFree (GetProcessHeap (), 0, snapshot->processArray);
+ SetLastError (INVALID_HANDLE_VALUE32);
+ ERR (toolhelp, "Error allocating %d bytes for snapshot\n",
+ sizeof (PDB32*) * numProcesses);
+ return INVALID_HANDLE_VALUE32;
+ }
+
+ snapshot->numProcs = numProcesses;
+
+ pdb = PROCESS_PDBList_Getfirst ();
+ for (i = 0; pdb && i < numProcesses; i++)
+ {
+ TRACE (toolhelp, "Saving ref to pdb %ld\n", PDB_TO_PROCESS_ID(pdb));
+ snapshot->processArray[i] = pdb;
+ K32OBJ_IncCount (&pdb->header);
+ pdb = PROCESS_PDBList_Getnext (pdb);
+ }
+ SYSTEM_UNLOCK ();
+
+ ssHandle = HANDLE_Alloc (PROCESS_Current (), &snapshot->header,
+ FILE_ALL_ACCESS, TRUE, -1);
+ if (ssHandle == INVALID_HANDLE_VALUE32)
+ {
+ /* HANDLE_Alloc is supposed to deallocate the
+ * heap memory if it fails. This code doesn't need to.
+ */
+ SetLastError (INVALID_HANDLE_VALUE32);
+ ERR (toolhelp, "Error allocating handle\n");
+ return INVALID_HANDLE_VALUE32;
+ }
+
+ TRACE (toolhelp, "snapshotted %d processes, expected %d\n",
+ i, numProcesses);
+ return ssHandle;
+ }
+
+ if (dwFlags & TH32CS_SNAPTHREAD)
+ {
+ FIXME(toolhelp,"(0x%08lx (TH32CS_SNAPMODULE),0x%08lx), stub!\n",
+ dwFlags,th32ProcessID);
+ return INVALID_HANDLE_VALUE32;
+ }
+
+ return INVALID_HANDLE_VALUE32;
+}
+
+/***********************************************************************
+ * Process32First
+ * Return info about the first process in a toolhelp32 snapshot
+ */
+BOOL32 WINAPI Process32First(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
+{
+ PDB32 *pdb;
+ SNAPSHOT_OBJECT *snapshot;
+ int i;
+
+ TRACE (toolhelp, "(0x%08lx,0x%08lx)\n", (DWORD) hSnapshot,
+ (DWORD) lppe);
+
+ if (lppe->dwSize < sizeof (PROCESSENTRY32))
+ {
+ SetLastError (ERROR_INSUFFICIENT_BUFFER);
+ ERR (toolhelp, "Result buffer too small\n");
+ return FALSE;
+ }
+
+ SYSTEM_LOCK ();
+ snapshot = (SNAPSHOT_OBJECT*) HANDLE_GetObjPtr (PROCESS_Current (),
+ hSnapshot,
+ K32OBJ_UNKNOWN,
+ FILE_ALL_ACCESS,
+ NULL);
+ if (!snapshot)
+ {
+ SYSTEM_UNLOCK ();
+ SetLastError (ERROR_INVALID_HANDLE);
+ ERR (toolhelp, "Error retreiving snapshot\n");
+ return FALSE;
+ }
+
+ snapshot->arrayCounter = i = 0;
+ pdb = snapshot->processArray[i];
+
+ if (!pdb)
+ {
+ SetLastError (ERROR_NO_MORE_FILES);
+ ERR (toolhelp, "End of snapshot array\n");
+ return FALSE;
+ }
+
+ TRACE (toolhelp, "Returning info on process %d, id %ld\n",
+ i, PDB_TO_PROCESS_ID (pdb));
+
+ lppe->cntUsage = 1;
+ lppe->th32ProcessID = PDB_TO_PROCESS_ID (pdb);
+ lppe->th32DefaultHeapID = (DWORD) pdb->heap;
+ lppe->cntThreads = pdb->threads;
+ lppe->th32ParentProcessID = PDB_TO_PROCESS_ID (pdb->parent);
+ lppe->pcPriClassBase = 6; /* FIXME: this is a made-up value */
+ lppe->dwFlags = -1; /* FIXME: RESERVED by Microsoft :-) */
+ if (pdb->exe_modref)
+ {
+ lppe->th32ModuleID = (DWORD) pdb->exe_modref->module;
+ strncpy (lppe->szExeFile, pdb->exe_modref->longname,
+ sizeof (lppe->szExeFile));
+ }
+ else
+ {
+ lppe->th32ModuleID = (DWORD) 0;
+ strcpy (lppe->szExeFile, "");
+ }
+
+ SYSTEM_UNLOCK ();
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * Process32Next
+ * Return info about the "next" process in a toolhelp32 snapshot
+ */
+BOOL32 WINAPI Process32Next(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
+{
+ PDB32 *pdb;
+ SNAPSHOT_OBJECT *snapshot;
+ int i;
+
+ TRACE (toolhelp, "(0x%08lx,0x%08lx)\n", (DWORD) hSnapshot,
+ (DWORD) lppe);
+
+ if (lppe->dwSize < sizeof (PROCESSENTRY32))
+ {
+ SetLastError (ERROR_INSUFFICIENT_BUFFER);
+ ERR (toolhelp, "Result buffer too small\n");
+ return FALSE;
+ }
+
+ SYSTEM_LOCK ();
+ snapshot = (SNAPSHOT_OBJECT*) HANDLE_GetObjPtr (PROCESS_Current (),
+ hSnapshot,
+ K32OBJ_UNKNOWN,
+ FILE_ALL_ACCESS,
+ NULL);
+ if (!snapshot)
+ {
+ SYSTEM_UNLOCK ();
+ SetLastError (ERROR_INVALID_HANDLE);
+ ERR (toolhelp, "Error retreiving snapshot\n");
+ return FALSE;
+ }
+
+ snapshot->arrayCounter ++;
+ i = snapshot->arrayCounter;
+ pdb = snapshot->processArray[i];
+
+ if (!pdb || snapshot->arrayCounter >= snapshot->numProcs)
+ {
+ SetLastError (ERROR_NO_MORE_FILES);
+ ERR (toolhelp, "End of snapshot array\n");
+ return FALSE;
+ }
+
+ TRACE (toolhelp, "Returning info on process %d, id %ld\n",
+ i, PDB_TO_PROCESS_ID (pdb));
+
+ lppe->cntUsage = 1;
+ lppe->th32ProcessID = PDB_TO_PROCESS_ID (pdb);
+ lppe->th32DefaultHeapID = (DWORD) pdb->heap;
+ lppe->cntThreads = pdb->threads;
+ lppe->th32ParentProcessID = PDB_TO_PROCESS_ID (pdb->parent);
+ lppe->pcPriClassBase = 6; /* FIXME: this is a made-up value */
+ lppe->dwFlags = -1; /* FIXME: RESERVED by Microsoft :-) */
+ if (pdb->exe_modref)
+ {
+ lppe->th32ModuleID = (DWORD) pdb->exe_modref->module;
+ strncpy (lppe->szExeFile, pdb->exe_modref->longname,
+ sizeof (lppe->szExeFile));
+ }
+ else
+ {
+ lppe->th32ModuleID = (DWORD) 0;
+ strcpy (lppe->szExeFile, "");
+ }
+
+ SYSTEM_UNLOCK ();
+
+ return TRUE;
}
diff --git a/scheduler/k32obj.c b/scheduler/k32obj.c
index 7eaab60..f6543bf 100644
--- a/scheduler/k32obj.c
+++ b/scheduler/k32obj.c
@@ -23,6 +23,7 @@
extern const K32OBJ_OPS MEM_MAPPED_FILE_Ops;
extern const K32OBJ_OPS DEVICE_Ops;
extern const K32OBJ_OPS CONSOLE_Ops;
+extern const K32OBJ_OPS SNAPSHOT_Ops;
static const K32OBJ_OPS K32OBJ_NullOps =
{
diff --git a/scheduler/process.c b/scheduler/process.c
index 19d7503..1432ea7 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -22,7 +22,6 @@
#include "task.h"
#include "server.h"
#include "debug.h"
-#include "toolhelp.h"
static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id );
static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id );
@@ -42,7 +41,8 @@
};
static DWORD PROCESS_InitialProcessID = 0;
-
+static PDB32 *PROCESS_PDBList = NULL;
+static DWORD PROCESS_PDBList_Size = 0;
/***********************************************************************
* PROCESS_Current
@@ -177,6 +177,105 @@
return TRUE;
}
+/***********************************************************************
+ * PROCESS_PDBList_Insert
+ * Insert this PDB into the global PDB list
+ */
+
+static void PROCESS_PDBList_Insert (PDB32 *pdb)
+{
+ TRACE (process, "Inserting PDB 0x%0lx, #%ld current\n",
+ PDB_TO_PROCESS_ID (pdb), PROCESS_PDBList_Size);
+
+ SYSTEM_LOCK (); /* FIXME: Do I need to worry about this ?
+ * I.e., could more than one process be
+ * created at once ?
+ */
+ if (PROCESS_PDBList == NULL)
+ {
+ PROCESS_PDBList = pdb;
+ pdb->list_next = NULL;
+ pdb->list_prev = NULL;
+ }
+ else
+ {
+ PDB32 *first = PROCESS_PDBList, *last = PROCESS_PDBList;
+ if (first->list_prev) last = first->list_prev;
+
+ PROCESS_PDBList = pdb;
+ pdb->list_next = first;
+ pdb->list_prev = last;
+ last->list_next = pdb;
+ first->list_prev = pdb;
+ }
+ PROCESS_PDBList_Size ++;
+ SYSTEM_UNLOCK ();
+}
+
+/***********************************************************************
+ * PROCESS_PDBList_Remove
+ * Remove this PDB from the global PDB list
+ */
+
+static void PROCESS_PDBList_Remove (PDB32 *pdb)
+{
+ PDB32 *next = pdb->list_next, *prev = pdb->list_prev;
+
+ TRACE (process, "Removing PDB 0x%0lx, #%ld current\n",
+ PDB_TO_PROCESS_ID (pdb), PROCESS_PDBList_Size);
+
+ SYSTEM_LOCK ();
+
+ if (prev == next)
+ {
+ next->list_prev = NULL;
+ next->list_next = NULL;
+ }
+ else
+ {
+ if (next) next->list_prev = prev;
+ if (prev) prev->list_next = next;
+ }
+
+ if (pdb == PROCESS_PDBList)
+ {
+ PROCESS_PDBList = next ? next : prev;
+ }
+ PROCESS_PDBList_Size --;
+
+ SYSTEM_UNLOCK ();
+}
+
+/***********************************************************************
+ * PROCESS_PDBList_Getsize
+ * Return the number of items in the global PDB list
+ */
+
+int PROCESS_PDBList_Getsize ()
+{
+ return PROCESS_PDBList_Size;
+}
+
+/***********************************************************************
+ * PROCESS_PDBList_Getfirst
+ * Return the head of the PDB list
+ */
+
+PDB32* PROCESS_PDBList_Getfirst ()
+{
+ return PROCESS_PDBList;
+}
+
+/***********************************************************************
+ * PROCESS_PDBList_Getnext
+ * Return the "next" pdb as referenced from the argument.
+ * If at the end of the list, return NULL.
+ */
+
+PDB32* PROCESS_PDBList_Getnext (PDB32 *pdb)
+{
+ return (pdb->list_next != PROCESS_PDBList) ? pdb->list_next : NULL;
+}
/***********************************************************************
* PROCESS_FreePDB
@@ -185,6 +284,13 @@
*/
static void PROCESS_FreePDB( PDB32 *pdb )
{
+ /*
+ * FIXME:
+ * If this routine is called because PROCESS_CreatePDB fails, the
+ * following call to PROCESS_PDBList_Remove will probably screw
+ * up.
+ */
+ PROCESS_PDBList_Remove (pdb);
pdb->header.type = K32OBJ_UNKNOWN;
if (pdb->handle_table) HANDLE_CloseAll( pdb, NULL );
ENV_FreeEnvironment( pdb );
@@ -230,6 +336,8 @@
if (!HANDLE_CreateTable( pdb, TRUE )) goto error;
+ PROCESS_PDBList_Insert (pdb);
+
return pdb;
error:
@@ -934,17 +1042,3 @@
SYSTEM_UNLOCK();
}
-BOOL32 WINAPI Process32First(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
-{
- FIXME (process, "(0x%08x,%p), stub!\n", hSnapshot, lppe);
- SetLastError (ERROR_NO_MORE_FILES);
- return FALSE;
-}
-
-BOOL32 WINAPI Process32Next(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
-{
- FIXME (process, "(0x%08x,%p), stub!\n", hSnapshot, lppe);
- SetLastError (ERROR_NO_MORE_FILES);
- return FALSE;
-}
-