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.

1584 lines
44 KiB

  1. /******************************************************************************
  2. Copyright (c) 1985-2001 Microsoft Corporation
  3. Title: drvr.c - Installable driver code. Common code
  4. Version: 1.00
  5. Date: 10-Jun-1990
  6. Author: DAVIDDS ROBWI
  7. ------------------------------------------------------------------------------
  8. Change log:
  9. DATE REV DESCRIPTION
  10. ----------- ----- -----------------------------------------------------------
  11. 10-JUN-1990 ROBWI From windows 3.1 installable driver code by davidds
  12. 28-FEB-1992 ROBINSP Port to NT
  13. *****************************************************************************/
  14. #include <windows.h>
  15. #include <winmmi.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include "drvr.h"
  19. int cInstalledDrivers = 0; // Count of installed drivers
  20. HANDLE hInstalledDriverList = 0; // List of installed drivers
  21. typedef LONG (FAR PASCAL *SENDDRIVERMESSAGE31)(HANDLE, UINT, LPARAM, LPARAM);
  22. typedef LRESULT (FAR PASCAL *DEFDRIVERPROC31)(DWORD_PTR, HANDLE, UINT, LPARAM, LPARAM);
  23. extern SENDDRIVERMESSAGE31 lpSendDriverMessage;
  24. extern DEFDRIVERPROC31 lpDefDriverProc;
  25. extern void lstrncpyW (LPWSTR pszTarget, LPCWSTR pszSource, size_t cch);
  26. __inline PWSTR lstrDuplicateW(PCWSTR pstr)
  27. {
  28. PWSTR pstrDuplicate = (PWSTR)HeapAlloc(hHeap, 0, (lstrlenW(pstr)+1)*sizeof(WCHAR));
  29. if (pstrDuplicate) lstrcpyW(pstrDuplicate, pstr);
  30. return pstrDuplicate;
  31. }
  32. //============================================================================
  33. // Basic hash helpers taken from LKRhash
  34. //============================================================================
  35. // Produce a scrambled, randomish number in the range 0 to RANDOM_PRIME-1.
  36. // Applying this to the results of the other hash functions is likely to
  37. // produce a much better distribution, especially for the identity hash
  38. // functions such as Hash(char c), where records will tend to cluster at
  39. // the low end of the hashtable otherwise. LKRhash applies this internally
  40. // to all hash signatures for exactly this reason.
  41. __inline DWORD
  42. HashScramble(DWORD dwHash)
  43. {
  44. // Here are 10 primes slightly greater than 10^9
  45. // 1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
  46. // 1000000093, 1000000097, 1000000103, 1000000123, 1000000181.
  47. // default value for "scrambling constant"
  48. const DWORD RANDOM_CONSTANT = 314159269UL;
  49. // large prime number, also used for scrambling
  50. const DWORD RANDOM_PRIME = 1000000007UL;
  51. return (RANDOM_CONSTANT * dwHash) % RANDOM_PRIME ;
  52. }
  53. // Small prime number used as a multiplier in the supplied hash functions
  54. const DWORD HASH_MULTIPLIER = 101;
  55. #undef HASH_SHIFT_MULTIPLY
  56. #ifdef HASH_SHIFT_MULTIPLY
  57. # define HASH_MULTIPLY(dw) (((dw) << 7) - (dw))
  58. #else
  59. # define HASH_MULTIPLY(dw) ((dw) * HASH_MULTIPLIER)
  60. #endif
  61. // Fast, simple hash function that tends to give a good distribution.
  62. // Apply HashScramble to the result if you're using this for something
  63. // other than LKRhash.
  64. __inline DWORD
  65. HashStringA(
  66. const char* psz,
  67. DWORD dwHash)
  68. {
  69. // force compiler to use unsigned arithmetic
  70. const unsigned char* upsz = (const unsigned char*) psz;
  71. for ( ; *upsz; ++upsz)
  72. dwHash = HASH_MULTIPLY(dwHash) + *upsz;
  73. return dwHash;
  74. }
  75. // Unicode version of above
  76. __inline DWORD
  77. HashStringW(
  78. const wchar_t* pwsz,
  79. DWORD dwHash)
  80. {
  81. for ( ; *pwsz; ++pwsz)
  82. dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
  83. return dwHash;
  84. }
  85. // Quick-'n'-dirty case-insensitive string hash function.
  86. // Make sure that you follow up with _stricmp or _mbsicmp. You should
  87. // also cache the length of strings and check those first. Caching
  88. // an uppercase version of a string can help too.
  89. // Again, apply HashScramble to the result if using with something other
  90. // than LKRhash.
  91. // Note: this is not really adequate for MBCS strings.
  92. __inline DWORD
  93. HashStringNoCase(
  94. const char* psz,
  95. DWORD dwHash)
  96. {
  97. const unsigned char* upsz = (const unsigned char*) psz;
  98. for ( ; *upsz; ++upsz)
  99. dwHash = HASH_MULTIPLY(dwHash)
  100. + (*upsz & 0xDF); // strip off lowercase bit
  101. return dwHash;
  102. }
  103. // Unicode version of above
  104. __inline DWORD
  105. HashStringNoCaseW(
  106. const wchar_t* pwsz,
  107. DWORD dwHash)
  108. {
  109. for ( ; *pwsz; ++pwsz)
  110. dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
  111. return dwHash;
  112. }
  113. /*
  114. FYI here are the first bunch of prime numbers up to around 1000
  115. 2 3 5 7 11 13 17 19 23 29
  116. 31 37 41 43 47 53 59 61 67 71
  117. 73 79 83 89 97 101 103 107 109 113
  118. 127 131 137 139 149 151 157 163 167 173
  119. 179 181 191 193 197 199 211 223 227 229
  120. 233 239 241 251 257 263 269 271 277 281
  121. 283 293 307 311 313 317 331 337 347 349
  122. 353 359 367 373 379 383 389 397 401 409
  123. 419 421 431 433 439 443 449 457 461 463
  124. 467 479 487 491 499 503 509 521 523 541
  125. 547 557 563 569 571 577 587 593 599 601
  126. 607 613 617 619 631 641 643 647 653 659
  127. 661 673 677 683 691 701 709 719 727 733
  128. 739 743 751 757 761 769 773 787 797 809
  129. 811 821 823 827 829 839 853 857 859 863
  130. 877 881 883 887 907 911 919 929 937 941
  131. 947 953 967 971 977 983 991 997 1009 1013
  132. */
  133. //============================================================================
  134. // StringId dictionary
  135. //============================================================================
  136. #define HASH_TABLESIZE (127)
  137. PMMDRV StringIdDict[HASH_TABLESIZE];
  138. /*****************************************************************************
  139. * @doc INTERNAL
  140. *
  141. * @api MMRESULT | StringId_Create | This function creates a unique string
  142. * identifying a particular MME device. The string can be used to
  143. * subsequently retrieve the ID for the same MME device even if the devices
  144. * have been renumbered.
  145. *
  146. * @parm IN PMMDRV | pdrv | Pointer to an MME driver.
  147. *
  148. * @parm IN UINT | port | Driver-relative device ID.
  149. *
  150. * @parm OPTIONAL OUT PWSTR* | pStringId | Address of a buffer to receive the
  151. * pointer to the string.
  152. *
  153. * @parm OPTIONAL OUT ULONG* | pcbStringId | Receives size of buffer required
  154. * to store the string.
  155. * @rdesc MMRESULT | Zero if successfull otherwise an error code defined
  156. * in mmsystem.h.
  157. *
  158. * @comm The string is allocated by this function using the heap identified
  159. * by the global variable hHeap. The caller is responsible for ensuring
  160. * the string is freed.
  161. *
  162. ****************************************************************************/
  163. MMRESULT StringId_Create(IN PMMDRV pdrv, IN UINT port, OUT PWSTR* pStringId, OUT ULONG* pcbStringId)
  164. {
  165. MMRESULT mmr;
  166. int cchStringId;
  167. PWSTR StringId;
  168. LONG StringIdType;
  169. PCWSTR StringIdBase;
  170. // 8 chars type field + next colon delimiter
  171. cchStringId = 8 + 1;
  172. if (pdrv->cookie)
  173. {
  174. // 8 chars for device interface length field + next colon delimiter
  175. cchStringId += 8 + 1;
  176. // device interface name + next colon delimiter
  177. cchStringId += lstrlenW(pdrv->cookie) + 1;
  178. StringIdType = 1;
  179. StringIdBase = pdrv->cookie;
  180. }
  181. else
  182. {
  183. // file name + next colon delimiter
  184. cchStringId += lstrlenW(pdrv->wszDrvEntry) + 1;
  185. StringIdType = 0;
  186. StringIdBase = pdrv->wszDrvEntry;
  187. }
  188. // message proc name + next colon delimiter
  189. cchStringId += lstrlenW(pdrv->wszMessage) + 1;
  190. // 8 chars driver-relative ID, 1 terminator
  191. cchStringId += 8 + 1;
  192. mmr = MMSYSERR_NOERROR;
  193. if (pStringId)
  194. {
  195. StringId = HeapAlloc(hHeap, 0, cchStringId * sizeof(WCHAR));
  196. if (StringId)
  197. {
  198. int cchPrinted;
  199. switch (StringIdType)
  200. {
  201. case 0:
  202. cchPrinted = swprintf(StringId, L"%08X:%s:%s:%08X", StringIdType, StringIdBase, pdrv->wszMessage, port);
  203. break;
  204. case 1:
  205. cchPrinted = swprintf(StringId, L"%08X:%08X:%s:%s:%08X", StringIdType, lstrlenW(StringIdBase), StringIdBase, pdrv->wszMessage, port);
  206. break;
  207. default:
  208. WinAssert(FALSE);
  209. break;
  210. }
  211. WinAssert(cchPrinted < cchStringId);
  212. *pStringId = StringId;
  213. // dprintf(("StringId_Create : note: created StringId=\"%ls\"", StringId));
  214. }
  215. else
  216. {
  217. mmr = MMSYSERR_NOMEM;
  218. }
  219. }
  220. if (!mmr && pcbStringId) *pcbStringId = cchStringId * sizeof(WCHAR);
  221. return mmr;
  222. }
  223. /*****************************************************************************
  224. * @doc INTERNAL
  225. *
  226. * @api MMRESULT | StringIdDict_Initialize | This function ensures the
  227. * dictionary is initialized. It should be called by any function that uses
  228. * the dictionary
  229. *
  230. * @rdesc void
  231. *
  232. ****************************************************************************/
  233. void StringIdDict_Initialize(void)
  234. {
  235. int i;
  236. static BOOL fInitialized = FALSE;
  237. if (fInitialized) return;
  238. for (i = 0; i < (sizeof(StringIdDict)/sizeof(StringIdDict[0])); i++) StringIdDict[i] = NULL;
  239. fInitialized = TRUE;
  240. }
  241. MMRESULT StringIdDict_SearchType0And1(IN ULONG Type, IN PWSTR pstrTypeXData, IN ULONG HashAx, OUT PMMDRV *ppdrv, OUT UINT *pport)
  242. {
  243. PWSTR pstrDriver = NULL;
  244. PWSTR pstrMessage = NULL;
  245. PWSTR pstrPort = NULL;
  246. PWSTR pstr = pstrTypeXData;
  247. MMRESULT mmr = MMSYSERR_NOERROR;
  248. WinAssert((0 == Type) || (1 == Type));
  249. if (0 == Type)
  250. {
  251. // "<driver-filename>:<driver-message-proc-name>:<driver-port>"
  252. pstrDriver = pstr;
  253. pstrMessage = wcschr(pstrDriver, L':');
  254. if (pstrMessage) *pstrMessage++ = L'\0';
  255. }
  256. else // 1 == Type
  257. {
  258. // "<driver-device-interface-length>:<driver-device-interface>:<driver-message-proc-name>:<driver-port>"
  259. int cchDeviceInterface = wcstol(pstr, &pstrDriver, 16);
  260. if (L':' != *pstrDriver) pstrDriver = NULL;
  261. if (pstrDriver) {
  262. *pstrDriver++ = L'\0';
  263. pstrMessage = pstrDriver + cchDeviceInterface;
  264. if (L':' == *pstrMessage) *pstrMessage++ = L'\0';
  265. else pstrMessage = NULL;
  266. }
  267. }
  268. if (pstrMessage)
  269. {
  270. pstrPort = wcschr(pstrMessage, L':');
  271. if (pstrPort) *pstrPort++ = L'\0';
  272. }
  273. // now hash the substrings and search the hash chain for a match
  274. if (pstrDriver && pstrMessage && pstrPort)
  275. {
  276. UINT port;
  277. PMMDRV pdrv;
  278. int cHashMisses;
  279. PWCHAR pch;
  280. HashAx = HashStringNoCaseW(pstrDriver, HashAx);
  281. HashAx = HashStringNoCaseW(pstrMessage, HashAx);
  282. HashAx = HashScramble(HashAx) % HASH_TABLESIZE;
  283. mmr = MMSYSERR_NODRIVER;
  284. port = wcstol(pstrPort, &pch, 16);
  285. for (pdrv = StringIdDict[HashAx], cHashMisses = 0;
  286. pdrv;
  287. pdrv = pdrv->NextStringIdDictNode, cHashMisses++)
  288. {
  289. if (0 == Type)
  290. {
  291. if (pdrv->cookie) continue;
  292. if (lstrcmpiW(pdrv->wszDrvEntry, pstrDriver)) continue;
  293. }
  294. else // 1 == Type
  295. {
  296. if (!pdrv->cookie) continue;
  297. if (lstrcmpiW(pdrv->cookie, pstrDriver)) continue;
  298. }
  299. if (lstrcmpiW(pdrv->wszMessage, pstrMessage)) continue;
  300. *ppdrv = pdrv;
  301. *pport = port;
  302. if (cHashMisses) dprintf(("StringIdDict_SearchType0And1 : note: %d hash misses", cHashMisses));
  303. mmr = MMSYSERR_NOERROR;
  304. break;
  305. }
  306. }
  307. else
  308. {
  309. mmr = MMSYSERR_INVALPARAM;
  310. }
  311. return mmr;
  312. }
  313. MMRESULT StringIdDict_Search(IN PCWSTR InStringId, OUT PMMDRV *ppdrv, OUT UINT *pport)
  314. {
  315. PWSTR StringId;
  316. MMRESULT mmr = MMSYSERR_NOERROR;
  317. StringIdDict_Initialize();
  318. StringId = lstrDuplicateW(InStringId);
  319. if (StringId)
  320. {
  321. ULONG Type;
  322. PWSTR pstr;
  323. PWSTR pstrType;
  324. pstr = StringId;
  325. pstrType = pstr;
  326. Type = wcstol(pstrType, &pstr, 16);
  327. if (*pstr == L':')
  328. {
  329. ULONG HashAx; // Hash accumulator
  330. *pstr++ = L'\0';
  331. HashAx = HashStringNoCaseW(pstrType, 0);
  332. switch (Type)
  333. {
  334. case 0:
  335. mmr = StringIdDict_SearchType0And1(Type, pstr, HashAx, ppdrv, pport);
  336. break;
  337. case 1:
  338. mmr = StringIdDict_SearchType0And1(Type, pstr, HashAx, ppdrv, pport);
  339. break;
  340. default:
  341. mmr = MMSYSERR_INVALPARAM;
  342. break;
  343. }
  344. }
  345. else
  346. {
  347. mmr = MMSYSERR_INVALPARAM;
  348. }
  349. HeapFree(hHeap, 0, StringId);
  350. }
  351. else
  352. {
  353. mmr = MMSYSERR_NOMEM;
  354. }
  355. if (mmr) dprintf(("StringIdDict_Search : error: returning mmresult %d", mmr));
  356. return mmr;
  357. }
  358. void StringIdDict_Insert(PMMDRV pdrv)
  359. {
  360. ULONG HashAx;
  361. MMRESULT mmr;
  362. StringIdDict_Initialize();
  363. if (!pdrv->cookie)
  364. {
  365. HashAx = HashStringNoCaseW(L"00000000", 0);
  366. HashAx = HashStringNoCaseW(pdrv->wszDrvEntry, HashAx);
  367. }
  368. else
  369. {
  370. HashAx = HashStringNoCaseW(L"00000001", 0);
  371. HashAx = HashStringNoCaseW(pdrv->cookie, HashAx);
  372. }
  373. HashAx = HashStringNoCaseW(pdrv->wszMessage, HashAx);
  374. HashAx = HashScramble(HashAx) % HASH_TABLESIZE;
  375. // dprintf(("StringIdDict_Insert : note: driver hashed to %d", HashAx));
  376. pdrv->NextStringIdDictNode = StringIdDict[HashAx];
  377. pdrv->PrevStringIdDictNode = NULL;
  378. if (pdrv->NextStringIdDictNode) pdrv->NextStringIdDictNode->PrevStringIdDictNode = pdrv;
  379. StringIdDict[HashAx] = pdrv;
  380. #if DBG
  381. {
  382. // Checking the consistency of the driver lists and the hash table
  383. UINT cDriversHash = 0;
  384. UINT cDrivers = 0;
  385. UINT ii;
  386. PMMDRV pLink, pStart;
  387. for (ii = (sizeof(StringIdDict)/sizeof(StringIdDict[0])); ii; ii--)
  388. {
  389. for (pLink = StringIdDict[ii-1]; pLink; pLink = pLink->NextStringIdDictNode)
  390. {
  391. cDriversHash++;
  392. }
  393. }
  394. for (pStart = (PMMDRV)&waveoutdrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  395. cDrivers++;
  396. for (pStart = (PMMDRV)&waveindrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  397. cDrivers++;
  398. for (pStart = (PMMDRV)&midioutdrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  399. cDrivers++;
  400. for (pStart = (PMMDRV)&midiindrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  401. cDrivers++;
  402. for (pStart = (PMMDRV)&mixerdrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  403. cDrivers++;
  404. for (pStart = (PMMDRV)&auxdrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  405. cDrivers++;
  406. WinAssert(cDriversHash == cDrivers);
  407. }
  408. #endif // DBG
  409. return;
  410. }
  411. void StringIdDict_Remove(PMMDRV pdrv)
  412. {
  413. if (pdrv->NextStringIdDictNode) pdrv->NextStringIdDictNode->PrevStringIdDictNode = pdrv->PrevStringIdDictNode;
  414. if (pdrv->PrevStringIdDictNode) {
  415. pdrv->PrevStringIdDictNode->NextStringIdDictNode = pdrv->NextStringIdDictNode;
  416. } else {
  417. int i;
  418. for ( i = 0; i < HASH_TABLESIZE; i++ ) {
  419. if (pdrv == StringIdDict[i]) {
  420. StringIdDict[i] = pdrv->NextStringIdDictNode;
  421. break;
  422. }
  423. }
  424. WinAssert(i != HASH_TABLESIZE);
  425. }
  426. #if DBG
  427. {
  428. // Checking the consistency of the driver lists and the hash table
  429. UINT cDriversHash = 0;
  430. UINT cDrivers = 0;
  431. UINT ii;
  432. PMMDRV pLink, pStart;
  433. for (ii = (sizeof(StringIdDict)/sizeof(StringIdDict[0])); ii; ii--)
  434. {
  435. for (pLink = StringIdDict[ii-1]; pLink; pLink = pLink->NextStringIdDictNode)
  436. {
  437. cDriversHash++;
  438. }
  439. }
  440. for (pStart = (PMMDRV)&waveoutdrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  441. cDrivers++;
  442. for (pStart = (PMMDRV)&waveindrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  443. cDrivers++;
  444. for (pStart = (PMMDRV)&midioutdrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  445. cDrivers++;
  446. for (pStart = (PMMDRV)&midiindrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  447. cDrivers++;
  448. for (pStart = (PMMDRV)&mixerdrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  449. cDrivers++;
  450. for (pStart = (PMMDRV)&auxdrvZ, pLink = pStart->Next; pLink != pStart; pLink = pLink->Next)
  451. cDrivers++;
  452. cDrivers--; // to account for the driver we just removed.
  453. WinAssert(cDriversHash == cDrivers);
  454. }
  455. #endif // DBG
  456. }
  457. //=============================================================================
  458. //=== Misc Utilities ===
  459. //=============================================================================
  460. /***************************************************************************
  461. *
  462. * @doc INTERNAL
  463. *
  464. * @api void | winmmGetBuildYearAndMonth | Returns build year and month
  465. * of this source file.
  466. *
  467. * @parm unsigned* | pBuildYear | Receives build year.
  468. *
  469. * @parm unsigned* | pBuildMonth | Receives build month.
  470. *
  471. * @rdesc No return value.
  472. *
  473. * @comm Computes build year and month based on compiler macro __DATE__
  474. *
  475. ***************************************************************************/
  476. void winmmGetBuildYearAndMonth(unsigned *pBuildYear, unsigned *pBuildMonth)
  477. {
  478. char szBuildDate[] = __DATE__;
  479. char *Month[12] = {"Jan", "Feb", "Mar",
  480. "Apr", "May", "Jun",
  481. "Jul", "Aug", "Sep",
  482. "Oct", "Nov", "Dec"};
  483. char szBuildMonth[4];
  484. int i;
  485. lstrcpynA(szBuildMonth, szBuildDate, 4);
  486. szBuildMonth[3] = '\0';
  487. for (i = 0; i < 12; i++)
  488. {
  489. if (!lstrcmpiA(Month[i], szBuildMonth)) break;
  490. }
  491. WinAssert(i < 12);
  492. *pBuildMonth = i + 1;
  493. *pBuildYear = atoi(&szBuildDate[7]);
  494. return;
  495. }
  496. /***************************************************************************
  497. *
  498. * @doc INTERNAL
  499. *
  500. * @api BOOL | winmmFileTimeIsPreXp | Determines whether given filetime is
  501. * before approximate XP ship date.
  502. *
  503. * @parm FILETIME* | FileTime | Points to file time to check.
  504. *
  505. * @rdesc BOOL | TRUE if file time is before approximate XP ship date
  506. *
  507. * @comm This is based on the build date of this source module, or the
  508. * anticipated Windows XP RC2 ship month, whichever is later.
  509. *
  510. ***************************************************************************/
  511. BOOL winmmFileTimeIsPreXp(CONST FILETIME *FileTime)
  512. {
  513. const unsigned XpRc2Month = 7;
  514. const unsigned XpRc2Year = 2001;
  515. SYSTEMTIME SystemTime;
  516. BOOL fPreXp = FALSE;
  517. if (FileTimeToSystemTime(FileTime, &SystemTime))
  518. {
  519. unsigned BuildYear, BuildMonth;
  520. winmmGetBuildYearAndMonth(&BuildYear, &BuildMonth);
  521. if (BuildYear > XpRc2Year) {
  522. BuildYear = XpRc2Year;
  523. BuildMonth = XpRc2Month;
  524. } else if ((BuildYear == XpRc2Year) && (BuildMonth > XpRc2Month)) {
  525. BuildMonth = XpRc2Month;
  526. }
  527. if ((SystemTime.wYear < BuildYear) ||
  528. ((SystemTime.wYear == BuildYear) && (SystemTime.wMonth < BuildMonth)))
  529. {
  530. fPreXp = TRUE;
  531. }
  532. }
  533. return fPreXp;
  534. }
  535. /***************************************************************************
  536. *
  537. * @doc INTERNAL
  538. *
  539. * @api LONG | InternalBroadcastDriverMessage | Send a message to a
  540. * range of drivers.
  541. *
  542. * @parm UINT | hDriverStart | index of first driver to send message to
  543. *
  544. * @parm UINT | message | Message to broadcast.
  545. *
  546. * @parm LONG | lParam1 | First message parameter.
  547. *
  548. * @parm LONG | lParam2 | Second message parameter.
  549. *
  550. * @parm UINT | flags | defines range of drivers as follows:
  551. *
  552. * @flag IBDM_SENDMESSAGE | Only send message to hDriverStart.
  553. *
  554. * @flag IBDM_ONEINSTANCEONLY | This flag is ignored if IBDM_SENDMESSAGE is
  555. * set. Only send message to single instance of each driver.
  556. *
  557. * @flag IBDM_REVERSE | This flag is ignored if IBDM_SENDMESSAGE is set.
  558. * Send message to drivers with indices between
  559. * hDriverStart and 1 instead of hDriverStart and cInstalledDrivers.
  560. * If IBDM_REVERSE is set and hDriverStart is 0 then send messages
  561. * to drivers with indices between cInstalledDrivers and 1.
  562. *
  563. * @rdesc returns non-zero if message was broadcast. If the IBDM_SENDMESSAGE
  564. * flag is set, returns the return result from the driver proc.
  565. *
  566. ***************************************************************************/
  567. LRESULT FAR PASCAL InternalBroadcastDriverMessage(UINT hDriverStart,
  568. UINT message,
  569. LPARAM lParam1,
  570. LPARAM lParam2,
  571. UINT flags)
  572. {
  573. LPDRIVERTABLE lpdt;
  574. LRESULT result=0;
  575. int id;
  576. int idEnd;
  577. DrvEnter();
  578. if (!hInstalledDriverList || (int)hDriverStart > cInstalledDrivers) {
  579. DrvLeave();
  580. return(FALSE);
  581. }
  582. if (flags & IBDM_SENDMESSAGE)
  583. {
  584. if (!hDriverStart) {
  585. DrvLeave();
  586. return (FALSE);
  587. }
  588. flags &= ~(IBDM_REVERSE | IBDM_ONEINSTANCEONLY);
  589. idEnd = hDriverStart;
  590. }
  591. else
  592. {
  593. if (flags & IBDM_REVERSE)
  594. {
  595. if (!hDriverStart)
  596. hDriverStart = cInstalledDrivers;
  597. idEnd = -1;
  598. }
  599. else
  600. {
  601. if (!hDriverStart) {
  602. DrvLeave();
  603. return (FALSE);
  604. }
  605. idEnd = cInstalledDrivers;
  606. }
  607. }
  608. hDriverStart--;
  609. lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
  610. for (id = hDriverStart; id != idEnd; ((flags & IBDM_REVERSE) ? id-- : id++))
  611. {
  612. DWORD_PTR dwDriverIdentifier;
  613. DRIVERPROC lpDriverEntryPoint;
  614. if (lpdt[id].hModule)
  615. {
  616. if ((flags & IBDM_ONEINSTANCEONLY) &&
  617. !lpdt[id].fFirstEntry)
  618. continue;
  619. lpDriverEntryPoint = lpdt[id].lpDriverEntryPoint;
  620. dwDriverIdentifier = lpdt[id].dwDriverIdentifier;
  621. /*
  622. * Allow normal messages to overlap - it's up to the
  623. * users not to send messages to stuff that's been unloaded
  624. */
  625. GlobalUnlock(hInstalledDriverList);
  626. DrvLeave();
  627. result =
  628. (*lpDriverEntryPoint)(dwDriverIdentifier,
  629. (HANDLE)(UINT_PTR)(id+1),
  630. message,
  631. lParam1,
  632. lParam2);
  633. if (flags & IBDM_SENDMESSAGE) {
  634. return result;
  635. }
  636. DrvEnter();
  637. lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
  638. }
  639. }
  640. GlobalUnlock(hInstalledDriverList);
  641. DrvLeave();
  642. return(result);
  643. }
  644. /***************************************************************************
  645. *
  646. * @doc DDK
  647. *
  648. * @api LONG | DrvSendMessage | This function sends a message
  649. * to a specified driver.
  650. *
  651. * @parm HANDLE | hDriver | Specifies the handle of the destination driver.
  652. *
  653. * @parm UINT | wMessage | Specifies a driver message.
  654. *
  655. * @parm LPARAM | lParam1 | Specifies the first message parameter.
  656. *
  657. * @parm LPARAM | lParam2 | Specifies the second message parameter.
  658. *
  659. * @rdesc Returns the results returned from the driver.
  660. *
  661. ***************************************************************************/
  662. LRESULT APIENTRY DrvSendMessage(HANDLE hDriver, UINT message, LPARAM lParam1, LPARAM lParam2)
  663. {
  664. if (fUseWinAPI)
  665. return (*lpSendDriverMessage)(hDriver, message, lParam1, lParam2);
  666. return(InternalBroadcastDriverMessage((UINT)(UINT_PTR)hDriver,
  667. message,
  668. lParam1,
  669. lParam2,
  670. IBDM_SENDMESSAGE));
  671. }
  672. /**************************************************************************
  673. *
  674. * @doc DDK
  675. *
  676. * @api LONG | DefDriverProc | This function provides default
  677. * handling of system messages.
  678. *
  679. * @parm DWORD | dwDriverIdentifier | Specifies the identifier of
  680. * the device driver.
  681. *
  682. * @parm HANDLE | hDriver | Specifies the handle of the device driver.
  683. *
  684. * @parm UINT | wMessage | Specifies a driver message.
  685. *
  686. * @parm LPARAM | lParam1 | Specifies the first message parameter.
  687. *
  688. * @parm LPARAM | lParam2 | Specifies the second message parameter.
  689. *
  690. * @rdesc Returns 1L for DRV_LOAD, DRV_FREE, DRV_ENABLE, and DRV_DISABLE.
  691. * It returns 0L for all other messages.
  692. *
  693. ***************************************************************************/
  694. LRESULT APIENTRY DefDriverProc(DWORD_PTR dwDriverIdentifier,
  695. HDRVR hDriver,
  696. UINT message,
  697. LPARAM lParam1,
  698. LPARAM lParam2)
  699. {
  700. switch (message)
  701. {
  702. case DRV_LOAD:
  703. case DRV_ENABLE:
  704. case DRV_DISABLE:
  705. case DRV_FREE:
  706. return(1L);
  707. break;
  708. case DRV_INSTALL:
  709. case DRV_REMOVE:
  710. return(DRV_OK);
  711. break;
  712. }
  713. return(0L);
  714. }
  715. /*****************************************************************************
  716. * @doc INTERNAL
  717. *
  718. * @api MMRESULT | DrvIsPreXp | Determines whether the installable driver's
  719. * last modified date is before the approximate Windows XP ship date.
  720. *
  721. * @parm HANDLE | hDriver | Handle to installable driver.
  722. *
  723. * @rdesc BOOL | TRUE if the installable driver's last modified date is before
  724. * the approximate Windows XP ship date.
  725. *
  726. * @comm If there was an error getting file attributes, then let's err on
  727. * the side of an old driver and return TRUE.
  728. *
  729. ****************************************************************************/
  730. BOOL DrvIsPreXp(IN HANDLE hDriver)
  731. {
  732. WIN32_FILE_ATTRIBUTE_DATA fad;
  733. HMODULE hModule;
  734. BOOL fPreXp = TRUE;
  735. hModule = DrvGetModuleHandle(hDriver);
  736. if (hModule)
  737. {
  738. TCHAR filename[MAX_PATH];
  739. if (GetModuleFileName(hModule, filename, sizeof(filename)/sizeof(TCHAR)))
  740. {
  741. if (GetFileAttributesEx(filename, GetFileExInfoStandard, &fad))
  742. {
  743. fPreXp = winmmFileTimeIsPreXp(&fad.ftLastWriteTime);
  744. }
  745. else
  746. {
  747. LONG error = GetLastError();
  748. dprintf(("DrvIsPreXp : error: GetFileAttributesEx failed, LastError=%d", error));
  749. }
  750. // dprintf(("DrvIsPreXp : note: %s fPreXp=%d", filename, fPreXp));
  751. }
  752. else
  753. {
  754. LONG error = GetLastError();
  755. dprintf(("DrvIsPreXp : error: GetModuleFileName failed, LastError=%d", error));
  756. }
  757. }
  758. else
  759. {
  760. dprintf(("DrvIsPreXp : error: DrvGetModuleHandle failed"));
  761. }
  762. return fPreXp;
  763. }
  764. MMRESULT mregCreateStringIdFromDriverPort(IN struct _MMDRV *pmmDrv, IN UINT port, OUT PWSTR* pStringId, OUT ULONG* pcbStringId)
  765. {
  766. return StringId_Create(pmmDrv, port, pStringId, pcbStringId);
  767. }
  768. /*****************************************************************************
  769. * @doc INTERNAL WAVE
  770. *
  771. * @api MMRESULT | mregGetIdFromStringId | This function finds the waveOut
  772. * device ID associated with the waveOut device identified by a unique
  773. * string created by waveOutCreateStringIdFromId.
  774. *
  775. * @parm PCWSTR | StringId | Pointer to a unicode string identifying a
  776. * waveOut device.
  777. *
  778. * @parm UINT* | puDeviceID | Address of a buffer to receive the waveOut
  779. * device ID.
  780. *
  781. * @rdesc MMRESULT | Zero if successfull otherwise an error code defined
  782. * in mmsystem.h.
  783. *
  784. * @comm The StringId is normally obtained by calling waveOutCreateStringIdFromId.
  785. *
  786. * @xref waveOutCreateStringIdFromId
  787. *
  788. ****************************************************************************/
  789. MMRESULT mregGetIdFromStringId(IN PMMDRV pdrvZ, IN PCWSTR StringId, OUT UINT *puDeviceID)
  790. {
  791. PMMDRV pdrv;
  792. PMMDRV pdrvTarget;
  793. UINT portTarget;
  794. UINT idTarget;
  795. MMRESULT mmr;
  796. if (!ValidateWritePointer(puDeviceID, sizeof(*puDeviceID))) return MMSYSERR_INVALPARAM;
  797. if (!ValidateStringW(StringId, (-1))) return MMSYSERR_INVALPARAM;
  798. EnterNumDevs("mregGetIdFromStringId");
  799. mmr = StringIdDict_Search(StringId, &pdrvTarget, &portTarget);
  800. if (!mmr)
  801. {
  802. idTarget = portTarget;
  803. for (pdrv = pdrvZ->Next; pdrv != pdrvZ; pdrv = pdrv->Next)
  804. {
  805. if (pdrv == pdrvTarget) break;
  806. // Skipping mapper...
  807. if (pdrv->fdwDriver & MMDRV_MAPPER) continue;
  808. idTarget += pdrv->NumDevs;
  809. }
  810. }
  811. LeaveNumDevs("mregGetIdFromStringId");
  812. WinAssert(pdrv != pdrvZ);
  813. *puDeviceID = idTarget;
  814. return mmr;
  815. }
  816. MMRESULT mregQueryStringId(IN PMMDRV pdrv, IN UINT port, OUT WCHAR* pStringIdBuffer, IN ULONG cbStringIdBuffer)
  817. {
  818. PWSTR StringId;
  819. MMRESULT mmr;
  820. mmr = mregCreateStringIdFromDriverPort(pdrv, port, &StringId, NULL);
  821. if (!mmr)
  822. {
  823. if (ValidateWritePointer(pStringIdBuffer, cbStringIdBuffer))
  824. {
  825. int cchStringIdBuffer = cbStringIdBuffer / sizeof(WCHAR);
  826. if (cchStringIdBuffer >= lstrlenW(StringId) + 1)
  827. {
  828. cchStringIdBuffer = lstrlenW(StringId) + 1;
  829. mmr = MMSYSERR_NOERROR;
  830. } else {
  831. mmr = MMSYSERR_MOREDATA;
  832. }
  833. lstrcpynW(pStringIdBuffer, StringId, cchStringIdBuffer);
  834. } else {
  835. mmr = MMSYSERR_INVALPARAM;
  836. }
  837. HeapFree(hHeap, 0, StringId);
  838. }
  839. return mmr;
  840. }
  841. MMRESULT mregQueryStringIdSize(IN PMMDRV pdrv, IN UINT port, OUT ULONG* pcbStringId)
  842. {
  843. PWSTR StringId;
  844. MMRESULT mmr;
  845. if (ValidateWritePointer(pcbStringId, sizeof(*pcbStringId)))
  846. {
  847. mmr = mregCreateStringIdFromDriverPort(pdrv, port, NULL, pcbStringId);
  848. }
  849. else
  850. {
  851. mmr = MMSYSERR_INVALPARAM;
  852. }
  853. return mmr;
  854. }
  855. PMMDRV mregGetDrvListFromClass(DWORD dwClass)
  856. {
  857. PMMDRV pdrvZ;
  858. switch (dwClass)
  859. {
  860. case TYPE_WAVEOUT:
  861. pdrvZ = &waveoutdrvZ;
  862. break;
  863. case TYPE_WAVEIN:
  864. pdrvZ = &waveindrvZ;
  865. break;
  866. case TYPE_MIDIOUT:
  867. pdrvZ = &midioutdrvZ;
  868. break;
  869. case TYPE_MIDIIN:
  870. pdrvZ = &midiindrvZ;
  871. break;
  872. case TYPE_AUX:
  873. pdrvZ = &auxdrvZ;
  874. break;
  875. case TYPE_MIXER:
  876. pdrvZ = &mixerdrvZ;
  877. break;
  878. default:
  879. pdrvZ = NULL;
  880. WinAssert(FALSE);
  881. }
  882. return pdrvZ;
  883. }
  884. /*==========================================================================*/
  885. BOOL FAR PASCAL mregHandleInternalMessages(
  886. PMMDRV pmmdrv,
  887. DWORD dwClass,
  888. UINT idPort,
  889. UINT uMessage,
  890. DWORD_PTR dwParam1,
  891. DWORD_PTR dwParam2,
  892. MMRESULT * pmmr)
  893. {
  894. UINT cbSize;
  895. PMMDRV pmd = (PMMDRV)pmmdrv;
  896. BOOL fResult = TRUE;
  897. MMRESULT mmr = MMSYSERR_NOERROR;
  898. HMODULE hModule;
  899. #ifndef UNICODE
  900. TCHAR szBuff[MAX_PATH];
  901. #endif // End UNICODE
  902. switch (uMessage)
  903. {
  904. case DRVM_MAPPER_PREFERRED_GET:
  905. if (TYPE_WAVEOUT == dwClass) {
  906. if ((pmmdrv->fdwDriver & MMDRV_MAPPER) &&
  907. ValidateWritePointer((PUINT)dwParam1, sizeof(UINT)) &&
  908. ValidateWritePointer((PDWORD)dwParam2, sizeof(DWORD)))
  909. {
  910. waveOutGetCurrentPreferredId((PUINT)dwParam1, (PDWORD)dwParam2);
  911. mmr = MMSYSERR_NOERROR;
  912. } else {
  913. mmr = MMSYSERR_INVALPARAM;
  914. }
  915. } else if (TYPE_WAVEIN == dwClass) {
  916. if ((pmmdrv->fdwDriver & MMDRV_MAPPER) &&
  917. ValidateWritePointer((PUINT)dwParam1, sizeof(UINT)) &&
  918. ValidateWritePointer((PDWORD)dwParam2, sizeof(DWORD)))
  919. {
  920. waveInGetCurrentPreferredId((PUINT)dwParam1, (PDWORD)dwParam2);
  921. mmr = MMSYSERR_NOERROR;
  922. } else {
  923. mmr = MMSYSERR_INVALPARAM;
  924. }
  925. } else if (TYPE_MIDIOUT == dwClass) {
  926. if ((pmmdrv->fdwDriver & MMDRV_MAPPER) &&
  927. ValidateWritePointer((PUINT)dwParam1, sizeof(UINT)) &&
  928. ValidateWritePointer((PDWORD)dwParam2, sizeof(DWORD)))
  929. {
  930. midiOutGetCurrentPreferredId((PUINT)dwParam1, (PDWORD)dwParam2);
  931. mmr = MMSYSERR_NOERROR;
  932. } else {
  933. mmr = MMSYSERR_INVALPARAM;
  934. }
  935. } else {
  936. mmr = MMSYSERR_INVALPARAM;
  937. }
  938. break;
  939. case DRVM_MAPPER_PREFERRED_SET:
  940. if (TYPE_WAVEOUT == dwClass) {
  941. if (pmmdrv->fdwDriver & MMDRV_MAPPER) {
  942. mmr = waveOutSetPersistentPreferredId((UINT)dwParam1, (DWORD)dwParam2);
  943. } else {
  944. mmr = MMSYSERR_INVALPARAM;
  945. }
  946. } else if (TYPE_WAVEIN == dwClass) {
  947. if (pmmdrv->fdwDriver & MMDRV_MAPPER) {
  948. mmr = waveInSetPersistentPreferredId((UINT)dwParam1, (DWORD)dwParam2);
  949. } else {
  950. mmr = MMSYSERR_INVALPARAM;
  951. }
  952. } else if (TYPE_MIDIOUT == dwClass) {
  953. if (pmmdrv->fdwDriver & MMDRV_MAPPER) {
  954. mmr = midiOutSetPersistentPreferredId((UINT)dwParam1, (DWORD)dwParam2);
  955. } else {
  956. mmr = MMSYSERR_INVALPARAM;
  957. }
  958. } else {
  959. mmr = MMSYSERR_INVALPARAM;
  960. }
  961. break;
  962. case DRVM_MAPPER_CONSOLEVOICECOM_GET:
  963. if (TYPE_WAVEOUT == dwClass) {
  964. if ((pmmdrv->fdwDriver & MMDRV_MAPPER) &&
  965. ValidateWritePointer((PUINT)dwParam1, sizeof(UINT)) &&
  966. ValidateWritePointer((PDWORD)dwParam2, sizeof(DWORD)))
  967. {
  968. waveOutGetCurrentConsoleVoiceComId((PUINT)dwParam1, (PDWORD)dwParam2);
  969. mmr = MMSYSERR_NOERROR;
  970. } else {
  971. mmr = MMSYSERR_INVALPARAM;
  972. }
  973. } else if (TYPE_WAVEIN == dwClass) {
  974. if ((pmmdrv->fdwDriver & MMDRV_MAPPER) &&
  975. ValidateWritePointer((PUINT)dwParam1, sizeof(UINT)) &&
  976. ValidateWritePointer((PDWORD)dwParam2, sizeof(DWORD)))
  977. {
  978. waveInGetCurrentConsoleVoiceComId((PUINT)dwParam1, (PDWORD)dwParam2);
  979. mmr = MMSYSERR_NOERROR;
  980. } else {
  981. mmr = MMSYSERR_INVALPARAM;
  982. }
  983. } else {
  984. mmr = MMSYSERR_INVALPARAM;
  985. }
  986. break;
  987. case DRVM_MAPPER_CONSOLEVOICECOM_SET:
  988. if (TYPE_WAVEOUT == dwClass) {
  989. if (pmmdrv->fdwDriver & MMDRV_MAPPER) {
  990. mmr = waveOutSetPersistentConsoleVoiceComId((UINT)dwParam1, (DWORD)dwParam2);
  991. } else {
  992. mmr = MMSYSERR_INVALPARAM;
  993. }
  994. } else if (TYPE_WAVEIN == dwClass) {
  995. if (pmmdrv->fdwDriver & MMDRV_MAPPER) {
  996. mmr = waveInSetPersistentConsoleVoiceComId((UINT)dwParam1, (DWORD)dwParam2);
  997. } else {
  998. mmr = MMSYSERR_INVALPARAM;
  999. }
  1000. } else {
  1001. mmr = MMSYSERR_INVALPARAM;
  1002. }
  1003. break;
  1004. case DRV_QUERYFILENAME:
  1005. // Get Driver's FileName
  1006. if ( ((cbSize = (DWORD)dwParam2 * sizeof(WCHAR)) > 0) &&
  1007. (ValidateWritePointer( (LPVOID)dwParam1, cbSize)) )
  1008. {
  1009. lstrncpyW ((LPWSTR)dwParam1,
  1010. pmd->wszDrvEntry,
  1011. (DWORD)dwParam2-1);
  1012. ((LPWSTR)dwParam1)[ dwParam2-1 ] = TEXT('\0');
  1013. }
  1014. else
  1015. {
  1016. mmr = MMSYSERR_INVALPARAM;
  1017. }
  1018. break;
  1019. case DRV_QUERYDRVENTRY:
  1020. case DRV_QUERYNAME:
  1021. case DRV_QUERYDEVNODE:
  1022. case DRV_QUERYDRIVERIDS:
  1023. // Note: Not applicable or obsolete.
  1024. mmr = MMSYSERR_NOTSUPPORTED;
  1025. break;
  1026. case DRV_QUERYDEVICEINTERFACE:
  1027. {
  1028. // dwParam1 is a pointer to a buffer to contain device interface
  1029. // dwParam2 is the length in bytes of the buffer
  1030. PWSTR pwstrDeviceInterfaceOut = (PWSTR)dwParam1;
  1031. UINT cbDeviceInterfaceOut = (UINT)dwParam2;
  1032. PWSTR pwstrDeviceInterface = (PWSTR)pmd->cookie;
  1033. int cchDeviceInterfaceOut = cbDeviceInterfaceOut / sizeof(WCHAR);
  1034. if (ValidateWritePointer(pwstrDeviceInterfaceOut, cbDeviceInterfaceOut))
  1035. {
  1036. if (pwstrDeviceInterface)
  1037. {
  1038. if (cchDeviceInterfaceOut >= lstrlenW(pwstrDeviceInterface) + 1)
  1039. {
  1040. cchDeviceInterfaceOut = lstrlenW(pwstrDeviceInterface) + 1;
  1041. mmr = MMSYSERR_NOERROR;
  1042. } else {
  1043. mmr = MMSYSERR_MOREDATA;
  1044. }
  1045. lstrcpynW(pwstrDeviceInterfaceOut, pwstrDeviceInterface, cchDeviceInterfaceOut);
  1046. } else {
  1047. if (cchDeviceInterfaceOut >= 1)
  1048. {
  1049. *pwstrDeviceInterfaceOut = '\0';
  1050. mmr = MMSYSERR_NOERROR;
  1051. } else {
  1052. mmr = MMSYSERR_MOREDATA;
  1053. }
  1054. }
  1055. } else {
  1056. mmr = MMSYSERR_INVALPARAM;
  1057. }
  1058. break;
  1059. }
  1060. case DRV_QUERYDEVICEINTERFACESIZE:
  1061. {
  1062. // dwParam1 is a pointer to a buffer to contain a ULONG count of bytes
  1063. // in the device interface name
  1064. PULONG pcbDeviceInterface = (PULONG)dwParam1;
  1065. if (ValidateWritePointer(pcbDeviceInterface, sizeof(ULONG)))
  1066. {
  1067. if (pmd->cookie)
  1068. {
  1069. *pcbDeviceInterface = (lstrlenW((PWSTR)pmd->cookie) + 1) * sizeof(WCHAR);
  1070. } else {
  1071. *pcbDeviceInterface = 1 * sizeof(WCHAR);
  1072. }
  1073. mmr = MMSYSERR_NOERROR;
  1074. } else {
  1075. mmr = MMSYSERR_INVALPARAM;
  1076. }
  1077. break;
  1078. }
  1079. case DRV_QUERYSTRINGID:
  1080. {
  1081. mmr = mregQueryStringId(pmmdrv, idPort, (WCHAR*)dwParam1, (ULONG)dwParam2);
  1082. break;
  1083. }
  1084. case DRV_QUERYSTRINGIDSIZE:
  1085. {
  1086. mmr = mregQueryStringIdSize(pmmdrv, idPort, (ULONG*)dwParam1);
  1087. break;
  1088. }
  1089. case DRV_QUERYIDFROMSTRINGID:
  1090. {
  1091. mmr = mregGetIdFromStringId(mregGetDrvListFromClass(dwClass), (PCWSTR)dwParam1, (UINT*)dwParam2);
  1092. break;
  1093. }
  1094. case DRV_QUERYMAPPABLE:
  1095. {
  1096. TCHAR szRegKey[MAX_PATH+1];
  1097. HKEY hKey;
  1098. if (dwParam1 || dwParam2)
  1099. return MMSYSERR_INVALPARAM;
  1100. #ifdef UNICODE
  1101. wsprintfW (szRegKey, TEXT("%s\\%s"), REGSTR_PATH_WAVEMAPPER, pmd->wszDrvEntry);
  1102. #else
  1103. {
  1104. CHAR aszDrvEntry[CHAR_GIVEN_BYTE(sizeof(pmd->wszDrvEntry))+1];
  1105. cbSize = sizeof(aszDrvEntry);
  1106. UnicodeStrToAsciiStr((LPBYTE)aszDrvEntry, (LPBYTE)aszDrvEntry + cbSize,
  1107. pmd->wszDrvEntry);
  1108. wsprintfA (szRegKey, TEXT("%s\\%s"), REGSTR_PATH_WAVEMAPPER, aszDrvEntry);
  1109. }
  1110. #endif
  1111. if (RegOpenKey (HKEY_LOCAL_MACHINE, szRegKey, &hKey) != ERROR_SUCCESS)
  1112. {
  1113. mmr = MMSYSERR_NOERROR;
  1114. }
  1115. else
  1116. {
  1117. DWORD dwMappable;
  1118. DWORD dwSize;
  1119. DWORD dwType;
  1120. dwSize = sizeof(dwMappable);
  1121. if (RegQueryValueEx (hKey,
  1122. REGSTR_VALUE_MAPPABLE,
  1123. NULL,
  1124. &dwType,
  1125. (void *)&dwMappable,
  1126. &dwSize) != ERROR_SUCCESS)
  1127. {
  1128. dwMappable = 1;
  1129. }
  1130. RegCloseKey (hKey);
  1131. mmr = (dwMappable) ? MMSYSERR_NOERROR :
  1132. MMSYSERR_NOTSUPPORTED;
  1133. }
  1134. }
  1135. break;
  1136. case DRV_QUERYMAPID:
  1137. WinAssert(DRV_QUERYMAPID != uMessage);
  1138. mmr = MMSYSERR_NOTSUPPORTED;
  1139. break;
  1140. case DRV_QUERYNUMPORTS:
  1141. if (ValidateWritePointer( (LPVOID)dwParam1, sizeof(DWORD)))
  1142. {
  1143. *((LPDWORD)dwParam1) = pmd->NumDevs;
  1144. }
  1145. else
  1146. {
  1147. mmr = MMSYSERR_INVALPARAM;
  1148. }
  1149. break;
  1150. case DRV_QUERYMODULE:
  1151. if (ValidateWritePointer( (LPVOID)dwParam1, sizeof(DWORD)))
  1152. {
  1153. hModule = DrvGetModuleHandle(pmd->hDriver);
  1154. *((HMODULE *)dwParam1) = hModule;
  1155. }
  1156. else
  1157. {
  1158. mmr = MMSYSERR_INVALPARAM;
  1159. }
  1160. break;
  1161. default:
  1162. // Not an internal message
  1163. fResult = FALSE;
  1164. break;
  1165. }
  1166. if (pmmr)
  1167. *pmmr = mmr;
  1168. return fResult;
  1169. } // End mregHandleInternalMessage
  1170. /*==========================================================================*/
  1171. /*
  1172. @doc INTERNAL MMSYSTEM
  1173. @func <t UINT> | mregRemoveDriver |
  1174. Sends exit message to the driver message entry, and closes the
  1175. installable driver. Then releases resources referenced by the MMDRV
  1176. structure. Finally removes the MMDRV structure from its list and
  1177. frees it.
  1178. @parm <t PMMDRV> | pdrv |
  1179. Pointer to the MMDRV node associated with the driver
  1180. @rdesc No return value
  1181. @comm This function assumes the list containing pdrv is locked.
  1182. @xref mregDecUsage
  1183. */
  1184. void mregRemoveDriver(PMMDRV pdrv)
  1185. {
  1186. WinAssert(pdrv->cookie);
  1187. WinAssert(pdrv->drvMessage);
  1188. WinAssert(pdrv->hDriver);
  1189. StringIdDict_Remove(pdrv);
  1190. pdrv->drvMessage(0, DRVM_EXIT, 0L, 0L, (DWORD_PTR)pdrv->cookie);
  1191. DrvClose(pdrv->hDriver, 0, 0);
  1192. pdrv->Prev->Next = pdrv->Next;
  1193. pdrv->Next->Prev = pdrv->Prev;
  1194. DeleteCriticalSection(&pdrv->MixerCritSec);
  1195. wdmDevInterfaceDec(pdrv->cookie);
  1196. ZeroMemory(pdrv, sizeof(*pdrv));
  1197. HeapFree(hHeap, 0, pdrv);
  1198. return;
  1199. }
  1200. void mregAddDriver(PMMDRV pdrvZ, PMMDRV pdrv)
  1201. {
  1202. pdrv->Prev = pdrvZ->Prev;
  1203. pdrv->Next = pdrvZ;
  1204. pdrv->Prev->Next = pdrv;
  1205. pdrv->Next->Prev = pdrv;
  1206. StringIdDict_Insert(pdrv);
  1207. }
  1208. /*==========================================================================*/
  1209. /*
  1210. @doc INTERNAL MMSYSTEM
  1211. @func <t UINT> | mregIncUsage |
  1212. Increments the usage count of the specified media resource. If the
  1213. usage count is non-zero, the media resource cannot be unloaded. The
  1214. usage count is increased when instances of the media resource are
  1215. opened, such as with a <f waveOutOpen> call.
  1216. @parm <t HMD> | hmd |
  1217. Contains the media resource handle to increment.
  1218. @rdesc Returns the current usage count.
  1219. @xref mregDecUsage, mregQueryUsage
  1220. */
  1221. UINT FAR PASCAL mregIncUsagePtr(
  1222. PMMDRV pmd
  1223. )
  1224. {
  1225. return InterlockedIncrement(&pmd->Usage);
  1226. }
  1227. UINT FAR PASCAL mregIncUsage(
  1228. HMD hmd
  1229. )
  1230. {
  1231. return mregIncUsagePtr(HtoPT(PMMDRV, hmd));
  1232. }
  1233. /*==========================================================================*/
  1234. /*
  1235. @doc INTERNAL MMSYSTEM
  1236. @func <t UINT> | mregDecUsage |
  1237. Decrements the usage count of the specified media resource. If the
  1238. usage count is zero, the media resource can be unloaded. The usage
  1239. count is decresed when instance of the media resource are closed, such
  1240. as with a <f waveOutClose> call.
  1241. @parm <t PMMDRV> | pdrv |
  1242. Pointer to the media resource to decrement.
  1243. @rdesc Returns the current usage count.
  1244. @comm Unless the caller has other usages on the pdrv, it must not use
  1245. it after this call returns.
  1246. @xref mregIncUsage, mregQueryUsage
  1247. */
  1248. UINT FAR PASCAL mregDecUsagePtr(
  1249. PMMDRV pdrv
  1250. )
  1251. {
  1252. UINT refcount;
  1253. EnterNumDevs("mregDecUsage");
  1254. refcount = InterlockedDecrement(&pdrv->Usage);
  1255. if (0 == refcount)
  1256. {
  1257. WinAssert(pdrv->fdwDriver & MMDRV_DESERTED);
  1258. mregRemoveDriver(pdrv);
  1259. }
  1260. LeaveNumDevs("mregDecUsage");
  1261. return refcount;
  1262. }
  1263. UINT FAR PASCAL mregDecUsage(
  1264. HMD hmd
  1265. )
  1266. {
  1267. return mregDecUsagePtr(HtoPT(PMMDRV, hmd));
  1268. }
  1269. /*==========================================================================*/
  1270. /*
  1271. @doc INTERNAL MMSYSTEM
  1272. @func <t MMRESULT> | mregFindDevice |
  1273. Given a Device Identifier of a specific Resource Class, returns the
  1274. corresponding Resource handle and port. This can then be used to
  1275. communicate with the driver. The resource handle is referenced
  1276. (i.e., its usage is incremented). The caller is responsible for
  1277. ensureing it is eventually released by calling mregDecUsage.
  1278. @parm <t UINT> | uDeviceID |
  1279. Contains the Device Identifier whose handle and port is to be returned.
  1280. If this contains -1, then it is assumed that a mapper of the specified
  1281. class is being sought. These identifiers correspond to the <lq>Device
  1282. IDs<rq> used with various functions such as <f waveOutOpen>. This
  1283. enables the various components to search for internal media resource
  1284. handles based on Device IDs passed to public APIs.
  1285. @parm <t WORD> | fwFindDevice |
  1286. Contains the flags specifying the class of device.
  1287. @flag <cl MMDRVI_WAVEIN> | Wave Input device.
  1288. @flag <cl MMDRVI_WAVEOUT> | Wave Output device.
  1289. @flag <cl MMDRVI_MIDIIN> | MIDI Input device.
  1290. @flag <cl MMDRVI_MIDIOUT> | MIDI Output device.
  1291. @flag <cl MMDRVI_AUX> | Aux device.
  1292. @flag <cl MMDRVI_MIXER> | Mixer device.
  1293. @flag <cl MMDRVI_JOY> | Joystick device.
  1294. @flag <cl MMDRVI_MAPPER> | Mapper device of the specified class. This is used
  1295. in addition to any of the above resource classes in order to specify
  1296. that the class mapper is to be returned. If this is not specified, the
  1297. mapper is not returned as a match to a query.
  1298. @parm <t HMD> <c FAR>* | phmd |
  1299. Points to a buffer in which to place the Media Resource Handle.
  1300. @parm <t UINT> <c FAR>* | puDevicePort |
  1301. Points to a buffer in which to place the Device Port. This is used as
  1302. a parameter when sending messages to the device to specify which port.
  1303. @rdesc Returns <cl MMSYSERR_BADDEVICEID> if the specified Device Identifier was
  1304. out of range, else <cl MMSYSERR_NOERROR> on success.
  1305. @xref mregEnumDevice, mregGetNumDevs, mregDecUsage
  1306. */
  1307. MMRESULT FAR PASCAL mregFindDevice(
  1308. UINT uDeviceID,
  1309. WORD fwFindDevice,
  1310. HMD FAR* phmd,
  1311. UINT FAR* puDevicePort)
  1312. {
  1313. PMMDRV pmd;
  1314. UINT port;
  1315. MMRESULT mmr;
  1316. WinAssert((TYPE_MIDIOUT == (fwFindDevice & MMDRVI_TYPE)) || (TYPE_MIDIIN == (fwFindDevice & MMDRVI_TYPE)));
  1317. switch (fwFindDevice & MMDRVI_TYPE)
  1318. {
  1319. case TYPE_MIDIOUT:
  1320. mmr = midiReferenceDriverById(&midioutdrvZ, uDeviceID, &pmd, &port);
  1321. break;
  1322. case TYPE_MIDIIN:
  1323. mmr = midiReferenceDriverById(&midiindrvZ, uDeviceID, &pmd, &port);
  1324. break;
  1325. default:
  1326. return MMSYSERR_BADDEVICEID;
  1327. }
  1328. if (!mmr)
  1329. {
  1330. WinAssert(pmd);
  1331. *phmd = PTtoH(HMD, pmd);
  1332. *puDevicePort = port;
  1333. }
  1334. return mmr;
  1335. }