[1/3] server: Add an extra step to desktop shutdowns that explorer can interrupt.

Vincent Povirk madewokherd at gmail.com
Fri Jan 24 15:11:31 CST 2014


-------------- next part --------------
From 18adb9fdf061bd1f19f78bfb0c415c5cd023aaf8 Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Fri, 24 Jan 2014 13:39:09 -0600
Subject: [PATCH 1/4] server: Add an extra step to desktop shutdowns that
 explorer can interrupt.

---
 dlls/user32/user32.spec     |  1 +
 dlls/user32/winstation.c    | 18 ++++++++++++++++++
 programs/explorer/desktop.c | 20 +++++++++++++++++++-
 server/protocol.def         |  6 ++++++
 server/winstation.c         | 29 +++++++++++++++++++++++++++--
 5 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index 4b1f4b5..26fd4ee 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -780,3 +780,4 @@
 #
 @ cdecl __wine_send_input(long ptr)
 @ cdecl __wine_set_pixel_format(long long)
+@ cdecl __wine_unlink_desktop(ptr)
diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c
index 12b9edc..832d9e1 100644
--- a/dlls/user32/winstation.c
+++ b/dlls/user32/winstation.c
@@ -483,6 +483,24 @@ HDESK WINAPI OpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access )
 
 
 /***********************************************************************
+ *              __wine_unlink_desktop  (USER32.@)
+ *
+ * Internal function to prevent new processes from accessing a desktop.
+ */
+BOOL CDECL __wine_unlink_desktop( HDESK handle )
+{
+    BOOL ret;
+    SERVER_START_REQ( unlink_desktop )
+    {
+        req->handle = wine_server_obj_handle( handle );
+        ret = !wine_server_call_err( req );
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/***********************************************************************
  *              GetUserObjectInformationA   (USER32.@)
  */
 BOOL WINAPI GetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DWORD len, LPDWORD needed )
diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c
index db6a355..4fa9351 100644
--- a/programs/explorer/desktop.c
+++ b/programs/explorer/desktop.c
@@ -492,6 +492,19 @@ static BOOL start_screensaver( void )
     return FALSE;
 }
 
+
+static void wine_unlink_desktop(HDESK desktop)
+{
+    BOOL (*CDECL __wine_unlink_desktop)(HDESK desktop) = NULL;
+
+    __wine_unlink_desktop = (void*)GetProcAddress(
+        GetModuleHandleA("user32"),
+        "__wine_unlink_desktop");
+
+    if (__wine_unlink_desktop != NULL)
+        __wine_unlink_desktop(desktop);
+}
+
 /* window procedure for the desktop window */
 static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPARAM lp )
 {
@@ -511,7 +524,12 @@ static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPAR
         return 0;
 
     case WM_CLOSE:
-        PostQuitMessage(0);
+        if (wp)
+            /* Desktop was unlinked */
+            PostQuitMessage(0);
+        else
+            /* Last process in this desktop quit */
+            wine_unlink_desktop( GetThreadDesktop( GetCurrentThreadId() ) );
         return 0;
 
     case WM_SETCURSOR:
diff --git a/server/protocol.def b/server/protocol.def
index fec5e75..ced9352 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2755,6 +2755,12 @@ enum coords_relative
 @END
 
 
+/* Prevent new processes from accessing a desktop */
+ at REQ(unlink_desktop)
+    obj_handle_t handle;          /* handle to the desktop */
+ at END
+
+
 /* Get/set information about a user object (window station or desktop) */
 @REQ(set_user_object_info)
     obj_handle_t handle;          /* handle to the object */
diff --git a/server/winstation.c b/server/winstation.c
index 08389bb..750637d 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -305,8 +305,7 @@ static void close_desktop_timeout( void *private )
     struct desktop *desktop = private;
 
     desktop->close_timeout = NULL;
-    unlink_named_object( &desktop->obj );  /* make sure no other process can open it */
-    post_desktop_message( desktop, WM_CLOSE, 0, 0 );  /* and signal the owner to quit */
+    post_desktop_message( desktop, WM_CLOSE, 0, 0 );  /* signal the owner to quit */
 }
 
 /* add a user of the desktop and cancel the close timeout */
@@ -724,3 +723,29 @@ DECL_HANDLER(enum_desktop)
     release_object( winstation );
     set_error( STATUS_NO_MORE_ENTRIES );
 }
+
+
+/* Prevent new processes from accessing a desktop */
+DECL_HANDLER(unlink_desktop)
+{
+    struct desktop *desktop;
+    struct process *desktop_owner;
+
+    if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle,
+                                                     0, &desktop_ops )))
+    {
+        desktop_owner = get_top_window_owner( desktop );
+
+        /* Fail if there are other processes still in the desktop. */
+        if (desktop->users > ((desktop_owner && desktop_owner != current->process) ? 2 : 1))
+            set_error( STATUS_DEVICE_BUSY );
+        else
+        {
+            unlink_named_object( &desktop->obj );
+            post_desktop_message( desktop, WM_CLOSE, 1, 0 );  /* signal the owner to quit */
+        }
+
+        release_object( desktop );
+    }
+}
+
-- 
1.8.1.2



More information about the wine-patches mailing list