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