Store window properties in the server. Moved property.c to dlls/user.

diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in
index b92b019..d3c4984 100644
--- a/dlls/user/Makefile.in
+++ b/dlls/user/Makefile.in
@@ -23,6 +23,7 @@
 	mouse.c \
 	msg16.c \
 	network.c \
+	property.c \
 	resource.c \
 	text.c \
 	thunk.c \
diff --git a/dlls/user/property.c b/dlls/user/property.c
new file mode 100644
index 0000000..a3d32ec
--- /dev/null
+++ b/dlls/user/property.c
@@ -0,0 +1,299 @@
+/*
+ * Window properties
+ *
+ * Copyright 1995, 1996, 2001 Alexandre Julliard
+ */
+
+#include <string.h>
+
+#include "windef.h"
+#include "wingdi.h"
+#include "wine/winuser16.h"
+#include "wine/server.h"
+#include "heap.h"
+
+/* size of buffer needed to store an atom string */
+#define ATOM_BUFFER_SIZE 256
+
+
+/***********************************************************************
+ *              get_properties
+ *
+ * Retrieve the list of properties of a given window.
+ * Returned buffer must be freed by caller.
+ */
+static property_data_t *get_properties( HWND hwnd, int *count )
+{
+    property_data_t *ret = NULL;
+
+    SERVER_START_VAR_REQ( get_window_properties, REQUEST_MAX_VAR_SIZE )
+    {
+        req->window = hwnd;
+        if (!SERVER_CALL())
+        {
+            size_t size = server_data_size(req);
+            if (size)
+            {
+                property_data_t *data = server_data_ptr(req);
+                if ((ret = HeapAlloc( GetProcessHeap(), 0, size ))) memcpy( ret, data, size );
+                *count = size / sizeof(*data);
+            }
+        }
+    }
+    SERVER_END_VAR_REQ;
+    return ret;
+}
+
+
+/***********************************************************************
+ *              EnumPropsA_relay
+ *
+ * relay to call the EnumProps callback function from EnumPropsEx
+ */
+static BOOL CALLBACK EnumPropsA_relay( HWND hwnd, LPCSTR str, HANDLE handle, ULONG_PTR lparam )
+{
+    PROPENUMPROCA func = (PROPENUMPROCA)lparam;
+    return func( hwnd, str, handle );
+}
+
+
+/***********************************************************************
+ *              EnumPropsW_relay
+ *
+ * relay to call the EnumProps callback function from EnumPropsEx
+ */
+static BOOL CALLBACK EnumPropsW_relay( HWND hwnd, LPCWSTR str, HANDLE handle, ULONG_PTR lparam )
+{
+    PROPENUMPROCW func = (PROPENUMPROCW)lparam;
+    return func( hwnd, str, handle );
+}
+
+
+/***********************************************************************
+ *              EnumPropsA   (USER32.@)
+ */
+INT WINAPI EnumPropsA( HWND hwnd, PROPENUMPROCA func )
+{
+    return EnumPropsExA( hwnd, EnumPropsA_relay, (LPARAM)func );
+}
+
+
+/***********************************************************************
+ *              EnumPropsW   (USER32.@)
+ */
+INT WINAPI EnumPropsW( HWND hwnd, PROPENUMPROCW func )
+{
+    return EnumPropsExW( hwnd, EnumPropsW_relay, (LPARAM)func );
+}
+
+
+/***********************************************************************
+ *              GetPropA   (USER32.@)
+ */
+HANDLE WINAPI GetPropA( HWND hwnd, LPCSTR str )
+{
+    ATOM atom;
+    HANDLE ret = 0;
+
+    if (!HIWORD(str)) atom = LOWORD(str);
+    else if (!(atom = GlobalFindAtomA( str ))) return 0;
+
+    SERVER_START_REQ( get_window_property )
+    {
+        req->window = hwnd;
+        req->atom = atom;
+        if (!SERVER_CALL_ERR()) ret = req->handle;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/***********************************************************************
+ *              GetPropW   (USER32.@)
+ */
+HANDLE WINAPI GetPropW( HWND hwnd, LPCWSTR str )
+{
+    ATOM atom;
+    HANDLE ret = 0;
+
+    if (!HIWORD(str)) atom = LOWORD(str);
+    else if (!(atom = GlobalFindAtomW( str ))) return 0;
+
+    SERVER_START_REQ( get_window_property )
+    {
+        req->window = hwnd;
+        req->atom = atom;
+        if (!SERVER_CALL_ERR()) ret = req->handle;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/***********************************************************************
+ *              SetPropA   (USER32.@)
+ */
+BOOL WINAPI SetPropA( HWND hwnd, LPCSTR str, HANDLE handle )
+{
+    ATOM atom;
+    BOOL ret;
+
+    if (!HIWORD(str)) atom = LOWORD(str);
+    else if (!(atom = GlobalAddAtomA( str ))) return FALSE;
+
+    SERVER_START_REQ( set_window_property )
+    {
+        req->window = hwnd;
+        req->atom   = atom;
+        req->string = (HIWORD(str) != 0);
+        req->handle = handle;
+        ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+
+    if (HIWORD(str)) GlobalDeleteAtom( atom );
+    return ret;
+}
+
+
+/***********************************************************************
+ *              SetPropW   (USER32.@)
+ */
+BOOL WINAPI SetPropW( HWND hwnd, LPCWSTR str, HANDLE handle )
+{
+    ATOM atom;
+    BOOL ret;
+
+    if (!HIWORD(str)) atom = LOWORD(str);
+    else if (!(atom = GlobalAddAtomW( str ))) return FALSE;
+
+    SERVER_START_REQ( set_window_property )
+    {
+        req->window = hwnd;
+        req->atom   = atom;
+        req->string = (HIWORD(str) != 0);
+        req->handle = handle;
+        ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+
+    if (HIWORD(str)) GlobalDeleteAtom( atom );
+    return ret;
+}
+
+
+/***********************************************************************
+ *              RemovePropA   (USER32.@)
+ */
+HANDLE WINAPI RemovePropA( HWND hwnd, LPCSTR str )
+{
+    ATOM atom;
+    HANDLE ret = 0;
+
+    if (!HIWORD(str)) return RemovePropW( hwnd, MAKEINTATOMW(LOWORD(str)) );
+
+    if ((atom = GlobalAddAtomA( str )))
+    {
+        ret = RemovePropW( hwnd, MAKEINTATOMW(atom) );
+        GlobalDeleteAtom( atom );
+    }
+    return ret;
+}
+
+
+/***********************************************************************
+ *              RemovePropW   (USER32.@)
+ */
+HANDLE WINAPI RemovePropW( HWND hwnd, LPCWSTR str )
+{
+    ATOM atom;
+    HANDLE ret = 0;
+
+    if (!HIWORD(str)) atom = LOWORD(str);
+    else if (!(atom = GlobalAddAtomW( str ))) return 0;
+
+    SERVER_START_REQ( remove_window_property )
+    {
+        req->window = hwnd;
+        req->atom   = atom;
+        if (!SERVER_CALL_ERR()) ret = req->handle;
+    }
+    SERVER_END_REQ;
+
+    if (HIWORD(str)) GlobalDeleteAtom( atom );
+    return ret;
+}
+
+
+/***********************************************************************
+ *              EnumPropsExA   (USER32.@)
+ */
+INT WINAPI EnumPropsExA(HWND hwnd, PROPENUMPROCEXA func, LPARAM lParam)
+{
+    int ret = -1, i, count;
+    property_data_t *list = get_properties( hwnd, &count );
+
+    if (list)
+    {
+        for (i = 0; i < count; i++)
+        {
+            char string[ATOM_BUFFER_SIZE];
+            if (!GlobalGetAtomNameA( list[i].atom, string, ATOM_BUFFER_SIZE )) continue;
+            if (!(ret = func( hwnd, string, list[i].handle, lParam ))) break;
+        }
+        HeapFree( GetProcessHeap(), 0, list );
+    }
+    return ret;
+}
+
+
+/***********************************************************************
+ *              EnumPropsExW   (USER32.@)
+ */
+INT WINAPI EnumPropsExW(HWND hwnd, PROPENUMPROCEXW func, LPARAM lParam)
+{
+    int ret = -1, i, count;
+    property_data_t *list = get_properties( hwnd, &count );
+
+    if (list)
+    {
+        for (i = 0; i < count; i++)
+        {
+            WCHAR string[ATOM_BUFFER_SIZE];
+            if (!GlobalGetAtomNameW( list[i].atom, string, ATOM_BUFFER_SIZE )) continue;
+            if (!(ret = func( hwnd, string, list[i].handle, lParam ))) break;
+        }
+        HeapFree( GetProcessHeap(), 0, list );
+    }
+    return ret;
+}
+
+
+/***********************************************************************
+ *              EnumProps   (USER.27)
+ */
+INT16 WINAPI EnumProps16( HWND16 hwnd, PROPENUMPROC16 func )
+{
+    int ret = -1, i, count;
+    property_data_t *list = get_properties( hwnd, &count );
+
+    if (list)
+    {
+        char *string = SEGPTR_ALLOC( ATOM_BUFFER_SIZE );
+        for (i = 0; i < count; i++)
+        {
+            if (list[i].string)  /* it was a string originally */
+            {
+                if (!GlobalGetAtomNameA( list[i].atom, string, ATOM_BUFFER_SIZE )) continue;
+                ret = func( hwnd, SEGPTR_GET(string), list[i].handle );
+            }
+            else
+                ret = func( hwnd, list[i].atom, list[i].handle );
+            if (!ret) break;
+        }
+        SEGPTR_FREE( string );
+        HeapFree( GetProcessHeap(), 0, list );
+    }
+    return ret;
+}
diff --git a/include/win.h b/include/win.h
index 5178844..f454d11 100644
--- a/include/win.h
+++ b/include/win.h
@@ -35,7 +35,6 @@
     LPWSTR        text;           /* Window text */
     void          *pVScroll;      /* Vertical scroll-bar info */
     void          *pHScroll;      /* Horizontal scroll-bar info */
-    void          *pProp;         /* Pointer to properties list */
     struct tagDCE *dce;           /* Window DCE (if CS_OWNDC or CS_CLASSDC) */
     HGLOBAL16      hmemTaskQ;     /* Task queue global memory handle */
     HRGN           hrgnUpdate;    /* Update region */
@@ -122,8 +121,6 @@
 extern BOOL16 DRAG_QueryUpdate( HWND, SEGPTR, BOOL );
 extern HBRUSH DEFWND_ControlColor( HDC hDC, UINT ctlType );  /* windows/defwnd.c */
 
-extern void PROPERTY_RemoveWindowProps( HWND hwnd );  /* windows/property.c */
-
 /* Classes functions */
 struct tagCLASS;  /* opaque structure */
 struct builtin_class_descr;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index d798532..5eeec43 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -132,6 +132,14 @@
 };
 
 
+typedef struct
+{
+    atom_t         atom;
+    short          string;
+    handle_t       handle;
+} property_data_t;
+
+
 
 
 
@@ -1644,6 +1652,46 @@
 };
 
 
+
+struct set_window_property_request
+{
+    struct request_header __header;
+    user_handle_t  window;
+    atom_t         atom;
+    int            string;
+    handle_t       handle;
+};
+
+
+
+struct remove_window_property_request
+{
+    struct request_header __header;
+    user_handle_t  window;
+    atom_t         atom;
+    handle_t       handle;
+};
+
+
+
+struct get_window_property_request
+{
+    struct request_header __header;
+    user_handle_t  window;
+    atom_t         atom;
+    handle_t       handle;
+};
+
+
+
+struct get_window_properties_request
+{
+    struct request_header __header;
+    user_handle_t  window;
+    /* VARARG(props,properties); */
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -1775,6 +1823,10 @@
     REQ_get_window_parents,
     REQ_get_window_children,
     REQ_get_window_tree,
+    REQ_set_window_property,
+    REQ_remove_window_property,
+    REQ_get_window_property,
+    REQ_get_window_properties,
     REQ_NB_REQUESTS
 };
 
@@ -1911,8 +1963,12 @@
     struct get_window_parents_request get_window_parents;
     struct get_window_children_request get_window_children;
     struct get_window_tree_request get_window_tree;
+    struct set_window_property_request set_window_property;
+    struct remove_window_property_request remove_window_property;
+    struct get_window_property_request get_window_property;
+    struct get_window_properties_request get_window_properties;
 };
 
-#define SERVER_PROTOCOL_VERSION 58
+#define SERVER_PROTOCOL_VERSION 59
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index fa0b81e..95bc13a 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -133,6 +133,14 @@
     int   signaled;  /* wait result */
 };
 
+/* structure returned in the list of window properties */
+typedef struct
+{
+    atom_t         atom;     /* property atom */
+    short          string;   /* was atom a string originally? */
+    handle_t       handle;   /* handle stored in property */
+} property_data_t;
+
 /****************************************************************/
 /* Request declarations */
 
@@ -1469,3 +1477,38 @@
     user_handle_t  first_child;   /* first child */
     user_handle_t  last_child;    /* last child */
 @END
+
+
+/* Set a window property */
+@REQ(set_window_property)
+    user_handle_t  window;        /* handle to the window */
+    atom_t         atom;          /* property atom (high-word set if it was a string) */
+    int            string;        /* was atom a string originally? */
+    handle_t       handle;        /* handle to store */
+@END
+
+
+/* Remove a window property */
+@REQ(remove_window_property)
+    user_handle_t  window;        /* handle to the window */
+    atom_t         atom;          /* property atom */
+@REPLY
+    handle_t       handle;        /* handle stored in property */
+@END
+
+
+/* Get a window property */
+@REQ(get_window_property)
+    user_handle_t  window;        /* handle to the window */
+    atom_t         atom;          /* property atom */
+@REPLY
+    handle_t       handle;        /* handle stored in property */
+@END
+
+
+/* Get the list of properties of a window */
+@REQ(get_window_properties)
+    user_handle_t  window;        /* handle to the window */
+@REPLY
+    VARARG(props,properties);     /* list of properties */
+@END
diff --git a/server/request.h b/server/request.h
index 1269e17..8939854 100644
--- a/server/request.h
+++ b/server/request.h
@@ -194,6 +194,10 @@
 DECL_HANDLER(get_window_parents);
 DECL_HANDLER(get_window_children);
 DECL_HANDLER(get_window_tree);
+DECL_HANDLER(set_window_property);
+DECL_HANDLER(remove_window_property);
+DECL_HANDLER(get_window_property);
+DECL_HANDLER(get_window_properties);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -329,6 +333,10 @@
     (req_handler)req_get_window_parents,
     (req_handler)req_get_window_children,
     (req_handler)req_get_window_tree,
+    (req_handler)req_set_window_property,
+    (req_handler)req_remove_window_property,
+    (req_handler)req_get_window_property,
+    (req_handler)req_get_window_properties,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index 094ff25..bd4de67 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -271,6 +271,23 @@
     return get_size(req);
 }
 
+static size_t dump_varargs_properties( const void *req )
+{
+    const property_data_t *prop = get_data(req);
+    size_t len = get_size(req) / sizeof(*prop);
+
+    fputc( '{', stderr );
+    while (len > 0)
+    {
+        fprintf( stderr, "{atom=%04x,str=%d,handle=%08x}",
+                 prop->atom, prop->string, prop->handle );
+        prop++;
+        if (--len) fputc( ',', stderr );
+    }
+    fputc( '}', stderr );
+    return get_size(req);
+}
+
 typedef void (*dump_func)( const void *req );
 
 /* Everything below this line is generated automatically by tools/make_requests */
@@ -1743,6 +1760,47 @@
     fprintf( stderr, " last_child=%08x", req->last_child );
 }
 
+static void dump_set_window_property_request( const struct set_window_property_request *req )
+{
+    fprintf( stderr, " window=%08x,", req->window );
+    fprintf( stderr, " atom=%04x,", req->atom );
+    fprintf( stderr, " string=%d,", req->string );
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_remove_window_property_request( const struct remove_window_property_request *req )
+{
+    fprintf( stderr, " window=%08x,", req->window );
+    fprintf( stderr, " atom=%04x", req->atom );
+}
+
+static void dump_remove_window_property_reply( const struct remove_window_property_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_get_window_property_request( const struct get_window_property_request *req )
+{
+    fprintf( stderr, " window=%08x,", req->window );
+    fprintf( stderr, " atom=%04x", req->atom );
+}
+
+static void dump_get_window_property_reply( const struct get_window_property_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_get_window_properties_request( const struct get_window_properties_request *req )
+{
+    fprintf( stderr, " window=%08x", req->window );
+}
+
+static void dump_get_window_properties_reply( const struct get_window_properties_request *req )
+{
+    fprintf( stderr, " props=" );
+    cur_pos += dump_varargs_properties( req );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -1873,6 +1931,10 @@
     (dump_func)dump_get_window_parents_request,
     (dump_func)dump_get_window_children_request,
     (dump_func)dump_get_window_tree_request,
+    (dump_func)dump_set_window_property_request,
+    (dump_func)dump_remove_window_property_request,
+    (dump_func)dump_get_window_property_request,
+    (dump_func)dump_get_window_properties_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -2005,6 +2067,10 @@
     (dump_func)dump_get_window_parents_reply,
     (dump_func)dump_get_window_children_reply,
     (dump_func)dump_get_window_tree_reply,
+    (dump_func)0,
+    (dump_func)dump_remove_window_property_reply,
+    (dump_func)dump_get_window_property_reply,
+    (dump_func)dump_get_window_properties_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -2137,6 +2203,10 @@
     "get_window_parents",
     "get_window_children",
     "get_window_tree",
+    "set_window_property",
+    "remove_window_property",
+    "get_window_property",
+    "get_window_properties",
 };
 
 /* ### make_requests end ### */
diff --git a/server/window.c b/server/window.c
index c57aadf..ff9ba82 100644
--- a/server/window.c
+++ b/server/window.c
@@ -12,6 +12,22 @@
 #include "process.h"
 #include "user.h"
 
+/* a window property */
+struct property
+{
+    unsigned short type;     /* property type (see below) */
+    atom_t         atom;     /* property atom */
+    handle_t       handle;   /* property handle (user-defined storage) */
+};
+
+enum property_type
+{
+    PROP_TYPE_FREE,   /* free entry */
+    PROP_TYPE_STRING, /* atom that was originally a string */
+    PROP_TYPE_ATOM    /* plain atom */
+};
+
+
 struct window
 {
     struct window   *parent;          /* parent window */
@@ -23,7 +39,10 @@
     struct window   *prev;            /* prev window in Z-order */
     user_handle_t    handle;          /* full handle for this window */
     struct thread   *thread;          /* thread owning the window */
-    unsigned int     atom;            /* class atom */
+    atom_t           atom;            /* class atom */
+    int              prop_inuse;      /* number of in-use window properties */
+    int              prop_alloc;      /* number of allocated window properties */
+    struct property *properties;      /* window properties array */
 };
 
 static struct window *top_window;  /* top-level (desktop) window */
@@ -83,6 +102,118 @@
     }
 }
 
+/* set a window property */
+static void set_property( struct window *win, atom_t atom, handle_t handle,
+                          enum property_type type )
+{
+    int i, free = -1;
+    struct property *new_props;
+
+    /* check if it exists already */
+    for (i = 0; i < win->prop_inuse; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE)
+        {
+            free = i;
+            continue;
+        }
+        if (win->properties[i].atom == atom)
+        {
+            win->properties[i].type = type;
+            win->properties[i].handle = handle;
+            return;
+        }
+    }
+
+    /* need to add an entry */
+    if (!grab_global_atom( atom )) return;
+    if (free == -1)
+    {
+        /* no free entry */
+        if (win->prop_inuse >= win->prop_alloc)
+        {
+            /* need to grow the array */
+            if (!(new_props = realloc( win->properties,
+                                       sizeof(*new_props) * (win->prop_alloc + 16) )))
+            {
+                set_error( STATUS_NO_MEMORY );
+                release_global_atom( atom );
+                return;
+            }
+            win->prop_alloc += 16;
+            win->properties = new_props;
+        }
+        free = win->prop_inuse++;
+    }
+    win->properties[free].atom   = atom;
+    win->properties[free].type   = type;
+    win->properties[free].handle = handle;
+}
+
+/* remove a window property */
+static handle_t remove_property( struct window *win, atom_t atom )
+{
+    int i;
+
+    for (i = 0; i < win->prop_inuse; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE) continue;
+        if (win->properties[i].atom == atom)
+        {
+            release_global_atom( atom );
+            win->properties[i].type = PROP_TYPE_FREE;
+            return win->properties[i].handle;
+        }
+    }
+    /* FIXME: last error? */
+    return 0;
+}
+
+/* find a window property */
+static handle_t get_property( struct window *win, atom_t atom )
+{
+    int i;
+
+    for (i = 0; i < win->prop_inuse; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE) continue;
+        if (win->properties[i].atom == atom) return win->properties[i].handle;
+    }
+    /* FIXME: last error? */
+    return 0;
+}
+
+/* destroy all properties of a window */
+inline static void destroy_properties( struct window *win )
+{
+    int i;
+
+    if (!win->properties) return;
+    for (i = 0; i < win->prop_inuse; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE) continue;
+        release_global_atom( win->properties[i].atom );
+    }
+    free( win->properties );
+}
+
+/* enum all properties into the data array */
+static int enum_properties( struct window *win, property_data_t *data, int max )
+{
+    int i, count;
+
+    for (i = count = 0; i < win->prop_inuse && count < max; i++)
+    {
+        if (win->properties[i].type == PROP_TYPE_FREE) continue;
+        data->atom   = win->properties[i].atom;
+        data->string = (win->properties[i].type == PROP_TYPE_STRING);
+        data->handle = win->properties[i].handle;
+        data++;
+        count++;
+    }
+    return count;
+}
+
 /* destroy a window */
 static void destroy_window( struct window *win )
 {
@@ -104,14 +235,14 @@
 
     if (win->thread->queue) queue_cleanup_window( win->thread, win->handle );
     free_user_handle( win->handle );
+    destroy_properties( win );
     unlink_window( win );
     memset( win, 0x55, sizeof(*win) );
     free( win );
 }
 
 /* create a new window structure (note: the window is not linked in the window tree) */
-static struct window *create_window( struct window *parent, struct window *owner,
-                                     unsigned int atom )
+static struct window *create_window( struct window *parent, struct window *owner, atom_t atom )
 {
     struct window *win = mem_alloc( sizeof(*win) );
     if (!win) return NULL;
@@ -128,6 +259,9 @@
     win->first_unlinked = NULL;
     win->thread         = current;
     win->atom           = atom;
+    win->prop_inuse     = 0;
+    win->prop_alloc     = 0;
+    win->properties     = NULL;
 
     if (parent)  /* put it on parent unlinked list */
     {
@@ -340,3 +474,43 @@
     req->first_child = win->first_child ? win->first_child->handle : 0;
     req->last_child  = win->last_child ? win->last_child->handle : 0;
 }
+
+
+/* set a window property */
+DECL_HANDLER(set_window_property)
+{
+    struct window *win = get_window( req->window );
+
+    if (win) set_property( win, req->atom, req->handle,
+                           req->string ? PROP_TYPE_STRING : PROP_TYPE_ATOM );
+}
+
+
+/* remove a window property */
+DECL_HANDLER(remove_window_property)
+{
+    struct window *win = get_window( req->window );
+    req->handle = 0;
+    if (win) req->handle = remove_property( win, req->atom );
+}
+
+
+/* get a window property */
+DECL_HANDLER(get_window_property)
+{
+    struct window *win = get_window( req->window );
+    req->handle = 0;
+    if (win) req->handle = get_property( win, req->atom );
+}
+
+
+/* get the list of properties of a window */
+DECL_HANDLER(get_window_properties)
+{
+    int count = 0;
+    property_data_t *data = get_req_data(req);
+    struct window *win = get_window( req->window );
+
+    if (win) count = enum_properties( win, data, get_req_data_size(req) / sizeof(*data) );
+    set_req_data_size( req, count * sizeof(*data) );
+}
diff --git a/windows/Makefile.in b/windows/Makefile.in
index a971ec6..f9ba851 100644
--- a/windows/Makefile.in
+++ b/windows/Makefile.in
@@ -26,7 +26,6 @@
 	multimon.c \
 	nonclient.c \
 	painting.c \
-	property.c \
 	queue.c \
 	rect.c \
 	scroll.c \
diff --git a/windows/property.c b/windows/property.c
deleted file mode 100644
index 4c5fce6..0000000
--- a/windows/property.c
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Window properties
- *
- * Copyright 1995, 1996 Alexandre Julliard
- */
-
-#include <string.h>
-
-#include "windef.h"
-#include "wingdi.h"
-#include "wine/winuser16.h"
-#include "win.h"
-#include "heap.h"
-#include "debugtools.h"
-
-DEFAULT_DEBUG_CHANNEL(prop);
-
-
-typedef struct tagPROPERTY
-{
-    struct tagPROPERTY *next;     /* Next property in window list */
-    HANDLE            handle;   /* User's data */
-    LPSTR               string;   /* Property string (or atom) */
-} PROPERTY;
-
-
-#define MAX_ATOM_LEN 255
-
-/***********************************************************************
- *           PROP_FindProp
- */
-static PROPERTY *PROP_FindProp( HWND hwnd, LPCSTR str )
-{
-    ATOM atom;
-    PROPERTY *prop;
-    WND *pWnd = WIN_FindWndPtr( hwnd );
-
-    if (!pWnd) return NULL;
-    if (HIWORD(str))
-    {
-        atom = GlobalFindAtomA( str );
-        for (prop = pWnd->pProp; prop; prop = prop->next)
-        {
-            if (HIWORD(prop->string))
-            {
-                if (!lstrcmpiA( prop->string, str )) goto END;
-            }
-            else if (LOWORD(prop->string) == atom) goto END;
-        }
-    }
-    else  /* atom */
-    {
-        atom = LOWORD(str);
-        for (prop = pWnd->pProp; (prop); prop = prop->next)
-        {
-            if (HIWORD(prop->string))
-            {
-                if (GlobalFindAtomA( prop->string ) == atom) goto END;
-            }
-            else if (LOWORD(prop->string) == atom) goto END;
-        }
-    }
-    prop = NULL;
-END:
-    WIN_ReleaseWndPtr(pWnd);
-    return prop;
-}
-
-
-/***********************************************************************
- *		GetPropA (USER32.@)
- */
-HANDLE WINAPI GetPropA( HWND hwnd, LPCSTR str )
-{
-    PROPERTY *prop = PROP_FindProp( hwnd, str );
-
-    if (HIWORD(str))
-        TRACE("(%08x,'%s'): returning %08x\n",
-                      hwnd, str, prop ? prop->handle : 0 );
-    else
-        TRACE("(%08x,#%04x): returning %08x\n",
-                      hwnd, LOWORD(str), prop ? prop->handle : 0 );
-
-    return prop ? prop->handle : 0;
-}
-
-
-/***********************************************************************
- *		GetPropW (USER32.@)
- */
-HANDLE WINAPI GetPropW( HWND hwnd, LPCWSTR str )
-{
-    LPSTR strA;
-    HANDLE ret;
-
-    if (!HIWORD(str)) return GetPropA( hwnd, (LPCSTR)(UINT)LOWORD(str) );
-    strA = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
-    ret = GetPropA( hwnd, strA );
-    HeapFree( GetProcessHeap(), 0, strA );
-    return ret;
-}
-
-
-/***********************************************************************
- *		SetPropA (USER32.@)
- */
-BOOL WINAPI SetPropA( HWND hwnd, LPCSTR str, HANDLE handle )
-{
-    PROPERTY *prop;
-
-    if (HIWORD(str))
-        TRACE("%04x '%s' %08x\n", hwnd, str, handle );
-    else
-        TRACE("%04x #%04x %08x\n",
-                      hwnd, LOWORD(str), handle );
-
-    if (!(prop = PROP_FindProp( hwnd, str )))
-    {
-        /* We need to create it */
-        WND *pWnd = WIN_FindWndPtr( hwnd );
-        if (!pWnd) return FALSE;
-        if (!(prop = HeapAlloc( GetProcessHeap(), 0, sizeof(*prop) )))
-        {
-            WIN_ReleaseWndPtr(pWnd);
-            return FALSE;
-        }
-        if (!(prop->string = SEGPTR_STRDUP(str)))
-        {
-            HeapFree( GetProcessHeap(), 0, prop );
-            WIN_ReleaseWndPtr(pWnd);
-            return FALSE;
-
-        }
-        prop->next  = pWnd->pProp;
-        pWnd->pProp = prop;
-        WIN_ReleaseWndPtr(pWnd);
-    }
-    prop->handle = handle;
-    return TRUE;
-}
-
-
-/***********************************************************************
- *		SetPropW (USER32.@)
- */
-BOOL WINAPI SetPropW( HWND hwnd, LPCWSTR str, HANDLE handle )
-{
-    BOOL ret;
-    LPSTR strA;
-
-    if (!HIWORD(str))
-        return SetPropA( hwnd, (LPCSTR)(UINT)LOWORD(str), handle );
-    strA = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
-    ret = SetPropA( hwnd, strA, handle );
-    HeapFree( GetProcessHeap(), 0, strA );
-    return ret;
-}
-
-
-/***********************************************************************
- *		RemovePropA (USER32.@)
- */
-HANDLE WINAPI RemovePropA( HWND hwnd, LPCSTR str )
-{
-    ATOM atom;
-    HANDLE handle;
-    PROPERTY **pprop, *prop;
-    WND *pWnd = WIN_FindWndPtr( hwnd );
-
-    if (HIWORD(str))
-      TRACE("%04x '%s'\n", hwnd, str );
-    else
-      TRACE("%04x #%04x\n", hwnd, LOWORD(str));
-
-
-    if (!pWnd) return (HANDLE)0;
-    if (HIWORD(str))
-    {
-        atom = GlobalFindAtomA( str );
-        for (pprop=(PROPERTY**)&pWnd->pProp; (*pprop); pprop = &(*pprop)->next)
-        {
-            if (HIWORD((*pprop)->string))
-            {
-                if (!lstrcmpiA( (*pprop)->string, str )) break;
-            }
-            else if (LOWORD((*pprop)->string) == atom) break;
-        }
-    }
-    else  /* atom */
-    {
-        atom = LOWORD(str);
-        for (pprop=(PROPERTY**)&pWnd->pProp; (*pprop); pprop = &(*pprop)->next)
-        {
-            if (HIWORD((*pprop)->string))
-            {
-                if (GlobalFindAtomA( (*pprop)->string ) == atom) break;
-            }
-            else if (LOWORD((*pprop)->string) == atom) break;
-        }
-    }
-    WIN_ReleaseWndPtr(pWnd);
-    if (!*pprop) return 0;
-    prop   = *pprop;
-    handle = prop->handle;
-    *pprop = prop->next;
-    SEGPTR_FREE(prop->string);
-    HeapFree( GetProcessHeap(), 0, prop );
-    return handle;
-}
-
-
-/***********************************************************************
- *		RemovePropW (USER32.@)
- */
-HANDLE WINAPI RemovePropW( HWND hwnd, LPCWSTR str )
-{
-    LPSTR strA;
-    HANDLE ret;
-
-    if (!HIWORD(str))
-        return RemovePropA( hwnd, (LPCSTR)(UINT)LOWORD(str) );
-    strA = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
-    ret = RemovePropA( hwnd, strA );
-    HeapFree( GetProcessHeap(), 0, strA );
-    return ret;
-}
-
-
-/***********************************************************************
- *           PROPERTY_RemoveWindowProps
- *
- * Remove all properties of a window.
- */
-void PROPERTY_RemoveWindowProps( HWND hwnd )
-{
-    PROPERTY *prop, *next;
-    WND *pWnd = WIN_FindWndPtr( hwnd );
-
-    if (!pWnd) return;
-    for (prop = pWnd->pProp; (prop); prop = next)
-    {
-        next = prop->next;
-        SEGPTR_FREE( prop->string );
-        HeapFree( GetProcessHeap(), 0, prop );
-    }
-    pWnd->pProp = NULL;
-    WIN_ReleaseWndPtr( pWnd );
-}
-
-
-/***********************************************************************
- *		EnumProps (USER.27)
- */
-INT16 WINAPI EnumProps16( HWND16 hwnd, PROPENUMPROC16 func )
-{
-    PROPERTY *prop, *next;
-    WND *pWnd;
-    INT16 ret = -1;
-
-    TRACE("%04x %08x\n", hwnd, (UINT)func );
-    if (!(pWnd = WIN_FindWndPtr16( hwnd ))) return -1;
-    for (prop = pWnd->pProp; (prop); prop = next)
-    {
-        /* Already get the next in case the callback */
-        /* function removes the current property.    */
-        next = prop->next;
-
-        /* SDK docu seems to suggest that EnumProps16 does not retrieve
-	 * the string in case of an atom handle, in contrast to Win32 */
-
-        TRACE("  Callback: handle=%08x str=%s\n",
-              prop->handle, debugstr_a(prop->string) );
-        ret = func( hwnd, SEGPTR_GET(prop->string), prop->handle );
-        if (!ret) break;
-    }
-    WIN_ReleaseWndPtr(pWnd);
-    return ret;
-}
-
-
-/* relay to call the EnumProps callback function from EnumPropsEx */
-static BOOL CALLBACK EnumPropsA_relay( HWND hwnd, LPCSTR str, HANDLE handle, ULONG_PTR lparam )
-{
-    PROPENUMPROCA func = (PROPENUMPROCA)lparam;
-    return func( hwnd, str, handle );
-}
-
-
-/***********************************************************************
- *		EnumPropsA (USER32.@)
- */
-INT WINAPI EnumPropsA( HWND hwnd, PROPENUMPROCA func )
-{
-    return EnumPropsExA( hwnd, EnumPropsA_relay, (LPARAM)func );
-}
-
-
-/***********************************************************************
- *		EnumPropsExA (USER32.@)
- */
-INT WINAPI EnumPropsExA(HWND hwnd, PROPENUMPROCEXA func, LPARAM lParam)
-{
-    PROPERTY *prop, *next;
-    WND *pWnd;
-    INT ret = -1;
-    char atomStr[MAX_ATOM_LEN+1];
-    char *pStr;
-
-    TRACE("%04x %p %08lx\n", hwnd, func, lParam);
-    if (!(pWnd = WIN_FindWndPtr( hwnd ))) return -1;
-    for (prop = pWnd->pProp; (prop); prop = next)
-    {
-        /* Already get the next in case the callback */
-        /* function removes the current property.    */
-        next = prop->next;
-
-        if (!HIWORD(prop->string))
-        { /* get "real" string the atom points to.
-	   * This seems to be done for Win32 only */
-            if (!(GlobalGetAtomNameA((ATOM)LOWORD(prop->string), atomStr, MAX_ATOM_LEN+1)))
-            {
-                ERR("huh ? Atom %04x not an atom ??\n", LOWORD(prop->string));
-                atomStr[0] = '\0';
-            }
-            pStr = atomStr;
-        }
-        else
-            pStr = prop->string;
-
-        TRACE("  Callback: handle=%08x str='%s'\n",
-            prop->handle, prop->string );
-
-        ret = func( hwnd, pStr, prop->handle, lParam );
-        if (!ret) break;
-    }
-    WIN_ReleaseWndPtr(pWnd);
-    return ret;
-}
-
-
-/* relay to call the EnumProps callback function from EnumPropsEx */
-static BOOL CALLBACK EnumPropsW_relay( HWND hwnd, LPCWSTR str, HANDLE handle, ULONG_PTR lparam )
-{
-    PROPENUMPROCW func = (PROPENUMPROCW)lparam;
-    return func( hwnd, str, handle );
-}
-
-/***********************************************************************
- *		EnumPropsW (USER32.@)
- */
-INT WINAPI EnumPropsW( HWND hwnd, PROPENUMPROCW func )
-{
-    return EnumPropsExW( hwnd, EnumPropsW_relay, (LPARAM)func );
-}
-
-/***********************************************************************
- *		EnumPropsExW (USER32.@)
- */
-INT WINAPI EnumPropsExW(HWND hwnd, PROPENUMPROCEXW func, LPARAM lParam)
-{
-    PROPERTY *prop, *next;
-    WND *pWnd;
-    INT ret = -1;
-    char atomStr[MAX_ATOM_LEN+1];
-    char *pStr;
-    LPWSTR strW;
-
-    TRACE("%04x %p %08lx\n", hwnd, func, lParam);
-    if (!(pWnd = WIN_FindWndPtr( hwnd ))) return -1;
-    for (prop = pWnd->pProp; (prop); prop = next)
-    {
-        /* Already get the next in case the callback */
-        /* function removes the current property.    */
-        next = prop->next;
-
-        if (!HIWORD(prop->string))
-        { /* get "real" string the atom points to.
-	   * This seems to be done for Win32 only */
-            if (!(GlobalGetAtomNameA((ATOM)LOWORD(prop->string), atomStr, MAX_ATOM_LEN+1)))
-            {
-                ERR("huh ? Atom %04x not an atom ??\n",
-                    (ATOM)LOWORD(prop->string));
-                atomStr[0] = '\0';
-            }
-            pStr = atomStr;
-        }
-        else
-            pStr = prop->string;
-
-        TRACE("  Callback: handle=%08x str='%s'\n",
-            prop->handle, prop->string );
-
-        strW = HEAP_strdupAtoW( GetProcessHeap(), 0, pStr );
-
-        ret = func( hwnd, strW, prop->handle, lParam );
-        HeapFree( GetProcessHeap(), 0, strW );
-        if (!ret) break;
-    }
-    WIN_ReleaseWndPtr(pWnd);
-    return ret;
-}
diff --git a/windows/win.c b/windows/win.c
index 5b37ec7..c35e7c0 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -549,7 +549,6 @@
     /* free resources associated with the window */
 
     TIMER_RemoveWindowTimers( hwnd );
-    PROPERTY_RemoveWindowProps( hwnd );
 
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return;
     wndPtr->hmemTaskQ = 0;
@@ -646,7 +645,6 @@
     pWndDesktop->dce               = NULL;
     pWndDesktop->pVScroll          = NULL;
     pWndDesktop->pHScroll          = NULL;
-    pWndDesktop->pProp             = NULL;
     pWndDesktop->wIDmenu           = 0;
     pWndDesktop->helpContext       = 0;
     pWndDesktop->flags             = 0;
@@ -859,7 +857,6 @@
     wndPtr->flags          = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
     wndPtr->pVScroll       = NULL;
     wndPtr->pHScroll       = NULL;
-    wndPtr->pProp          = NULL;
     wndPtr->userdata       = 0;
     wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU)
 			     ? MENU_GetSysMenu( hwnd, 0 ) : 0;