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/atom.c b/server/atom.c
index 52797ca..b1291d3 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -76,6 +76,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
atom_table_destroy /* destroy */
};
diff --git a/server/change.c b/server/change.c
index 51867dd..5ccdfb8 100644
--- a/server/change.c
+++ b/server/change.c
@@ -73,6 +73,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
change_destroy /* destroy */
};
diff --git a/server/console.c b/server/console.c
index cc57418..871a66e 100644
--- a/server/console.c
+++ b/server/console.c
@@ -48,6 +48,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
console_input_destroy /* destroy */
};
@@ -73,6 +74,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
console_input_events_destroy /* destroy */
};
@@ -109,6 +111,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
screen_buffer_destroy /* destroy */
};
diff --git a/server/debugger.c b/server/debugger.c
index b1ba9b1..e8fbb0c 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -74,6 +74,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
debug_event_destroy /* destroy */
};
@@ -91,6 +92,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
debug_ctx_destroy /* destroy */
};
diff --git a/server/event.c b/server/event.c
index fa1dbbf..3445185 100644
--- a/server/event.c
+++ b/server/event.c
@@ -53,6 +53,7 @@
event_satisfied, /* satisfied */
event_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
no_destroy /* destroy */
};
diff --git a/server/fd.c b/server/fd.c
index 797f77f..d3143cd 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -163,6 +163,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
fd_destroy /* destroy */
};
@@ -193,6 +194,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
inode_destroy /* destroy */
};
@@ -224,6 +226,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
no_destroy /* destroy */
};
diff --git a/server/file.c b/server/file.c
index dd38e19..9000b61 100644
--- a/server/file.c
+++ b/server/file.c
@@ -80,6 +80,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
file_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
file_destroy /* destroy */
};
diff --git a/server/handle.c b/server/handle.c
index efcbe27..4a70843 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -108,6 +108,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
handle_table_destroy /* destroy */
};
@@ -323,6 +324,11 @@
return 0;
}
obj = entry->ptr;
+ if (!obj->ops->close_handle( obj, process, handle ))
+ {
+ set_error( STATUS_INVALID_HANDLE );
+ return 0;
+ }
entry->ptr = NULL;
if (fd) *fd = entry->fd;
else if (entry->fd != -1) return 1; /* silently ignore close attempt if we cannot close the fd */
@@ -330,8 +336,6 @@
table = handle_is_global(handle) ? global_table : process->handles;
if (entry < table->entries + table->free) table->free = entry - table->entries;
if (entry == table->entries + table->last) shrink_handle_table( table );
- /* hack: windows seems to treat registry handles differently */
- registry_close_handle( obj, handle );
release_object( obj );
return 1;
}
diff --git a/server/hook.c b/server/hook.c
index 125f346..c3a0244 100644
--- a/server/hook.c
+++ b/server/hook.c
@@ -79,6 +79,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
hook_table_destroy /* destroy */
};
diff --git a/server/mailslot.c b/server/mailslot.c
index 6f24126..347d19f 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -76,6 +76,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
mailslot_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
mailslot_destroy /* destroy */
};
@@ -118,6 +119,7 @@
NULL, /* satisfied */
no_signal, /* signal */
mail_writer_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
mail_writer_destroy /* destroy */
};
diff --git a/server/mapping.c b/server/mapping.c
index 046bc0b..886edc6 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -64,6 +64,7 @@
NULL, /* satisfied */
no_signal, /* signal */
mapping_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
mapping_destroy /* destroy */
};
diff --git a/server/mutex.c b/server/mutex.c
index c1b59bb..c9bee83 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -56,6 +56,7 @@
mutex_satisfied, /* satisfied */
mutex_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
mutex_destroy /* destroy */
};
diff --git a/server/named_pipe.c b/server/named_pipe.c
index bbf011e..ab4a39d 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -112,6 +112,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
named_pipe_destroy /* destroy */
};
@@ -132,6 +133,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
pipe_server_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
pipe_server_destroy /* destroy */
};
@@ -162,6 +164,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
pipe_client_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
pipe_client_destroy /* destroy */
};
diff --git a/server/object.c b/server/object.c
index 90aa35c..1a629ec 100644
--- a/server/object.c
+++ b/server/object.c
@@ -294,6 +294,11 @@
return NULL;
}
+int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
+{
+ return 1; /* ok to close */
+}
+
void no_destroy( struct object *obj )
{
}
diff --git a/server/object.h b/server/object.h
index 9fd6581..6551cf8 100644
--- a/server/object.h
+++ b/server/object.h
@@ -63,6 +63,8 @@
int (*signal)(struct object *, unsigned int);
/* return an fd object that can be used to read/write from the object */
struct fd *(*get_fd)(struct object *);
+ /* close a handle to this object */
+ int (*close_handle)(struct object *,struct process *,obj_handle_t);
/* destroy on refcount == 0 */
void (*destroy)(struct object *);
};
@@ -102,6 +104,7 @@
extern int no_satisfied( struct object *obj, struct thread *thread );
extern int no_signal( struct object *obj, unsigned int access );
extern struct fd *no_get_fd( struct object *obj );
+extern int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
extern void no_destroy( struct object *obj );
#ifdef DEBUG_OBJECTS
extern void dump_objects(void);
@@ -146,7 +149,6 @@
extern void init_registry(void);
extern void flush_registry(void);
extern void close_registry(void);
-extern void registry_close_handle( struct object *obj, obj_handle_t hkey );
/* signal functions */
diff --git a/server/process.c b/server/process.c
index f2b4012..32d3be0 100644
--- a/server/process.c
+++ b/server/process.c
@@ -70,8 +70,9 @@
remove_queue, /* remove_queue */
process_signaled, /* signaled */
no_satisfied, /* satisfied */
- no_signal, /* signal */
+ no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
process_destroy /* destroy */
};
@@ -119,6 +120,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
startup_info_destroy /* destroy */
};
diff --git a/server/queue.c b/server/queue.c
index 38e5d67..d827c0f 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -148,6 +148,7 @@
msg_queue_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
msg_queue_destroy /* destroy */
};
@@ -162,6 +163,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
thread_input_destroy /* destroy */
};
diff --git a/server/registry.c b/server/registry.c
index 5d2d0b9..a38682d 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -129,6 +129,7 @@
static void key_dump( struct object *obj, int verbose );
+static int key_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
static void key_destroy( struct object *obj );
static const struct object_ops key_ops =
@@ -141,6 +142,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ key_close_handle, /* close_handle */
key_destroy /* destroy */
};
@@ -293,17 +295,12 @@
}
/* close the notification associated with a handle */
-void registry_close_handle( struct object *obj, obj_handle_t hkey )
+static int key_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
{
struct key * key = (struct key *) obj;
- struct notify *notify;
-
- if( obj->ops != &key_ops )
- return;
- notify = find_notify( key, hkey );
- if( !notify )
- return;
- do_notification( key, notify, 1 );
+ struct notify *notify = find_notify( key, handle );
+ if (notify) do_notification( key, notify, 1 );
+ return 1; /* ok to close */
}
static void key_destroy( struct object *obj )
diff --git a/server/request.c b/server/request.c
index aa5c09d..4a2c80a 100644
--- a/server/request.c
+++ b/server/request.c
@@ -95,6 +95,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
master_socket_destroy /* destroy */
};
diff --git a/server/semaphore.c b/server/semaphore.c
index 7886842..64c3447 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -53,6 +53,7 @@
semaphore_satisfied, /* satisfied */
semaphore_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
no_destroy /* destroy */
};
diff --git a/server/serial.c b/server/serial.c
index 014142e..73d73ae 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -103,6 +103,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
serial_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
serial_destroy /* destroy */
};
diff --git a/server/signal.c b/server/signal.c
index f3b0f5f..9ce3640 100644
--- a/server/signal.c
+++ b/server/signal.c
@@ -64,6 +64,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
handler_destroy /* destroy */
};
diff --git a/server/snapshot.c b/server/snapshot.c
index 7f1670c..6c71b75 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -63,6 +63,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
snapshot_destroy /* destroy */
};
diff --git a/server/sock.c b/server/sock.c
index 3fa3049..535786e 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -109,6 +109,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
sock_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
sock_destroy /* destroy */
};
diff --git a/server/thread.c b/server/thread.c
index 3fb06c5..b021dc0 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -94,6 +94,7 @@
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
destroy_thread /* destroy */
};
diff --git a/server/timer.c b/server/timer.c
index 2329c6c..c4ab0e8 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -61,6 +61,7 @@
timer_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
timer_destroy /* destroy */
};
diff --git a/server/token.c b/server/token.c
index ca1a7ff..0c11edf 100644
--- a/server/token.c
+++ b/server/token.c
@@ -109,6 +109,7 @@
NULL, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
+ no_close_handle, /* close_handle */
token_destroy /* destroy */
};
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 );
}
}