- changed ATOM support in wineserver to match NTDLL needs
- adapted accordingly kernel32 atom support

diff --git a/server/atom.c b/server/atom.c
index 341cf6b..c4de578 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -31,6 +31,7 @@
 #include "request.h"
 #include "object.h"
 #include "process.h"
+#include "handle.h"
 
 #define HASH_SIZE     37
 #define MIN_HASH_SIZE 4
@@ -45,6 +46,7 @@
     struct atom_entry *next;   /* hash table list */
     struct atom_entry *prev;   /* hash table list */
     int                count;  /* reference count */
+    int                pinned; /* whether the atom is pinned or not */
     int                hash;   /* string hash */
     atom_t             atom;   /* atom handle */
     WCHAR              str[1]; /* atom string */
@@ -185,8 +187,9 @@
     {
         struct atom_entry *entry = table->handles[i];
         if (!entry) continue;
-        fprintf( stderr, "  %04x: ref=%d hash=%d \"", entry->atom, entry->count, entry->hash );
-        dump_strW( entry->str, strlenW(entry->str), stderr, "\"\"");
+        fprintf( stderr, "  %04x: ref=%d pinned=%c hash=%d \"", 
+                 entry->atom, entry->count, entry->pinned ? 'Y' : 'N', entry->hash );
+        dump_strW( entry->str, strlenW( entry->str ), stderr, "\"\"");
         fprintf( stderr, "\"\n" );
     }
 }
@@ -249,6 +252,7 @@
             if ((entry->next = table->entries[hash])) entry->next->prev = entry;
             table->entries[hash] = entry;
             entry->count = 1;
+            entry->pinned = 0;
             entry->hash  = hash;
             strcpyW( entry->str, str );
         }
@@ -302,53 +306,128 @@
     if (atom >= MIN_STR_ATOM) delete_atom( global_table, atom );
 }
 
+static struct atom_table* get_table( obj_handle_t h )
+{
+    struct atom_table *table;
+
+    if (h)
+    {
+        table = (struct atom_table*)get_handle_obj( current->process, h,
+                                                    0, &atom_table_ops );
+    }
+    else
+    {
+        if (!global_table && !(global_table = create_table( HASH_SIZE )))
+            return NULL;
+        table = (struct atom_table*)grab_object( global_table );
+    }
+    return table;
+}
+
 /* add a global atom */
 DECL_HANDLER(add_atom)
 {
-    struct atom_table **table_ptr = req->local ? &current->process->atom_table : &global_table;
-
-    if (!*table_ptr) *table_ptr = create_table(0);
-    if (*table_ptr)
+    struct atom_table *table = get_table( req->table );
+    if (table)
     {
         const WCHAR *name = copy_request_name();
-        if (name) reply->atom = add_atom( *table_ptr, name );
+        if (name) reply->atom = add_atom( table, name );
+        release_object( table );
     }
 }
 
 /* delete a global atom */
 DECL_HANDLER(delete_atom)
 {
-    delete_atom( req->local ? current->process->atom_table : global_table, req->atom );
+    struct atom_table *table = get_table( req->table );
+    if (table)
+    {
+        delete_atom( table, req->atom );
+        release_object( table );
+    }
 }
 
 /* find a global atom */
 DECL_HANDLER(find_atom)
 {
-    const WCHAR *name = copy_request_name();
-    if (name)
-        reply->atom = find_atom( req->local ? current->process->atom_table : global_table, name );
-}
-
-/* get global atom name */
-DECL_HANDLER(get_atom_name)
-{
-    struct atom_entry *entry;
-    size_t len = 0;
-
-    reply->count = -1;
-    if ((entry = get_atom_entry( req->local ? current->process->atom_table : global_table,
-                                 req->atom )))
+    struct atom_table *table = get_table( req->table );
+    if (table)
     {
-        reply->count = entry->count;
-        len = strlenW( entry->str ) * sizeof(WCHAR);
-        if (len <= get_reply_max_size()) set_reply_data( entry->str, len );
-        else set_error( STATUS_BUFFER_OVERFLOW );
+        const WCHAR *name = copy_request_name();
+        if (name)
+            reply->atom = find_atom( table, name );
+        release_object( table );
     }
 }
 
-/* init the process atom table */
+/* get global atom name */
+DECL_HANDLER(get_atom_information)
+{
+    struct atom_table *table = get_table( req->table );
+    if (table)
+    {
+        struct atom_entry *entry;
+
+        if ((entry = get_atom_entry( table, req->atom )))
+        {
+            size_t len = strlenW( entry->str ) * sizeof(WCHAR);
+            if (len <= get_reply_max_size()) set_reply_data( entry->str, len );
+            else set_error( STATUS_BUFFER_OVERFLOW );
+            reply->count = entry->count;
+            reply->pinned = entry->pinned;
+        }
+        else reply->count = -1;
+        release_object( table );
+    }
+}
+
+/* set global atom name */
+DECL_HANDLER(set_atom_information)
+{
+    struct atom_table *table = get_table( req->table );
+    if (table)
+    {
+        struct atom_entry *entry;
+
+        if ((entry = get_atom_entry( table, req->atom )))
+        {
+            if (req->pinned) entry->pinned = 1;
+        }
+        release_object( table );
+    }
+}
+
+/* init a (local) atom table */
 DECL_HANDLER(init_atom_table)
 {
-    if (!current->process->atom_table)
-        current->process->atom_table = create_table( req->entries );
+    struct atom_table* table;
+
+    table = create_table( req->entries );
+    reply->table = alloc_handle( current->process, table, 0, FALSE);
+    release_object( table );
+}
+
+/* set global atom name */
+DECL_HANDLER(empty_atom_table)
+{
+    struct atom_table *table = get_table( req->table );
+    if (table)
+    {
+        int i;
+        struct atom_entry *entry;
+
+        for (i = 0; i <= table->last; i++)
+        {
+            entry = table->handles[i];
+            if (entry && (!entry->pinned || req->if_pinned))
+            {
+                if (entry->next) entry->next->prev = entry->prev;
+                if (entry->prev) entry->prev->next = entry->next;
+                else table->entries[entry->hash] = entry->next;
+                table->handles[i] = NULL;
+                free( entry );
+            }
+        }
+        release_object( table );
+    }
 }
diff --git a/server/process.c b/server/process.c
index d2f8c89..24a34c8 100644
--- a/server/process.c
+++ b/server/process.c
@@ -278,7 +278,6 @@
     process->startup_info    = NULL;
     process->idle_event      = NULL;
     process->queue           = NULL;
-    process->atom_table      = NULL;
     process->peb             = NULL;
     process->ldt_copy        = NULL;
     process->exe.file        = NULL;
@@ -422,7 +421,6 @@
     list_remove( &process->entry );
     if (process->idle_event) release_object( process->idle_event );
     if (process->queue) release_object( process->queue );
-    if (process->atom_table) release_object( process->atom_table );
     if (process->exe.file) release_object( process->exe.file );
     if (process->exe.filename) free( process->exe.filename );
     if (process->id) free_ptid( process->id );
diff --git a/server/process.h b/server/process.h
index 8c90117..d203ebd 100644
--- a/server/process.h
+++ b/server/process.h
@@ -72,7 +72,6 @@
     struct startup_info *startup_info;    /* startup info while init is in progress */
     struct event        *idle_event;      /* event for input idle */
     struct msg_queue    *queue;           /* main message queue */
-    struct atom_table   *atom_table;      /* pointer to local atom table */
     struct token        *token;           /* security token associated with this process */
     struct process_dll   exe;             /* main exe file */
     struct list          dlls;            /* list of loaded dlls */
diff --git a/server/protocol.def b/server/protocol.def
index 97b51bf..c21c8f5 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1418,7 +1418,7 @@
 
 /* Add an atom */
 @REQ(add_atom)
-    int           local;       /* is atom in local process table? */
+    obj_handle_t  table;       /* which table to add atom to */
     VARARG(name,unicode_str);  /* atom name */
 @REPLY
     atom_t        atom;        /* resulting atom */
@@ -1427,33 +1427,51 @@
 
 /* Delete an atom */
 @REQ(delete_atom)
+    obj_handle_t  table;       /* which table to delete atom from */
     atom_t        atom;        /* atom handle */
-    int           local;       /* is atom in local process table? */
 @END
 
 
 /* Find an atom */
 @REQ(find_atom)
-    int          local;        /* is atom in local process table? */
+    obj_handle_t table;        /* which table to find atom from */
     VARARG(name,unicode_str);  /* atom name */
 @REPLY
     atom_t       atom;         /* atom handle */
 @END
 
 
-/* Get an atom name */
-@REQ(get_atom_name)
+/* Get information about an atom */
+@REQ(get_atom_information)
+    obj_handle_t table;        /* which table to find atom from */
     atom_t       atom;         /* atom handle */
-    int          local;        /* is atom in local process table? */
 @REPLY
     int          count;        /* atom lock count */
+    int          pinned;       /* whether the atom has been pinned */
     VARARG(name,unicode_str);  /* atom name */
 @END
 
 
-/* Init the process atom table */
+/* Set information about an atom */
+@REQ(set_atom_information)
+    obj_handle_t table;        /* which table to find atom from */
+    atom_t       atom;         /* atom handle */
+    int          pinned;       /* whether to bump atom information */
+@END
+
+
+/* Empty an atom table */
+@REQ(empty_atom_table)
+    obj_handle_t table;        /* which table to find atom from */
+    int          if_pinned;    /* whether to delete pinned atoms */
+@END
+
+
+/* Init an atom table */
 @REQ(init_atom_table)
-    int          entries;      /* number of entries */
+    int          entries;      /* number of entries (only for local) */
+@REPLY
+    obj_handle_t table;        /* handle to the atom table */
 @END
 
 
diff --git a/server/request.h b/server/request.h
index 8a6ac16..29b53a0 100644
--- a/server/request.h
+++ b/server/request.h
@@ -216,7 +216,9 @@
 DECL_HANDLER(add_atom);
 DECL_HANDLER(delete_atom);
 DECL_HANDLER(find_atom);
-DECL_HANDLER(get_atom_name);
+DECL_HANDLER(get_atom_information);
+DECL_HANDLER(set_atom_information);
+DECL_HANDLER(empty_atom_table);
 DECL_HANDLER(init_atom_table);
 DECL_HANDLER(get_msg_queue);
 DECL_HANDLER(set_queue_mask);
@@ -412,7 +414,9 @@
     (req_handler)req_add_atom,
     (req_handler)req_delete_atom,
     (req_handler)req_find_atom,
-    (req_handler)req_get_atom_name,
+    (req_handler)req_get_atom_information,
+    (req_handler)req_set_atom_information,
+    (req_handler)req_empty_atom_table,
     (req_handler)req_init_atom_table,
     (req_handler)req_get_msg_queue,
     (req_handler)req_set_queue_mask,
diff --git a/server/trace.c b/server/trace.c
index f79e8e3..65ee3e9 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1758,7 +1758,7 @@
 
 static void dump_add_atom_request( const struct add_atom_request *req )
 {
-    fprintf( stderr, " local=%d,", req->local );
+    fprintf( stderr, " table=%p,", req->table );
     fprintf( stderr, " name=" );
     dump_varargs_unicode_str( cur_size );
 }
@@ -1770,13 +1770,13 @@
 
 static void dump_delete_atom_request( const struct delete_atom_request *req )
 {
-    fprintf( stderr, " atom=%04x,", req->atom );
-    fprintf( stderr, " local=%d", req->local );
+    fprintf( stderr, " table=%p,", req->table );
+    fprintf( stderr, " atom=%04x", req->atom );
 }
 
 static void dump_find_atom_request( const struct find_atom_request *req )
 {
-    fprintf( stderr, " local=%d,", req->local );
+    fprintf( stderr, " table=%p,", req->table );
     fprintf( stderr, " name=" );
     dump_varargs_unicode_str( cur_size );
 }
@@ -1786,24 +1786,43 @@
     fprintf( stderr, " atom=%04x", req->atom );
 }
 
-static void dump_get_atom_name_request( const struct get_atom_name_request *req )
+static void dump_get_atom_information_request( const struct get_atom_information_request *req )
 {
-    fprintf( stderr, " atom=%04x,", req->atom );
-    fprintf( stderr, " local=%d", req->local );
+    fprintf( stderr, " table=%p,", req->table );
+    fprintf( stderr, " atom=%04x", req->atom );
 }
 
-static void dump_get_atom_name_reply( const struct get_atom_name_reply *req )
+static void dump_get_atom_information_reply( const struct get_atom_information_reply *req )
 {
     fprintf( stderr, " count=%d,", req->count );
+    fprintf( stderr, " pinned=%d,", req->pinned );
     fprintf( stderr, " name=" );
     dump_varargs_unicode_str( cur_size );
 }
 
+static void dump_set_atom_information_request( const struct set_atom_information_request *req )
+{
+    fprintf( stderr, " table=%p,", req->table );
+    fprintf( stderr, " atom=%04x,", req->atom );
+    fprintf( stderr, " pinned=%d", req->pinned );
+}
+
+static void dump_empty_atom_table_request( const struct empty_atom_table_request *req )
+{
+    fprintf( stderr, " table=%p,", req->table );
+    fprintf( stderr, " if_pinned=%d", req->if_pinned );
+}
+
 static void dump_init_atom_table_request( const struct init_atom_table_request *req )
 {
     fprintf( stderr, " entries=%d", req->entries );
 }
 
+static void dump_init_atom_table_reply( const struct init_atom_table_reply *req )
+{
+    fprintf( stderr, " table=%p", req->table );
+}
+
 static void dump_get_msg_queue_request( const struct get_msg_queue_request *req )
 {
 }
@@ -2885,7 +2904,9 @@
     (dump_func)dump_add_atom_request,
     (dump_func)dump_delete_atom_request,
     (dump_func)dump_find_atom_request,
-    (dump_func)dump_get_atom_name_request,
+    (dump_func)dump_get_atom_information_request,
+    (dump_func)dump_set_atom_information_request,
+    (dump_func)dump_empty_atom_table_request,
     (dump_func)dump_init_atom_table_request,
     (dump_func)dump_get_msg_queue_request,
     (dump_func)dump_set_queue_mask_request,
@@ -3078,8 +3099,10 @@
     (dump_func)dump_add_atom_reply,
     (dump_func)0,
     (dump_func)dump_find_atom_reply,
-    (dump_func)dump_get_atom_name_reply,
+    (dump_func)dump_get_atom_information_reply,
     (dump_func)0,
+    (dump_func)0,
+    (dump_func)dump_init_atom_table_reply,
     (dump_func)dump_get_msg_queue_reply,
     (dump_func)dump_set_queue_mask_reply,
     (dump_func)dump_get_queue_status_reply,
@@ -3271,7 +3294,9 @@
     "add_atom",
     "delete_atom",
     "find_atom",
-    "get_atom_name",
+    "get_atom_information",
+    "set_atom_information",
+    "empty_atom_table",
     "init_atom_table",
     "get_msg_queue",
     "set_queue_mask",