The desktop of a new thread should be set from the process initial
desktop, not from the parent thread.
Fixed a couple of bugs in the desktop name handling.

diff --git a/dlls/user/tests/winstation.c b/dlls/user/tests/winstation.c
index d40ae19..2855448 100644
--- a/dlls/user/tests/winstation.c
+++ b/dlls/user/tests/winstation.c
@@ -42,6 +42,8 @@
         trace( "obj %p type '%s'\n", obj, buffer );
 }
 
+static HDESK initial_desktop;
+
 static DWORD CALLBACK thread( LPVOID arg )
 {
     HDESK d1, d2;
@@ -49,6 +51,7 @@
     ok( hwnd != 0, "CreateWindow failed\n" );
     d1 = GetThreadDesktop(GetCurrentThreadId());
     trace( "thread %p desktop: %p\n", arg, d1 );
+    ok( d1 == initial_desktop, "thread %p doesn't use initial desktop\n", arg );
 
     if (0)  /* FIXME: this should be todo_wine but it would break the rest of the test */
     {
@@ -150,6 +153,7 @@
 
     /* desktops */
     d1 = GetThreadDesktop(GetCurrentThreadId());
+    initial_desktop = d1;
     ok( GetThreadDesktop(GetCurrentThreadId()) == d1,
         "GetThreadDesktop returned different handles\n" );
 
@@ -201,8 +205,8 @@
         ok( d1 == d2, "got different handles after close\n" );
     }
 
-    trace( "thread 1 desktop: %p\n", d2 );
-    print_object( d2 );
+    trace( "thread 1 desktop: %p\n", d1 );
+    print_object( d1 );
     hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id );
     Sleep(1000);
     trace( "get other thread desktop: %p\n", GetThreadDesktop(id) );
diff --git a/server/handle.c b/server/handle.c
index 347960d..efcbe27 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -56,7 +56,7 @@
 static struct handle_table *global_table;
 
 /* reserved handle access rights */
-#define RESERVED_SHIFT         25
+#define RESERVED_SHIFT         26
 #define RESERVED_INHERIT       (HANDLE_FLAG_INHERIT << RESERVED_SHIFT)
 #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
 #define RESERVED_ALL           (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
diff --git a/server/process.c b/server/process.c
index e69fe1b..f2b4012 100644
--- a/server/process.c
+++ b/server/process.c
@@ -281,6 +281,7 @@
     process->peb             = NULL;
     process->ldt_copy        = NULL;
     process->winstation      = 0;
+    process->desktop         = 0;
     process->exe.file        = NULL;
     process->exe.dbg_offset  = 0;
     process->exe.dbg_size    = 0;
@@ -379,7 +380,8 @@
 
     /* connect to the window station and desktop */
     connect_process_winstation( process, NULL, 0 );
-    connect_thread_desktop( current, NULL, 0 );
+    connect_process_desktop( process, NULL, 0 );
+    current->desktop = process->desktop;
 
     /* set the process console */
     if (!set_process_console( process, parent_thread, info, reply )) return NULL;
diff --git a/server/process.h b/server/process.h
index c82848b..3949bc4 100644
--- a/server/process.h
+++ b/server/process.h
@@ -73,6 +73,7 @@
     struct event        *idle_event;      /* event for input idle */
     struct msg_queue    *queue;           /* main message queue */
     obj_handle_t         winstation;      /* main handle to process window station */
+    obj_handle_t         desktop;         /* handle to desktop to use for new threads */
     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/thread.c b/server/thread.c
index 9d69bf1..3fb06c5 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -137,7 +137,6 @@
     thread->priority        = THREAD_PRIORITY_NORMAL;
     thread->affinity        = 1;
     thread->suspend         = 0;
-    thread->desktop         = 0;
     thread->creation_time   = time(NULL);
     thread->exit_time       = 0;
 
@@ -159,6 +158,7 @@
     init_thread_structure( thread );
 
     thread->process = (struct process *)grab_object( process );
+    thread->desktop = process->desktop;
     if (!current) current = thread;
 
     if (!booting_thread)  /* first thread ever */
@@ -834,7 +834,6 @@
     if ((thread = create_thread( request_fd, current->process )))
     {
         if (req->suspend) thread->suspend++;
-        thread->desktop = current->desktop;
         reply->tid = get_thread_id( thread );
         if ((reply->handle = alloc_handle( current->process, thread,
                                            THREAD_ALL_ACCESS, req->inherit )))
diff --git a/server/user.h b/server/user.h
index ff8af79..ec83199 100644
--- a/server/user.h
+++ b/server/user.h
@@ -121,7 +121,7 @@
 /* windows station functions */
 
 extern void connect_process_winstation( struct process *process, const WCHAR *name, size_t len );
-extern void connect_thread_desktop( struct thread *thread, const WCHAR *name, size_t len );
+extern void connect_process_desktop( struct process *process, const WCHAR *name, size_t len );
 extern void close_thread_desktop( struct thread *thread );
 
 #endif  /* __WINE_SERVER_USER_H */
diff --git a/server/winstation.c b/server/winstation.c
index 57b5d45..7e7adab 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -162,7 +162,7 @@
     if (!(full_name = mem_alloc( *res_len ))) return NULL;
     memcpy( full_name, winstation_name, winstation_len );
     full_name[winstation_len / sizeof(WCHAR)] = '\\';
-    memcpy( full_name + (winstation_len + 1) / sizeof(WCHAR), name, len );
+    memcpy( full_name + winstation_len / sizeof(WCHAR) + 1, name, len );
     return full_name;
 }
 
@@ -207,21 +207,17 @@
     release_object( desktop->winstation );
 }
 
-/* close a desktop handle if allowed */
-static void close_desktop_handle( struct process *process, obj_handle_t handle )
+/* check if a desktop handle is currently used by the process */
+static int is_desktop_in_use( struct process *process, obj_handle_t handle )
 {
     struct thread *thread;
 
-    /* make sure it's not in use by any thread in the process */
+    if (process->desktop == handle) return 1;
+
     LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
-    {
-        if (thread->desktop == handle)
-        {
-            set_error( STATUS_DEVICE_BUSY );
-            return;
-        }
-    }
-    close_handle( process, handle, NULL );
+        if (thread->desktop == handle) return 1;
+
+    return 0;
 }
 
 /* connect a process to its window station */
@@ -262,14 +258,13 @@
     clear_error();  /* ignore errors */
 }
 
-/* connect a thread to its desktop */
-void connect_thread_desktop( struct thread *thread, const WCHAR *name, size_t len )
+/* connect a process to its main desktop */
+void connect_process_desktop( struct process *process, const WCHAR *name, size_t len )
 {
     struct desktop *desktop;
     struct winstation *winstation;
-    struct process *process = thread->process;
 
-    if (thread->desktop) return;  /* already has one */
+    if (process->desktop) return;  /* already has one */
 
     if ((winstation = get_process_winstation( process, WINSTA_CREATEDESKTOP )))
     {
@@ -282,7 +277,7 @@
         }
         if ((desktop = create_desktop( name, len, 0, winstation )))
         {
-            thread->desktop = alloc_handle( process, desktop, DESKTOP_ALL_ACCESS, FALSE );
+            process->desktop = alloc_handle( process, desktop, DESKTOP_ALL_ACCESS, FALSE );
             release_object( desktop );
         }
         release_object( winstation );
@@ -296,8 +291,8 @@
     obj_handle_t handle = thread->desktop;
 
     thread->desktop = 0;
-    if (handle) close_desktop_handle( thread->process, handle );
-    clear_error();  /* ignore errors */
+    if (handle && !is_desktop_in_use( thread->process, handle ))
+        close_handle( thread->process, handle, NULL );
 }
 
 
@@ -413,7 +408,10 @@
     if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle,
                                                      0, &desktop_ops )))
     {
-        close_desktop_handle( current->process, req->handle );
+        if (!is_desktop_in_use( current->process, req->handle ))
+            close_handle( current->process, req->handle, NULL );
+        else
+            set_error( STATUS_DEVICE_BUSY );
         release_object( desktop );
     }
 }
@@ -479,8 +477,8 @@
         /* if there is a backslash return the part of the name after it */
         if (name && (ptr = memchrW( name, '\\', len )))
         {
+            len -= (ptr + 1 - name) * sizeof(WCHAR);
             name = ptr + 1;
-            len -= (ptr - name) * sizeof(WCHAR);
         }
         if (name) set_reply_data( name, min( len, get_reply_max_size() ));
     }