Source code of Windows XP (NT5)
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.

666 lines
19 KiB

  1. /**********************************************************************
  2. Copyright (c) 1992-1999 Microsoft Corporation
  3. mididev.c
  4. DESCRIPTION:
  5. Code to match device ID's with associated registry entries
  6. HISTORY:
  7. 02/24/95 [jimge] created.
  8. *********************************************************************/
  9. #include <windows.h>
  10. #include <windowsx.h>
  11. #include <winerror.h>
  12. #include <regstr.h>
  13. #include <mmsystem.h>
  14. #include <mmddkp.h>
  15. #include "idf.h"
  16. #include "midimap.h"
  17. #include "debug.h"
  18. typedef struct tagMDEV_NODE *PMDEV_NODE;
  19. typedef struct tagMDEV_NODE
  20. {
  21. PMDEV_NODE pNext;
  22. TCHAR szAlias[CB_MAXALIAS];
  23. DWORD dwDevNode;
  24. TCHAR szDriver[CB_MAXDRIVER];
  25. UINT uDeviceID;
  26. UINT uPort;
  27. BOOL fNewDriver;
  28. } MDEV_NODE;
  29. static TCHAR BCODE gszMediaRsrcKey[] =
  30. REGSTR_PATH_MEDIARESOURCES TEXT ("\\MIDI");
  31. static TCHAR BCODE gszDriverKey[] =
  32. REGSTR_PATH_MEDIARESOURCES TEXT ("\\MIDI\\%s");
  33. static TCHAR BCODE gszDriverValue[] = TEXT ("Driver");
  34. static TCHAR BCODE gszDevNodeValue[] = TEXT ("DevNode");
  35. static TCHAR BCODE gszPortValue[] = TEXT ("Port");
  36. static TCHAR BCODE gszActiveValue[] = TEXT ("Active");
  37. static TCHAR BCODE gszMapperConfig[] = TEXT ("MapperConfig");
  38. static PMDEV_NODE gpMDevList = NULL;
  39. static DWORD gdwNewDrivers = (DWORD)-1L;
  40. PRIVATE BOOL FNLOCAL mdev_BuildRegList(
  41. void);
  42. PRIVATE BOOL FNLOCAL mdev_SyncDeviceIDs(
  43. void);
  44. PRIVATE BOOL FNLOCAL mdev_MarkActiveDrivers(
  45. void);
  46. #ifdef DEBUG
  47. PRIVATE VOID FNLOCAL mdev_ListActiveDrivers(
  48. void);
  49. #endif
  50. BOOL FNGLOBAL mdev_Init(
  51. void)
  52. {
  53. if (gpMDevList)
  54. mdev_Free();
  55. if ((!mdev_BuildRegList()) ||
  56. (!mdev_SyncDeviceIDs()) ||
  57. (!mdev_MarkActiveDrivers()))
  58. {
  59. mdev_Free();
  60. return FALSE;
  61. }
  62. #ifdef DEBUG
  63. mdev_ListActiveDrivers();
  64. #endif
  65. return TRUE;
  66. }
  67. //
  68. // mdev_BuildRegList
  69. //
  70. // Builds the base device list out of the registry
  71. //
  72. // Assumes the list has been cleared
  73. //
  74. // For each alias (key) under MediaResources\MIDI
  75. // Make sure the Active value exists and is '1'
  76. // Allocate a list node
  77. // Try to read the alias's devnode
  78. // If the alias's devnode is 0 or missing,
  79. // Read the alias's driver name
  80. // Read the alias's port number
  81. // Add the alias to the global list
  82. //
  83. // The uDeviceID member will not be initialized by this routine;
  84. // mdev_SyncDeviceIDs must be called to figure out the current
  85. // device ID mapping.
  86. //
  87. PRIVATE BOOL FNLOCAL mdev_BuildRegList(
  88. void)
  89. {
  90. BOOL fRet = FALSE;
  91. HKEY hKeyMediaRsrc = NULL;
  92. HKEY hKeyThisAlias = NULL;
  93. DWORD dwEnumAlias = 0;
  94. LPTSTR pstrAlias = NULL;
  95. PMDEV_NODE pmd = NULL;
  96. TCHAR szActive[2];
  97. DWORD dwPort;
  98. DWORD cbValue;
  99. DWORD dwType;
  100. DWORD dwMapperConfig;
  101. cbValue = CB_MAXALIAS * sizeof(TCHAR);
  102. pstrAlias = (LPTSTR)LocalAlloc(LPTR, CB_MAXALIAS * sizeof(TCHAR));
  103. if (NULL == pstrAlias)
  104. {
  105. DPF(1, TEXT ("mdev_Init: Out of memory"));
  106. goto mBRL_Cleanup;
  107. }
  108. if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,
  109. gszMediaRsrcKey,
  110. &hKeyMediaRsrc))
  111. {
  112. DPF(1, TEXT ("mdev_Init: Could not open ...\\MediaResoruces\\MIDI"));
  113. goto mBRL_Cleanup;
  114. }
  115. while (ERROR_SUCCESS == RegEnumKey(hKeyMediaRsrc,
  116. dwEnumAlias++,
  117. pstrAlias,
  118. CB_MAXALIAS))
  119. {
  120. if (ERROR_SUCCESS != (RegOpenKey(hKeyMediaRsrc,
  121. pstrAlias,
  122. &hKeyThisAlias)))
  123. {
  124. DPF(1, TEXT ("mdev_Init: Could not open enum'ed key %s"), (LPTSTR)pstrAlias);
  125. continue;
  126. }
  127. // MUST have Active == "1" to be running
  128. //
  129. cbValue = sizeof(szActive);
  130. if (ERROR_SUCCESS != (RegQueryValueEx(hKeyThisAlias,
  131. gszActiveValue,
  132. NULL,
  133. &dwType,
  134. (LPSTR)szActive,
  135. &cbValue)) ||
  136. *szActive != '1')
  137. {
  138. DPF(2, TEXT ("mdev_Init: Device %s exists but is not loaded."),
  139. (LPTSTR)pstrAlias);
  140. RegCloseKey(hKeyThisAlias);
  141. continue;
  142. }
  143. // Determine if we have ever configured with this driver before
  144. //
  145. cbValue = sizeof(dwMapperConfig);
  146. if (ERROR_SUCCESS != (RegQueryValueEx(hKeyThisAlias,
  147. gszMapperConfig,
  148. NULL,
  149. &dwType,
  150. (LPSTR)&dwMapperConfig,
  151. &cbValue)))
  152. dwMapperConfig = 0;
  153. #ifdef DEBUG
  154. if (!dwMapperConfig)
  155. DPF(1, TEXT ("Alias '%s' is a new driver."),
  156. (LPTSTR)pstrAlias);
  157. #endif
  158. // We have a running driver, go ahead and alloc a node
  159. // for it
  160. //
  161. pmd = (PMDEV_NODE)LocalAlloc(LPTR, sizeof(*pmd));
  162. if (NULL == pmd)
  163. {
  164. DPF(1, TEXT ("mdev_Init: Out of memory allocating node for %s"),
  165. (LPTSTR)pstrAlias);
  166. RegCloseKey(hKeyThisAlias);
  167. continue;
  168. }
  169. lstrcpyn(pmd->szAlias, pstrAlias, sizeof(pmd->szAlias) - 1);
  170. pmd->szAlias[sizeof(pmd->szAlias) - 1] = '\0';
  171. pmd->fNewDriver = (dwMapperConfig ? FALSE : TRUE);
  172. // Try to get the DevNode value
  173. //
  174. cbValue = sizeof(pmd->dwDevNode);
  175. if (ERROR_SUCCESS != RegQueryValueEx(hKeyThisAlias,
  176. gszDevNodeValue,
  177. NULL,
  178. &dwType,
  179. (LPSTR)(LPDWORD)&pmd->dwDevNode,
  180. &cbValue))
  181. {
  182. // Ok to not have a devnode value, 3.1 drivers don't
  183. //
  184. DPF(2, TEXT ("mdev_Init: Device %s has no devnode; must be 3.1"),
  185. (LPTSTR)pstrAlias);
  186. pmd->dwDevNode = 0;
  187. }
  188. // Leave something reasonable in driver even if we don't
  189. // expect to use it
  190. //
  191. *pmd->szDriver = '\0';
  192. // If we didn't get a devnode or it was 0, and we can't find the
  193. // driver name to match against, we can't use this entry. (If it
  194. // has no ring 3 driver, it can't be running anyway).
  195. //
  196. if (!pmd->dwDevNode)
  197. {
  198. cbValue = sizeof(pmd->szDriver);
  199. if (ERROR_SUCCESS != RegQueryValueEx(
  200. hKeyThisAlias,
  201. gszDriverValue,
  202. NULL,
  203. &dwType,
  204. (LPSTR)pmd->szDriver,
  205. &cbValue))
  206. {
  207. DPF(1, TEXT ("mdev_Init: Device %s has no ring 3 driver entry"),
  208. (LPTSTR)pstrAlias);
  209. LocalFree((HLOCAL)pmd);
  210. RegCloseKey(hKeyThisAlias);
  211. continue;
  212. }
  213. }
  214. // Success! Now try to figure out the port number
  215. //
  216. cbValue = sizeof(dwPort);
  217. // Guard against INF's which only specify a byte's worth of
  218. // port value
  219. //
  220. dwPort = 0;
  221. if (ERROR_SUCCESS != RegQueryValueEx(hKeyThisAlias,
  222. gszPortValue,
  223. NULL,
  224. &dwType,
  225. (LPSTR)(LPDWORD)&dwPort,
  226. &cbValue))
  227. {
  228. DPF(2, TEXT ("mdev_Init: Device %s has no port entry; using 0."),
  229. (LPTSTR)pstrAlias);
  230. dwPort = 0;
  231. }
  232. pmd->uPort = (UINT)dwPort;
  233. // We have a valid node, put it into the list
  234. //
  235. pmd->pNext = gpMDevList;
  236. gpMDevList = pmd;
  237. RegCloseKey(hKeyThisAlias);
  238. }
  239. fRet = TRUE;
  240. mBRL_Cleanup:
  241. if (hKeyMediaRsrc) RegCloseKey(hKeyMediaRsrc);
  242. if (pstrAlias) LocalFree((HLOCAL)pstrAlias);
  243. return fRet;
  244. }
  245. //
  246. // mdev_SyncDeviceIDs
  247. //
  248. // Traverse the device list and bring the uDeviceID members up to date.
  249. // Also remove any devices which MMSYSTEM claims are not really running.
  250. //
  251. // NOTE: The uDeviceID member is actually the device ID of the base driver.
  252. // If you want to open the device, you have to add uDeviceID and uPort for
  253. // the node you want to open.
  254. //
  255. // Set all uDeviceID's to NO_DEVICEID
  256. //
  257. // For each base device ID in MMSYSTEM (i.e. port 0 on each loaded driver)
  258. // Get the matching alias from MMSYSTEM
  259. // Locate the node with that alias in the device list
  260. // Set that node's uDeviceID
  261. //
  262. // For each node in the device list with non-zero port
  263. // If this node has a DevNode
  264. // Find a matching node by DevNode with port == 0 and get its device ID
  265. // else
  266. // Find a matching node by driver name with port == 0 and get its device ID
  267. //
  268. // NOTE: We match by driver name on DevNode == 0 (3.1 devices) because it
  269. // isn't possible to have multiple instances of a 3.1 driver loaded.
  270. //
  271. // For each node in the device list,
  272. // If the node's uDeviceID is still not set,
  273. // Remove and free the node
  274. //
  275. PRIVATE BOOL FNLOCAL mdev_SyncDeviceIDs(
  276. void)
  277. {
  278. BOOL fRet = FALSE;
  279. LPTSTR pstrAlias = NULL;
  280. PMDEV_NODE pmdCurr;
  281. PMDEV_NODE pmdPrev;
  282. PMDEV_NODE pmdEnum;
  283. UINT cDev;
  284. UINT idxDev;
  285. DWORD cPort;
  286. MMRESULT mmr;
  287. DWORD cbSize;
  288. cbSize = CB_MAXALIAS * sizeof(TCHAR);
  289. pstrAlias = (LPTSTR)LocalAlloc(LPTR, cbSize);
  290. if (NULL == pstrAlias)
  291. {
  292. goto mSDI_Cleanup;
  293. }
  294. // The device list has been built and the uPort member is valid.
  295. // Now update the uDeviceID field to be proper. First, walk the list
  296. // and set them all to NO_DEVICEID.
  297. for (pmdCurr = gpMDevList; pmdCurr; pmdCurr = pmdCurr->pNext)
  298. pmdCurr->uDeviceID = NO_DEVICEID;
  299. // Now walk MMSYSTEM's list of loaded drivers and fill in all the port 0
  300. // nodes with their proper device ID
  301. //
  302. cDev = midiOutGetNumDevs();
  303. for (idxDev = 0; idxDev < cDev; )
  304. {
  305. mmr = (MMRESULT)midiOutMessage((HMIDIOUT)(UINT_PTR)idxDev,
  306. #ifdef WINNT
  307. DRV_QUERYNUMPORTS,
  308. #else
  309. MODM_GETNUMDEVS,
  310. #endif // End WINNT
  311. (DWORD_PTR)(LPDWORD)&cPort,
  312. 0);
  313. if (mmr)
  314. {
  315. DPF(1, TEXT ("mdev_Sync: Device ID %u returned %u for MODM_GETNUMDEVS"),
  316. (UINT)idxDev,
  317. (UINT)mmr);
  318. ++idxDev;
  319. continue;
  320. }
  321. mmr = (MMRESULT)midiOutMessage((HMIDIOUT)(UINT_PTR)idxDev,
  322. DRV_QUERYDRVENTRY,
  323. #ifdef WINNT
  324. (DWORD_PTR)(LPTSTR)pstrAlias,
  325. #else
  326. (DWORD_PTR)(LPTSTR)pstrPath,
  327. #endif // End Winnt
  328. CB_MAXALIAS);
  329. if (!mmr)
  330. {
  331. for (pmdCurr = gpMDevList; pmdCurr; pmdCurr = pmdCurr->pNext)
  332. {
  333. if ((0 == pmdCurr->uPort) &&
  334. (! lstrcmpi(pstrAlias, pmdCurr->szAlias)))
  335. {
  336. pmdCurr->uDeviceID = idxDev;
  337. break;
  338. }
  339. }
  340. #ifdef DEBUG
  341. if (!pmdCurr)
  342. {
  343. DPF(1, TEXT ("mdev_Sync: Device ID %u not found in device list."),
  344. (UINT)idxDev);
  345. }
  346. #endif
  347. }
  348. else
  349. {
  350. DPF(1, TEXT ("mdev_Sync: Device ID %u returned %u for DRV_QUERYDRVENTRY"),
  351. (UINT)idxDev,
  352. (UINT)mmr);
  353. }
  354. idxDev += (UINT)cPort;
  355. }
  356. // Now walk the list again. This time we catch all the non-zero ports
  357. // and set their uDeviceID properly.
  358. //
  359. for (pmdCurr = gpMDevList; pmdCurr; pmdCurr = pmdCurr->pNext)
  360. {
  361. if (!pmdCurr->uPort)
  362. continue;
  363. if (pmdCurr->dwDevNode)
  364. {
  365. for (pmdEnum = gpMDevList; pmdEnum; pmdEnum = pmdEnum->pNext)
  366. if (0 == pmdEnum->uPort &&
  367. pmdEnum->dwDevNode == pmdCurr->dwDevNode)
  368. {
  369. pmdCurr->uDeviceID = pmdEnum->uDeviceID;
  370. break;
  371. }
  372. }
  373. else
  374. {
  375. for (pmdEnum = gpMDevList; pmdEnum; pmdEnum = pmdEnum->pNext)
  376. if (0 == pmdEnum->uPort &&
  377. !lstrcmpi(pmdEnum->szDriver, pmdCurr->szDriver))
  378. {
  379. pmdCurr->uDeviceID = pmdEnum->uDeviceID;
  380. break;
  381. }
  382. }
  383. #ifdef DEBUG
  384. if (!pmdEnum)
  385. {
  386. DPF(1, TEXT ("mdev_Sync: No parent driver found for %s"),
  387. (LPTSTR)pmdCurr->szAlias);
  388. }
  389. #endif
  390. }
  391. // Now we walk the list one more time and discard anyone without a device
  392. // ID assigned.
  393. //
  394. pmdPrev = NULL;
  395. pmdCurr = gpMDevList;
  396. while (pmdCurr)
  397. {
  398. if (NO_DEVICEID == pmdCurr->uDeviceID)
  399. {
  400. DPF(1, TEXT ("mdev_Sync: Removing %s; never found a device ID"),
  401. (LPTSTR)pmdCurr->szAlias);
  402. if (pmdPrev)
  403. pmdPrev->pNext = pmdCurr->pNext;
  404. else
  405. gpMDevList = pmdCurr->pNext;
  406. LocalFree((HLOCAL)pmdCurr);
  407. pmdCurr = (pmdPrev ? pmdPrev->pNext : gpMDevList);
  408. }
  409. else
  410. {
  411. pmdPrev = pmdCurr;
  412. pmdCurr = pmdCurr->pNext;
  413. }
  414. }
  415. fRet = TRUE;
  416. mSDI_Cleanup:
  417. if (pstrAlias) LocalFree((HLOCAL)pstrAlias);
  418. return fRet;
  419. }
  420. //
  421. // mdev_MarkActiveDrivers
  422. //
  423. // Mark drivers which are loaded and have not been seen before by
  424. // mapper configuration as seen. Also flag that we want to run
  425. // RunOnce if there are any of these
  426. //
  427. PRIVATE BOOL FNLOCAL mdev_MarkActiveDrivers(
  428. void)
  429. {
  430. BOOL fRet = FALSE;
  431. HKEY hKeyMediaRsrc = NULL;
  432. HKEY hKeyThisAlias = NULL;
  433. DWORD dwMapperConfig;
  434. PMDEV_NODE pmd;
  435. if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,
  436. gszMediaRsrcKey,
  437. &hKeyMediaRsrc))
  438. {
  439. DPF(1, TEXT ("mdev_MarkActiveDrivers: Could not open ")
  440. TEXT ("...\\MediaResources\\MIDI"));
  441. goto mMAD_Cleanup;
  442. }
  443. gdwNewDrivers = 0;
  444. for (pmd = gpMDevList; pmd; pmd = pmd->pNext)
  445. if (pmd->fNewDriver)
  446. {
  447. ++gdwNewDrivers;
  448. // Mark this driver as seen
  449. //
  450. if (ERROR_SUCCESS != (RegOpenKey(hKeyMediaRsrc,
  451. pmd->szAlias,
  452. &hKeyThisAlias)))
  453. {
  454. DPF(1, TEXT ("mdev_MarkActiveDrivers: Could not open alias '%s'"),
  455. (LPTSTR)pmd->szAlias);
  456. goto mMAD_Cleanup;
  457. }
  458. dwMapperConfig = 1;
  459. RegSetValueEx(hKeyThisAlias,
  460. gszMapperConfig,
  461. 0,
  462. REG_DWORD,
  463. (LPSTR)&dwMapperConfig,
  464. sizeof(dwMapperConfig));
  465. RegCloseKey(hKeyThisAlias);
  466. }
  467. fRet = TRUE;
  468. mMAD_Cleanup:
  469. if (hKeyMediaRsrc) RegCloseKey(hKeyMediaRsrc);
  470. return fRet;
  471. }
  472. //
  473. // mdev_ListActiveDrivers
  474. //
  475. // List the currently loaded drivers to debug output
  476. //
  477. #ifdef DEBUG
  478. PRIVATE VOID FNLOCAL mdev_ListActiveDrivers(
  479. void)
  480. {
  481. PMDEV_NODE pmd;
  482. static TCHAR BCODE szNo[] = TEXT ("No");
  483. static TCHAR BCODE szYes[] = TEXT ("Yes");
  484. DPF(2, TEXT ("=== mdev_ListActiveDrivers start ==="));
  485. for (pmd = gpMDevList; pmd; pmd = pmd->pNext)
  486. {
  487. DPF(2, TEXT ("Alias %-31.31s Driver %-31.31s"),
  488. (LPTSTR)pmd->szAlias,
  489. (LPTSTR)pmd->szDriver);
  490. DPF(2, TEXT (" dwDevNode %08lX uDeviceID %u uPort %u fNewDriver %s"),
  491. pmd->dwDevNode,
  492. pmd->uDeviceID,
  493. pmd->uPort,
  494. (LPTSTR)(pmd->fNewDriver ? szYes : szNo));
  495. }
  496. DPF(2, TEXT ("=== mdev_ListActiveDrivers end ==="));
  497. }
  498. #endif
  499. //
  500. // mdev_Free
  501. //
  502. // Discard the current device list
  503. //
  504. void FNGLOBAL mdev_Free(
  505. void)
  506. {
  507. PMDEV_NODE pmdNext;
  508. PMDEV_NODE pmdCurr;
  509. pmdCurr = gpMDevList;
  510. while (pmdCurr)
  511. {
  512. pmdNext = pmdCurr->pNext;
  513. LocalFree((HLOCAL)pmdCurr);
  514. pmdCurr = pmdNext;
  515. }
  516. gpMDevList = NULL;
  517. gdwNewDrivers = (DWORD)-1L;
  518. }
  519. //
  520. // mdev_GetDeviceID
  521. //
  522. // Get the current device ID for the given alias.
  523. //
  524. UINT FNGLOBAL mdev_GetDeviceID(
  525. LPTSTR lpstrAlias)
  526. {
  527. PMDEV_NODE pmd;
  528. for (pmd = gpMDevList; pmd; pmd = pmd->pNext)
  529. if (!lstrcmpi(pmd->szAlias, lpstrAlias))
  530. return pmd->uDeviceID + pmd->uPort;
  531. DPF(1, TEXT ("mdev_GetDeviceID: Failed for %s"), lpstrAlias);
  532. return NO_DEVICEID;
  533. }
  534. //
  535. // mdev_GetAlias
  536. //
  537. // Get the registry alias for the requested device ID
  538. //
  539. BOOL FNGLOBAL mdev_GetAlias(
  540. UINT uDeviceID,
  541. LPTSTR lpstrBuffer,
  542. UINT cbBuffer)
  543. {
  544. PMDEV_NODE pmd;
  545. for (pmd = gpMDevList; pmd; pmd = pmd->pNext)
  546. if (uDeviceID == (pmd->uDeviceID + pmd->uPort))
  547. {
  548. lstrcpyn(lpstrBuffer, pmd->szAlias, cbBuffer);
  549. return TRUE;
  550. }
  551. DPF(1, TEXT ("mdev_GetAlias: Failed for device ID %u"), uDeviceID);
  552. return FALSE;
  553. }
  554. //
  555. // mdev_NewDrivers
  556. //
  557. // Returns TRUE if there were new drivers in the registry that we've never
  558. // encountered before
  559. //
  560. BOOL FNGLOBAL mdev_NewDrivers(
  561. void)
  562. {
  563. if (gdwNewDrivers == (DWORD)-1L)
  564. {
  565. DPF(0, TEXT ("mdevNewDrivers() called before mdev_Init()!"));
  566. return FALSE;
  567. }
  568. return (BOOL)(gdwNewDrivers != 0);
  569. }