[MMSYS] Properly save Audio/MIDI In/Out in the registry
[reactos.git] / dll / cpl / mmsys / audio.c
1 /*
2 *
3 * PROJECT: ReactOS Multimedia Control Panel
4 * FILE: dll/cpl/mmsys/audio.c
5 * PURPOSE: ReactOS Multimedia Control Panel
6 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
7 * Johannes Anderwald <janderwald@reactos.com>
8 * Dmitry Chapyshev <dmitry@reactos.org>
9 */
10
11 #include "mmsys.h"
12
13 typedef struct _GLOBAL_DATA
14 {
15 BOOL bNoAudioOut;
16 BOOL bNoAudioIn;
17 BOOL bNoMIDIOut;
18
19 BOOL bAudioOutChanged;
20 BOOL bAudioInChanged;
21 BOOL bMIDIOutChanged;
22
23 } GLOBAL_DATA, *PGLOBAL_DATA;
24
25 VOID
26 InitAudioDlg(HWND hwnd, PGLOBAL_DATA pGlobalData)
27 {
28 WAVEOUTCAPSW waveOutputPaps;
29 WAVEINCAPS waveInputPaps;
30 MIDIOUTCAPS midiOutCaps;
31 TCHAR szNoDevices[256];
32 UINT DevsNum;
33 UINT uIndex;
34 HWND hCB;
35 LRESULT Res;
36
37 LoadString(hApplet, IDS_NO_DEVICES, szNoDevices, _countof(szNoDevices));
38
39 // Init sound playback devices list
40 hCB = GetDlgItem(hwnd, IDC_DEVICE_PLAY_LIST);
41
42 DevsNum = waveOutGetNumDevs();
43 if (DevsNum < 1)
44 {
45 Res = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
46 SendMessage(hCB, CB_SETCURSEL, (WPARAM) Res, 0);
47 pGlobalData->bNoAudioOut = TRUE;
48 }
49 else
50 {
51 WCHAR DefaultDevice[MAX_PATH] = {0};
52 HKEY hKey;
53 DWORD dwSize = sizeof(DefaultDevice);
54 UINT DefaultIndex = 0;
55
56 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Multimedia\\Sound Mapper", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
57 {
58 RegQueryValueExW(hKey, L"Playback", NULL, NULL, (LPBYTE)DefaultDevice, &dwSize);
59 DefaultDevice[MAX_PATH-1] = L'\0';
60 RegCloseKey(hKey);
61 }
62
63 for (uIndex = 0; uIndex < DevsNum; uIndex++)
64 {
65 if (waveOutGetDevCapsW(uIndex, &waveOutputPaps, sizeof(waveOutputPaps)))
66 continue;
67
68 Res = SendMessageW(hCB, CB_ADDSTRING, 0, (LPARAM) waveOutputPaps.szPname);
69
70 if (CB_ERR != Res)
71 {
72 SendMessage(hCB, CB_SETITEMDATA, Res, (LPARAM) uIndex);
73 if (!wcsicmp(waveOutputPaps.szPname, DefaultDevice))
74 DefaultIndex = Res;
75 }
76 }
77 SendMessage(hCB, CB_SETCURSEL, (WPARAM) DefaultIndex, 0);
78 }
79
80 // Init sound recording devices list
81 hCB = GetDlgItem(hwnd, IDC_DEVICE_REC_LIST);
82
83 DevsNum = waveInGetNumDevs();
84 if (DevsNum < 1)
85 {
86 Res = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
87 SendMessage(hCB, CB_SETCURSEL, (WPARAM) Res, 0);
88 pGlobalData->bNoAudioIn = TRUE;
89 }
90 else
91 {
92 WCHAR DefaultDevice[MAX_PATH] = {0};
93 HKEY hKey;
94 DWORD dwSize = sizeof(DefaultDevice);
95 UINT DefaultIndex = 0;
96
97 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Multimedia\\Sound Mapper", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
98 {
99 RegQueryValueExW(hKey, L"Record", NULL, NULL, (LPBYTE)DefaultDevice, &dwSize);
100 DefaultDevice[MAX_PATH-1] = L'\0';
101 RegCloseKey(hKey);
102 }
103
104
105 for (uIndex = 0; uIndex < DevsNum; uIndex++)
106 {
107 if (waveInGetDevCaps(uIndex, &waveInputPaps, sizeof(waveInputPaps)))
108 continue;
109
110 Res = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM) waveInputPaps.szPname);
111
112 if (CB_ERR != Res)
113 {
114 SendMessage(hCB, CB_SETITEMDATA, Res, (LPARAM) uIndex);
115 if (!wcsicmp(waveInputPaps.szPname, DefaultDevice))
116 DefaultIndex = Res;
117 }
118 }
119 SendMessage(hCB, CB_SETCURSEL, (WPARAM) DefaultIndex, 0);
120 }
121
122 // Init MIDI devices list
123 hCB = GetDlgItem(hwnd, IDC_DEVICE_MIDI_LIST);
124
125 DevsNum = midiOutGetNumDevs();
126 if (DevsNum < 1)
127 {
128 Res = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
129 SendMessage(hCB, CB_SETCURSEL, (WPARAM) Res, 0);
130 pGlobalData->bNoMIDIOut = TRUE;
131 }
132 else
133 {
134 WCHAR DefaultDevice[MAX_PATH] = {0};
135 HKEY hKey;
136 DWORD dwSize = sizeof(DefaultDevice);
137 UINT DefaultIndex = 0;
138
139 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
140 {
141 RegQueryValueExW(hKey, L"szPname", NULL, NULL, (LPBYTE)DefaultDevice, &dwSize);
142 DefaultDevice[MAX_PATH-1] = L'\0';
143 RegCloseKey(hKey);
144 }
145
146 for (uIndex = 0; uIndex < DevsNum; uIndex++)
147 {
148 if (midiOutGetDevCaps(uIndex, &midiOutCaps, sizeof(midiOutCaps)))
149 continue;
150
151 Res = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM) midiOutCaps.szPname);
152
153 if (CB_ERR != Res)
154 {
155 SendMessage(hCB, CB_SETITEMDATA, Res, (LPARAM) uIndex);
156 if (!wcsicmp(midiOutCaps.szPname, DefaultDevice))
157 DefaultIndex = Res;
158 }
159 }
160 SendMessage(hCB, CB_SETCURSEL, (WPARAM) DefaultIndex, 0);
161 }
162 }
163
164 VOID
165 UpdateRegistryString(HWND hwnd, INT ctrl, LPWSTR key, LPWSTR value)
166 {
167 HWND hwndCombo = GetDlgItem(hwnd, ctrl);
168 INT CurSel = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
169 UINT TextLen;
170 WCHAR SelectedDevice[MAX_PATH] = {0};
171 HKEY hKey;
172
173 if (CurSel == CB_ERR)
174 return;
175
176 TextLen = SendMessageW(hwndCombo, CB_GETLBTEXTLEN, CurSel, 0) + 1;
177
178 if (TextLen > _countof(SelectedDevice))
179 return;
180
181 SendMessageW(hwndCombo, CB_GETLBTEXT, CurSel, (LPARAM)SelectedDevice);
182
183 if (RegCreateKeyExW(HKEY_CURRENT_USER, key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
184 return;
185
186 RegSetValueExW(hKey, value, 0, REG_SZ, (BYTE *)SelectedDevice, (wcslen(SelectedDevice) + 1) * sizeof(WCHAR));
187 RegCloseKey(hKey);
188 }
189
190 VOID
191 SaveAudioDlg(HWND hwnd, PGLOBAL_DATA pGlobalData)
192 {
193 if (pGlobalData->bAudioOutChanged)
194 {
195 UpdateRegistryString(hwnd,
196 IDC_DEVICE_PLAY_LIST,
197 L"Software\\Microsoft\\Multimedia\\Sound Mapper",
198 L"Playback");
199 }
200
201 if (pGlobalData->bAudioInChanged)
202 {
203 UpdateRegistryString(hwnd,
204 IDC_DEVICE_REC_LIST,
205 L"Software\\Microsoft\\Multimedia\\Sound Mapper",
206 L"Record");
207 }
208
209 if (pGlobalData->bMIDIOutChanged)
210 {
211 UpdateRegistryString(hwnd,
212 IDC_DEVICE_MIDI_LIST,
213 L"Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap",
214 L"szPname");
215 }
216 }
217
218 static UINT
219 GetDevNum(HWND hControl, DWORD Id)
220 {
221 int iCurSel;
222 UINT DevNum;
223
224 iCurSel = SendMessage(hControl, CB_GETCURSEL, 0, 0);
225
226 if (iCurSel == CB_ERR)
227 return 0;
228
229 DevNum = (UINT) SendMessage(hControl, CB_GETITEMDATA, iCurSel, 0);
230 if (DevNum == (UINT) CB_ERR)
231 return 0;
232
233 if (mixerGetID((HMIXEROBJ)IntToPtr(DevNum), &DevNum, Id) != MMSYSERR_NOERROR)
234 return 0;
235
236 return DevNum;
237 }
238
239 /* Audio property page dialog callback */
240 INT_PTR CALLBACK
241 AudioDlgProc(HWND hwndDlg,
242 UINT uMsg,
243 WPARAM wParam,
244 LPARAM lParam)
245 {
246 PGLOBAL_DATA pGlobalData;
247
248 pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
249
250 switch(uMsg)
251 {
252 case WM_INITDIALOG:
253 {
254 UINT NumWavOut = waveOutGetNumDevs();
255
256 pGlobalData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBAL_DATA));
257 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
258
259 if (!pGlobalData)
260 break;
261
262 InitAudioDlg(hwndDlg, pGlobalData);
263
264 if (!NumWavOut)
265 {
266 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_PLAY_LIST), FALSE);
267 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_REC_LIST), FALSE);
268 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_MIDI_LIST), FALSE);
269 EnableWindow(GetDlgItem(hwndDlg, IDC_DEFAULT_DEV_CHECKBOX), FALSE);
270 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME1_BTN), FALSE);
271 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV2_BTN), FALSE);
272 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME2_BTN), FALSE);
273 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV1_BTN), FALSE);
274 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME3_BTN), FALSE);
275 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV3_BTN), FALSE);
276 }
277
278 if (pGlobalData->bNoAudioOut)
279 {
280 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_PLAY_LIST), FALSE);
281 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME1_BTN), FALSE);
282 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV2_BTN), FALSE);
283 }
284
285 if (pGlobalData->bNoAudioIn)
286 {
287 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_REC_LIST), FALSE);
288 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME2_BTN), FALSE);
289 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV1_BTN), FALSE);
290 }
291
292 if (pGlobalData->bNoMIDIOut)
293 {
294 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_MIDI_LIST), FALSE);
295 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME3_BTN), FALSE);
296 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV3_BTN), FALSE);
297 }
298 }
299 break;
300
301 case WM_COMMAND:
302 {
303 STARTUPINFO si;
304 PROCESS_INFORMATION pi;
305 WCHAR szPath[MAX_PATH];
306
307 if (!pGlobalData)
308 break;
309
310 switch(LOWORD(wParam))
311 {
312 case IDC_VOLUME1_BTN:
313 {
314 wsprintf(szPath, L"sndvol32.exe -d %d",
315 GetDevNum(GetDlgItem(hwndDlg, IDC_DEVICE_PLAY_LIST), MIXER_OBJECTF_WAVEOUT));
316
317 ZeroMemory(&si, sizeof(si));
318 si.cb = sizeof(si);
319 si.dwFlags = STARTF_USESHOWWINDOW;
320 si.wShowWindow = SW_SHOW;
321
322 CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
323 }
324 break;
325
326 case IDC_ADV2_BTN:
327 {
328
329 }
330 break;
331
332 case IDC_VOLUME2_BTN:
333 {
334 wsprintf(szPath, L"sndvol32.exe -r -d %d",
335 GetDevNum(GetDlgItem(hwndDlg, IDC_DEVICE_REC_LIST), MIXER_OBJECTF_WAVEIN));
336
337 ZeroMemory(&si, sizeof(si));
338 si.cb = sizeof(si);
339 si.dwFlags = STARTF_USESHOWWINDOW;
340 si.wShowWindow = SW_SHOW;
341
342 CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
343 }
344 break;
345
346 case IDC_ADV1_BTN:
347 {
348
349 }
350 break;
351
352 case IDC_VOLUME3_BTN:
353 {
354 wsprintf(szPath, L"sndvol32.exe -d %d",
355 GetDevNum(GetDlgItem(hwndDlg, IDC_DEVICE_MIDI_LIST), MIXER_OBJECTF_MIDIOUT));
356
357 ZeroMemory(&si, sizeof(si));
358 si.cb = sizeof(si);
359 si.dwFlags = STARTF_USESHOWWINDOW;
360 si.wShowWindow = SW_SHOW;
361
362 CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
363 }
364 break;
365
366 case IDC_ADV3_BTN:
367 {
368
369 }
370 break;
371
372 case IDC_DEVICE_PLAY_LIST:
373 {
374 if (HIWORD(wParam) == CBN_SELCHANGE)
375 {
376 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
377 pGlobalData->bAudioOutChanged = TRUE;
378 }
379 }
380 break;
381
382 case IDC_DEVICE_REC_LIST:
383 {
384 if (HIWORD(wParam) == CBN_SELCHANGE)
385 {
386 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
387 pGlobalData->bAudioInChanged = TRUE;
388 }
389 }
390
391 case IDC_DEVICE_MIDI_LIST:
392 {
393 if (HIWORD(wParam) == CBN_SELCHANGE)
394 {
395 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
396 pGlobalData->bMIDIOutChanged = TRUE;
397 }
398 }
399 break;
400 }
401 }
402 break;
403
404 case WM_DESTROY:
405 if (!pGlobalData)
406 break;
407
408 HeapFree(GetProcessHeap(), 0, pGlobalData);
409 break;
410
411 case WM_NOTIFY:
412 if (!pGlobalData)
413 break;
414
415 if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
416 {
417 SaveAudioDlg(hwndDlg, pGlobalData);
418 }
419 return TRUE;
420 }
421
422 return FALSE;
423 }