ntdll: Move the LDT section to ntdll and make it an uninterruptible section.
[wine] / dlls / ddrawex / regsvr.c
1 /*
2  *      self-registerable dll functions for ddrawex.dll
3  *
4  * Copyright (C) 2003 John K. Hohm
5  * Copyright (C) 2007 Francois Gouget for CodeWeavers
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 "winreg.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winerror.h"
31
32 #include "ddraw.h"
33 #include "ddrawex_private.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
38
39 /*
40  * Near the bottom of this file are the exported DllRegisterServer and
41  * DllUnregisterServer, which make all this worthwhile.
42  */
43
44 /***********************************************************************
45  *              interface for self-registering
46  */
47
48 struct regsvr_coclass
49 {
50     CLSID const *clsid;         /* NULL for end of list */
51     LPCSTR name;                /* can be NULL to omit */
52     LPCSTR ips;                 /* can be NULL to omit */
53     LPCSTR ips32;               /* can be NULL to omit */
54     LPCSTR ips32_tmodel;        /* can be NULL to omit */
55     LPCSTR clsid_str;           /* can be NULL to omit */
56     LPCSTR progid;              /* can be NULL to omit */
57 };
58
59 static HRESULT register_coclasses(struct regsvr_coclass const *list);
60 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
61
62 /***********************************************************************
63  *              static string constants
64  */
65 static WCHAR const interface_keyname[10] = {
66     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
67 static WCHAR const base_ifa_keyname[14] = {
68     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
69     'e', 0 };
70 static WCHAR const num_methods_keyname[11] = {
71     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
72 static WCHAR const ps_clsid_keyname[15] = {
73     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
74     'i', 'd', 0 };
75 static WCHAR const ps_clsid32_keyname[17] = {
76     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
77     'i', 'd', '3', '2', 0 };
78 static WCHAR const clsid_keyname[6] = {
79     'C', 'L', 'S', 'I', 'D', 0 };
80 static WCHAR const ips_keyname[13] = {
81     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
82     0 };
83 static WCHAR const ips32_keyname[15] = {
84     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
85     '3', '2', 0 };
86 static WCHAR const progid_keyname[7] = {
87     'P', 'r', 'o', 'g', 'I', 'D', 0 };
88 static char const tmodel_valuename[] = "ThreadingModel";
89
90 /***********************************************************************
91  *              static helper functions
92  */
93 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
94                                    WCHAR const *value);
95 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
96                                    char const *value);
97 static LONG recursive_delete_key(HKEY key);
98 static LONG recursive_delete_keyA(HKEY base, char const *name);
99 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
100
101 /***********************************************************************
102  *              register_coclasses
103  */
104 static HRESULT register_coclasses(struct regsvr_coclass const *list)
105 {
106     LONG res = ERROR_SUCCESS;
107     HKEY coclass_key;
108
109     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
110                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
111     if (res != ERROR_SUCCESS) goto error_return;
112
113     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
114         WCHAR buf[39];
115         HKEY clsid_key;
116
117         StringFromGUID2(list->clsid, buf, 39);
118         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
119                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
120         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
121
122         if (list->name) {
123             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
124                                  (CONST BYTE*)(list->name),
125                                  strlen(list->name) + 1);
126             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
127         }
128
129         if (list->ips) {
130             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
131             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
132         }
133
134         if (list->ips32) {
135             HKEY ips32_key;
136
137             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
138                                   KEY_READ | KEY_WRITE, NULL,
139                                   &ips32_key, NULL);
140             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
141
142             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
143                                  (CONST BYTE*)list->ips32,
144                                  lstrlenA(list->ips32) + 1);
145             if (res == ERROR_SUCCESS && list->ips32_tmodel)
146                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
147                                      (CONST BYTE*)list->ips32_tmodel,
148                                      strlen(list->ips32_tmodel) + 1);
149             RegCloseKey(ips32_key);
150             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
151         }
152
153         if (list->clsid_str) {
154             res = register_key_defvalueA(clsid_key, clsid_keyname,
155                                          list->clsid_str);
156             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
157         }
158
159         if (list->progid) {
160             HKEY progid_key;
161
162             res = register_key_defvalueA(clsid_key, progid_keyname,
163                                          list->progid);
164             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
165
166             res = RegCreateKeyExA(HKEY_CLASSES_ROOT, list->progid, 0,
167                                   NULL, 0, KEY_READ | KEY_WRITE, NULL,
168                                   &progid_key, NULL);
169             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
170
171             res = register_key_defvalueW(progid_key, clsid_keyname, buf);
172             RegCloseKey(progid_key);
173             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
174         }
175
176     error_close_clsid_key:
177         RegCloseKey(clsid_key);
178     }
179
180 error_close_coclass_key:
181     RegCloseKey(coclass_key);
182 error_return:
183     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
184 }
185
186 /***********************************************************************
187  *              unregister_coclasses
188  */
189 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
190 {
191     LONG res = ERROR_SUCCESS;
192     HKEY coclass_key;
193
194     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
195                         KEY_READ | KEY_WRITE, &coclass_key);
196     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
197     if (res != ERROR_SUCCESS) goto error_return;
198
199     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
200         WCHAR buf[39];
201
202         StringFromGUID2(list->clsid, buf, 39);
203         res = recursive_delete_keyW(coclass_key, buf);
204         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
205
206         if (list->progid) {
207             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
208             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
209         }
210     }
211
212 error_close_coclass_key:
213     RegCloseKey(coclass_key);
214 error_return:
215     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
216 }
217
218 /***********************************************************************
219  *              regsvr_key_defvalueW
220  */
221 static LONG register_key_defvalueW(
222     HKEY base,
223     WCHAR const *name,
224     WCHAR const *value)
225 {
226     LONG res;
227     HKEY key;
228
229     res = RegCreateKeyExW(base, name, 0, NULL, 0,
230                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
231     if (res != ERROR_SUCCESS) return res;
232     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
233                          (lstrlenW(value) + 1) * sizeof(WCHAR));
234     RegCloseKey(key);
235     return res;
236 }
237
238 /***********************************************************************
239  *              regsvr_key_defvalueA
240  */
241 static LONG register_key_defvalueA(
242     HKEY base,
243     WCHAR const *name,
244     char const *value)
245 {
246     LONG res;
247     HKEY key;
248
249     res = RegCreateKeyExW(base, name, 0, NULL, 0,
250                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
251     if (res != ERROR_SUCCESS) return res;
252     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
253                          lstrlenA(value) + 1);
254     RegCloseKey(key);
255     return res;
256 }
257
258 /***********************************************************************
259  *              recursive_delete_key
260  */
261 static LONG recursive_delete_key(HKEY key)
262 {
263     LONG res;
264     WCHAR subkey_name[MAX_PATH];
265     DWORD cName;
266     HKEY subkey;
267
268     for (;;) {
269         cName = sizeof(subkey_name) / sizeof(WCHAR);
270         res = RegEnumKeyExW(key, 0, subkey_name, &cName,
271                             NULL, NULL, NULL, NULL);
272         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
273             res = ERROR_SUCCESS; /* presumably we're done enumerating */
274             break;
275         }
276         res = RegOpenKeyExW(key, subkey_name, 0,
277                             KEY_READ | KEY_WRITE, &subkey);
278         if (res == ERROR_FILE_NOT_FOUND) continue;
279         if (res != ERROR_SUCCESS) break;
280
281         res = recursive_delete_key(subkey);
282         RegCloseKey(subkey);
283         if (res != ERROR_SUCCESS) break;
284     }
285
286     if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
287     return res;
288 }
289
290 /***********************************************************************
291  *              recursive_delete_keyA
292  */
293 static LONG recursive_delete_keyA(HKEY base, char const *name)
294 {
295     LONG res;
296     HKEY key;
297
298     res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
299     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
300     if (res != ERROR_SUCCESS) return res;
301     res = recursive_delete_key(key);
302     RegCloseKey(key);
303     return res;
304 }
305
306 /***********************************************************************
307  *              recursive_delete_keyW
308  */
309 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
310 {
311     LONG res;
312     HKEY key;
313
314     res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
315     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
316     if (res != ERROR_SUCCESS) return res;
317     res = recursive_delete_key(key);
318     RegCloseKey(key);
319     return res;
320 }
321
322 /***********************************************************************
323  *              coclass list
324  */
325
326 static struct regsvr_coclass const coclass_list[] = {
327     {   &CLSID_DirectDrawFactory,
328         NULL,
329         NULL,
330         "ddrawex.dll",
331         "Both"
332     },
333     { NULL }                    /* list terminator */
334 };
335
336 /***********************************************************************
337  *              DllRegisterServer (DDRAWEX.@)
338  */
339 HRESULT WINAPI DllRegisterServer(void)
340 {
341     HRESULT hr;
342
343     TRACE("\n");
344
345     hr = register_coclasses(coclass_list);
346     return hr;
347 }
348
349 /***********************************************************************
350  *              DllUnregisterServer (DDRAWEX.@)
351  */
352 HRESULT WINAPI DllUnregisterServer(void)
353 {
354     HRESULT hr;
355
356     TRACE("\n");
357
358     hr = unregister_coclasses(coclass_list);
359     return hr;
360 }