xref: /reactos/sdk/lib/drivers/sound/mment4/detect.c (revision 9e066abe)
1 /*
2  * PROJECT:     ReactOS Sound System "MME Buddy" NT4 Library
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        lib/drivers/sound/mment4/detect.c
5  *
6  * PURPOSE:     Assists in locating Windows NT4 compatible sound devices,
7  *              which mostly use the same device naming convention and/or
8  *              store their created device names within their service key
9  *              within the registry.
10  *
11  * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
12 */
13 
14 #include "precomp.h"
15 
16 #include <mment4.h>
17 #include <mmebuddy_debug.h>
18 
19 /*
20     This is the "nice" way to discover audio devices in NT4 - go into the
21     service registry key and enumerate the Parameters\Device*\Devices
22     values. The value names represent the device name, whereas the data
23     assigned to them identifies the type of device.
24 */
25 MMRESULT
EnumerateNt4ServiceSoundDevices(IN LPWSTR ServiceName,IN MMDEVICE_TYPE DeviceType,IN SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc)26 EnumerateNt4ServiceSoundDevices(
27     IN  LPWSTR ServiceName,
28     IN  MMDEVICE_TYPE DeviceType,
29     IN  SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc)
30 {
31     HKEY Key;
32     DWORD KeyIndex = 0;
33 
34     VALIDATE_MMSYS_PARAMETER( ServiceName );
35 
36     /* Device type zero means "all" */
37     VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) ||
38                               DeviceType == 0 );
39 
40     while ( OpenSoundDeviceRegKey(ServiceName, KeyIndex, &Key) == MMSYSERR_NOERROR )
41     {
42         HKEY DevicesKey;
43         DWORD ValueType = REG_NONE, ValueIndex = 0;
44         DWORD MaxNameLength = 0, ValueNameLength = 0;
45         PWSTR DevicePath = NULL, ValueName = NULL;
46         DWORD ValueDataLength = sizeof(DWORD);
47         DWORD ValueData;
48 
49         if ( RegOpenKeyEx(Key,
50                           REG_DEVICES_KEY_NAME_U,
51                           0,
52                           KEY_READ,
53                           &DevicesKey) == ERROR_SUCCESS )
54         {
55             /* Find out how much memory is needed for the key name */
56             if ( RegQueryInfoKey(DevicesKey,
57                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
58                                  &MaxNameLength,
59                                  NULL, NULL, NULL) != ERROR_SUCCESS )
60             {
61                 SND_ERR(L"Failed to query registry key information\n");
62                 RegCloseKey(DevicesKey);
63                 RegCloseKey(Key);
64 
65                 return MMSYSERR_ERROR;
66             }
67 
68             DevicePath = AllocateWideString(MaxNameLength +
69                                             strlen("\\\\.\\"));
70 
71             /* Check that the memory allocation was successful */
72             if ( ! DevicePath )
73             {
74                 /* There's no point in going further */
75                 RegCloseKey(DevicesKey);
76                 RegCloseKey(Key);
77 
78                 return MMSYSERR_NOMEM;
79             }
80 
81             /* Insert the device path prefix */
82             wsprintf(DevicePath, L"\\\\.\\");
83 
84             /* The offset of the string following this prefix */
85             ValueName = DevicePath + strlen("\\\\.\\");
86 
87             /* Copy this so that it may be overwritten - include NULL */
88             ValueNameLength = MaxNameLength + sizeof(WCHAR);
89 
90             SND_TRACE(L"Interested in devices beginning with %wS\n", DevicePath);
91 
92             while ( RegEnumValue(DevicesKey,
93                                  ValueIndex,
94                                  ValueName,
95                                  &ValueNameLength,
96                                  NULL,
97                                  &ValueType,
98                                  (LPBYTE) &ValueData,
99                                  &ValueDataLength) == ERROR_SUCCESS )
100             {
101                 /* Device types are stored as DWORDs */
102                 if ( ( ValueType == REG_DWORD ) &&
103                      ( ValueDataLength == sizeof(DWORD) ) )
104                 {
105                     if ( ( DeviceType == 0 ) ||
106                          ( DeviceType == ValueData ) )
107                     {
108                         SND_TRACE(L"Found device: %wS\n", DevicePath);
109                         SoundDeviceDetectedProc(ValueData, DevicePath);
110                     }
111                 }
112 
113                 /* Reset variables for the next iteration */
114                 ValueNameLength = MaxNameLength + sizeof(WCHAR);
115                 ZeroMemory(ValueName, (MaxNameLength+1)*sizeof(WCHAR));
116                 /*ZeroWideString(ValueName);*/
117                 ValueDataLength = sizeof(DWORD);
118                 ValueData = 0;
119                 ValueType = REG_NONE;
120 
121                 ++ ValueIndex;
122             }
123 
124             FreeMemory(DevicePath);
125 
126             RegCloseKey(DevicesKey);
127         }
128         else
129         {
130             SND_WARN(L"Unable to open the Devices key!\n");
131         }
132 
133         ++ KeyIndex;
134 
135         RegCloseKey(Key);
136     }
137 
138     return MMSYSERR_NOERROR;
139 }
140 
141 /*
142     Brute-force device detection, using a base device name (eg: \\.\WaveOut).
143 
144     This will add the device number as a suffix to the end of the string and
145     attempt to open the device based on that name. On success, it will
146     increment the device number and repeat this process.
147 
148     When it runs out of devices, it will give up.
149 */
150 MMRESULT
DetectNt4SoundDevices(IN MMDEVICE_TYPE DeviceType,IN PWSTR BaseDeviceName,IN SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc)151 DetectNt4SoundDevices(
152     IN  MMDEVICE_TYPE DeviceType,
153     IN  PWSTR BaseDeviceName,
154     IN  SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc)
155 {
156     SIZE_T DeviceNameLength = 0;
157     PWSTR DeviceName = NULL;
158     ULONG Index = 0;
159     HANDLE DeviceHandle;
160     BOOLEAN DoSearch = TRUE;
161 
162     VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
163 
164     DeviceNameLength = wcslen(BaseDeviceName);
165     /* Consider the length of the number */
166     DeviceNameLength += GetDigitCount(Index);
167 
168     DeviceName = AllocateWideString(DeviceNameLength);
169 
170     if ( ! DeviceName )
171     {
172         return MMSYSERR_NOMEM;
173     }
174 
175     while ( DoSearch )
176     {
177         /* Nothing like a nice clean device name */
178         ZeroWideString(DeviceName);
179         wsprintf(DeviceName, L"%ls%d", BaseDeviceName, Index);
180 
181         if ( OpenKernelSoundDeviceByName(DeviceName,
182                                          TRUE,
183                                          &DeviceHandle) == MMSYSERR_NOERROR )
184         {
185             /* Notify the callback function */
186             SND_TRACE(L"Found device: %wS\n", DeviceName);
187             SoundDeviceDetectedProc(DeviceType, DeviceName);
188 
189             CloseHandle(DeviceHandle);
190 
191             ++ Index;
192         }
193         else
194         {
195             DoSearch = FALSE;
196         }
197     }
198 
199     FreeMemory(DeviceName);
200 
201     return MMSYSERR_NOERROR;
202 }
203