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.

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