Implemented thread and (partial) module snapshots, based on the work
of Andreas Mohr <amohr@student.ei.uni-stuttgart.de>.

diff --git a/include/server.h b/include/server.h
index 3ccf97e..72b2442 100644
--- a/include/server.h
+++ b/include/server.h
@@ -789,6 +789,7 @@
 {
     IN  int          inherit;       /* inherit flag */
     IN  int          flags;         /* snapshot flags (TH32CS_*) */
+    IN  void*        pid;           /* process id */
     OUT int          handle;        /* handle to the snapshot */
 };
 
@@ -798,9 +799,33 @@
 {
     IN  int          handle;        /* handle to the snapshot */
     IN  int          reset;         /* reset snapshot position? */
-    OUT void*        pid;          /* process id */
-    OUT int          threads;      /* number of threads */
-    OUT int          priority;     /* process priority */
+    OUT int          count;         /* process usage count */
+    OUT void*        pid;           /* process id */
+    OUT int          threads;       /* number of threads */
+    OUT int          priority;      /* process priority */
+};
+
+
+/* Get the next thread from a snapshot */
+struct next_thread_request
+{
+    IN  int          handle;        /* handle to the snapshot */
+    IN  int          reset;         /* reset snapshot position? */
+    OUT int          count;         /* thread usage count */
+    OUT void*        pid;           /* process id */
+    OUT void*        tid;           /* thread id */
+    OUT int          base_pri;      /* base priority */
+    OUT int          delta_pri;     /* delta priority */
+};
+
+
+/* Get the next module from a snapshot */
+struct next_module_request
+{
+    IN  int          handle;        /* handle to the snapshot */
+    IN  int          reset;         /* reset snapshot position? */
+    OUT void*        pid;           /* process id */
+    OUT void*        base;          /* module base address */
 };
 
 
@@ -1184,6 +1209,8 @@
     REQ_CREATE_DEVICE,
     REQ_CREATE_SNAPSHOT,
     REQ_NEXT_PROCESS,
+    REQ_NEXT_THREAD,
+    REQ_NEXT_MODULE,
     REQ_WAIT_DEBUG_EVENT,
     REQ_EXCEPTION_EVENT,
     REQ_OUTPUT_DEBUG_STRING,
@@ -1219,7 +1246,7 @@
     REQ_NB_REQUESTS
 };
 
-#define SERVER_PROTOCOL_VERSION 8
+#define SERVER_PROTOCOL_VERSION 9
 
 /* ### make_requests end ### */
 /* Everything above this line is generated automatically by tools/make_requests */
diff --git a/include/tlhelp32.h b/include/tlhelp32.h
index 05e6fcb..797aa7f 100644
--- a/include/tlhelp32.h
+++ b/include/tlhelp32.h
@@ -1,19 +1,13 @@
 #ifndef __WINE_TLHELP32_H
 #define __WINE_TLHELP32_H
 
-#include "windef.h"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-  /*===================================================================
-   *  Arguments for Toolhelp routines
-   */
-
-  /*
-   * CreateToolhelp32Snapshot
-   */
+/*
+ * CreateToolhelp32Snapshot
+ */
 
 #define TH32CS_SNAPHEAPLIST 0x00000001
 #define TH32CS_SNAPPROCESS  0x00000002
@@ -22,6 +16,118 @@
 #define TH32CS_SNAPALL     (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE)
 #define TH32CS_INHERIT     0x80000000
 
+HANDLE WINAPI CreateToolhelp32Snapshot(DWORD,DWORD);
+
+/*
+ * thread entry list as created by CreateToolHelp32Snapshot 
+ */
+
+typedef struct tagTHREADENTRY32
+{
+    DWORD dwSize; 
+    DWORD cntUsage; 
+    DWORD th32ThreadID; 
+    DWORD th32OwnerProcessID; 
+    LONG  tbBasePri; 
+    LONG  tbDeltaPri; 
+    DWORD dwFlags; 
+} THREADENTRY32, *PTHREADENTRY32, *LPTHREADENTRY32; 
+
+BOOL WINAPI Thread32First(HANDLE,LPTHREADENTRY32);
+BOOL WINAPI Thread32Next(HANDLE,LPTHREADENTRY32);
+
+/*
+ * Process entry list as created by CreateToolHelp32Snapshot 
+ */
+
+typedef struct tagPROCESSENTRY32
+{
+    DWORD dwSize; 
+    DWORD cntUsage; 
+    DWORD th32ProcessID; 
+    DWORD th32DefaultHeapID; 
+    DWORD th32ModuleID; 
+    DWORD cntThreads; 
+    DWORD th32ParentProcessID; 
+    LONG  pcPriClassBase; 
+    DWORD dwFlags; 
+    char szExeFile[MAX_PATH]; 
+} PROCESSENTRY32, *PPROCESSENTRY32, *LPPROCESSENTRY32; 
+
+typedef struct tagPROCESSENTRY32W
+{
+    DWORD dwSize; 
+    DWORD cntUsage; 
+    DWORD th32ProcessID; 
+    DWORD th32DefaultHeapID; 
+    DWORD th32ModuleID; 
+    DWORD cntThreads; 
+    DWORD th32ParentProcessID; 
+    LONG  pcPriClassBase; 
+    DWORD dwFlags; 
+    WCHAR szExeFile[MAX_PATH]; 
+} PROCESSENTRY32W, *PPROCESSENTRY32W, *LPPROCESSENTRY32W; 
+
+BOOL WINAPI Process32First(HANDLE,LPPROCESSENTRY32);
+BOOL WINAPI Process32FirstW(HANDLE,LPPROCESSENTRY32W);
+BOOL WINAPI Process32Next(HANDLE,LPPROCESSENTRY32);
+BOOL WINAPI Process32NextW(HANDLE,LPPROCESSENTRY32W);
+
+#ifdef UNICODE
+#define Process32First Process32FirstW
+#define Process32Next Process32NextW
+#define PROCESSENTRY32 PROCESSENTRY32W
+#define PPROCESSENTRY32 PPROCESSENTRY32W
+#define LPPROCESSENTRY32 LPPROCESSENTRY32W
+#endif
+
+/*
+ * Module entry list as created by CreateToolHelp32Snapshot 
+ */
+
+#define MAX_MODULE_NAME32 255
+
+typedef struct tagMODULEENTRY32
+{
+    DWORD  dwSize; 
+    DWORD  th32ModuleID;
+    DWORD  th32ProcessID; 
+    DWORD  GlblcntUsage;
+    DWORD  ProccntUsage;
+    BYTE  *modBaseAddr;
+    DWORD  modBaseSize;
+    DWORD  hModule;
+    char   szModule[MAX_MODULE_NAME32 + 1];
+    char   szExePath[MAX_PATH]; 
+} MODULEENTRY32, *PMODULEENTRY32, *LPMODULEENTRY32; 
+
+typedef struct tagMODULEENTRY32W
+{
+    DWORD  dwSize; 
+    DWORD  th32ModuleID;
+    DWORD  th32ProcessID; 
+    DWORD  GlblcntUsage;
+    DWORD  ProccntUsage;
+    BYTE  *modBaseAddr;
+    DWORD  modBaseSize;
+    DWORD  hModule;
+    WCHAR  szModule[MAX_MODULE_NAME32 + 1];
+    WCHAR  szExePath[MAX_PATH]; 
+} MODULEENTRY32W, *PMODULEENTRY32W, *LPMODULEENTRY32W; 
+
+BOOL WINAPI Module32First(HANDLE,LPMODULEENTRY32);
+BOOL WINAPI Module32FirstW(HANDLE,LPMODULEENTRY32W);
+BOOL WINAPI Module32Next(HANDLE,LPMODULEENTRY32);
+BOOL WINAPI Module32NextW(HANDLE,LPMODULEENTRY32W);
+
+#ifdef UNICODE
+#define Module32First Module32FirstW
+#define Module32Next Module32NextW
+#define MODULEENTRY32 MODULEENTRY32W
+#define PMODULEENTRY32 PMODULEENTRY32W
+#define LPMODULEENTRY32 LPMODULEENTRY32W
+#endif
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/include/toolhelp.h b/include/toolhelp.h
index 1fef7cd..735c4bb 100644
--- a/include/toolhelp.h
+++ b/include/toolhelp.h
@@ -2,7 +2,6 @@
 #define __WINE_TOOLHELP_H
 
 #include "windef.h"
-#include "tlhelp32.h"
 
 #define MAX_DATA	11
 #define MAX_MODULE_NAME	9
@@ -397,44 +396,4 @@
 
 #include "poppack.h"
 
-/*
- * Thread entry list as created by CreateToolHelp32Snapshot 
- */
-
-typedef struct tagTHREADENTRY { 
-    DWORD dwSize; 
-    DWORD cntUsage; 
-    DWORD th32ThreadID; 
-    DWORD th32OwnerProcessID; 
-    DWORD tbBasePri; 
-    DWORD tbDeltaPri; 
-    DWORD dwFlags; 
-    DWORD th32AccessKey;
-    DWORD th32CurrentProcessID;
-} THREADENTRY, *PTHREADENTRY, *LPTHREADENTRY; 
-
-BOOL      WINAPI Thread32First(HANDLE,LPTHREADENTRY);
-BOOL      WINAPI Thread32Next(HANDLE,LPTHREADENTRY);
-
-/*
- * Process entry list as created by CreateToolHelp32Snapshot 
- */
-
-typedef struct tagPROCESSENTRY { 
-    DWORD dwSize; 
-    DWORD cntUsage; 
-    DWORD th32ProcessID; 
-    DWORD th32DefaultHeapID; 
-    DWORD th32ModuleID; 
-    DWORD cntThreads; 
-    DWORD th32ParentProcessID; 
-    LONG  pcPriClassBase; 
-    DWORD dwFlags; 
-    char szExeFile[MAX_PATH]; 
-} PROCESSENTRY, *PPROCESSENTRY, *LPPROCESSENTRY; 
-
-BOOL      WINAPI Process32First(HANDLE,LPPROCESSENTRY);
-BOOL      WINAPI Process32Next(HANDLE,LPPROCESSENTRY);
-
-
 #endif /* __WINE_TOOLHELP_H */
diff --git a/misc/toolhelp.c b/misc/toolhelp.c
index 36097af..4fb9529 100644
--- a/misc/toolhelp.c
+++ b/misc/toolhelp.c
@@ -19,7 +19,7 @@
 #include "server.h"
 #include "debugtools.h"
 
-DEFAULT_DEBUG_CHANNEL(toolhelp)
+DEFAULT_DEBUG_CHANNEL(toolhelp);
 
 
 /* FIXME: to make this working, we have to callback all these registered 
@@ -150,10 +150,9 @@
     struct create_snapshot_request *req = get_req_buffer();
 
     TRACE("%lx,%lx\n", flags, process );
-    if (flags & (TH32CS_SNAPHEAPLIST|TH32CS_SNAPMODULE|TH32CS_SNAPTHREAD))
-        FIXME("flags %lx not implemented\n", flags );
-    if (!(flags & TH32CS_SNAPPROCESS))
+    if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE)))
     {
+        FIXME("flags %lx not implemented\n", flags );
         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
         return INVALID_HANDLE_VALUE;
     }
@@ -161,23 +160,47 @@
     /* Now do the snapshot */
     req->flags   = flags & ~TH32CS_INHERIT;
     req->inherit = (flags & TH32CS_INHERIT) != 0;
+    req->pid     = (void *)process;
     server_call( REQ_CREATE_SNAPSHOT );
     return req->handle;
 }
 
 
 /***********************************************************************
+ *		TOOLHELP_Thread32Next
+ *
+ * Implementation of Thread32First/Next
+ */
+static BOOL TOOLHELP_Thread32Next( HANDLE handle, LPTHREADENTRY32 lpte, BOOL first )
+{
+    struct next_thread_request *req = get_req_buffer();
+
+    if (lpte->dwSize < sizeof(THREADENTRY32))
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(THREADENTRY32), lpte->dwSize);
+        return FALSE;
+    }
+    req->handle = handle;
+    req->reset = first;
+    if (server_call( REQ_NEXT_THREAD )) return FALSE;
+    lpte->cntUsage           = req->count;
+    lpte->th32ThreadID       = (DWORD)req->tid;
+    lpte->th32OwnerProcessID = (DWORD)req->pid;
+    lpte->tbBasePri          = req->base_pri; 
+    lpte->tbDeltaPri         = req->delta_pri;
+    lpte->dwFlags            = 0;  /* SDK: "reserved; do not use" */
+    return TRUE;
+}
+
+/***********************************************************************
  *		Thread32First    (KERNEL32.686)
  *
  * Return info about the first thread in a toolhelp32 snapshot
  */
-BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY lpte)
+BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
 {
-    if (!lpte)
-	return FALSE;
-
-    FIXME("(%d,%p),stub!\n",hSnapshot,lpte);
-    return FALSE;
+    return TOOLHELP_Thread32Next(hSnapshot, lpte, TRUE);
 }
 
 /***********************************************************************
@@ -185,13 +208,9 @@
  *
  * Return info about the "next" thread in a toolhelp32 snapshot
  */
-BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY lpte)
+BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
 {
-    if (!lpte)
-	return FALSE;
-
-    FIXME("(%d,%p),stub!\n",hSnapshot,lpte);
-    return FALSE;
+    return TOOLHELP_Thread32Next(hSnapshot, lpte, FALSE);
 }
 
 /***********************************************************************
@@ -199,20 +218,20 @@
  *
  * Implementation of Process32First/Next
  */
-static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY lppe, BOOL first )
+static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY32 lppe, BOOL first )
 {
     struct next_process_request *req = get_req_buffer();
 
-    if (lppe->dwSize < sizeof (PROCESSENTRY))
+    if (lppe->dwSize < sizeof(PROCESSENTRY32))
     {
         SetLastError( ERROR_INSUFFICIENT_BUFFER );
-        ERR("Result buffer too small\n");
+        ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(PROCESSENTRY32), lppe->dwSize);
         return FALSE;
     }
     req->handle = handle;
     req->reset = first;
     if (server_call( REQ_NEXT_PROCESS )) return FALSE;
-    lppe->cntUsage            = 1;
+    lppe->cntUsage            = req->count;
     lppe->th32ProcessID       = (DWORD)req->pid;
     lppe->th32DefaultHeapID   = 0;  /* FIXME */ 
     lppe->th32ModuleID        = 0;  /* FIXME */
@@ -230,7 +249,7 @@
  *
  * Return info about the first process in a toolhelp32 snapshot
  */
-BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY lppe)
+BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
 {
     return TOOLHELP_Process32Next( hSnapshot, lppe, TRUE );
 }
@@ -240,20 +259,50 @@
  *
  * Return info about the "next" process in a toolhelp32 snapshot
  */
-BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY lppe)
+BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
 {
     return TOOLHELP_Process32Next( hSnapshot, lppe, FALSE );
 }
 
+
+/***********************************************************************
+ *		TOOLHELP_Module32Next
+ *
+ * Implementation of Module32First/Next
+ */
+static BOOL TOOLHELP_Module32Next( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first )
+{
+    struct next_module_request *req = get_req_buffer();
+    
+    if (lpme->dwSize < sizeof (MODULEENTRY32))
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32), lpme->dwSize);
+        return FALSE;
+    }
+    req->handle = handle;
+    req->reset = first;
+    if (server_call( REQ_NEXT_MODULE )) return FALSE;
+    lpme->th32ModuleID   = 0;  /* toolhelp internal id, never used */
+    lpme->th32ProcessID  = (DWORD)req->pid;
+    lpme->GlblcntUsage   = 0; /* FIXME */
+    lpme->ProccntUsage   = 0; /* FIXME */ 
+    lpme->modBaseAddr    = req->base;
+    lpme->modBaseSize    = 0; /* FIXME */
+    lpme->hModule        = (DWORD)req->base;
+    lpme->szModule[0]    = 0;  /* FIXME */
+    lpme->szExePath[0]   = 0;  /* FIXME */
+    return TRUE;
+}
+
 /***********************************************************************
  *		Module32First   (KERNEL32.527)
  *
  * Return info about the "first" module in a toolhelp32 snapshot
  */
-BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY lpme)
+BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
 {
-    FIXME("(%d,%p),stub!\n",hSnapshot,lpme);
-    return FALSE;
+    return TOOLHELP_Module32Next( hSnapshot, lpme, TRUE );
 }
 
 /***********************************************************************
@@ -261,10 +310,9 @@
  *
  * Return info about the "next" module in a toolhelp32 snapshot
  */
-BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY lpme)
+BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
 {
-    FIXME("(%d,%p),stub!\n",hSnapshot,lpme);
-    return FALSE;
+    return TOOLHELP_Module32Next( hSnapshot, lpme, FALSE );
 }
 
 /************************************************************************
diff --git a/server/process.c b/server/process.c
index 3cc87f6..c84672d 100644
--- a/server/process.c
+++ b/server/process.c
@@ -563,6 +563,7 @@
         if (!process->running_threads) continue;
         ptr->process  = process;
         ptr->threads  = process->running_threads;
+        ptr->count    = process->obj.refcount;
         ptr->priority = process->priority;
         grab_object( process );
         ptr++;
@@ -571,6 +572,25 @@
     return snapshot;
 }
 
+/* take a snapshot of the modules of a process */
+struct module_snapshot *module_snap( struct process *process, int *count )
+{
+    struct module_snapshot *snapshot, *ptr;
+    struct process_dll *dll;
+    int total = 0;
+
+    for (dll = &process->exe; dll; dll = dll->next) total++;
+    if (!(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL;
+
+    for (ptr = snapshot, dll = &process->exe; dll; dll = dll->next, ptr++)
+    {
+        ptr->base = dll->base;
+    }
+    *count = total;
+    return snapshot;
+}
+
+
 /* create a new process */
 DECL_HANDLER(new_process)
 {
diff --git a/server/process.h b/server/process.h
index 6cdbb6a..6e98a47 100644
--- a/server/process.h
+++ b/server/process.h
@@ -55,10 +55,16 @@
 {
     struct process *process;  /* process ptr */
     struct process *parent;   /* process parent */
+    int             count;    /* process refcount */
     int             threads;  /* number of threads */
     int             priority; /* priority class */
 };
 
+struct module_snapshot
+{
+    void           *base;     /* module base addr */
+};
+
 /* process functions */
 
 extern struct thread *create_process( int fd, struct process *parent,
@@ -75,6 +81,7 @@
 extern void resume_process( struct process *process );
 extern void kill_debugged_processes( struct thread *debugger, int exit_code );
 extern struct process_snapshot *process_snap( int *count );
+extern struct module_snapshot *module_snap( struct process *process, int *count );
 
 static inline void *get_process_id( struct process *process ) { return process; }
 
diff --git a/server/request.h b/server/request.h
index 03943d9..c7b970b 100644
--- a/server/request.h
+++ b/server/request.h
@@ -138,6 +138,8 @@
 DECL_HANDLER(create_device);
 DECL_HANDLER(create_snapshot);
 DECL_HANDLER(next_process);
+DECL_HANDLER(next_thread);
+DECL_HANDLER(next_module);
 DECL_HANDLER(wait_debug_event);
 DECL_HANDLER(exception_event);
 DECL_HANDLER(output_debug_string);
@@ -244,6 +246,8 @@
     (req_handler)req_create_device,
     (req_handler)req_create_snapshot,
     (req_handler)req_next_process,
+    (req_handler)req_next_thread,
+    (req_handler)req_next_module,
     (req_handler)req_wait_debug_event,
     (req_handler)req_exception_event,
     (req_handler)req_output_debug_string,
diff --git a/server/snapshot.c b/server/snapshot.c
index 2a16ac5..3f806be 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1999 Alexandre Julliard
  *
- * FIXME: only process snapshots implemented for now
+ * FIXME: heap snapshots not implemented
  */
 
 #include <assert.h>
@@ -22,9 +22,16 @@
 struct snapshot
 {
     struct object             obj;           /* object header */
-    struct process_snapshot  *process;       /* processes snapshot */
+    struct process           *process;       /* process of this snapshot (for modules and heaps) */
+    struct process_snapshot  *processes;     /* processes snapshot */
     int                       process_count; /* count of processes */
     int                       process_pos;   /* current position in proc snapshot */
+    struct thread_snapshot   *threads;       /* threads snapshot */
+    int                       thread_count;  /* count of threads */
+    int                       thread_pos;    /* current position in thread snapshot */
+    struct module_snapshot   *modules;       /* modules snapshot */
+    int                       module_count;  /* count of modules */
+    int                       module_pos;    /* current position in module snapshot */
 };
 
 static void snapshot_dump( struct object *obj, int verbose );
@@ -49,18 +56,41 @@
 
 
 /* create a new snapshot */
-static struct snapshot *create_snapshot( int flags )
+static struct snapshot *create_snapshot( void *pid, int flags )
 {
+    struct process *process = NULL;
     struct snapshot *snapshot;
 
-    if ((snapshot = alloc_object( &snapshot_ops, -1 )))
+    /* need a process for modules and heaps */
+    if (flags & (TH32CS_SNAPMODULE|TH32CS_SNAPHEAPLIST))
     {
-        if (flags & TH32CS_SNAPPROCESS)
-            snapshot->process = process_snap( &snapshot->process_count );
-        else
-            snapshot->process_count = 0;
-        snapshot->process_pos = 0;
+        if (!pid) process = (struct process *)grab_object( current->process );
+        else if (!(process = get_process_from_id( pid ))) return NULL;
     }
+
+    if (!(snapshot = alloc_object( &snapshot_ops, -1 )))
+    {
+        if (process) release_object( process );
+        return NULL;
+    }
+
+    snapshot->process = process;
+
+    snapshot->process_pos = 0;
+    snapshot->process_count = 0;
+    if (flags & TH32CS_SNAPPROCESS)
+        snapshot->processes = process_snap( &snapshot->process_count );
+
+    snapshot->thread_pos = 0;
+    snapshot->thread_count = 0;
+    if (flags & TH32CS_SNAPTHREAD)
+        snapshot->threads = thread_snap( &snapshot->thread_count );
+
+    snapshot->module_pos = 0;
+    snapshot->module_count = 0;
+    if (flags & TH32CS_SNAPMODULE)
+        snapshot->modules = module_snap( process, &snapshot->module_count );
+
     return snapshot;
 }
 
@@ -80,19 +110,67 @@
         set_error( STATUS_NO_MORE_FILES );
         return 0;
     }
-    ptr = &snapshot->process[snapshot->process_pos++];
-    req->pid      = ptr->process;
+    ptr = &snapshot->processes[snapshot->process_pos++];
+    req->count    = ptr->count;
+    req->pid      = get_process_id( ptr->process );
     req->threads  = ptr->threads;
     req->priority = ptr->priority;
     return 1;
 }
 
+/* get the next thread in the snapshot */
+static int snapshot_next_thread( struct snapshot *snapshot, struct next_thread_request *req )
+{
+    struct thread_snapshot *ptr;
+
+    if (!snapshot->thread_count)
+    {
+        set_error( STATUS_INVALID_PARAMETER );  /* FIXME */
+        return 0;
+    }
+    if (req->reset) snapshot->thread_pos = 0;
+    else if (snapshot->thread_pos >= snapshot->thread_count)
+    {
+        set_error( STATUS_NO_MORE_FILES );
+        return 0;
+    }
+    ptr = &snapshot->threads[snapshot->thread_pos++];
+    req->count     = ptr->count;
+    req->pid       = get_process_id( ptr->thread->process );
+    req->tid       = get_thread_id( ptr->thread );
+    req->base_pri  = ptr->priority;
+    req->delta_pri = 0;  /* FIXME */
+    return 1;
+}
+
+/* get the next module in the snapshot */
+static int snapshot_next_module( struct snapshot *snapshot, struct next_module_request *req )
+{
+    struct module_snapshot *ptr;
+
+    if (!snapshot->module_count)
+    {
+        set_error( STATUS_INVALID_PARAMETER );  /* FIXME */
+        return 0;
+    }
+    if (req->reset) snapshot->module_pos = 0;
+    else if (snapshot->module_pos >= snapshot->module_count)
+    {
+        set_error( STATUS_NO_MORE_FILES );
+        return 0;
+    }
+    ptr = &snapshot->modules[snapshot->module_pos++];
+    req->pid  = get_process_id( snapshot->process );
+    req->base = ptr->base;
+    return 1;
+}
+
 static void snapshot_dump( struct object *obj, int verbose )
 {
     struct snapshot *snapshot = (struct snapshot *)obj;
     assert( obj->ops == &snapshot_ops );
-    fprintf( stderr, "Snapshot: %d processes\n",
-             snapshot->process_count );
+    fprintf( stderr, "Snapshot: %d procs %d threads %d modules\n",
+             snapshot->process_count, snapshot->thread_count, snapshot->module_count );
 }
 
 static void snapshot_destroy( struct object *obj )
@@ -103,9 +181,17 @@
     if (snapshot->process_count)
     {
         for (i = 0; i < snapshot->process_count; i++)
-            release_object( snapshot->process[i].process );
-        free( snapshot->process );
+            release_object( snapshot->processes[i].process );
+        free( snapshot->processes );
     }
+    if (snapshot->thread_count)
+    {
+        for (i = 0; i < snapshot->thread_count; i++)
+            release_object( snapshot->threads[i].thread );
+        free( snapshot->threads );
+    }
+    if (snapshot->module_count) free( snapshot->modules );
+    if (snapshot->process) release_object( snapshot->process );
 }
 
 /* create a snapshot */
@@ -114,7 +200,7 @@
     struct snapshot *snapshot;
 
     req->handle = -1;
-    if ((snapshot = create_snapshot( req->flags )))
+    if ((snapshot = create_snapshot( req->pid, req->flags )))
     {
         req->handle = alloc_handle( current->process, snapshot, 0, req->inherit );
         release_object( snapshot );
@@ -133,3 +219,29 @@
         release_object( snapshot );
     }
 }
+
+/* get the next thread from a snapshot */
+DECL_HANDLER(next_thread)
+{
+    struct snapshot *snapshot;
+
+    if ((snapshot = (struct snapshot *)get_handle_obj( current->process, req->handle,
+                                                       0, &snapshot_ops )))
+    {
+        snapshot_next_thread( snapshot, req );
+        release_object( snapshot );
+    }
+}
+
+/* get the next module from a snapshot */
+DECL_HANDLER(next_module)
+{
+    struct snapshot *snapshot;
+
+    if ((snapshot = (struct snapshot *)get_handle_obj( current->process, req->handle,
+                                                       0, &snapshot_ops )))
+    {
+        snapshot_next_module( snapshot, req );
+        release_object( snapshot );
+    }
+}
diff --git a/server/thread.c b/server/thread.c
index 3963f60..eeedd2b 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -580,6 +580,30 @@
     release_object( thread );
 }
 
+/* take a snapshot of currently running threads */
+struct thread_snapshot *thread_snap( int *count )
+{
+    struct thread_snapshot *snapshot, *ptr;
+    struct thread *thread;
+    int total = 0;
+
+    for (thread = first_thread; thread; thread = thread->next)
+        if (thread->state != TERMINATED) total++;
+    if (!total || !(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL;
+    ptr = snapshot;
+    for (thread = first_thread; thread; thread = thread->next)
+    {
+        if (thread->state == TERMINATED) continue;
+        ptr->thread   = thread;
+        ptr->count    = thread->obj.refcount;
+        ptr->priority = thread->priority;
+        grab_object( thread );
+        ptr++;
+    }
+    *count = total;
+    return snapshot;
+}
+
 /* signal that we are finished booting on the client side */
 DECL_HANDLER(boot_done)
 {
diff --git a/server/thread.h b/server/thread.h
index 2913a42..6f836dc 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -58,6 +58,13 @@
     enum request        last_req;  /* last request received (for debugging) */
 };
 
+struct thread_snapshot
+{
+    struct thread  *thread;    /* thread ptr */
+    int             count;     /* thread refcount */
+    int             priority;  /* priority class */
+};
+
 /* callback function for building the thread reply when sleep_on is finished */
 typedef void (*sleep_reply)( struct thread *thread, struct object *obj, int signaled );
 
@@ -79,6 +86,7 @@
 extern void wake_up( struct object *obj, int max );
 extern int sleep_on( int count, struct object *objects[], int flags,
                      int timeout, sleep_reply func );
+extern struct thread_snapshot *thread_snap( int *count );
 
 /* ptrace functions */
 
diff --git a/server/trace.c b/server/trace.c
index aeba409..66b48bd 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -929,7 +929,8 @@
 static void dump_create_snapshot_request( const struct create_snapshot_request *req )
 {
     fprintf( stderr, " inherit=%d,", req->inherit );
-    fprintf( stderr, " flags=%d", req->flags );
+    fprintf( stderr, " flags=%d,", req->flags );
+    fprintf( stderr, " pid=%p", req->pid );
 }
 
 static void dump_create_snapshot_reply( const struct create_snapshot_request *req )
@@ -945,11 +946,39 @@
 
 static void dump_next_process_reply( const struct next_process_request *req )
 {
+    fprintf( stderr, " count=%d,", req->count );
     fprintf( stderr, " pid=%p,", req->pid );
     fprintf( stderr, " threads=%d,", req->threads );
     fprintf( stderr, " priority=%d", req->priority );
 }
 
+static void dump_next_thread_request( const struct next_thread_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " reset=%d", req->reset );
+}
+
+static void dump_next_thread_reply( const struct next_thread_request *req )
+{
+    fprintf( stderr, " count=%d,", req->count );
+    fprintf( stderr, " pid=%p,", req->pid );
+    fprintf( stderr, " tid=%p,", req->tid );
+    fprintf( stderr, " base_pri=%d,", req->base_pri );
+    fprintf( stderr, " delta_pri=%d", req->delta_pri );
+}
+
+static void dump_next_module_request( const struct next_module_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " reset=%d", req->reset );
+}
+
+static void dump_next_module_reply( const struct next_module_request *req )
+{
+    fprintf( stderr, " pid=%p,", req->pid );
+    fprintf( stderr, " base=%p", req->base );
+}
+
 static void dump_wait_debug_event_request( const struct wait_debug_event_request *req )
 {
     fprintf( stderr, " timeout=%d", req->timeout );
@@ -1364,6 +1393,8 @@
     (dump_func)dump_create_device_request,
     (dump_func)dump_create_snapshot_request,
     (dump_func)dump_next_process_request,
+    (dump_func)dump_next_thread_request,
+    (dump_func)dump_next_module_request,
     (dump_func)dump_wait_debug_event_request,
     (dump_func)dump_exception_event_request,
     (dump_func)dump_output_debug_string_request,
@@ -1467,6 +1498,8 @@
     (dump_func)dump_create_device_reply,
     (dump_func)dump_create_snapshot_reply,
     (dump_func)dump_next_process_reply,
+    (dump_func)dump_next_thread_reply,
+    (dump_func)dump_next_module_reply,
     (dump_func)dump_wait_debug_event_reply,
     (dump_func)dump_exception_event_reply,
     (dump_func)0,
@@ -1570,6 +1603,8 @@
     "create_device",
     "create_snapshot",
     "next_process",
+    "next_thread",
+    "next_module",
     "wait_debug_event",
     "exception_event",
     "output_debug_string",