shell32: Build language resource files separately.
[wine] / dlls / dsound / regsvr.c
1 /*
2  *      self-registerable dll functions for dsound.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #define NONAMELESSSTRUCT
24 #define NONAMELESSUNION
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29
30 #include "mmsystem.h"
31 #include "dsound.h"
32
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
37
38 static LSTATUS (WINAPI *pRegDeleteTreeW)(HKEY,LPCWSTR);
39 static LSTATUS (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
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     LPCSTR ips;                 /* can be NULL to omit */
67     LPCSTR ips32;               /* can be NULL to omit */
68     LPCSTR ips32_tmodel;        /* can be NULL to omit */
69     LPCSTR progid;              /* can be NULL to omit */
70     LPCSTR viprogid;            /* can be NULL to omit */
71     LPCSTR progid_extra;        /* can be NULL to omit */
72 };
73
74 static HRESULT register_coclasses(struct regsvr_coclass const *list);
75 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
76
77 /***********************************************************************
78  *              static string constants
79  */
80 static WCHAR const interface_keyname[10] = {
81     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
82 static WCHAR const base_ifa_keyname[14] = {
83     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
84     'e', 0 };
85 static WCHAR const num_methods_keyname[11] = {
86     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
87 static WCHAR const ps_clsid_keyname[15] = {
88     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
89     'i', 'd', 0 };
90 static WCHAR const ps_clsid32_keyname[17] = {
91     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
92     'i', 'd', '3', '2', 0 };
93 static WCHAR const clsid_keyname[6] = {
94     'C', 'L', 'S', 'I', 'D', 0 };
95 static WCHAR const curver_keyname[7] = {
96     'C', 'u', 'r', 'V', 'e', 'r', 0 };
97 static WCHAR const ips_keyname[13] = {
98     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
99     0 };
100 static WCHAR const ips32_keyname[15] = {
101     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
102     '3', '2', 0 };
103 static WCHAR const progid_keyname[7] = {
104     'P', 'r', 'o', 'g', 'I', 'D', 0 };
105 static WCHAR const viprogid_keyname[25] = {
106     'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
107     'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
108     0 };
109 static char const tmodel_valuename[] = "ThreadingModel";
110
111 /***********************************************************************
112  *              static helper functions
113  */
114 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
115 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
116                                    WCHAR const *value);
117 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
118                                    char const *value);
119 static LONG register_progid(WCHAR const *clsid,
120                             char const *progid, char const *curver_progid,
121                             char const *name, char const *extra);
122
123 /***********************************************************************
124  *              register_interfaces
125  */
126 static HRESULT register_interfaces(struct regsvr_interface const *list)
127 {
128     LONG res = ERROR_SUCCESS;
129     HKEY interface_key;
130
131     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
132                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
133     if (res != ERROR_SUCCESS) goto error_return;
134
135     for (; res == ERROR_SUCCESS && list->iid; ++list) {
136         WCHAR buf[39];
137         HKEY iid_key;
138
139         StringFromGUID2(list->iid, buf, 39);
140         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
141                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
142         if (res != ERROR_SUCCESS) goto error_close_interface_key;
143
144         if (list->name) {
145             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
146                                  (CONST BYTE*)(list->name),
147                                  strlen(list->name) + 1);
148             if (res != ERROR_SUCCESS) goto error_close_iid_key;
149         }
150
151         if (list->base_iid) {
152             res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
153             if (res != ERROR_SUCCESS) goto error_close_iid_key;
154         }
155
156         if (0 <= list->num_methods) {
157             static WCHAR const fmt[3] = { '%', 'd', 0 };
158             HKEY key;
159
160             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
161                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
162             if (res != ERROR_SUCCESS) goto error_close_iid_key;
163
164             sprintfW(buf, fmt, list->num_methods);
165             res = RegSetValueExW(key, NULL, 0, REG_SZ,
166                                  (CONST BYTE*)buf,
167                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
168             RegCloseKey(key);
169
170             if (res != ERROR_SUCCESS) goto error_close_iid_key;
171         }
172
173         if (list->ps_clsid) {
174             res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
175             if (res != ERROR_SUCCESS) goto error_close_iid_key;
176         }
177
178         if (list->ps_clsid32) {
179             res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
180             if (res != ERROR_SUCCESS) goto error_close_iid_key;
181         }
182
183     error_close_iid_key:
184         RegCloseKey(iid_key);
185     }
186
187 error_close_interface_key:
188     RegCloseKey(interface_key);
189 error_return:
190     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
191 }
192
193 /***********************************************************************
194  *              unregister_interfaces
195  */
196 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
197 {
198     LONG res = ERROR_SUCCESS;
199     HKEY interface_key;
200
201     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
202                         KEY_READ | KEY_WRITE, &interface_key);
203     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
204     if (res != ERROR_SUCCESS) goto error_return;
205
206     for (; res == ERROR_SUCCESS && list->iid; ++list) {
207         WCHAR buf[39];
208
209         StringFromGUID2(list->iid, buf, 39);
210         res = pRegDeleteTreeW(interface_key, buf);
211         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
212     }
213
214     RegCloseKey(interface_key);
215 error_return:
216     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
217 }
218
219 /***********************************************************************
220  *              register_coclasses
221  */
222 static HRESULT register_coclasses(struct regsvr_coclass const *list)
223 {
224     LONG res = ERROR_SUCCESS;
225     HKEY coclass_key;
226
227     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
228                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
229     if (res != ERROR_SUCCESS) goto error_return;
230
231     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
232         WCHAR buf[39];
233         HKEY clsid_key;
234
235         StringFromGUID2(list->clsid, buf, 39);
236         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
237                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
238         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
239
240         if (list->name) {
241             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
242                                  (CONST BYTE*)(list->name),
243                                  strlen(list->name) + 1);
244             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
245         }
246
247         if (list->ips) {
248             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
249             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
250         }
251
252         if (list->ips32) {
253             HKEY ips32_key;
254
255             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
256                                   KEY_READ | KEY_WRITE, NULL,
257                                   &ips32_key, NULL);
258             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
259
260             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
261                                  (CONST BYTE*)list->ips32,
262                                  lstrlenA(list->ips32) + 1);
263             if (res == ERROR_SUCCESS && list->ips32_tmodel)
264                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
265                                      (CONST BYTE*)list->ips32_tmodel,
266                                      strlen(list->ips32_tmodel) + 1);
267             RegCloseKey(ips32_key);
268             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
269         }
270
271         if (list->progid) {
272             res = register_key_defvalueA(clsid_key, progid_keyname,
273                                          list->progid);
274             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
275
276             res = register_progid(buf, list->progid, NULL,
277                                   list->name, list->progid_extra);
278             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
279         }
280
281         if (list->viprogid) {
282             res = register_key_defvalueA(clsid_key, viprogid_keyname,
283                                          list->viprogid);
284             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
285
286             res = register_progid(buf, list->viprogid, list->progid,
287                                   list->name, list->progid_extra);
288             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
289         }
290
291     error_close_clsid_key:
292         RegCloseKey(clsid_key);
293     }
294
295 error_close_coclass_key:
296     RegCloseKey(coclass_key);
297 error_return:
298     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
299 }
300
301 /***********************************************************************
302  *              unregister_coclasses
303  */
304 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
305 {
306     LONG res = ERROR_SUCCESS;
307     HKEY coclass_key;
308
309     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
310                         KEY_READ | KEY_WRITE, &coclass_key);
311     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
312     if (res != ERROR_SUCCESS) goto error_return;
313
314     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
315         WCHAR buf[39];
316
317         StringFromGUID2(list->clsid, buf, 39);
318         res = pRegDeleteTreeW(coclass_key, buf);
319         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
320         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
321
322         if (list->progid) {
323             res = pRegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
324             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
325             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
326         }
327
328         if (list->viprogid) {
329             res = pRegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
330             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
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  *              coclass list
444  */
445 static GUID const CLSID_DirectSoundBufferConfig = {
446     0xB2F586D4, 0x5558, 0x49D1, {0xA0,0x7B,0x32,0x49,0xDB,0xBB,0x33,0xC2} };
447
448 static struct regsvr_coclass const coclass_list[] = {
449     {   &CLSID_DirectSound,
450         "DirectSound Object",
451         NULL,
452         "dsound.dll",
453         "Both"
454     },
455     {   &CLSID_DirectSound8,
456         "DirectSound 8.0 Object",
457         NULL,
458         "dsound.dll",
459         "Both"
460     },
461     {   &CLSID_DirectSoundBufferConfig,
462         "DirectSoundBufferConfig Object",
463         NULL,
464         "dsound.dll",
465         "Both"
466     },
467     {   &CLSID_DirectSoundCapture,
468         "DirectSoundCapture Object",
469         NULL,
470         "dsound.dll",
471         "Both"
472     },
473     {   &CLSID_DirectSoundCapture8,
474         "DirectSoundCapture 8.0 Object",
475         NULL,
476         "dsound.dll",
477         "Both"
478     },
479     {   &CLSID_DirectSoundFullDuplex,
480         "DirectSoundFullDuplex Object",
481         NULL,
482         "dsound.dll",
483         "Both"
484     },
485     { NULL }                    /* list terminator */
486 };
487
488 /***********************************************************************
489  *              interface list
490  */
491
492 static struct regsvr_interface const interface_list[] = {
493     { NULL }                    /* list terminator */
494 };
495
496 /***********************************************************************
497  *              DllRegisterServer (DSOUND.@)
498  */
499 HRESULT WINAPI DllRegisterServer(void)
500 {
501     HRESULT hr;
502
503     TRACE("\n");
504
505     hr = register_coclasses(coclass_list);
506     if (SUCCEEDED(hr))
507         hr = register_interfaces(interface_list);
508     return hr;
509 }
510
511 /***********************************************************************
512  *              DllUnregisterServer (DSOUND.@)
513  */
514 HRESULT WINAPI DllUnregisterServer(void)
515 {
516     HRESULT hr;
517
518     HMODULE advapi32 = GetModuleHandleA("advapi32");
519     if (!advapi32) return E_FAIL;
520     pRegDeleteTreeA = (void *) GetProcAddress(advapi32, "RegDeleteTreeA");
521     pRegDeleteTreeW = (void *) GetProcAddress(advapi32, "RegDeleteTreeW");
522     if (!pRegDeleteTreeA || !pRegDeleteTreeW) return E_FAIL;
523
524     TRACE("\n");
525
526     hr = unregister_coclasses(coclass_list);
527     if (SUCCEEDED(hr))
528         hr = unregister_interfaces(interface_list);
529     return hr;
530 }