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.

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