Windows NT 4.0 source code leak
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.

971 lines
24 KiB

4 years ago
  1. /****************************************************************************
  2. *
  3. * drvutil.c
  4. *
  5. * Multimedia kernel driver support component (drvlib)
  6. *
  7. * Copyright (c) Microsoft Corporation 1993 - 1995. All rights reserved.
  8. *
  9. * Support functions common to multiple multi-media drivers :
  10. *
  11. * -- Open a device
  12. * -- Translate a kernel IO return code to a multi-media return code
  13. * -- Count the number of devices of a given type
  14. * -- Set and Get data synchronously to a kernel device
  15. *
  16. * History
  17. * 01-Feb-1992 - Robin Speed (RobinSp) wrote it
  18. * 04-Feb-1992 - Reviewed by SteveDav
  19. *
  20. ***************************************************************************/
  21. #include <drvlib.h>
  22. #include <ntddwave.h>
  23. #include <ntddmidi.h>
  24. #include <ntddaux.h>
  25. #include <registry.h>
  26. /*
  27. ** External name of driver
  28. */
  29. extern TCHAR DriverName[];
  30. /*
  31. ** We need an hInstance module handle to get strings from since the kernel
  32. ** driver returns string Ids in its structures
  33. */
  34. extern HINSTANCE hInstance;
  35. /*
  36. ** Internal structures
  37. */
  38. /*
  39. ** List of cached device descriptions. This is generated when the
  40. ** driver is loaded from the data in the registry so that multiple
  41. ** queries are faster and consistent.
  42. */
  43. typedef struct _DEVICE_LIST {
  44. struct _DEVICE_LIST *Next; // Next pointer
  45. DWORD DeviceType; // Type of device
  46. ULONG CardIndex; // Card entry registry key index
  47. PVOID DeviceInstanceData; // Instance data for this specific device
  48. // if needed.
  49. ULONG DeviceInstanceDataSize;
  50. WCHAR Name[1]; // Device name
  51. } DEVICE_LIST, *PDEVICE_LIST;
  52. PDEVICE_LIST DeviceList;
  53. /*
  54. ** Internal routines
  55. */
  56. PDEVICE_LIST sndFindDevice(DWORD DeviceType, DWORD dwId);
  57. BOOL sndProcessDevices(HKEY DevicesKey, PDEVICE_LIST *DeviceList, DWORD CardIndex);
  58. BOOL sndAppendToDeviceList(PDEVICE_LIST *pList, DWORD DeviceType, DWORD CardIndex,
  59. LPWSTR Name);
  60. VOID sndFreeDeviceList(VOID);
  61. BOOL sndEnumKey(HKEY Key, DWORD Index, LPTSTR OurKey, HKEY *pSubkey);
  62. /****************************************************************************
  63. * @doc INTERNAL
  64. *
  65. * @api MMRESULT | sndOpenDev | Open the kernel driver device corresponding
  66. * to a logical wave device id
  67. *
  68. * @parm UINT | DeviceType | The type of device
  69. *
  70. * @parm DWORD | dwId | The device id
  71. *
  72. * @parm PHANDLE | phDev | Where to return the kernel device handle
  73. *
  74. * @parm ACCESS_MASK | Access | The desired access
  75. *
  76. * @comm For our sound devices the only relevant access are read and
  77. * read/write. Device should ALWAYS allow opens for read unless some
  78. * resource or access-rights restriction occurs.
  79. ***************************************************************************/
  80. MMRESULT sndOpenDev(UINT DeviceType, DWORD dwId,
  81. PHANDLE phDev, DWORD Access)
  82. {
  83. PDEVICE_LIST List;
  84. WCHAR cDev[SOUND_MAX_DEVICE_NAME + 4];
  85. List = sndFindDevice(DeviceType, dwId);
  86. *phDev = INVALID_HANDLE_VALUE; // Always initialise the return value
  87. if (List == NULL) {
  88. return MMSYSERR_BADDEVICEID;
  89. }
  90. //
  91. // Create the device name and open it - remove '\Device'
  92. //
  93. wsprintf(cDev, L"\\\\.\\%ls", List->Name);
  94. *phDev = CreateFile(cDev,
  95. Access,
  96. FILE_SHARE_WRITE,
  97. NULL,
  98. OPEN_EXISTING,
  99. Access != GENERIC_READ ? FILE_FLAG_OVERLAPPED : 0,
  100. NULL);
  101. //
  102. // Check up on the driver for refusing to open
  103. // multiply for read
  104. //
  105. WinAssert(!(GetLastError() == ERROR_ACCESS_DENIED &&
  106. Access == GENERIC_READ));
  107. //
  108. // Return status to caller
  109. //
  110. return *phDev != INVALID_HANDLE_VALUE ? MMSYSERR_NOERROR : sndTranslateStatus();
  111. }
  112. /****************************************************************************
  113. * @doc INTERNAL
  114. *
  115. * @api void | sndTranslateStatus | This function translates an NT status
  116. * code into a multi-media error code as far as possible.
  117. *
  118. * @parm NTSTATUS | Status | The NT base operating system return status.
  119. *
  120. *
  121. * @rdesc The multi-media error code.
  122. ***************************************************************************/
  123. DWORD sndTranslateStatus(void)
  124. {
  125. #if DBG
  126. UINT n;
  127. switch (n=GetLastError()) {
  128. #else
  129. switch (GetLastError()) {
  130. #endif
  131. case NO_ERROR:
  132. case ERROR_IO_PENDING:
  133. return MMSYSERR_NOERROR;
  134. case ERROR_BUSY:
  135. return MMSYSERR_ALLOCATED;
  136. case ERROR_NOT_SUPPORTED:
  137. case ERROR_INVALID_FUNCTION:
  138. return MMSYSERR_NOTSUPPORTED;
  139. case ERROR_NOT_ENOUGH_MEMORY:
  140. return MMSYSERR_NOMEM;
  141. case ERROR_ACCESS_DENIED:
  142. return MMSYSERR_BADDEVICEID;
  143. case ERROR_INSUFFICIENT_BUFFER:
  144. return MMSYSERR_INVALPARAM;
  145. default:
  146. dprintf2(("sndTranslateStatus: LastError = %d", n));
  147. return MMSYSERR_ERROR;
  148. }
  149. }
  150. /****************************************************************************
  151. * @doc INTERNAL
  152. *
  153. * @api DWORD | sndGetNumDevs | This function returns the number of (kernel)
  154. *
  155. * @parm UINT | DeviceType | The Device type
  156. *
  157. * @rdesc The number of devices.
  158. ***************************************************************************/
  159. DWORD sndGetNumDevs(UINT DeviceType)
  160. {
  161. //
  162. // Search the device list for devices of our type
  163. //
  164. int i;
  165. PDEVICE_LIST List;
  166. for (List = DeviceList, i= 0; List != NULL; List = List->Next) {
  167. if (List->DeviceType == DeviceType) {
  168. i++;
  169. }
  170. }
  171. return i;
  172. }
  173. /****************************************************************************
  174. * @doc INTERNAL
  175. *
  176. * @api DWORD | sndSetData | This function sets the volume given a device id
  177. * and could be used for other soft value setting
  178. * when only read access is required to the device
  179. *
  180. * @parm UINT | DeviceType | The Device type
  181. *
  182. * @parm UINT | DeviceId | The device id
  183. *
  184. * @parm UINT | Length | Length of data to set
  185. *
  186. * @parm PBYTE | Data | Data to set
  187. *
  188. * @parm ULONG | Ioctl | The Ioctl to use
  189. *
  190. * @rdesc MM... return code.
  191. ***************************************************************************/
  192. MMRESULT sndSetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
  193. ULONG Ioctl)
  194. {
  195. HANDLE hDev;
  196. MMRESULT mRet;
  197. DWORD BytesReturned;
  198. //
  199. // Open the device
  200. //
  201. mRet = sndOpenDev(DeviceType, DeviceId, &hDev, GENERIC_READ);
  202. if (mRet != MMSYSERR_NOERROR) {
  203. return mRet;
  204. }
  205. //
  206. // Set our data.
  207. //
  208. // Setting the overlapped parameter (last) to null means we
  209. // wait until the operation completes.
  210. //
  211. mRet = DeviceIoControl(hDev, Ioctl, Data, Length, NULL, 0,
  212. &BytesReturned, NULL) ?
  213. MMSYSERR_NOERROR : sndTranslateStatus();
  214. //
  215. // Close our file and return
  216. //
  217. CloseHandle(hDev);
  218. return mRet;
  219. }
  220. /****************************************************************************
  221. * @doc INTERNAL
  222. *
  223. * @api DWORD | sndGetData | This function gets data from a given device
  224. * specified by device id when read-only access is
  225. * sufficient
  226. *
  227. * @parm UINT | DeviceType | The Device type
  228. *
  229. * @parm UINT | DeviceId | The device id
  230. *
  231. * @parm UINT | Length | Length of data to set
  232. *
  233. * @parm PBYTE | Data | Data to set
  234. *
  235. * @parm ULONG | Ioctl | The Ioctl to use
  236. *
  237. * @rdesc MM... return code.
  238. ***************************************************************************/
  239. MMRESULT sndGetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
  240. ULONG Ioctl)
  241. {
  242. HANDLE hDev;
  243. MMRESULT mRet;
  244. DWORD BytesReturned;
  245. //
  246. // Open the wave output device
  247. //
  248. mRet = sndOpenDev(DeviceType, DeviceId, &hDev, GENERIC_READ);
  249. if (mRet != MMSYSERR_NOERROR) {
  250. return mRet;
  251. }
  252. //
  253. // Set our data.
  254. //
  255. // Setting the overlapped parameter (last) to null means we
  256. // wait until the operation completes.
  257. //
  258. mRet = DeviceIoControl(hDev, Ioctl, NULL, 0, (LPVOID)Data, Length,
  259. &BytesReturned, NULL) ?
  260. MMSYSERR_NOERROR : sndTranslateStatus();
  261. //
  262. // Close our file and return
  263. //
  264. CloseHandle(hDev);
  265. return mRet;
  266. }
  267. /****************************************************************************
  268. * @doc INTERNAL
  269. *
  270. * @api MMRESULT | sndGetHandleData | Get data from a device using its handle
  271. *
  272. * @parm PWAVEALLOC | pClient | Client handle.
  273. *
  274. * @parm DWORD | dwSize | Size of the data
  275. *
  276. * @parm PVOID | pData | Where to put the data.
  277. *
  278. * @parm ULONG | Function | The Ioctl to use
  279. *
  280. * @rdesc MMSYS... return value.
  281. ***************************************************************************/
  282. MMRESULT sndGetHandleData(HANDLE hDev,
  283. DWORD dwSize,
  284. PVOID pData,
  285. ULONG Ioctl,
  286. HANDLE hEvent)
  287. {
  288. OVERLAPPED Overlap;
  289. DWORD BytesReturned;
  290. WinAssert(hDev != NULL);
  291. memset(&Overlap, 0, sizeof(Overlap));
  292. Overlap.hEvent = hEvent;
  293. //
  294. // Issue the IO control. We must wait with our own event because
  295. // setting the overlapped object to null will complete if other
  296. // IOs complete.
  297. //
  298. if (!DeviceIoControl(hDev,
  299. Ioctl,
  300. NULL,
  301. 0,
  302. pData,
  303. dwSize,
  304. &BytesReturned,
  305. &Overlap)) {
  306. DWORD cbTransfer;
  307. //
  308. // Wait for completion if necessary
  309. //
  310. if (GetLastError() == ERROR_IO_PENDING) {
  311. if (!GetOverlappedResult(hDev, &Overlap, &cbTransfer,
  312. TRUE)) {
  313. return sndTranslateStatus();
  314. }
  315. } else {
  316. return sndTranslateStatus();
  317. }
  318. }
  319. //
  320. // We'd better peek aleratbly to flush out any IO
  321. // completions so that things like RESET only
  322. // return when all buffers have been completed
  323. //
  324. // This relies on the fact that SleepEx will return
  325. // WAIT_IO_COMPLETION in preference to OK
  326. //
  327. while (SetEvent(hEvent) &&
  328. WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_IO_COMPLETION) {}
  329. return MMSYSERR_NOERROR;
  330. }
  331. /****************************************************************************
  332. * @doc INTERNAL
  333. *
  334. * @api MMRESULT | sndSetHandleData | Pass data to a device using its handle
  335. *
  336. * @parm PWAVEALLOC | pClient | Client handle.
  337. *
  338. * @parm DWORD | dwSize | Size of the data
  339. *
  340. * @parm PVOID | pData | Data to send.
  341. *
  342. * @parm ULONG | Function | The Ioctl to use
  343. *
  344. * @rdesc MMSYS... return value.
  345. ***************************************************************************/
  346. MMRESULT sndSetHandleData(HANDLE hDev,
  347. DWORD dwSize,
  348. PVOID pData,
  349. ULONG Ioctl,
  350. HANDLE hEvent)
  351. {
  352. OVERLAPPED Overlap;
  353. DWORD BytesReturned;
  354. WinAssert(hDev != NULL);
  355. memset((PVOID)&Overlap, 0, sizeof(Overlap));
  356. Overlap.hEvent = hEvent;
  357. //
  358. // Issue the IO control. We must wait with our own event because
  359. // setting the overlapped object to null will complete if other
  360. // IOs complete.
  361. //
  362. if (!DeviceIoControl(hDev,
  363. Ioctl,
  364. pData,
  365. dwSize,
  366. NULL,
  367. 0,
  368. &BytesReturned,
  369. &Overlap)) {
  370. DWORD cbTransfer;
  371. //
  372. // Wait for completion if necessary
  373. //
  374. if (GetLastError() == ERROR_IO_PENDING) {
  375. if (!GetOverlappedResult(hDev, &Overlap, &cbTransfer,
  376. TRUE)) {
  377. return sndTranslateStatus();
  378. }
  379. } else {
  380. return sndTranslateStatus();
  381. }
  382. }
  383. //
  384. // We'd better peek alertably to flush out any IO
  385. // completions so that things like RESET only
  386. // return when all buffers have been completed
  387. //
  388. // This relies on the fact that SleepEx will return
  389. // WAIT_IO_COMPLETION in preference to OK
  390. //
  391. while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) {}
  392. return MMSYSERR_NOERROR;
  393. }
  394. HKEY sndOpenParametersKey(VOID)
  395. {
  396. return DrvOpenRegKey(DriverName, TEXT(""));
  397. }
  398. /****************************************************************************
  399. * @doc INTERNAL
  400. *
  401. * @api MMRESULT | sndFindDevices | Find all the devices using its handle
  402. *
  403. * @parm HKEY | Key| Handle to
  404. *
  405. * @parm PDEVICE_LIST * | DeviceList | The data about the devices found is
  406. * returned here.
  407. *
  408. * @rdesc MMSYS... return value.
  409. *
  410. * @comm
  411. * The registry structure is assumed to be (eg)
  412. *
  413. * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\sndsys\Parameters..
  414. *
  415. * Parameters
  416. * Device0 One key for each card found
  417. * DriverParameters
  418. * Interrupt REG_DWORD
  419. * Port REG_DWORD
  420. * DmaChannel REG_DWORD
  421. * Devices (Volatile key)
  422. * WSSWave0 REG_BINARY (device data)
  423. * WSSMix1 REG_BINARY (device data)
  424. * MixerSettings REG_BINARY
  425. *
  426. * The (device data) for each device contains :
  427. *
  428. * DWORD DeviceType
  429. * BYTE DeviceInstanceData[]
  430. *
  431. * NOTE - DON'T use the 'standard' names (eg WaveOut0) for your device
  432. * or mmdrv will try to grab those devices.
  433. *
  434. *
  435. ***************************************************************************/
  436. MMRESULT sndFindDevices(VOID)
  437. {
  438. DWORD Index;
  439. HKEY DriverKey;
  440. WinAssert(DeviceList == NULL);
  441. /*
  442. ** Open the driver's registry key
  443. */
  444. DriverKey = sndOpenParametersKey();
  445. if (DriverKey == NULL) {
  446. return sndTranslateStatus();
  447. }
  448. for (Index = 0; ; Index++) {
  449. BOOL Rc;
  450. HKEY Subkey;
  451. if (!sndEnumKey(DriverKey, Index, SOUND_DEVICES_SUBKEY, &Subkey)) {
  452. sndFreeDeviceList();
  453. RegCloseKey(DriverKey);
  454. return sndTranslateStatus();
  455. }
  456. /*
  457. ** Null returned subkey means end of list
  458. */
  459. if (Subkey == NULL) {
  460. break;
  461. }
  462. /*
  463. ** Process all the data for this device :
  464. */
  465. Rc = sndProcessDevices(Subkey, &DeviceList, Index);
  466. RegCloseKey(Subkey);
  467. if (!Rc) {
  468. sndFreeDeviceList();
  469. RegCloseKey(DriverKey);
  470. return sndTranslateStatus();
  471. }
  472. }
  473. RegCloseKey(DriverKey);
  474. return MMSYSERR_NOERROR;
  475. }
  476. BOOL sndProcessDevices(HKEY DevicesKey, PDEVICE_LIST *DeviceList, DWORD CardIndex)
  477. {
  478. BOOL Rc;
  479. DWORD Index;
  480. DWORD Length;
  481. DWORD Type;
  482. DWORD Value;
  483. Rc = TRUE;
  484. for (Index = 0; ; Index++) {
  485. WCHAR DeviceName[SOUND_MAX_DEVICE_NAME];
  486. DWORD Error;
  487. DWORD cbSize;
  488. PBYTE Data;
  489. Length = sizeof(DeviceName) / sizeof(DeviceName[0]);
  490. cbSize = 0;
  491. /*
  492. ** Can't get the value at the same time as the key name because
  493. ** bugs in RegEnumValue mean that if the value is too big you
  494. ** won't get any of it!
  495. */
  496. Error = RegEnumValue(DevicesKey,
  497. Index,
  498. DeviceName,
  499. &Length,
  500. NULL,
  501. NULL,
  502. NULL,
  503. &cbSize);
  504. if (Error == ERROR_NO_MORE_ITEMS) {
  505. break;
  506. }
  507. /*
  508. ** Check we got the data we wanted
  509. */
  510. if (Error != ERROR_SUCCESS) {
  511. Rc = FALSE;
  512. break;
  513. }
  514. if (cbSize < sizeof(DWORD)) {
  515. SetLastError(ERROR_INVALID_DATA);
  516. Rc = FALSE;
  517. break;
  518. }
  519. /*
  520. ** Get some space for the value
  521. */
  522. Data = (PBYTE)HeapAlloc(hHeap, 0, cbSize);
  523. if (Data == NULL) {
  524. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  525. Rc = FALSE;
  526. break;
  527. }
  528. /*
  529. ** Read the actual value
  530. */
  531. Error = RegQueryValueEx(DevicesKey,
  532. DeviceName,
  533. NULL,
  534. &Type,
  535. Data,
  536. &cbSize);
  537. Value = *(LPDWORD)Data;
  538. HeapFree(hHeap, 0, Data);
  539. /*
  540. ** The kernel driver is supposed to put either a binary or
  541. ** DWORD into the registry
  542. */
  543. if (Error != ERROR_SUCCESS) {
  544. Rc = FALSE;
  545. break;
  546. }
  547. if (Type != REG_DWORD && Type != REG_BINARY ||
  548. cbSize < sizeof(DWORD)) {
  549. dprintf(("Invalid device type!"));
  550. WinAssert(FALSE);
  551. SetLastError(ERROR_INVALID_DATA);
  552. Rc = FALSE;
  553. break;
  554. }
  555. /*
  556. ** Store the device data in the table
  557. **
  558. ** When we actually open it we're going to need to append
  559. ** \\.\ .. to it
  560. */
  561. if (!sndAppendToDeviceList(DeviceList, Value, CardIndex, DeviceName)) {
  562. Rc = FALSE;
  563. break;
  564. }
  565. }
  566. return Rc;
  567. }
  568. BOOL sndEnumKey(HKEY Key, DWORD Index, LPTSTR OurKey, HKEY *pSubkey)
  569. {
  570. DWORD cchName;
  571. WCHAR SubKeyName[50];
  572. HKEY Subkey;
  573. UINT OurKeyLen;
  574. OurKeyLen = lstrlen(OurKey);
  575. cchName = sizeof(SubKeyName) / sizeof(SubKeyName[0]) - OurKeyLen;
  576. switch (RegEnumKeyEx(Key,
  577. Index,
  578. SubKeyName,
  579. &cchName,
  580. NULL,
  581. NULL,
  582. NULL,
  583. NULL)) {
  584. case ERROR_SUCCESS:
  585. if (OurKeyLen != 0) {
  586. wcscat(SubKeyName, TEXT("\\"));
  587. }
  588. wcscat(SubKeyName, OurKey);
  589. if (ERROR_SUCCESS != RegOpenKeyEx(Key,
  590. SubKeyName,
  591. 0,
  592. KEY_READ,
  593. &Subkey)) {
  594. return FALSE;
  595. } else {
  596. *pSubkey = Subkey;
  597. return TRUE;
  598. }
  599. case ERROR_NO_MORE_ITEMS:
  600. *pSubkey = NULL;
  601. return TRUE;
  602. default:
  603. return FALSE;
  604. }
  605. }
  606. BOOL sndAppendToDeviceList(
  607. PDEVICE_LIST *pList,
  608. DWORD DeviceType,
  609. DWORD CardIndex,
  610. LPWSTR Name)
  611. {
  612. PDEVICE_LIST pNew;
  613. #if DBG
  614. PDEVICE_LIST List;
  615. for (List = *pList; List != NULL; List = List->Next) {
  616. if (List->DeviceType == DeviceType &&
  617. lstrcmpi(List->Name, Name) == 0) {
  618. dprintf(("Duplicate device name found - %ls!!", Name));
  619. DebugBreak();
  620. }
  621. }
  622. #endif // DBG
  623. /*
  624. ** Allocate space for the new entry.
  625. **
  626. ** Note that the space for the trailing null in the name is accounted
  627. ** for by the length of 1 given to the Name structure entry.
  628. */
  629. pNew = (PDEVICE_LIST)HeapAlloc(
  630. hHeap,
  631. 0,
  632. sizeof(DEVICE_LIST) + lstrlen(Name) * sizeof(WCHAR));
  633. if (pNew == NULL) {
  634. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  635. return FALSE;
  636. }
  637. /*
  638. ** Fill in the new entry
  639. */
  640. pNew->DeviceType = DeviceType;
  641. pNew->CardIndex = CardIndex;
  642. lstrcpy(pNew->Name, Name);
  643. pNew->DeviceInstanceData = NULL;
  644. pNew->Next = *pList;
  645. *pList = pNew;
  646. return TRUE;
  647. }
  648. VOID sndFreeDeviceList(VOID)
  649. {
  650. PDEVICE_LIST pFree;
  651. for (; DeviceList != NULL; ) {
  652. pFree = DeviceList;
  653. DeviceList = pFree->Next;
  654. if (pFree->DeviceInstanceData != NULL) {
  655. HeapFree(hHeap, 0, (LPVOID)pFree->DeviceInstanceData);
  656. }
  657. HeapFree(hHeap, 0, (LPSTR)pFree);
  658. }
  659. }
  660. /*
  661. ** Load the device data into the device list
  662. */
  663. PVOID sndLoadDeviceData(DWORD DeviceType, DWORD dwId, LPDWORD pSize)
  664. {
  665. PDEVICE_LIST List;
  666. HKEY DriverKey;
  667. DWORD Index;
  668. BOOL Rc;
  669. PVOID DeviceData;
  670. DeviceData = NULL;
  671. List = sndFindDevice(DeviceType, dwId);
  672. WinAssert(List != NULL);
  673. /*
  674. ** Search through all the entries trying to open the key with the
  675. ** device name. Note that it's possible for the registry to have
  676. ** totally changed so we can't assume all this is going to work
  677. ** or give the correct result. We can check the device type of
  678. ** the entry we open and of course the name must be correct.
  679. */
  680. DriverKey = sndOpenParametersKey();
  681. for (Index = 0, Rc = FALSE; ; Index++) {
  682. HKEY Subkey;
  683. DWORD Type;
  684. DWORD Size;
  685. if (!sndEnumKey(DriverKey, Index, SOUND_DEVICES_SUBKEY, &Subkey)) {
  686. RegCloseKey(DriverKey);
  687. return FALSE;
  688. }
  689. /*
  690. ** Null returned subkey means end of list
  691. */
  692. if (Subkey == NULL) {
  693. break;
  694. }
  695. if (Rc) {
  696. /*
  697. ** Try to get the data for this device
  698. */
  699. Size = 0;
  700. Rc = (ERROR_SUCCESS == RegQueryValueEx(Subkey,
  701. List->Name,
  702. NULL,
  703. &Type,
  704. NULL,
  705. &Size));
  706. }
  707. if (Rc) {
  708. /*
  709. ** Allocate some space and try to load it
  710. */
  711. DeviceData = (PVOID)HeapAlloc(hHeap, 0, Size);
  712. if (DeviceData != NULL) {
  713. Rc = (ERROR_SUCCESS == RegQueryValueEx(Subkey,
  714. List->Name,
  715. NULL,
  716. &Type,
  717. DeviceData,
  718. &Size));
  719. RegCloseKey(Subkey);
  720. if (!Rc ||
  721. *(LPDWORD)DeviceData != DeviceType) {
  722. LocalFree((HLOCAL)DeviceData);
  723. DeviceData = NULL;
  724. } else {
  725. *pSize = Size;
  726. }
  727. }
  728. /*
  729. ** This was the one we wanted
  730. */
  731. break;
  732. } else {
  733. RegCloseKey(Subkey);
  734. }
  735. }
  736. RegCloseKey(DriverKey);
  737. return DeviceData;
  738. }
  739. PDEVICE_LIST sndFindDevice(DWORD DeviceType, DWORD dwId)
  740. {
  741. PDEVICE_LIST List;
  742. DWORD CurrentId;
  743. for (List = DeviceList, CurrentId = 0; List != NULL; List = List->Next) {
  744. if (List->DeviceType == DeviceType) {
  745. if (CurrentId == dwId) {
  746. break;
  747. } else {
  748. CurrentId++;
  749. }
  750. }
  751. }
  752. return List;
  753. }
  754. BOOL sndFindDeviceInstanceData(DWORD DeviceType, DWORD dwId,
  755. PVOID *InstanceData)
  756. {
  757. PDEVICE_LIST List;
  758. List = sndFindDevice(DeviceType, dwId);
  759. if (List == NULL) {
  760. return FALSE;
  761. }
  762. *InstanceData = List->DeviceInstanceData;
  763. return TRUE;
  764. }
  765. BOOL sndSetDeviceInstanceData(DWORD DeviceType, DWORD dwId,
  766. PVOID InstanceData)
  767. {
  768. PDEVICE_LIST List;
  769. List = sndFindDevice(DeviceType, dwId);
  770. WinAssert(List != NULL);
  771. WinAssert(List->DeviceInstanceData == NULL);
  772. List->DeviceInstanceData = InstanceData;
  773. return TRUE;
  774. }
  775. /*
  776. ** Package up LoadString a bit
  777. */
  778. void InternalLoadString(UINT StringId, LPTSTR pszString, UINT Length)
  779. {
  780. ZeroMemory(pszString, Length * sizeof(pszString[0]));
  781. if (StringId != 0) {
  782. LoadString(hInstance, StringId, pszString, Length);
  783. }
  784. }