ASIO to JACK driver for WINE
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

594 lines
17KB

  1. /*
  2. * self-registerable dll functions for wineasio.dll
  3. *
  4. * Copyright (C) 2003 John K. Hohm
  5. * Copyright (C) 2006 Robert Reif
  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. #include <stdarg.h>
  22. #define NONAMELESSSTRUCT
  23. #define NONAMELESSUNION
  24. #include "windef.h"
  25. #include "winbase.h"
  26. #include "winuser.h"
  27. #include "winreg.h"
  28. #include "objbase.h"
  29. #ifdef DEBUG
  30. #include "wine/debug.h"
  31. #endif
  32. /* WINE_DEFAULT_DEBUG_CHANNEL(asio); */
  33. /*
  34. * Near the bottom of this file are the exported DllRegisterServer and
  35. * DllUnregisterServer, which make all this worthwhile.
  36. */
  37. /***********************************************************************
  38. * interface for self-registering
  39. */
  40. struct regsvr_interface
  41. {
  42. IID const *iid; /* NULL for end of list */
  43. LPCSTR name; /* can be NULL to omit */
  44. IID const *base_iid; /* can be NULL to omit */
  45. int num_methods; /* can be <0 to omit */
  46. CLSID const *ps_clsid; /* can be NULL to omit */
  47. CLSID const *ps_clsid32; /* can be NULL to omit */
  48. };
  49. static HRESULT register_interfaces(struct regsvr_interface const *list);
  50. static HRESULT unregister_interfaces(struct regsvr_interface const *list);
  51. struct regsvr_coclass
  52. {
  53. CLSID const *clsid; /* NULL for end of list */
  54. LPCSTR name; /* can be NULL to omit */
  55. LPCSTR ips; /* can be NULL to omit */
  56. LPCSTR ips32; /* can be NULL to omit */
  57. LPCSTR ips32_tmodel; /* can be NULL to omit */
  58. LPCSTR progid; /* can be NULL to omit */
  59. LPCSTR viprogid; /* can be NULL to omit */
  60. LPCSTR progid_extra; /* can be NULL to omit */
  61. };
  62. static HRESULT register_coclasses(struct regsvr_coclass const *list);
  63. static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
  64. /***********************************************************************
  65. * static string constants
  66. */
  67. static WCHAR const interface_keyname[10] = {
  68. 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
  69. static WCHAR const base_ifa_keyname[14] = {
  70. 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
  71. static WCHAR const num_methods_keyname[11] = {
  72. 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
  73. static WCHAR const ps_clsid_keyname[15] = {
  74. 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', 'i', 'd', 0 };
  75. static WCHAR const ps_clsid32_keyname[17] = {
  76. 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', 'i', 'd', '3', '2', 0 };
  77. static WCHAR const clsid_keyname[6] = {
  78. 'C', 'L', 'S', 'I', 'D', 0 };
  79. static WCHAR const curver_keyname[7] = {
  80. 'C', 'u', 'r', 'V', 'e', 'r', 0 };
  81. static WCHAR const ips_keyname[13] = {
  82. 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', 0 };
  83. static WCHAR const ips32_keyname[15] = {
  84. 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', '3', '2', 0 };
  85. static WCHAR const progid_keyname[7] = {
  86. 'P', 'r', 'o', 'g', 'I', 'D', 0 };
  87. static WCHAR const viprogid_keyname[25] = {
  88. 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', 0 };
  89. static char const tmodel_valuename[] = "ThreadingModel";
  90. /***********************************************************************
  91. * static helper functions
  92. */
  93. static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
  94. static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
  95. WCHAR const *value);
  96. static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
  97. char const *value);
  98. static LONG register_progid(WCHAR const *clsid,
  99. char const *progid, char const *curver_progid,
  100. char const *name, char const *extra);
  101. static LONG recursive_delete_key(HKEY key);
  102. static LONG recursive_delete_keyA(HKEY base, char const *name);
  103. static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
  104. /***********************************************************************
  105. * register_interfaces
  106. */
  107. static HRESULT register_interfaces(struct regsvr_interface const *list)
  108. {
  109. LONG res = ERROR_SUCCESS;
  110. HKEY interface_key;
  111. res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
  112. KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
  113. if (res != ERROR_SUCCESS) goto error_return;
  114. for (; res == ERROR_SUCCESS && list->iid; ++list) {
  115. WCHAR buf[39];
  116. HKEY iid_key;
  117. StringFromGUID2(list->iid, buf, 39);
  118. res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
  119. KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
  120. if (res != ERROR_SUCCESS) goto error_close_interface_key;
  121. if (list->name) {
  122. res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
  123. (const BYTE*)(list->name),
  124. strlen(list->name) + 1);
  125. if (res != ERROR_SUCCESS) goto error_close_iid_key;
  126. }
  127. if (list->base_iid) {
  128. res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
  129. if (res != ERROR_SUCCESS) goto error_close_iid_key;
  130. }
  131. if (0 <= list->num_methods) {
  132. static WCHAR const fmt[3] = { '%', 'd', 0 };
  133. HKEY key;
  134. res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
  135. KEY_READ | KEY_WRITE, NULL, &key, NULL);
  136. if (res != ERROR_SUCCESS) goto error_close_iid_key;
  137. wsprintfW(buf, fmt, list->num_methods);
  138. res = RegSetValueExW(key, NULL, 0, REG_SZ,
  139. (const BYTE*)buf,
  140. (lstrlenW(buf) + 1) * sizeof(WCHAR));
  141. RegCloseKey(key);
  142. if (res != ERROR_SUCCESS) goto error_close_iid_key;
  143. }
  144. if (list->ps_clsid) {
  145. res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
  146. if (res != ERROR_SUCCESS) goto error_close_iid_key;
  147. }
  148. if (list->ps_clsid32) {
  149. res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
  150. if (res != ERROR_SUCCESS) goto error_close_iid_key;
  151. }
  152. error_close_iid_key:
  153. RegCloseKey(iid_key);
  154. }
  155. error_close_interface_key:
  156. RegCloseKey(interface_key);
  157. error_return:
  158. return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
  159. }
  160. /***********************************************************************
  161. * unregister_interfaces
  162. */
  163. static HRESULT unregister_interfaces(struct regsvr_interface const *list)
  164. {
  165. LONG res = ERROR_SUCCESS;
  166. HKEY interface_key;
  167. res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
  168. KEY_READ | KEY_WRITE, &interface_key);
  169. if (res == ERROR_FILE_NOT_FOUND) return S_OK;
  170. if (res != ERROR_SUCCESS) goto error_return;
  171. for (; res == ERROR_SUCCESS && list->iid; ++list) {
  172. WCHAR buf[39];
  173. StringFromGUID2(list->iid, buf, 39);
  174. res = recursive_delete_keyW(interface_key, buf);
  175. }
  176. RegCloseKey(interface_key);
  177. error_return:
  178. return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
  179. }
  180. /***********************************************************************
  181. * register_coclasses
  182. */
  183. static HRESULT register_coclasses(struct regsvr_coclass const *list)
  184. {
  185. LONG res = ERROR_SUCCESS;
  186. HKEY coclass_key;
  187. res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
  188. KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
  189. if (res != ERROR_SUCCESS) goto error_return;
  190. for (; res == ERROR_SUCCESS && list->clsid; ++list) {
  191. WCHAR buf[39];
  192. HKEY clsid_key;
  193. StringFromGUID2(list->clsid, buf, 39);
  194. res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
  195. KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
  196. if (res != ERROR_SUCCESS) goto error_close_coclass_key;
  197. if (list->name) {
  198. res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
  199. (const BYTE*)(list->name),
  200. strlen(list->name) + 1);
  201. if (res != ERROR_SUCCESS) goto error_close_clsid_key;
  202. }
  203. if (list->ips) {
  204. res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
  205. if (res != ERROR_SUCCESS) goto error_close_clsid_key;
  206. }
  207. if (list->ips32) {
  208. HKEY ips32_key;
  209. res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
  210. KEY_READ | KEY_WRITE, NULL,
  211. &ips32_key, NULL);
  212. if (res != ERROR_SUCCESS) goto error_close_clsid_key;
  213. res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
  214. (const BYTE*)list->ips32,
  215. lstrlenA(list->ips32) + 1);
  216. if (res == ERROR_SUCCESS && list->ips32_tmodel)
  217. res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
  218. (const BYTE*)list->ips32_tmodel,
  219. strlen(list->ips32_tmodel) + 1);
  220. RegCloseKey(ips32_key);
  221. if (res != ERROR_SUCCESS) goto error_close_clsid_key;
  222. }
  223. if (list->progid) {
  224. res = register_key_defvalueA(clsid_key, progid_keyname,
  225. list->progid);
  226. if (res != ERROR_SUCCESS) goto error_close_clsid_key;
  227. res = register_progid(buf, list->progid, NULL,
  228. list->name, list->progid_extra);
  229. if (res != ERROR_SUCCESS) goto error_close_clsid_key;
  230. }
  231. if (list->viprogid) {
  232. res = register_key_defvalueA(clsid_key, viprogid_keyname,
  233. list->viprogid);
  234. if (res != ERROR_SUCCESS) goto error_close_clsid_key;
  235. res = register_progid(buf, list->viprogid, list->progid,
  236. list->name, list->progid_extra);
  237. if (res != ERROR_SUCCESS) goto error_close_clsid_key;
  238. }
  239. error_close_clsid_key:
  240. RegCloseKey(clsid_key);
  241. }
  242. error_close_coclass_key:
  243. RegCloseKey(coclass_key);
  244. error_return:
  245. return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
  246. }
  247. /***********************************************************************
  248. * unregister_coclasses
  249. */
  250. static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
  251. {
  252. LONG res = ERROR_SUCCESS;
  253. HKEY coclass_key;
  254. res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
  255. KEY_READ | KEY_WRITE, &coclass_key);
  256. if (res == ERROR_FILE_NOT_FOUND) return S_OK;
  257. if (res != ERROR_SUCCESS) goto error_return;
  258. for (; res == ERROR_SUCCESS && list->clsid; ++list) {
  259. WCHAR buf[39];
  260. StringFromGUID2(list->clsid, buf, 39);
  261. res = recursive_delete_keyW(coclass_key, buf);
  262. if (res != ERROR_SUCCESS) goto error_close_coclass_key;
  263. if (list->progid) {
  264. res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
  265. if (res != ERROR_SUCCESS) goto error_close_coclass_key;
  266. }
  267. if (list->viprogid) {
  268. res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
  269. if (res != ERROR_SUCCESS) goto error_close_coclass_key;
  270. }
  271. }
  272. error_close_coclass_key:
  273. RegCloseKey(coclass_key);
  274. error_return:
  275. return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
  276. }
  277. /***********************************************************************
  278. * regsvr_key_guid
  279. */
  280. static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
  281. {
  282. WCHAR buf[39];
  283. StringFromGUID2(guid, buf, 39);
  284. return register_key_defvalueW(base, name, buf);
  285. }
  286. /***********************************************************************
  287. * regsvr_key_defvalueW
  288. */
  289. static LONG register_key_defvalueW(
  290. HKEY base,
  291. WCHAR const *name,
  292. WCHAR const *value)
  293. {
  294. LONG res;
  295. HKEY key;
  296. res = RegCreateKeyExW(base, name, 0, NULL, 0,
  297. KEY_READ | KEY_WRITE, NULL, &key, NULL);
  298. if (res != ERROR_SUCCESS) return res;
  299. res = RegSetValueExW(key, NULL, 0, REG_SZ, (const BYTE*)value,
  300. (lstrlenW(value) + 1) * sizeof(WCHAR));
  301. RegCloseKey(key);
  302. return res;
  303. }
  304. /***********************************************************************
  305. * regsvr_key_defvalueA
  306. */
  307. static LONG register_key_defvalueA(
  308. HKEY base,
  309. WCHAR const *name,
  310. char const *value)
  311. {
  312. LONG res;
  313. HKEY key;
  314. res = RegCreateKeyExW(base, name, 0, NULL, 0,
  315. KEY_READ | KEY_WRITE, NULL, &key, NULL);
  316. if (res != ERROR_SUCCESS) return res;
  317. res = RegSetValueExA(key, NULL, 0, REG_SZ, (const BYTE*)value,
  318. lstrlenA(value) + 1);
  319. RegCloseKey(key);
  320. return res;
  321. }
  322. /***********************************************************************
  323. * regsvr_progid
  324. */
  325. static LONG register_progid(
  326. WCHAR const *clsid,
  327. char const *progid,
  328. char const *curver_progid,
  329. char const *name,
  330. char const *extra)
  331. {
  332. LONG res;
  333. HKEY progid_key;
  334. res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
  335. NULL, 0, KEY_READ | KEY_WRITE, NULL,
  336. &progid_key, NULL);
  337. if (res != ERROR_SUCCESS) return res;
  338. if (name) {
  339. res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
  340. (const BYTE*)name, strlen(name) + 1);
  341. if (res != ERROR_SUCCESS) goto error_close_progid_key;
  342. }
  343. if (clsid) {
  344. res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
  345. if (res != ERROR_SUCCESS) goto error_close_progid_key;
  346. }
  347. if (curver_progid) {
  348. res = register_key_defvalueA(progid_key, curver_keyname,
  349. curver_progid);
  350. if (res != ERROR_SUCCESS) goto error_close_progid_key;
  351. }
  352. if (extra) {
  353. HKEY extra_key;
  354. res = RegCreateKeyExA(progid_key, extra, 0,
  355. NULL, 0, KEY_READ | KEY_WRITE, NULL,
  356. &extra_key, NULL);
  357. if (res == ERROR_SUCCESS)
  358. RegCloseKey(extra_key);
  359. }
  360. error_close_progid_key:
  361. RegCloseKey(progid_key);
  362. return res;
  363. }
  364. /***********************************************************************
  365. * recursive_delete_key
  366. */
  367. static LONG recursive_delete_key(HKEY key)
  368. {
  369. LONG res;
  370. WCHAR subkey_name[MAX_PATH];
  371. DWORD cName;
  372. HKEY subkey;
  373. for (;;) {
  374. cName = sizeof(subkey_name) / sizeof(WCHAR);
  375. res = RegEnumKeyExW(key, 0, subkey_name, &cName,
  376. NULL, NULL, NULL, NULL);
  377. if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
  378. res = ERROR_SUCCESS; /* presumably we're done enumerating */
  379. break;
  380. }
  381. res = RegOpenKeyExW(key, subkey_name, 0,
  382. KEY_READ | KEY_WRITE, &subkey);
  383. if (res == ERROR_FILE_NOT_FOUND) continue;
  384. if (res != ERROR_SUCCESS) break;
  385. res = recursive_delete_key(subkey);
  386. RegCloseKey(subkey);
  387. if (res != ERROR_SUCCESS) break;
  388. }
  389. if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
  390. return res;
  391. }
  392. /***********************************************************************
  393. * recursive_delete_keyA
  394. */
  395. static LONG recursive_delete_keyA(HKEY base, char const *name)
  396. {
  397. LONG res;
  398. HKEY key;
  399. res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
  400. if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
  401. if (res != ERROR_SUCCESS) return res;
  402. res = recursive_delete_key(key);
  403. RegCloseKey(key);
  404. return res;
  405. }
  406. /***********************************************************************
  407. * recursive_delete_keyW
  408. */
  409. static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
  410. {
  411. LONG res;
  412. HKEY key;
  413. res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
  414. if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
  415. if (res != ERROR_SUCCESS) return res;
  416. res = recursive_delete_key(key);
  417. RegCloseKey(key);
  418. return res;
  419. }
  420. /***********************************************************************
  421. * coclass list
  422. */
  423. // {48D0C522-BFCC-45cc-8B84-17F25F33E6E9}
  424. static GUID const CLSID_WineASIO = {
  425. 0x48d0c522, 0xbfcc, 0x45cc, { 0x8b, 0x84, 0x17, 0xf2, 0x5f, 0x33, 0xe6, 0xe9 } };
  426. static struct regsvr_coclass const coclass_list[] = {
  427. { &CLSID_WineASIO, "MOD Desktop ASIO Object", NULL, "mod-desktop-asio.dll", "Apartment" },
  428. { NULL } /* list terminator */
  429. };
  430. /***********************************************************************
  431. * interface list
  432. */
  433. static struct regsvr_interface const interface_list[] = {
  434. { NULL } /* list terminator */
  435. };
  436. /***********************************************************************
  437. * register driver
  438. */
  439. static HRESULT register_driver(void)
  440. {
  441. LPCSTR asio_key = "Software\\ASIO\\MOD Desktop";
  442. LPCSTR clsid = "CLSID";
  443. LPCSTR wine_clsid = "{48D0C522-BFCC-45CC-8B84-17F25F33E6E9}";
  444. LPCSTR desc = "Description";
  445. LPCSTR wine_desc = "MOD Desktop";
  446. HKEY key;
  447. LONG rc;
  448. rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, asio_key, 0, KEY_READ | KEY_WRITE, &key);
  449. if (rc != ERROR_SUCCESS)
  450. rc = RegCreateKeyExA(HKEY_LOCAL_MACHINE, asio_key, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &key, 0);
  451. if (rc == ERROR_SUCCESS)
  452. {
  453. rc = RegSetValueExA(key, clsid, 0, REG_SZ, (const BYTE *)wine_clsid, strlen(wine_clsid) + 1);
  454. if (rc == ERROR_SUCCESS)
  455. rc = RegSetValueExA(key, desc, 0, REG_SZ, (const BYTE *)wine_desc, strlen(wine_desc) + 1);
  456. RegCloseKey(key);
  457. }
  458. return rc;
  459. }
  460. /***********************************************************************
  461. * DllRegisterServer (wineasio.@)
  462. */
  463. HRESULT WINAPI DllRegisterServer(void)
  464. {
  465. HRESULT hr;
  466. /* TRACE("\n"); */
  467. hr = register_coclasses(coclass_list);
  468. if (SUCCEEDED(hr))
  469. {
  470. hr = register_interfaces(interface_list);
  471. if (SUCCEEDED(hr))
  472. hr = register_driver();
  473. }
  474. return hr;
  475. }
  476. /***********************************************************************
  477. * register driver
  478. */
  479. static HRESULT unregister_driver(void)
  480. {
  481. LPCSTR asio_key = "Software\\ASIO\\MOD Desktop";
  482. /* FIXME */
  483. return recursive_delete_keyA(HKEY_LOCAL_MACHINE, asio_key);
  484. }
  485. /***********************************************************************
  486. * DllUnregisterServer (wineasio.@)
  487. */
  488. HRESULT WINAPI DllUnregisterServer(void)
  489. {
  490. HRESULT hr;
  491. /* TRACE("\n"); */
  492. hr = unregister_coclasses(coclass_list);
  493. if (SUCCEEDED(hr))
  494. {
  495. hr = unregister_interfaces(interface_list);
  496. if (SUCCEEDED(hr))
  497. hr = unregister_driver();
  498. }
  499. return hr;
  500. }