2 * self-registerable dll functions for dinput.dll
4 * Copyright (C) 2003 John K. Hohm
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.
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.
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
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
38 * Near the bottom of this file are the exported DllRegisterServer and
39 * DllUnregisterServer, which make all this worthwhile.
42 /***********************************************************************
43 * interface for self-registering
45 struct regsvr_interface
47 IID const *iid; /* NULL for end of list */
48 LPCSTR name; /* can be NULL to omit */
49 IID const *base_iid; /* can be NULL to omit */
50 int num_methods; /* can be <0 to omit */
51 CLSID const *ps_clsid; /* can be NULL to omit */
52 CLSID const *ps_clsid32; /* can be NULL to omit */
55 static HRESULT register_interfaces(struct regsvr_interface const *list);
56 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
60 CLSID const *clsid; /* NULL for end of list */
61 LPCSTR name; /* can be NULL to omit */
62 LPCSTR ips; /* can be NULL to omit */
63 LPCSTR ips32; /* can be NULL to omit */
64 LPCSTR ips32_tmodel; /* can be NULL to omit */
65 LPCSTR progid; /* can be NULL to omit */
66 LPCSTR viprogid; /* can be NULL to omit */
67 LPCSTR progid_extra; /* can be NULL to omit */
70 static HRESULT register_coclasses(struct regsvr_coclass const *list);
71 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
73 /***********************************************************************
74 * static string constants
76 static WCHAR const interface_keyname[10] = {
77 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
78 static WCHAR const base_ifa_keyname[14] = {
79 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
81 static WCHAR const num_methods_keyname[11] = {
82 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
83 static WCHAR const ps_clsid_keyname[15] = {
84 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
86 static WCHAR const ps_clsid32_keyname[17] = {
87 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
88 'i', 'd', '3', '2', 0 };
89 static WCHAR const clsid_keyname[6] = {
90 'C', 'L', 'S', 'I', 'D', 0 };
91 static WCHAR const curver_keyname[7] = {
92 'C', 'u', 'r', 'V', 'e', 'r', 0 };
93 static WCHAR const ips_keyname[13] = {
94 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
96 static WCHAR const ips32_keyname[15] = {
97 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
99 static WCHAR const progid_keyname[7] = {
100 'P', 'r', 'o', 'g', 'I', 'D', 0 };
101 static WCHAR const viprogid_keyname[25] = {
102 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
103 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
105 static char const tmodel_valuename[] = "ThreadingModel";
107 /***********************************************************************
108 * static helper functions
110 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
111 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
113 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
115 static LONG register_progid(WCHAR const *clsid,
116 char const *progid, char const *curver_progid,
117 char const *name, char const *extra);
118 static LONG recursive_delete_key(HKEY key);
119 static LONG recursive_delete_keyA(HKEY base, char const *name);
120 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
122 /***********************************************************************
123 * register_interfaces
125 static HRESULT register_interfaces(struct regsvr_interface const *list)
127 LONG res = ERROR_SUCCESS;
130 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
131 KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
132 if (res != ERROR_SUCCESS) goto error_return;
134 for (; res == ERROR_SUCCESS && list->iid; ++list) {
138 StringFromGUID2(list->iid, buf, 39);
139 res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
140 KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
141 if (res != ERROR_SUCCESS) goto error_close_interface_key;
144 res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
145 (CONST BYTE*)(list->name),
146 strlen(list->name) + 1);
147 if (res != ERROR_SUCCESS) goto error_close_iid_key;
150 if (list->base_iid) {
151 res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
152 if (res != ERROR_SUCCESS) goto error_close_iid_key;
155 if (0 <= list->num_methods) {
156 static WCHAR const fmt[3] = { '%', 'd', 0 };
159 res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
160 KEY_READ | KEY_WRITE, NULL, &key, NULL);
161 if (res != ERROR_SUCCESS) goto error_close_iid_key;
163 wsprintfW(buf, fmt, list->num_methods);
164 res = RegSetValueExW(key, NULL, 0, REG_SZ,
166 (lstrlenW(buf) + 1) * sizeof(WCHAR));
169 if (res != ERROR_SUCCESS) goto error_close_iid_key;
172 if (list->ps_clsid) {
173 res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
174 if (res != ERROR_SUCCESS) goto error_close_iid_key;
177 if (list->ps_clsid32) {
178 res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
179 if (res != ERROR_SUCCESS) goto error_close_iid_key;
183 RegCloseKey(iid_key);
186 error_close_interface_key:
187 RegCloseKey(interface_key);
189 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
192 /***********************************************************************
193 * unregister_interfaces
195 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
197 LONG res = ERROR_SUCCESS;
200 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
201 KEY_READ | KEY_WRITE, &interface_key);
202 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
203 if (res != ERROR_SUCCESS) goto error_return;
205 for (; res == ERROR_SUCCESS && list->iid; ++list) {
208 StringFromGUID2(list->iid, buf, 39);
209 res = recursive_delete_keyW(interface_key, buf);
212 RegCloseKey(interface_key);
214 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
217 /***********************************************************************
220 static HRESULT register_coclasses(struct regsvr_coclass const *list)
222 LONG res = ERROR_SUCCESS;
225 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
226 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
227 if (res != ERROR_SUCCESS) goto error_return;
229 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
233 StringFromGUID2(list->clsid, buf, 39);
234 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
235 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
236 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
239 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
240 (CONST BYTE*)(list->name),
241 strlen(list->name) + 1);
242 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
246 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
247 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
253 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
254 KEY_READ | KEY_WRITE, NULL,
256 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
258 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
259 (CONST BYTE*)list->ips32,
260 lstrlenA(list->ips32) + 1);
261 if (res == ERROR_SUCCESS && list->ips32_tmodel)
262 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
263 (CONST BYTE*)list->ips32_tmodel,
264 strlen(list->ips32_tmodel) + 1);
265 RegCloseKey(ips32_key);
266 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
270 res = register_key_defvalueA(clsid_key, progid_keyname,
272 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
274 res = register_progid(buf, list->progid, NULL,
275 list->name, list->progid_extra);
276 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
279 if (list->viprogid) {
280 res = register_key_defvalueA(clsid_key, viprogid_keyname,
282 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
284 res = register_progid(buf, list->viprogid, list->progid,
285 list->name, list->progid_extra);
286 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
289 error_close_clsid_key:
290 RegCloseKey(clsid_key);
293 error_close_coclass_key:
294 RegCloseKey(coclass_key);
296 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
299 /***********************************************************************
300 * unregister_coclasses
302 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
304 LONG res = ERROR_SUCCESS;
307 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
308 KEY_READ | KEY_WRITE, &coclass_key);
309 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
310 if (res != ERROR_SUCCESS) goto error_return;
312 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
315 StringFromGUID2(list->clsid, buf, 39);
316 res = recursive_delete_keyW(coclass_key, buf);
317 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
320 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
321 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
324 if (list->viprogid) {
325 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
326 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
330 error_close_coclass_key:
331 RegCloseKey(coclass_key);
333 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
336 /***********************************************************************
339 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
343 StringFromGUID2(guid, buf, 39);
344 return register_key_defvalueW(base, name, buf);
347 /***********************************************************************
348 * regsvr_key_defvalueW
350 static LONG register_key_defvalueW(
358 res = RegCreateKeyExW(base, name, 0, NULL, 0,
359 KEY_READ | KEY_WRITE, NULL, &key, NULL);
360 if (res != ERROR_SUCCESS) return res;
361 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
362 (lstrlenW(value) + 1) * sizeof(WCHAR));
367 /***********************************************************************
368 * regsvr_key_defvalueA
370 static LONG register_key_defvalueA(
378 res = RegCreateKeyExW(base, name, 0, NULL, 0,
379 KEY_READ | KEY_WRITE, NULL, &key, NULL);
380 if (res != ERROR_SUCCESS) return res;
381 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
382 lstrlenA(value) + 1);
387 /***********************************************************************
390 static LONG register_progid(
393 char const *curver_progid,
400 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
401 NULL, 0, KEY_READ | KEY_WRITE, NULL,
403 if (res != ERROR_SUCCESS) return res;
406 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
407 (CONST BYTE*)name, strlen(name) + 1);
408 if (res != ERROR_SUCCESS) goto error_close_progid_key;
412 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
413 if (res != ERROR_SUCCESS) goto error_close_progid_key;
417 res = register_key_defvalueA(progid_key, curver_keyname,
419 if (res != ERROR_SUCCESS) goto error_close_progid_key;
425 res = RegCreateKeyExA(progid_key, extra, 0,
426 NULL, 0, KEY_READ | KEY_WRITE, NULL,
428 if (res == ERROR_SUCCESS)
429 RegCloseKey(extra_key);
432 error_close_progid_key:
433 RegCloseKey(progid_key);
437 /***********************************************************************
438 * recursive_delete_key
440 static LONG recursive_delete_key(HKEY key)
443 WCHAR subkey_name[MAX_PATH];
448 cName = sizeof(subkey_name) / sizeof(WCHAR);
449 res = RegEnumKeyExW(key, 0, subkey_name, &cName,
450 NULL, NULL, NULL, NULL);
451 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
452 res = ERROR_SUCCESS; /* presumably we're done enumerating */
455 res = RegOpenKeyExW(key, subkey_name, 0,
456 KEY_READ | KEY_WRITE, &subkey);
457 if (res == ERROR_FILE_NOT_FOUND) continue;
458 if (res != ERROR_SUCCESS) break;
460 res = recursive_delete_key(subkey);
462 if (res != ERROR_SUCCESS) break;
465 if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
469 /***********************************************************************
470 * recursive_delete_keyA
472 static LONG recursive_delete_keyA(HKEY base, char const *name)
477 res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
478 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
479 if (res != ERROR_SUCCESS) return res;
480 res = recursive_delete_key(key);
485 /***********************************************************************
486 * recursive_delete_keyW
488 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
493 res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
494 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
495 if (res != ERROR_SUCCESS) return res;
496 res = recursive_delete_key(key);
501 /***********************************************************************
504 static struct regsvr_coclass const coclass_list[] = {
507 "DirectInput Object",
513 &CLSID_DirectInputDevice,
514 "DirectInputDevice Object",
519 { NULL } /* list terminator */
522 /***********************************************************************
526 static struct regsvr_interface const interface_list[] = {
527 { NULL } /* list terminator */
530 /***********************************************************************
531 * DllRegisterServer (DINPUT.@)
533 HRESULT WINAPI DllRegisterServer(void)
539 hr = register_coclasses(coclass_list);
541 hr = register_interfaces(interface_list);
545 /***********************************************************************
546 * DllUnregisterServer (DINPUT.@)
548 HRESULT WINAPI DllUnregisterServer(void)
554 hr = unregister_coclasses(coclass_list);
556 hr = unregister_interfaces(interface_list);