shdocvw/tests: Fix test failures on XP SP2 and higher.
[wine] / dlls / inseng / regsvr.c
1 /*
2  *      self-registerable dll functions for inseng.dll
3  *
4  * Copyright (C) 2003 John K. Hohm
5  * Copyright (C) 2004 Steven Edwards for ReactOS
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winerror.h"
31
32 #include "objbase.h"
33 #include "initguid.h"
34
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(inseng);
39
40 DEFINE_GUID(CLSID_ActiveSetupEng, 0x6e449686,0xc509,0x11cf,0xaa,0xfa,0x00,0xaa,0x00,0xb6,0x01,0x5c );
41 DEFINE_GUID(CLSID_DLManager, 0xBFC880F1,0x7484,0x11D0,0x83,0x09,0x00,0xAA,0x00,0xB6,0x01,0x5C);
42
43 /*
44  * Near the bottom of this file are the exported DllRegisterServer and
45  * DllUnregisterServer, which make all this worthwhile.
46  */
47
48 /***********************************************************************
49  *              interface for self-registering
50  */
51 struct regsvr_interface
52 {
53     IID const *iid;             /* NULL for end of list */
54     LPCSTR name;                /* can be NULL to omit */
55     IID const *base_iid;        /* can be NULL to omit */
56     int num_methods;            /* can be <0 to omit */
57     CLSID const *ps_clsid;      /* can be NULL to omit */
58     CLSID const *ps_clsid32;    /* can be NULL to omit */
59 };
60
61 static HRESULT register_interfaces(struct regsvr_interface const *list);
62 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
63
64 struct regsvr_coclass
65 {
66     CLSID const *clsid;         /* NULL for end of list */
67     LPCSTR name;                /* can be NULL to omit */
68     LPCSTR ips;                 /* can be NULL to omit */
69     LPCSTR ips32;               /* can be NULL to omit */
70     LPCSTR ips32_tmodel;        /* can be NULL to omit */
71     LPCSTR progid;              /* can be NULL to omit */
72     LPCSTR viprogid;            /* can be NULL to omit */
73     LPCSTR progid_extra;        /* can be NULL to omit */
74 };
75
76 static HRESULT register_coclasses(struct regsvr_coclass const *list);
77 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
78
79 /***********************************************************************
80  *              static string constants
81  */
82 static WCHAR const interface_keyname[10] = {
83     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
84 static WCHAR const base_ifa_keyname[14] = {
85     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
86     'e', 0 };
87 static WCHAR const num_methods_keyname[11] = {
88     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
89 static WCHAR const ps_clsid_keyname[15] = {
90     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
91     'i', 'd', 0 };
92 static WCHAR const ps_clsid32_keyname[17] = {
93     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
94     'i', 'd', '3', '2', 0 };
95 static WCHAR const clsid_keyname[6] = {
96     'C', 'L', 'S', 'I', 'D', 0 };
97 static WCHAR const curver_keyname[7] = {
98     'C', 'u', 'r', 'V', 'e', 'r', 0 };
99 static WCHAR const ips_keyname[13] = {
100     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
101     0 };
102 static WCHAR const ips32_keyname[15] = {
103     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
104     '3', '2', 0 };
105 static WCHAR const progid_keyname[7] = {
106     'P', 'r', 'o', 'g', 'I', 'D', 0 };
107 static WCHAR const viprogid_keyname[25] = {
108     'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
109     'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
110     0 };
111 static char const tmodel_valuename[] = "ThreadingModel";
112
113 /***********************************************************************
114  *              static helper functions
115  */
116 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
117 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
118                                    WCHAR const *value);
119 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
120                                    char const *value);
121 static LONG register_progid(WCHAR const *clsid,
122                             char const *progid, char const *curver_progid,
123                             char const *name, char const *extra);
124
125 /***********************************************************************
126  *              register_interfaces
127  */
128 static HRESULT register_interfaces(struct regsvr_interface const *list)
129 {
130     LONG res = ERROR_SUCCESS;
131     HKEY interface_key;
132
133     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
134                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
135     if (res != ERROR_SUCCESS) goto error_return;
136
137     for (; res == ERROR_SUCCESS && list->iid; ++list) {
138         WCHAR buf[39];
139         HKEY iid_key;
140
141         StringFromGUID2(list->iid, buf, 39);
142         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
143                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
144         if (res != ERROR_SUCCESS) goto error_close_interface_key;
145
146         if (list->name) {
147             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
148                                  (CONST BYTE*)(list->name),
149                                  strlen(list->name) + 1);
150             if (res != ERROR_SUCCESS) goto error_close_iid_key;
151         }
152
153         if (list->base_iid) {
154             res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
155             if (res != ERROR_SUCCESS) goto error_close_iid_key;
156         }
157
158         if (0 <= list->num_methods) {
159             static WCHAR const fmt[3] = { '%', 'd', 0 };
160             HKEY key;
161
162             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
163                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
164             if (res != ERROR_SUCCESS) goto error_close_iid_key;
165
166             sprintfW(buf, fmt, list->num_methods);
167             res = RegSetValueExW(key, NULL, 0, REG_SZ,
168                                  (CONST BYTE*)buf,
169                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
170             RegCloseKey(key);
171
172             if (res != ERROR_SUCCESS) goto error_close_iid_key;
173         }
174
175         if (list->ps_clsid) {
176             res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
177             if (res != ERROR_SUCCESS) goto error_close_iid_key;
178         }
179
180         if (list->ps_clsid32) {
181             res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
182             if (res != ERROR_SUCCESS) goto error_close_iid_key;
183         }
184
185     error_close_iid_key:
186         RegCloseKey(iid_key);
187     }
188
189 error_close_interface_key:
190     RegCloseKey(interface_key);
191 error_return:
192     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
193 }
194
195 /***********************************************************************
196  *              unregister_interfaces
197  */
198 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
199 {
200     LONG res = ERROR_SUCCESS;
201     HKEY interface_key;
202
203     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
204                         KEY_READ | KEY_WRITE, &interface_key);
205     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
206     if (res != ERROR_SUCCESS) goto error_return;
207
208     for (; res == ERROR_SUCCESS && list->iid; ++list) {
209         WCHAR buf[39];
210
211         StringFromGUID2(list->iid, buf, 39);
212         res = RegDeleteTreeW(interface_key, buf);
213         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
214     }
215
216     RegCloseKey(interface_key);
217 error_return:
218     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
219 }
220
221 /***********************************************************************
222  *              register_coclasses
223  */
224 static HRESULT register_coclasses(struct regsvr_coclass const *list)
225 {
226     LONG res = ERROR_SUCCESS;
227     HKEY coclass_key;
228
229     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
230                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
231     if (res != ERROR_SUCCESS) goto error_return;
232
233     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
234         WCHAR buf[39];
235         HKEY clsid_key;
236
237         StringFromGUID2(list->clsid, buf, 39);
238         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
239                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
240         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
241
242         if (list->name) {
243             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
244                                  (CONST BYTE*)(list->name),
245                                  strlen(list->name) + 1);
246             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
247         }
248
249         if (list->ips) {
250             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
251             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
252         }
253
254         if (list->ips32) {
255             HKEY ips32_key;
256
257             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
258                                   KEY_READ | KEY_WRITE, NULL,
259                                   &ips32_key, NULL);
260             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
261
262             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
263                                  (CONST BYTE*)list->ips32,
264                                  lstrlenA(list->ips32) + 1);
265             if (res == ERROR_SUCCESS && list->ips32_tmodel)
266                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
267                                      (CONST BYTE*)list->ips32_tmodel,
268                                      strlen(list->ips32_tmodel) + 1);
269             RegCloseKey(ips32_key);
270             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
271         }
272
273         if (list->progid) {
274             res = register_key_defvalueA(clsid_key, progid_keyname,
275                                          list->progid);
276             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
277
278             res = register_progid(buf, list->progid, NULL,
279                                   list->name, list->progid_extra);
280             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
281         }
282
283         if (list->viprogid) {
284             res = register_key_defvalueA(clsid_key, viprogid_keyname,
285                                          list->viprogid);
286             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
287
288             res = register_progid(buf, list->viprogid, list->progid,
289                                   list->name, list->progid_extra);
290             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
291         }
292
293     error_close_clsid_key:
294         RegCloseKey(clsid_key);
295     }
296
297 error_close_coclass_key:
298     RegCloseKey(coclass_key);
299 error_return:
300     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
301 }
302
303 /***********************************************************************
304  *              unregister_coclasses
305  */
306 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
307 {
308     LONG res = ERROR_SUCCESS;
309     HKEY coclass_key;
310
311     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
312                         KEY_READ | KEY_WRITE, &coclass_key);
313     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
314     if (res != ERROR_SUCCESS) goto error_return;
315
316     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
317         WCHAR buf[39];
318
319         StringFromGUID2(list->clsid, buf, 39);
320         res = RegDeleteTreeW(coclass_key, buf);
321         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
322         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
323
324         if (list->progid) {
325             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
326             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
327             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
328         }
329
330         if (list->viprogid) {
331             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
332             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
333             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
334         }
335     }
336
337 error_close_coclass_key:
338     RegCloseKey(coclass_key);
339 error_return:
340     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
341 }
342
343 /***********************************************************************
344  *              regsvr_key_guid
345  */
346 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
347 {
348     WCHAR buf[39];
349
350     StringFromGUID2(guid, buf, 39);
351     return register_key_defvalueW(base, name, buf);
352 }
353
354 /***********************************************************************
355  *              regsvr_key_defvalueW
356  */
357 static LONG register_key_defvalueW(
358     HKEY base,
359     WCHAR const *name,
360     WCHAR const *value)
361 {
362     LONG res;
363     HKEY key;
364
365     res = RegCreateKeyExW(base, name, 0, NULL, 0,
366                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
367     if (res != ERROR_SUCCESS) return res;
368     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
369                          (lstrlenW(value) + 1) * sizeof(WCHAR));
370     RegCloseKey(key);
371     return res;
372 }
373
374 /***********************************************************************
375  *              regsvr_key_defvalueA
376  */
377 static LONG register_key_defvalueA(
378     HKEY base,
379     WCHAR const *name,
380     char const *value)
381 {
382     LONG res;
383     HKEY key;
384
385     res = RegCreateKeyExW(base, name, 0, NULL, 0,
386                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
387     if (res != ERROR_SUCCESS) return res;
388     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
389                          lstrlenA(value) + 1);
390     RegCloseKey(key);
391     return res;
392 }
393
394 /***********************************************************************
395  *              regsvr_progid
396  */
397 static LONG register_progid(
398     WCHAR const *clsid,
399     char const *progid,
400     char const *curver_progid,
401     char const *name,
402     char const *extra)
403 {
404     LONG res;
405     HKEY progid_key;
406
407     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
408                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
409                           &progid_key, NULL);
410     if (res != ERROR_SUCCESS) return res;
411
412     if (name) {
413         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
414                              (CONST BYTE*)name, strlen(name) + 1);
415         if (res != ERROR_SUCCESS) goto error_close_progid_key;
416     }
417
418     if (clsid) {
419         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
420         if (res != ERROR_SUCCESS) goto error_close_progid_key;
421     }
422
423     if (curver_progid) {
424         res = register_key_defvalueA(progid_key, curver_keyname,
425                                      curver_progid);
426         if (res != ERROR_SUCCESS) goto error_close_progid_key;
427     }
428
429     if (extra) {
430         HKEY extra_key;
431
432         res = RegCreateKeyExA(progid_key, extra, 0,
433                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
434                               &extra_key, NULL);
435         if (res == ERROR_SUCCESS)
436             RegCloseKey(extra_key);
437     }
438
439 error_close_progid_key:
440     RegCloseKey(progid_key);
441     return res;
442 }
443
444 /***********************************************************************
445  *              coclass list
446  */
447 static struct regsvr_coclass const coclass_list[] = {
448     {
449         &CLSID_ActiveSetupEng,
450         "Microsoft Active Setup Engine",
451         NULL,
452         "inseng.dll",
453         "Apartment"
454     },
455     {
456         &CLSID_DLManager,
457         "Download Site Manager",
458         NULL,
459         "inseng.dll",
460         "Apartment"
461     },
462     { NULL }    /* list terminator */
463 };
464
465 /***********************************************************************
466  *              interface list
467  */
468
469 static struct regsvr_interface const interface_list[] = {
470     { NULL }                    /* list terminator */
471 };
472
473 /***********************************************************************
474  *              DllRegisterServer (INSENG.@)
475  */
476 HRESULT WINAPI DllRegisterServer(void)
477 {
478     HRESULT hr;
479
480     TRACE("\n");
481
482     hr = register_coclasses(coclass_list);
483     if (SUCCEEDED(hr))
484         hr = register_interfaces(interface_list);
485     return hr;
486 }
487
488 /***********************************************************************
489  *              DllUnregisterServer (INSENG.@)
490  */
491 HRESULT WINAPI DllUnregisterServer(void)
492 {
493     HRESULT hr;
494
495     TRACE("\n");
496
497     hr = unregister_coclasses(coclass_list);
498     if (SUCCEEDED(hr))
499         hr = unregister_interfaces(interface_list);
500     return hr;
501 }