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

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",