Make ole32 a delay-load import of shell32.
[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
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "winerror.h"
29
30 #include "ole2.h"
31 #include "shlguid.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
36
37 /*
38  * Near the bottom of this file are the exported DllRegisterServer and
39  * DllUnregisterServer, which make all this worthwhile.
40  */
41
42 /***********************************************************************
43  *              interface for self-registering
44  */
45 struct regsvr_interface
46 {
47     IID const *iid;             /* NULL for end of list */
48     LPCSTR name;                /* can be NULL to omit */
49     IID const *base_iid;        /* can be NULL to omit */
50     int num_methods;            /* can be <0 to omit */
51     CLSID const *ps_clsid;      /* can be NULL to omit */
52     CLSID const *ps_clsid32;    /* can be NULL to omit */
53 };
54
55 static HRESULT register_interfaces(struct regsvr_interface const *list);
56 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
57
58 struct regsvr_coclass
59 {
60     CLSID const *clsid;         /* NULL for end of list */
61     LPCSTR name;                /* can be NULL to omit */
62     LPCSTR ips;                 /* can be NULL to omit */
63     LPCSTR ips32;               /* can be NULL to omit */
64     LPCSTR ips32_tmodel;        /* can be NULL to omit */
65     DWORD flags;
66     LPCSTR clsid_str;           /* can be NULL to omit */
67     LPCSTR progid;              /* can be NULL to omit */
68 };
69
70 /* flags for regsvr_coclass.flags */
71 #define SHELLEX_MAYCHANGEDEFAULTMENU 0x00000001
72
73 static HRESULT register_coclasses(struct regsvr_coclass const *list);
74 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
75
76 /***********************************************************************
77  *              static string constants
78  */
79 static WCHAR const interface_keyname[10] = {
80     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
81 static WCHAR const base_ifa_keyname[14] = {
82     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
83     'e', 0 };
84 static WCHAR const num_methods_keyname[11] = {
85     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
86 static WCHAR const ps_clsid_keyname[15] = {
87     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
88     'i', 'd', 0 };
89 static WCHAR const ps_clsid32_keyname[17] = {
90     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
91     'i', 'd', '3', '2', 0 };
92 static WCHAR const clsid_keyname[6] = {
93     'C', 'L', 'S', 'I', 'D', 0 };
94 static WCHAR const ips_keyname[13] = {
95     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
96     0 };
97 static WCHAR const ips32_keyname[15] = {
98     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
99     '3', '2', 0 };
100 static WCHAR const progid_keyname[7] = {
101     'P', 'r', 'o', 'g', 'I', 'D', 0 };
102 static WCHAR const shellex_keyname[8] = {
103     's', 'h', 'e', 'l', 'l', 'e', 'x', 0 };
104 static WCHAR const mcdm_keyname[21] = {
105     'M', 'a', 'y', 'C', 'h', 'a', 'n', 'g', 'e', 'D', 'e', 'f',
106     'a', 'u', 'l', 't', 'M', 'e', 'n', 'u', 0 };
107 static char const tmodel_valuename[] = "ThreadingModel";
108
109 /***********************************************************************
110  *              static helper functions
111  */
112 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
113 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
114                                    WCHAR const *value);
115 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
116                                    char const *value);
117 static LONG recursive_delete_key(HKEY key);
118 static LONG recursive_delete_keyA(HKEY base, char const *name);
119 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
120
121 /***********************************************************************
122  *              register_interfaces
123  */
124 static HRESULT register_interfaces(struct regsvr_interface const *list)
125 {
126     LONG res = ERROR_SUCCESS;
127     HKEY interface_key;
128
129     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
130                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
131     if (res != ERROR_SUCCESS) goto error_return;
132
133     for (; res == ERROR_SUCCESS && list->iid; ++list) {
134         WCHAR buf[39];
135         HKEY iid_key;
136
137         StringFromGUID2(list->iid, buf, 39);
138         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
139                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
140         if (res != ERROR_SUCCESS) goto error_close_interface_key;
141
142         if (list->name) {
143             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
144                                  (CONST BYTE*)(list->name),
145                                  strlen(list->name) + 1);
146             if (res != ERROR_SUCCESS) goto error_close_iid_key;
147         }
148
149         if (list->base_iid) {
150             register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
151             if (res != ERROR_SUCCESS) goto error_close_iid_key;
152         }
153
154         if (0 <= list->num_methods) {
155             static WCHAR const fmt[3] = { '%', 'd', 0 };
156             HKEY key;
157
158             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
159                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
160             if (res != ERROR_SUCCESS) goto error_close_iid_key;
161
162             wsprintfW(buf, fmt, list->num_methods);
163             res = RegSetValueExW(key, NULL, 0, REG_SZ,
164                                  (CONST BYTE*)buf,
165                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
166             RegCloseKey(key);
167
168             if (res != ERROR_SUCCESS) goto error_close_iid_key;
169         }
170
171         if (list->ps_clsid) {
172             register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
173             if (res != ERROR_SUCCESS) goto error_close_iid_key;
174         }
175
176         if (list->ps_clsid32) {
177             register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
178             if (res != ERROR_SUCCESS) goto error_close_iid_key;
179         }
180
181     error_close_iid_key:
182         RegCloseKey(iid_key);
183     }
184
185 error_close_interface_key:
186     RegCloseKey(interface_key);
187 error_return:
188     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
189 }
190
191 /***********************************************************************
192  *              unregister_interfaces
193  */
194 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
195 {
196     LONG res = ERROR_SUCCESS;
197     HKEY interface_key;
198
199     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
200                         KEY_READ | KEY_WRITE, &interface_key);
201     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
202     if (res != ERROR_SUCCESS) goto error_return;
203
204     for (; res == ERROR_SUCCESS && list->iid; ++list) {
205         WCHAR buf[39];
206
207         StringFromGUID2(list->iid, buf, 39);
208         res = recursive_delete_keyW(interface_key, buf);
209     }
210
211     RegCloseKey(interface_key);
212 error_return:
213     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
214 }
215
216 /***********************************************************************
217  *              register_coclasses
218  */
219 static HRESULT register_coclasses(struct regsvr_coclass const *list)
220 {
221     LONG res = ERROR_SUCCESS;
222     HKEY coclass_key;
223
224     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
225                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
226     if (res != ERROR_SUCCESS) goto error_return;
227
228     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
229         WCHAR buf[39];
230         HKEY clsid_key;
231
232         StringFromGUID2(list->clsid, buf, 39);
233         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
234                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
235         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
236
237         if (list->name) {
238             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
239                                  (CONST BYTE*)(list->name),
240                                  strlen(list->name) + 1);
241             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
242         }
243
244         if (list->ips) {
245             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
246             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
247         }
248
249         if (list->ips32) {
250             HKEY ips32_key;
251
252             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
253                                   KEY_READ | KEY_WRITE, NULL,
254                                   &ips32_key, NULL);
255             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
256
257             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
258                                  (CONST BYTE*)list->ips32,
259                                  lstrlenA(list->ips32) + 1);
260             if (res == ERROR_SUCCESS && list->ips32_tmodel)
261                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
262                                      (CONST BYTE*)list->ips32_tmodel,
263                                      strlen(list->ips32_tmodel) + 1);
264             RegCloseKey(ips32_key);
265             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
266         }
267
268         if (list->flags & SHELLEX_MAYCHANGEDEFAULTMENU) {
269             HKEY shellex_key, mcdm_key;
270
271             res = RegCreateKeyExW(clsid_key, shellex_keyname, 0, NULL, 0,
272                                   KEY_READ | KEY_WRITE, NULL,
273                                   &shellex_key, NULL);
274             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
275             res = RegCreateKeyExW(shellex_key, mcdm_keyname, 0, NULL, 0,
276                                   KEY_READ | KEY_WRITE, NULL,
277                                   &mcdm_key, NULL);
278             RegCloseKey(shellex_key);
279             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
280             RegCloseKey(mcdm_key);
281         }
282
283         if (list->clsid_str) {
284             res = register_key_defvalueA(clsid_key, clsid_keyname,
285                                          list->clsid_str);
286             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
287         }
288
289         if (list->progid) {
290             HKEY progid_key;
291
292             res = register_key_defvalueA(clsid_key, progid_keyname,
293                                          list->progid);
294             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
295
296             res = RegCreateKeyExA(HKEY_CLASSES_ROOT, list->progid, 0,
297                                   NULL, 0, KEY_READ | KEY_WRITE, NULL,
298                                   &progid_key, NULL);
299             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
300
301             res = register_key_defvalueW(progid_key, clsid_keyname, buf);
302             RegCloseKey(progid_key);
303             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
304         }
305
306     error_close_clsid_key:
307         RegCloseKey(clsid_key);
308     }
309
310 error_close_coclass_key:
311     RegCloseKey(coclass_key);
312 error_return:
313     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
314 }
315
316 /***********************************************************************
317  *              unregister_coclasses
318  */
319 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
320 {
321     LONG res = ERROR_SUCCESS;
322     HKEY coclass_key;
323
324     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
325                         KEY_READ | KEY_WRITE, &coclass_key);
326     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
327     if (res != ERROR_SUCCESS) goto error_return;
328
329     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
330         WCHAR buf[39];
331
332         StringFromGUID2(list->clsid, buf, 39);
333         res = recursive_delete_keyW(coclass_key, buf);
334         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
335
336         if (list->progid) {
337             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
338             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
339         }
340     }
341
342 error_close_coclass_key:
343     RegCloseKey(coclass_key);
344 error_return:
345     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
346 }
347
348 /***********************************************************************
349  *              regsvr_key_guid
350  */
351 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
352 {
353     WCHAR buf[39];
354
355     StringFromGUID2(guid, buf, 39);
356     return register_key_defvalueW(base, name, buf);
357 }
358
359 /***********************************************************************
360  *              regsvr_key_defvalueW
361  */
362 static LONG register_key_defvalueW(
363     HKEY base,
364     WCHAR const *name,
365     WCHAR const *value)
366 {
367     LONG res;
368     HKEY key;
369
370     res = RegCreateKeyExW(base, name, 0, NULL, 0,
371                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
372     if (res != ERROR_SUCCESS) return res;
373     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
374                          (lstrlenW(value) + 1) * sizeof(WCHAR));
375     RegCloseKey(key);
376     return res;
377 }
378
379 /***********************************************************************
380  *              regsvr_key_defvalueA
381  */
382 static LONG register_key_defvalueA(
383     HKEY base,
384     WCHAR const *name,
385     char const *value)
386 {
387     LONG res;
388     HKEY key;
389
390     res = RegCreateKeyExW(base, name, 0, NULL, 0,
391                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
392     if (res != ERROR_SUCCESS) return res;
393     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
394                          lstrlenA(value) + 1);
395     RegCloseKey(key);
396     return res;
397 }
398
399 /***********************************************************************
400  *              recursive_delete_key
401  */
402 static LONG recursive_delete_key(HKEY key)
403 {
404     LONG res;
405     WCHAR subkey_name[MAX_PATH];
406     DWORD cName;
407     HKEY subkey;
408
409     for (;;) {
410         cName = sizeof(subkey_name) / sizeof(WCHAR);
411         res = RegEnumKeyExW(key, 0, subkey_name, &cName,
412                             NULL, NULL, NULL, NULL);
413         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
414             res = ERROR_SUCCESS; /* presumably we're done enumerating */
415             break;
416         }
417         res = RegOpenKeyExW(key, subkey_name, 0,
418                             KEY_READ | KEY_WRITE, &subkey);
419         if (res == ERROR_FILE_NOT_FOUND) continue;
420         if (res != ERROR_SUCCESS) break;
421
422         res = recursive_delete_key(subkey);
423         RegCloseKey(subkey);
424         if (res != ERROR_SUCCESS) break;
425     }
426
427     if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
428     return res;
429 }
430
431 /***********************************************************************
432  *              recursive_delete_keyA
433  */
434 static LONG recursive_delete_keyA(HKEY base, char const *name)
435 {
436     LONG res;
437     HKEY key;
438
439     res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
440     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
441     if (res != ERROR_SUCCESS) return res;
442     res = recursive_delete_key(key);
443     RegCloseKey(key);
444     return res;
445 }
446
447 /***********************************************************************
448  *              recursive_delete_keyW
449  */
450 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
451 {
452     LONG res;
453     HKEY key;
454
455     res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
456     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
457     if (res != ERROR_SUCCESS) return res;
458     res = recursive_delete_key(key);
459     RegCloseKey(key);
460     return res;
461 }
462
463 /***********************************************************************
464  *              coclass list
465  */
466 static GUID const CLSID_Desktop = {
467     0x00021400, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
468
469 static GUID const CLSID_Shortcut = {
470     0x00021401, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
471
472 static struct regsvr_coclass const coclass_list[] = {
473     {   &CLSID_Desktop,
474         "Desktop",
475         NULL,
476         "shell32.dll",
477         "Apartment"
478     },
479     {   &CLSID_MyComputer,
480         "My Computer",
481         NULL,
482         "shell32.dll",
483         "Apartment"
484     },
485     {   &CLSID_Shortcut,
486         "Shortcut",
487         NULL,
488         "shell32.dll",
489         "Apartment",
490         SHELLEX_MAYCHANGEDEFAULTMENU
491     },
492     {   &CLSID_AutoComplete,
493         "AutoComplete",
494         NULL,
495         "shell32.dll",
496         "Apartment",
497     },
498     { NULL }                    /* list terminator */
499 };
500
501 /***********************************************************************
502  *              interface list
503  */
504
505 static struct regsvr_interface const interface_list[] = {
506     { NULL }                    /* list terminator */
507 };
508
509 /***********************************************************************
510  *              DllRegisterServer (SHELL32.@)
511  */
512 HRESULT WINAPI SHELL32_DllRegisterServer()
513 {
514     HRESULT hr;
515
516     TRACE("\n");
517
518     hr = register_coclasses(coclass_list);
519     if (SUCCEEDED(hr))
520         hr = register_interfaces(interface_list);
521     return hr;
522 }
523
524 /***********************************************************************
525  *              DllUnregisterServer (SHELL32.@)
526  */
527 HRESULT WINAPI SHELL32_DllUnregisterServer()
528 {
529     HRESULT hr;
530
531     TRACE("\n");
532
533     hr = unregister_coclasses(coclass_list);
534     if (SUCCEEDED(hr))
535         hr = unregister_interfaces(interface_list);
536     return hr;
537 }