diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index e4ea1c9d567259de3f26aeeb3fd7bf9b745a70cd..d86a7a03a462e22ef1b5c7e21d03f409dfe2da1d 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -1669,8 +1669,24 @@ LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
  */
 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
 {
-    FIXME("(%p,%s): stub\n",hkey, debugstr_w(lpSubKey));
-    return ERROR_SUCCESS;
+    DWORD ret;
+    HKEY shkey;
+
+    TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
+
+    ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
+    if( ret )
+        return ERROR_INVALID_PARAMETER;
+
+    SERVER_START_REQ( unload_registry )
+    {
+        req->hkey  = shkey;
+        ret = RtlNtStatusToDosError( wine_server_call(req) );
+    }
+    SERVER_END_REQ;
+    RegCloseKey(shkey);
+
+    return ret;
 }
 
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index b5645734dbd331e2e76794bf08c1e8dffaf37f26..7882662d7a05a527239e5c4ecfdca377928570e7 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1918,6 +1918,18 @@ struct load_registry_reply
 
 
 
+struct unload_registry_request
+{
+    struct request_header __header;
+    obj_handle_t hkey;
+};
+struct unload_registry_reply
+{
+    struct reply_header __header;
+};
+
+
+
 struct save_registry_request
 {
     struct request_header __header;
@@ -3204,6 +3216,7 @@ enum request
     REQ_enum_key_value,
     REQ_delete_key_value,
     REQ_load_registry,
+    REQ_unload_registry,
     REQ_save_registry,
     REQ_save_registry_atexit,
     REQ_set_registry_levels,
@@ -3388,6 +3401,7 @@ union generic_request
     struct enum_key_value_request enum_key_value_request;
     struct delete_key_value_request delete_key_value_request;
     struct load_registry_request load_registry_request;
+    struct unload_registry_request unload_registry_request;
     struct save_registry_request save_registry_request;
     struct save_registry_atexit_request save_registry_atexit_request;
     struct set_registry_levels_request set_registry_levels_request;
@@ -3570,6 +3584,7 @@ union generic_reply
     struct enum_key_value_reply enum_key_value_reply;
     struct delete_key_value_reply delete_key_value_reply;
     struct load_registry_reply load_registry_reply;
+    struct unload_registry_reply unload_registry_reply;
     struct save_registry_reply save_registry_reply;
     struct save_registry_atexit_reply save_registry_atexit_reply;
     struct set_registry_levels_reply set_registry_levels_reply;
@@ -3646,6 +3661,6 @@ union generic_reply
     struct open_token_reply open_token_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 119
+#define SERVER_PROTOCOL_VERSION 120
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index 4cc823d3e77244d420db946d417649918050bcc5..20b87db5d5b9d56a6ed1dcafe439a485f7aea645 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1386,6 +1386,12 @@ enum char_info_mode
 @END
 
 
+/* UnLoad a registry branch from a file */
+@REQ(unload_registry)
+    obj_handle_t hkey;         /* root key to unload to */
+@END
+
+
 /* Save a registry branch to a file */
 @REQ(save_registry)
     obj_handle_t hkey;         /* key to save */
diff --git a/server/registry.c b/server/registry.c
index c2f69b01e82049a0e685e9d20f814985a04118ad..cf5e7fb9676411d37a2d904a42dd6aa1c5823799 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -770,7 +770,7 @@ static void enum_key( const struct key *key, int index, int info_class,
 }
 
 /* delete a key and its values */
-static void delete_key( struct key *key )
+static int delete_key( struct key *key, int recurse )
 {
     int index;
     struct key *parent;
@@ -779,13 +779,18 @@ static void delete_key( struct key *key )
     if (key->flags & KEY_ROOT)
     {
         set_error( STATUS_ACCESS_DENIED );
-        return;
+        return -1;
     }
     if (!(parent = key->parent) || (key->flags & KEY_DELETED))
     {
         set_error( STATUS_KEY_DELETED );
-        return;
+        return -1;
     }
+
+    while (recurse && (key->last_subkey>=0))
+        if(0>delete_key(key->subkeys[key->last_subkey], 1))
+            return -1;
+
     for (index = 0; index <= parent->last_subkey; index++)
         if (parent->subkeys[index] == key) break;
     assert( index <= parent->last_subkey );
@@ -794,11 +799,13 @@ static void delete_key( struct key *key )
     if ((key->flags & KEY_ROOT) || (key->last_subkey >= 0))
     {
         set_error( STATUS_ACCESS_DENIED );
-        return;
+        return -1;
     }
+
     if (debug_level > 1) dump_operation( key, NULL, "Delete" );
     free_subkey( parent, index );
     touch_key( parent, REG_NOTIFY_CHANGE_NAME );
+    return 0;
 }
 
 /* try to grow the array of values; return 1 if OK, 0 on error */
@@ -1764,7 +1771,7 @@ DECL_HANDLER(delete_key)
 
     if ((key = get_hkey_obj( req->hkey, 0 /*FIXME*/ )))
     {
-        delete_key( key );
+        delete_key( key, 0);
         release_object( key );
     }
 }
@@ -1856,6 +1863,17 @@ DECL_HANDLER(load_registry)
     }
 }
 
+DECL_HANDLER(unload_registry)
+{
+    struct key *key;
+
+    if ((key = get_hkey_obj( req->hkey, 0 )))
+    {
+        delete_key( key, 1 );     /* FIXME */
+        release_object( key );
+    }
+}
+
 /* save a registry branch to a file */
 DECL_HANDLER(save_registry)
 {
diff --git a/server/request.h b/server/request.h
index a25dc507272a286f0a88ffdc05f0ce8abe1d8dc4..8f9f9d6a5eb9d2b0c88069d3f8ec17b9035c6f70 100644
--- a/server/request.h
+++ b/server/request.h
@@ -206,6 +206,7 @@ DECL_HANDLER(get_key_value);
 DECL_HANDLER(enum_key_value);
 DECL_HANDLER(delete_key_value);
 DECL_HANDLER(load_registry);
+DECL_HANDLER(unload_registry);
 DECL_HANDLER(save_registry);
 DECL_HANDLER(save_registry_atexit);
 DECL_HANDLER(set_registry_levels);
@@ -389,6 +390,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_enum_key_value,
     (req_handler)req_delete_key_value,
     (req_handler)req_load_registry,
+    (req_handler)req_unload_registry,
     (req_handler)req_save_registry,
     (req_handler)req_save_registry_atexit,
     (req_handler)req_set_registry_levels,
diff --git a/server/trace.c b/server/trace.c
index 3dd62ca4cf60d4e081a1ff50529bfed10ad45b7a..8ba7d3aa48184aa9b919c464ece7180d0fc1a93d 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1624,6 +1624,11 @@ static void dump_load_registry_request( const struct load_registry_request *req
     dump_varargs_unicode_str( cur_size );
 }
 
+static void dump_unload_registry_request( const struct unload_registry_request *req )
+{
+    fprintf( stderr, " hkey=%p", req->hkey );
+}
+
 static void dump_save_registry_request( const struct save_registry_request *req )
 {
     fprintf( stderr, " hkey=%p,", req->hkey );
@@ -2601,6 +2606,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_enum_key_value_request,
     (dump_func)dump_delete_key_value_request,
     (dump_func)dump_load_registry_request,
+    (dump_func)dump_unload_registry_request,
     (dump_func)dump_save_registry_request,
     (dump_func)dump_save_registry_atexit_request,
     (dump_func)dump_set_registry_levels_request,
@@ -2785,6 +2791,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)0,
     (dump_func)0,
     (dump_func)0,
+    (dump_func)0,
     (dump_func)dump_create_timer_reply,
     (dump_func)dump_open_timer_reply,
     (dump_func)dump_set_timer_reply,
@@ -2961,6 +2968,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "enum_key_value",
     "delete_key_value",
     "load_registry",
+    "unload_registry",
     "save_registry",
     "save_registry_atexit",
     "set_registry_levels",