wininet: Added Esperanto language.
[wine] / dlls / shell32 / regsvr.c
1 /*
2  *      self-registerable dll functions for shell32.dll
3 *
4  * Copyright (C) 2003 John K. Hohm
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <string.h>
23 #include <stdio.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "winerror.h"
30
31 #include "ole2.h"
32 #include "shlguid.h"
33 #include "shell32_main.h"
34 #include "shfldr.h"
35 #include "shresdef.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40
41 /*
42  * Near the bottom of this file are the exported DllRegisterServer and
43  * DllUnregisterServer, which make all this worthwhile.
44  */
45
46 /***********************************************************************
47  *              interface for self-registering
48  */
49 struct regsvr_interface
50 {
51     IID const *iid;             /* NULL for end of list */
52     LPCSTR name;                /* can be NULL to omit */
53     IID const *base_iid;        /* can be NULL to omit */
54     int num_methods;            /* can be <0 to omit */
55     CLSID const *ps_clsid;      /* can be NULL to omit */
56     CLSID const *ps_clsid32;    /* can be NULL to omit */
57 };
58
59 static HRESULT register_interfaces(struct regsvr_interface const *list);
60 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
61
62 struct regsvr_coclass
63 {
64     CLSID const *clsid;         /* NULL for end of list */
65     LPCSTR name;                /* can be NULL to omit */
66     UINT idName;                /* can be 0 to omit */
67     LPCSTR ips;                 /* can be NULL to omit */
68     LPCSTR ips32;               /* can be NULL to omit */
69     LPCSTR ips32_tmodel;        /* can be NULL to omit */
70     DWORD flags;
71     DWORD dwAttributes;
72     DWORD dwCallForAttributes;
73     LPCSTR clsid_str;           /* can be NULL to omit */
74     LPCSTR progid;              /* can be NULL to omit */
75 };
76
77 /* flags for regsvr_coclass.flags */
78 #define SHELLEX_MAYCHANGEDEFAULTMENU  0x00000001
79 #define SHELLFOLDER_WANTSFORPARSING   0x00000002
80 #define SHELLFOLDER_ATTRIBUTES        0x00000004
81 #define SHELLFOLDER_CALLFORATTRIBUTES 0x00000008
82
83 static HRESULT register_coclasses(struct regsvr_coclass const *list);
84 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
85
86 struct regsvr_namespace
87 {
88     CLSID const *clsid; /* CLSID of the namespace extension. NULL for end of list */
89     LPCWSTR parent;     /* Mount point (MyComputer, Desktop, ..). */
90     LPCWSTR value;      /* Display name of the extension. */
91 };
92
93 static HRESULT register_namespace_extensions(struct regsvr_namespace const *list);
94 static HRESULT unregister_namespace_extensions(struct regsvr_namespace const *list);
95
96 /***********************************************************************
97  *              static string constants
98  */
99 static WCHAR const interface_keyname[10] = {
100     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
101 static WCHAR const base_ifa_keyname[14] = {
102     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
103     'e', 0 };
104 static WCHAR const num_methods_keyname[11] = {
105     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
106 static WCHAR const ps_clsid_keyname[15] = {
107     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
108     'i', 'd', 0 };
109 static WCHAR const ps_clsid32_keyname[17] = {
110     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
111     'i', 'd', '3', '2', 0 };
112 static WCHAR const clsid_keyname[6] = {
113     'C', 'L', 'S', 'I', 'D', 0 };
114 static WCHAR const ips_keyname[13] = {
115     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
116     0 };
117 static WCHAR const ips32_keyname[15] = {
118     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
119     '3', '2', 0 };
120 static WCHAR const progid_keyname[7] = {
121     'P', 'r', 'o', 'g', 'I', 'D', 0 };
122 static WCHAR const shellex_keyname[8] = {
123     's', 'h', 'e', 'l', 'l', 'e', 'x', 0 };
124 static WCHAR const shellfolder_keyname[12] = {
125     'S', 'h', 'e', 'l', 'l', 'F', 'o', 'l', 'd', 'e', 'r', 0 };
126 static WCHAR const mcdm_keyname[21] = {
127     'M', 'a', 'y', 'C', 'h', 'a', 'n', 'g', 'e', 'D', 'e', 'f',
128     'a', 'u', 'l', 't', 'M', 'e', 'n', 'u', 0 };
129 static char const tmodel_valuename[] = "ThreadingModel";
130 static char const wfparsing_valuename[] = "WantsFORPARSING";
131 static char const attributes_valuename[] = "Attributes";
132 static char const cfattributes_valuename[] = "CallForAttributes";
133 static char const localized_valuename[] = "LocalizedString";
134
135 /***********************************************************************
136  *              static helper functions
137  */
138 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
139 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
140                                    WCHAR const *value);
141 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
142                                    char const *value);
143 static LONG recursive_delete_key(HKEY key);
144 static LONG recursive_delete_keyA(HKEY base, char const *name);
145 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
146
147 /***********************************************************************
148  *              register_interfaces
149  */
150 static HRESULT register_interfaces(struct regsvr_interface const *list)
151 {
152     LONG res = ERROR_SUCCESS;
153     HKEY interface_key;
154
155     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
156                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
157     if (res != ERROR_SUCCESS) goto error_return;
158
159     for (; res == ERROR_SUCCESS && list->iid; ++list) {
160         WCHAR buf[39];
161         HKEY iid_key;
162
163         StringFromGUID2(list->iid, buf, 39);
164         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
165                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
166         if (res != ERROR_SUCCESS) goto error_close_interface_key;
167
168         if (list->name) {
169             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
170                                  (CONST BYTE*)(list->name),
171                                  strlen(list->name) + 1);
172             if (res != ERROR_SUCCESS) goto error_close_iid_key;
173         }
174
175         if (list->base_iid) {
176             register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
177             if (res != ERROR_SUCCESS) goto error_close_iid_key;
178         }
179
180         if (0 <= list->num_methods) {
181             static WCHAR const fmt[3] = { '%', 'd', 0 };
182             HKEY key;
183
184             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
185                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
186             if (res != ERROR_SUCCESS) goto error_close_iid_key;
187
188             wsprintfW(buf, fmt, list->num_methods);
189             res = RegSetValueExW(key, NULL, 0, REG_SZ,
190                                  (CONST BYTE*)buf,
191                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
192             RegCloseKey(key);
193
194             if (res != ERROR_SUCCESS) goto error_close_iid_key;
195         }
196
197         if (list->ps_clsid) {
198             register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
199             if (res != ERROR_SUCCESS) goto error_close_iid_key;
200         }
201
202         if (list->ps_clsid32) {
203             register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
204             if (res != ERROR_SUCCESS) goto error_close_iid_key;
205         }
206
207     error_close_iid_key:
208         RegCloseKey(iid_key);
209     }
210
211 error_close_interface_key:
212     RegCloseKey(interface_key);
213 error_return:
214     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
215 }
216
217 /***********************************************************************
218  *              unregister_interfaces
219  */
220 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
221 {
222     LONG res = ERROR_SUCCESS;
223     HKEY interface_key;
224
225     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
226                         KEY_READ | KEY_WRITE, &interface_key);
227     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
228     if (res != ERROR_SUCCESS) goto error_return;
229
230     for (; res == ERROR_SUCCESS && list->iid; ++list) {
231         WCHAR buf[39];
232
233         StringFromGUID2(list->iid, buf, 39);
234         res = recursive_delete_keyW(interface_key, buf);
235     }
236
237     RegCloseKey(interface_key);
238 error_return:
239     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
240 }
241
242 /***********************************************************************
243  *              register_coclasses
244  */
245 static HRESULT register_coclasses(struct regsvr_coclass const *list)
246 {
247     LONG res = ERROR_SUCCESS;
248     HKEY coclass_key;
249
250     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
251                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
252     if (res != ERROR_SUCCESS) goto error_return;
253
254     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
255         WCHAR buf[39];
256         HKEY clsid_key;
257
258         StringFromGUID2(list->clsid, buf, 39);
259         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
260                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
261         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
262
263         if (list->name) {
264             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
265                                  (CONST BYTE*)(list->name),
266                                  strlen(list->name) + 1);
267             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
268         }
269
270         if (list->idName) {
271             char buffer[64] = "@%SYSTEMROOT%\\system32\\shell32.dll,-";
272             sprintf(buffer+strlen(buffer), "%u", list->idName);
273             res = RegSetValueExA(clsid_key, localized_valuename, 0, REG_EXPAND_SZ,
274                                  (CONST BYTE*)(buffer), strlen(buffer)+1);
275             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
276         }
277
278         if (list->ips) {
279             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
280             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
281         }
282
283         if (list->ips32) {
284             HKEY ips32_key;
285
286             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
287                                   KEY_READ | KEY_WRITE, NULL,
288                                   &ips32_key, NULL);
289             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
290
291             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
292                                  (CONST BYTE*)list->ips32,
293                                  lstrlenA(list->ips32) + 1);
294             if (res == ERROR_SUCCESS && list->ips32_tmodel)
295                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
296                                      (CONST BYTE*)list->ips32_tmodel,
297                                      strlen(list->ips32_tmodel) + 1);
298             RegCloseKey(ips32_key);
299             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
300         }
301
302         if (list->flags & SHELLEX_MAYCHANGEDEFAULTMENU) {
303             HKEY shellex_key, mcdm_key;
304
305             res = RegCreateKeyExW(clsid_key, shellex_keyname, 0, NULL, 0,
306                                   KEY_READ | KEY_WRITE, NULL,
307                                   &shellex_key, NULL);
308             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
309             res = RegCreateKeyExW(shellex_key, mcdm_keyname, 0, NULL, 0,
310                                   KEY_READ | KEY_WRITE, NULL,
311                                   &mcdm_key, NULL);
312             RegCloseKey(shellex_key);
313             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
314             RegCloseKey(mcdm_key);
315         }
316
317         if (list->flags & 
318                 (SHELLFOLDER_WANTSFORPARSING|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES))
319         {
320             HKEY shellfolder_key;
321
322             res = RegCreateKeyExW(clsid_key, shellfolder_keyname, 0, NULL, 0,
323                                   KEY_READ | KEY_WRITE, NULL,
324                                   &shellfolder_key, NULL);
325             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
326             if (list->flags & SHELLFOLDER_WANTSFORPARSING)
327                 res = RegSetValueExA(shellfolder_key, wfparsing_valuename, 0, REG_SZ, (LPBYTE)"", 1);
328             if (list->flags & SHELLFOLDER_ATTRIBUTES) 
329                 res = RegSetValueExA(shellfolder_key, attributes_valuename, 0, REG_DWORD, 
330                                      (LPBYTE)&list->dwAttributes, sizeof(DWORD));
331             if (list->flags & SHELLFOLDER_CALLFORATTRIBUTES) 
332                 res = RegSetValueExA(shellfolder_key, cfattributes_valuename, 0, REG_DWORD,
333                                      (LPBYTE)&list->dwCallForAttributes, sizeof(DWORD));
334             RegCloseKey(shellfolder_key);
335             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
336         }
337
338         if (list->clsid_str) {
339             res = register_key_defvalueA(clsid_key, clsid_keyname,
340                                          list->clsid_str);
341             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
342         }
343
344         if (list->progid) {
345             HKEY progid_key;
346
347             res = register_key_defvalueA(clsid_key, progid_keyname,
348                                          list->progid);
349             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
350
351             res = RegCreateKeyExA(HKEY_CLASSES_ROOT, list->progid, 0,
352                                   NULL, 0, KEY_READ | KEY_WRITE, NULL,
353                                   &progid_key, NULL);
354             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
355
356             res = register_key_defvalueW(progid_key, clsid_keyname, buf);
357             RegCloseKey(progid_key);
358             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
359         }
360
361     error_close_clsid_key:
362         RegCloseKey(clsid_key);
363     }
364
365 error_close_coclass_key:
366     RegCloseKey(coclass_key);
367 error_return:
368     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
369 }
370
371 /***********************************************************************
372  *              unregister_coclasses
373  */
374 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
375 {
376     LONG res = ERROR_SUCCESS;
377     HKEY coclass_key;
378
379     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
380                         KEY_READ | KEY_WRITE, &coclass_key);
381     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
382     if (res != ERROR_SUCCESS) goto error_return;
383
384     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
385         WCHAR buf[39];
386
387         StringFromGUID2(list->clsid, buf, 39);
388         res = recursive_delete_keyW(coclass_key, buf);
389         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
390
391         if (list->progid) {
392             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
393             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
394         }
395     }
396
397 error_close_coclass_key:
398     RegCloseKey(coclass_key);
399 error_return:
400     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
401 }
402
403 /**********************************************************************
404  * register_namespace_extensions
405  */
406 static WCHAR *get_namespace_key(struct regsvr_namespace const *list) {
407     static const WCHAR wszExplorerKey[] = {
408         'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
409         'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
410         'E','x','p','l','o','r','e','r','\\',0 };
411     static const WCHAR wszNamespace[] = { '\\','N','a','m','e','s','p','a','c','e','\\',0 };
412     WCHAR *pwszKey, *pwszCLSID;
413
414     pwszKey = HeapAlloc(GetProcessHeap(), 0, sizeof(wszExplorerKey)+sizeof(wszNamespace)+
415                                              sizeof(WCHAR)*(lstrlenW(list->parent)+CHARS_IN_GUID));
416     if (!pwszKey)
417         return NULL;
418
419     lstrcpyW(pwszKey, wszExplorerKey);
420     lstrcatW(pwszKey, list->parent);
421     lstrcatW(pwszKey, wszNamespace);
422     if (FAILED(StringFromCLSID(list->clsid, &pwszCLSID))) {
423         HeapFree(GetProcessHeap(), 0, pwszKey);
424         return NULL;
425     }
426     lstrcatW(pwszKey, pwszCLSID);
427     CoTaskMemFree(pwszCLSID);
428
429     return pwszKey;
430 }
431
432 static HRESULT register_namespace_extensions(struct regsvr_namespace const *list) {
433     WCHAR *pwszKey;
434     HKEY hKey;
435     
436     for (; list->clsid; list++) {
437         pwszKey = get_namespace_key(list);
438             
439         /* Create the key and set the value. */
440         if (pwszKey && ERROR_SUCCESS == 
441             RegCreateKeyExW(HKEY_LOCAL_MACHINE, pwszKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL)) 
442         {
443             RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)list->value, sizeof(WCHAR)*(lstrlenW(list->value)+1));
444             RegCloseKey(hKey);
445         }
446
447         HeapFree(GetProcessHeap(), 0, pwszKey);
448     }
449     return S_OK;
450 }
451
452 static HRESULT unregister_namespace_extensions(struct regsvr_namespace const *list) {
453     WCHAR *pwszKey;
454     
455     for (; list->clsid; list++) {
456         pwszKey = get_namespace_key(list);
457         RegDeleteKeyW(HKEY_LOCAL_MACHINE, pwszKey);
458         HeapFree(GetProcessHeap(), 0, pwszKey);
459     }
460     return S_OK;
461 }
462
463 /***********************************************************************
464  *              regsvr_key_guid
465  */
466 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
467 {
468     WCHAR buf[39];
469
470     StringFromGUID2(guid, buf, 39);
471     return register_key_defvalueW(base, name, buf);
472 }
473
474 /***********************************************************************
475  *              regsvr_key_defvalueW
476  */
477 static LONG register_key_defvalueW(
478     HKEY base,
479     WCHAR const *name,
480     WCHAR const *value)
481 {
482     LONG res;
483     HKEY key;
484
485     res = RegCreateKeyExW(base, name, 0, NULL, 0,
486                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
487     if (res != ERROR_SUCCESS) return res;
488     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
489                          (lstrlenW(value) + 1) * sizeof(WCHAR));
490     RegCloseKey(key);
491     return res;
492 }
493
494 /***********************************************************************
495  *              regsvr_key_defvalueA
496  */
497 static LONG register_key_defvalueA(
498     HKEY base,
499     WCHAR const *name,
500     char const *value)
501 {
502     LONG res;
503     HKEY key;
504
505     res = RegCreateKeyExW(base, name, 0, NULL, 0,
506                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
507     if (res != ERROR_SUCCESS) return res;
508     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
509                          lstrlenA(value) + 1);
510     RegCloseKey(key);
511     return res;
512 }
513
514 /***********************************************************************
515  *              recursive_delete_key
516  */
517 static LONG recursive_delete_key(HKEY key)
518 {
519     LONG res;
520     WCHAR subkey_name[MAX_PATH];
521     DWORD cName;
522     HKEY subkey;
523
524     for (;;) {
525         cName = sizeof(subkey_name) / sizeof(WCHAR);
526         res = RegEnumKeyExW(key, 0, subkey_name, &cName,
527                             NULL, NULL, NULL, NULL);
528         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
529             res = ERROR_SUCCESS; /* presumably we're done enumerating */
530             break;
531         }
532         res = RegOpenKeyExW(key, subkey_name, 0,
533                             KEY_READ | KEY_WRITE, &subkey);
534         if (res == ERROR_FILE_NOT_FOUND) continue;
535         if (res != ERROR_SUCCESS) break;
536
537         res = recursive_delete_key(subkey);
538         RegCloseKey(subkey);
539         if (res != ERROR_SUCCESS) break;
540     }
541
542     if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
543     return res;
544 }
545
546 /***********************************************************************
547  *              recursive_delete_keyA
548  */
549 static LONG recursive_delete_keyA(HKEY base, char const *name)
550 {
551     LONG res;
552     HKEY key;
553
554     res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
555     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
556     if (res != ERROR_SUCCESS) return res;
557     res = recursive_delete_key(key);
558     RegCloseKey(key);
559     return res;
560 }
561
562 /***********************************************************************
563  *              recursive_delete_keyW
564  */
565 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
566 {
567     LONG res;
568     HKEY key;
569
570     res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
571     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
572     if (res != ERROR_SUCCESS) return res;
573     res = recursive_delete_key(key);
574     RegCloseKey(key);
575     return res;
576 }
577
578 /***********************************************************************
579  *              coclass list
580  */
581 static GUID const CLSID_Desktop = {
582     0x00021400, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
583
584 static GUID const CLSID_Shortcut = {
585     0x00021401, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
586
587 static struct regsvr_coclass const coclass_list[] = {
588     {   &CLSID_Desktop,
589         "Desktop",
590         IDS_DESKTOP,
591         NULL,
592         "shell32.dll",
593         "Apartment"
594     },
595     {   &CLSID_DragDropHelper,
596         "Shell Drag and Drop Helper",
597         0,
598         NULL,
599         "shell32.dll",
600         "Apartment"
601     },
602     {   &CLSID_MyComputer,
603         "My Computer",
604         IDS_MYCOMPUTER,
605         NULL,
606         "shell32.dll",
607         "Apartment"
608     },
609     {   &CLSID_Shortcut,
610         "Shortcut",
611         0,
612         NULL,
613         "shell32.dll",
614         "Apartment",
615         SHELLEX_MAYCHANGEDEFAULTMENU
616     },
617     {   &CLSID_AutoComplete,
618         "AutoComplete",
619         0,
620         NULL,
621         "shell32.dll",
622         "Apartment",
623     },
624     {   &CLSID_UnixFolder,
625         "/",
626         0,
627         NULL,
628         "shell32.dll",
629         "Apartment",
630         SHELLFOLDER_WANTSFORPARSING
631     },
632     {   &CLSID_UnixDosFolder,
633         "/",
634         0,
635         NULL,
636         "shell32.dll",
637         "Apartment",
638         SHELLFOLDER_WANTSFORPARSING|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES,
639         SFGAO_FILESYSANCESTOR|SFGAO_FOLDER|SFGAO_HASSUBFOLDER,
640         SFGAO_FILESYSTEM
641     },
642     {   &CLSID_FolderShortcut,
643         "Foldershortcut",
644         0,
645         NULL,
646         "shell32.dll",
647         "Apartment",
648         SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES,
649         SFGAO_FILESYSTEM|SFGAO_FOLDER|SFGAO_LINK,
650         SFGAO_HASSUBFOLDER|SFGAO_FILESYSTEM|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR
651     },
652     {   &CLSID_MyDocuments,
653         "My Documents",
654         IDS_PERSONAL,
655         NULL,
656         "shell32.dll",
657         "Apartment",
658         SHELLFOLDER_WANTSFORPARSING|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES,
659         SFGAO_FILESYSANCESTOR|SFGAO_FOLDER|SFGAO_HASSUBFOLDER,
660         SFGAO_FILESYSTEM
661     },
662     { NULL }                    /* list terminator */
663 };
664
665 /***********************************************************************
666  *              interface list
667  */
668
669 static struct regsvr_interface const interface_list[] = {
670     { NULL }                    /* list terminator */
671 };
672
673 /***********************************************************************
674  *              namespace extensions list
675  */
676 static const WCHAR wszDesktop[] = { 'D','e','s','k','t','o','p',0 };
677 static const WCHAR wszSlash[] = { '/', 0 };
678 static const WCHAR wszMyDocuments[] = { 'M','y',' ','D','o','c','u','m','e','n','t','s', 0 };
679
680 static struct regsvr_namespace const namespace_extensions_list[] = {
681     {   
682         &CLSID_UnixDosFolder,
683         wszDesktop,
684         wszSlash
685     },
686     {   
687         &CLSID_MyDocuments,
688         wszDesktop,
689         wszMyDocuments
690     },
691     { NULL }
692 };
693
694 /***********************************************************************
695  *              DllRegisterServer (SHELL32.@)
696  */
697 HRESULT WINAPI DllRegisterServer(void)
698 {
699     HRESULT hr;
700
701     TRACE("\n");
702
703     hr = register_coclasses(coclass_list);
704     if (SUCCEEDED(hr))
705         hr = register_interfaces(interface_list);
706     if (SUCCEEDED(hr))
707         hr = SHELL_RegisterShellFolders();
708     if (SUCCEEDED(hr))
709         hr = register_namespace_extensions(namespace_extensions_list);
710     return hr;
711 }
712
713 /***********************************************************************
714  *              DllUnregisterServer (SHELL32.@)
715  */
716 HRESULT WINAPI DllUnregisterServer(void)
717 {
718     HRESULT hr;
719
720     TRACE("\n");
721
722     hr = unregister_coclasses(coclass_list);
723     if (SUCCEEDED(hr))
724         hr = unregister_interfaces(interface_list);
725     if (SUCCEEDED(hr))
726         hr = unregister_namespace_extensions(namespace_extensions_list);
727     return hr;
728 }