Added a close_handle method to the object operations, and use it to
implement registry notifications and the strange behavior of
CloseHandle on winstation/desktop handles.
diff --git a/server/winstation.c b/server/winstation.c
index 7e7adab..d42ed66 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -56,8 +56,10 @@
static struct namespace *winstation_namespace;
static void winstation_dump( struct object *obj, int verbose );
+static int winstation_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
static void winstation_destroy( struct object *obj );
static void desktop_dump( struct object *obj, int verbose );
+static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
static void desktop_destroy( struct object *obj );
static const struct object_ops winstation_ops =
@@ -70,6 +72,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ winstation_close_handle, /* close_handle */
winstation_destroy /* destroy */
};
@@ -84,6 +87,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ desktop_close_handle, /* close_handle */
desktop_destroy /* destroy */
};
@@ -125,6 +129,11 @@
fputc( '\n', stderr );
}
+static int winstation_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
+{
+ return (process->winstation != handle);
+}
+
static void winstation_destroy( struct object *obj )
{
struct winstation *winstation = (struct winstation *)obj;
@@ -199,6 +208,17 @@
fputc( '\n', stderr );
}
+static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
+{
+ struct thread *thread;
+
+ /* check if the handle is currently used by the process or one of its threads */
+ if (process->desktop == handle) return 0;
+ LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
+ if (thread->desktop == handle) return 0;
+ return 1;
+}
+
static void desktop_destroy( struct object *obj )
{
struct desktop *desktop = (struct desktop *)obj;
@@ -207,19 +227,6 @@
release_object( desktop->winstation );
}
-/* 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;
-
- if (process->desktop == handle) return 1;
-
- LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
- if (thread->desktop == handle) return 1;
-
- return 0;
-}
-
/* connect a process to its window station */
void connect_process_winstation( struct process *process, const WCHAR *name, size_t len )
{
@@ -246,13 +253,7 @@
}
if (winstation)
{
- if ((process->winstation = alloc_handle( process, winstation, WINSTA_ALL_ACCESS, FALSE )))
- {
- int fd = -1;
- /* FIXME: Windows doesn't do it this way */
- set_handle_info( process, process->winstation, HANDLE_FLAG_PROTECT_FROM_CLOSE,
- HANDLE_FLAG_PROTECT_FROM_CLOSE, &fd );
- }
+ process->winstation = alloc_handle( process, winstation, WINSTA_ALL_ACCESS, FALSE );
release_object( winstation );
}
clear_error(); /* ignore errors */
@@ -291,8 +292,8 @@
obj_handle_t handle = thread->desktop;
thread->desktop = 0;
- if (handle && !is_desktop_in_use( thread->process, handle ))
- close_handle( thread->process, handle, NULL );
+ if (handle) close_handle( thread->process, handle, NULL );
+ clear_error(); /* ignore errors */
}
@@ -328,10 +329,7 @@
if ((winstation = (struct winstation *)get_handle_obj( current->process, req->handle,
0, &winstation_ops )))
{
- if (req->handle != current->process->winstation)
- close_handle( current->process, req->handle, NULL );
- else
- set_error( STATUS_ACCESS_DENIED );
+ if (!close_handle( current->process, req->handle, NULL )) set_error( STATUS_ACCESS_DENIED );
release_object( winstation );
}
}
@@ -408,10 +406,7 @@
if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle,
0, &desktop_ops )))
{
- if (!is_desktop_in_use( current->process, req->handle ))
- close_handle( current->process, req->handle, NULL );
- else
- set_error( STATUS_DEVICE_BUSY );
+ if (!close_handle( current->process, req->handle, NULL )) set_error( STATUS_DEVICE_BUSY );
release_object( desktop );
}
}