comctl32: Dangling pointers fix.
[wine] / dlls / ddraw / regsvr.c
1 /*
2  *      self-registerable dll functions for ddraw.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 #include <string.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30
31 #include "ddraw.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
36
37 static LSTATUS (WINAPI *pRegDeleteTreeW)(HKEY,LPCWSTR);
38 static LSTATUS (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
39
40 /*
41  * Near the bottom of this file are the exported DllRegisterServer and
42  * DllUnregisterServer, which make all this worthwhile.
43  */
44
45 /***********************************************************************
46  *              interface for self-registering
47  */
48 struct regsvr_interface
49 {
50     IID const *iid;             /* NULL for end of list */
51     LPCSTR name;                /* can be NULL to omit */
52     IID const *base_iid;        /* can be NULL to omit */
53     int num_methods;            /* can be <0 to omit */
54     CLSID const *ps_clsid;      /* can be NULL to omit */
55     CLSID const *ps_clsid32;    /* can be NULL to omit */
56 };
57
58 static HRESULT register_interfaces(struct regsvr_interface const *list);
59 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
60
61 struct regsvr_coclass
62 {
63     CLSID const *clsid;         /* NULL for end of list */
64     LPCSTR name;                /* can be NULL to omit */
65     LPCSTR ips;                 /* can be NULL to omit */
66     LPCSTR ips32;               /* can be NULL to omit */
67     LPCSTR ips32_tmodel;        /* can be NULL to omit */
68     LPCSTR clsid_str;           /* can be NULL to omit */
69     LPCSTR progid;              /* can be NULL to omit */
70 };
71
72 static HRESULT register_coclasses(struct regsvr_coclass const *list);
73 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
74
75 /***********************************************************************
76  *              static string constants
77  */
78 static WCHAR const interface_keyname[10] = {
79     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
80 static WCHAR const base_ifa_keyname[14] = {
81     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
82     'e', 0 };
83 static WCHAR const num_methods_keyname[11] = {
84     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
85 static WCHAR const ps_clsid_keyname[15] = {
86     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
87     'i', 'd', 0 };
88 static WCHAR const ps_clsid32_keyname[17] = {
89     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
90     'i', 'd', '3', '2', 0 };
91 static WCHAR const clsid_keyname[6] = {
92     'C', 'L', 'S', 'I', 'D', 0 };
93 static WCHAR const ips_keyname[13] = {
94     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
95     0 };
96 static WCHAR const ips32_keyname[15] = {
97     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
98     '3', '2', 0 };
99 static WCHAR const progid_keyname[7] = {
100     'P', 'r', 'o', 'g', 'I', 'D', 0 };
101 static char const tmodel_valuename[] = "ThreadingModel";
102
103 /***********************************************************************
104  *              static helper functions
105  */
106 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
107 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
108                                    WCHAR const *value);
109 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
110                                    char const *value);
111
112 /***********************************************************************
113  *              register_interfaces
114  */
115 static HRESULT register_interfaces(struct regsvr_interface const *list)
116 {
117     LONG res = ERROR_SUCCESS;
118     HKEY interface_key;
119
120     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
121                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
122     if (res != ERROR_SUCCESS) goto error_return;
123
124     for (; res == ERROR_SUCCESS && list->iid; ++list) {
125         WCHAR buf[39];
126         HKEY iid_key;
127
128         StringFromGUID2(list->iid, buf, 39);
129         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
130                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
131         if (res != ERROR_SUCCESS) goto error_close_interface_key;
132
133         if (list->name) {
134             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
135                                  (CONST BYTE*)(list->name),
136                                  strlen(list->name) + 1);
137             if (res != ERROR_SUCCESS) goto error_close_iid_key;
138         }
139
140         if (list->base_iid) {
141             res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
142             if (res != ERROR_SUCCESS) goto error_close_iid_key;
143         }
144
145         if (0 <= list->num_methods) {
146             static WCHAR const fmt[3] = { '%', 'd', 0 };
147             HKEY key;
148
149             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
150                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
151             if (res != ERROR_SUCCESS) goto error_close_iid_key;
152
153             wsprintfW(buf, fmt, list->num_methods);
154             res = RegSetValueExW(key, NULL, 0, REG_SZ,
155                                  (CONST BYTE*)buf,
156                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
157             RegCloseKey(key);
158
159             if (res != ERROR_SUCCESS) goto error_close_iid_key;
160         }
161
162         if (list->ps_clsid) {
163             res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
164             if (res != ERROR_SUCCESS) goto error_close_iid_key;
165         }
166
167         if (list->ps_clsid32) {
168             res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
169             if (res != ERROR_SUCCESS) goto error_close_iid_key;
170         }
171
172     error_close_iid_key:
173         RegCloseKey(iid_key);
174     }
175
176 error_close_interface_key:
177     RegCloseKey(interface_key);
178 error_return:
179     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
180 }
181
182 /***********************************************************************
183  *              unregister_interfaces
184  */
185 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
186 {
187     LONG res = ERROR_SUCCESS;
188     HKEY interface_key;
189
190     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
191                         KEY_READ | KEY_WRITE, &interface_key);
192     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
193     if (res != ERROR_SUCCESS) goto error_return;
194
195     for (; res == ERROR_SUCCESS && list->iid; ++list) {
196         WCHAR buf[39];
197
198         StringFromGUID2(list->iid, buf, 39);
199         res = pRegDeleteTreeW(interface_key, buf);
200         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
201     }
202
203     RegCloseKey(interface_key);
204 error_return:
205     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
206 }
207
208 /***********************************************************************
209  *              register_coclasses
210  */
211 static HRESULT register_coclasses(struct regsvr_coclass const *list)
212 {
213     LONG res = ERROR_SUCCESS;
214     HKEY coclass_key;
215
216     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
217                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
218     if (res != ERROR_SUCCESS) goto error_return;
219
220     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
221         WCHAR buf[39];
222         HKEY clsid_key;
223
224         StringFromGUID2(list->clsid, buf, 39);
225         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
226                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
227         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
228
229         if (list->name) {
230             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
231                                  (CONST BYTE*)(list->name),
232                                  strlen(list->name) + 1);
233             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
234         }
235
236         if (list->ips) {
237             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
238             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
239         }
240
241         if (list->ips32) {
242             HKEY ips32_key;
243
244             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
245                                   KEY_READ | KEY_WRITE, NULL,
246                                   &ips32_key, NULL);
247             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
248
249             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
250                                  (CONST BYTE*)list->ips32,
251                                  lstrlenA(list->ips32) + 1);
252             if (res == ERROR_SUCCESS && list->ips32_tmodel)
253                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
254                                      (CONST BYTE*)list->ips32_tmodel,
255                                      strlen(list->ips32_tmodel) + 1);
256             RegCloseKey(ips32_key);
257             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
258         }
259
260         if (list->clsid_str) {
261             res = register_key_defvalueA(clsid_key, clsid_keyname,
262                                          list->clsid_str);
263             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
264         }
265
266         if (list->progid) {
267             HKEY progid_key;
268
269             res = register_key_defvalueA(clsid_key, progid_keyname,
270                                          list->progid);
271             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
272
273             res = RegCreateKeyExA(HKEY_CLASSES_ROOT, list->progid, 0,
274                                   NULL, 0, KEY_READ | KEY_WRITE, NULL,
275                                   &progid_key, NULL);
276             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
277
278             res = register_key_defvalueW(progid_key, clsid_keyname, buf);
279             RegCloseKey(progid_key);
280             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
281         }
282
283     error_close_clsid_key:
284         RegCloseKey(clsid_key);
285     }
286
287 error_close_coclass_key:
288     RegCloseKey(coclass_key);
289 error_return:
290     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
291 }
292
293 /***********************************************************************
294  *              unregister_coclasses
295  */
296 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
297 {
298     LONG res = ERROR_SUCCESS;
299     HKEY coclass_key;
300
301     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
302                         KEY_READ | KEY_WRITE, &coclass_key);
303     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
304     if (res != ERROR_SUCCESS) goto error_return;
305
306     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
307         WCHAR buf[39];
308
309         StringFromGUID2(list->clsid, buf, 39);
310         res = pRegDeleteTreeW(coclass_key, buf);
311         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
312         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
313
314         if (list->progid) {
315             res = pRegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
316             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
317             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
318         }
319     }
320
321 error_close_coclass_key:
322     RegCloseKey(coclass_key);
323 error_return:
324     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
325 }
326
327 /***********************************************************************
328  *              regsvr_key_guid
329  */
330 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
331 {
332     WCHAR buf[39];
333
334     StringFromGUID2(guid, buf, 39);
335     return register_key_defvalueW(base, name, buf);
336 }
337
338 /***********************************************************************
339  *              regsvr_key_defvalueW
340  */
341 static LONG register_key_defvalueW(
342     HKEY base,
343     WCHAR const *name,
344     WCHAR const *value)
345 {
346     LONG res;
347     HKEY key;
348
349     res = RegCreateKeyExW(base, name, 0, NULL, 0,
350                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
351     if (res != ERROR_SUCCESS) return res;
352     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
353                          (lstrlenW(value) + 1) * sizeof(WCHAR));
354     RegCloseKey(key);
355     return res;
356 }
357
358 /***********************************************************************
359  *              regsvr_key_defvalueA
360  */
361 static LONG register_key_defvalueA(
362     HKEY base,
363     WCHAR const *name,
364     char const *value)
365 {
366     LONG res;
367     HKEY key;
368
369     res = RegCreateKeyExW(base, name, 0, NULL, 0,
370                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
371     if (res != ERROR_SUCCESS) return res;
372     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
373                          lstrlenA(value) + 1);
374     RegCloseKey(key);
375     return res;
376 }
377
378 /***********************************************************************
379  *              coclass list
380  */
381
382 static struct regsvr_coclass const coclass_list[] = {
383     {   &CLSID_DirectDraw,
384         "DirectDraw Object",
385         NULL,
386         "ddraw.dll",
387         "Both"
388     },
389     {   &CLSID_DirectDraw7,
390         "DirectDraw 7 Object",
391         NULL,
392         "ddraw.dll",
393         "Both"
394     },
395     {   &CLSID_DirectDrawClipper,
396         "DirectDraw Clipper Object",
397         NULL,
398         "ddraw.dll",
399         "Both"
400     },
401     { NULL }                    /* list terminator */
402 };
403
404 /***********************************************************************
405  *              interface list
406  */
407
408 static struct regsvr_interface const interface_list[] = {
409     { NULL }                    /* list terminator */
410 };
411
412 /***********************************************************************
413  *              DllRegisterServer (DDRAW.@)
414  */
415 HRESULT WINAPI DllRegisterServer(void)
416 {
417     HRESULT hr;
418
419     TRACE("\n");
420
421     hr = register_coclasses(coclass_list);
422     if (SUCCEEDED(hr))
423         hr = register_interfaces(interface_list);
424     return hr;
425 }
426
427 /***********************************************************************
428  *              DllUnregisterServer (DDRAW.@)
429  */
430 HRESULT WINAPI DllUnregisterServer(void)
431 {
432     HRESULT hr;
433
434     HMODULE advapi32 = GetModuleHandleA("advapi32");
435     if (!advapi32) return E_FAIL;
436     pRegDeleteTreeA = (void *) GetProcAddress(advapi32, "RegDeleteTreeA");
437     pRegDeleteTreeW = (void *) GetProcAddress(advapi32, "RegDeleteTreeW");
438     if (!pRegDeleteTreeA || !pRegDeleteTreeW) return E_FAIL;
439
440     TRACE("\n");
441
442     hr = unregister_coclasses(coclass_list);
443     if (SUCCEEDED(hr))
444         hr = unregister_interfaces(interface_list);
445     return hr;
446 }