Reactos
1/*
2 * PROJECT: ReactOS Multimedia Control Panel
3 * FILE: dll/cpl/mmsys/volume.c
4 * PURPOSE: ReactOS Multimedia Control Panel
5 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
6 * Johannes Anderwald <janderwald@reactos.com>
7 * Dmitry Chapyshev <dmitry@reactos.org>
8 */
9
10#include "mmsys.h"
11
12#include <shellapi.h>
13
14
15typedef struct _GLOBAL_DATA
16{
17 HMIXER hMixer;
18 HICON hIconMuted;
19 HICON hIconUnMuted;
20 HICON hIconNoHW;
21 HICON hIconSpeakImg;
22
23 LONG muteVal;
24 DWORD muteControlID;
25
26 DWORD volumeControlID;
27 DWORD volumeChannels;
28 DWORD volumeMinimum;
29 DWORD volumeMaximum;
30 DWORD volumeStep;
31
32 DWORD maxVolume;
33 PMIXERCONTROLDETAILS_UNSIGNED volumeInitialValues;
34 PMIXERCONTROLDETAILS_UNSIGNED volumePreviousValues;
35 PMIXERCONTROLDETAILS_UNSIGNED volumeCurrentValues;
36
37} GLOBAL_DATA, *PGLOBAL_DATA;
38
39
40VOID
41GetMuteControl(PGLOBAL_DATA pGlobalData)
42{
43 MIXERLINEW mxln;
44 MIXERCONTROLW mxc;
45 MIXERLINECONTROLSW mxlctrl;
46
47 if (pGlobalData->hMixer == NULL)
48 return;
49
50 mxln.cbStruct = sizeof(MIXERLINEW);
51 mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
52
53 if (mixerGetLineInfoW((HMIXEROBJ)pGlobalData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE)
54 != MMSYSERR_NOERROR)
55 return;
56
57 mxlctrl.cbStruct = sizeof(MIXERLINECONTROLSW);
58 mxlctrl.dwLineID = mxln.dwLineID;
59 mxlctrl.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
60 mxlctrl.cControls = 1;
61 mxlctrl.cbmxctrl = sizeof(MIXERCONTROLW);
62 mxlctrl.pamxctrl = &mxc;
63
64 if (mixerGetLineControlsW((HMIXEROBJ)pGlobalData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE)
65 != MMSYSERR_NOERROR)
66 return;
67
68 pGlobalData->muteControlID = mxc.dwControlID;
69}
70
71
72VOID
73GetMuteState(PGLOBAL_DATA pGlobalData)
74{
75 MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
76 MIXERCONTROLDETAILS mxcd;
77
78 if (pGlobalData->hMixer == NULL)
79 return;
80
81 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
82 mxcd.dwControlID = pGlobalData->muteControlID;
83 mxcd.cChannels = 1;
84 mxcd.cMultipleItems = 0;
85 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
86 mxcd.paDetails = &mxcdMute;
87
88 if (mixerGetControlDetailsW((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE)
89 != MMSYSERR_NOERROR)
90 return;
91
92 pGlobalData->muteVal = mxcdMute.fValue;
93}
94
95
96VOID
97SwitchMuteState(PGLOBAL_DATA pGlobalData)
98{
99 MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
100 MIXERCONTROLDETAILS mxcd;
101
102 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
103 mxcd.dwControlID = pGlobalData->muteControlID;
104 mxcd.cChannels = 1;
105 mxcd.cMultipleItems = 0;
106 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
107 mxcd.paDetails = &mxcdMute;
108
109 mxcdMute.fValue = !pGlobalData->muteVal;
110 if (mixerSetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)
111 != MMSYSERR_NOERROR)
112 return;
113
114 pGlobalData->muteVal = mxcdMute.fValue;
115}
116
117
118VOID
119GetVolumeControl(PGLOBAL_DATA pGlobalData)
120{
121 MIXERLINEW mxln;
122 MIXERCONTROLW mxc;
123 MIXERLINECONTROLSW mxlc;
124
125 if (pGlobalData->hMixer == NULL)
126 return;
127
128 mxln.cbStruct = sizeof(MIXERLINEW);
129 mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
130 if (mixerGetLineInfoW((HMIXEROBJ)pGlobalData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE)
131 != MMSYSERR_NOERROR)
132 return;
133
134 pGlobalData->volumeChannels = mxln.cChannels;
135
136 mxlc.cbStruct = sizeof(MIXERLINECONTROLSW);
137 mxlc.dwLineID = mxln.dwLineID;
138 mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
139 mxlc.cControls = 1;
140 mxlc.cbmxctrl = sizeof(MIXERCONTROLW);
141 mxlc.pamxctrl = &mxc;
142 if (mixerGetLineControlsW((HMIXEROBJ)pGlobalData->hMixer, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE)
143 != MMSYSERR_NOERROR)
144 return;
145
146 pGlobalData->volumeMinimum = mxc.Bounds.dwMinimum;
147 pGlobalData->volumeMaximum = mxc.Bounds.dwMaximum;
148 pGlobalData->volumeControlID = mxc.dwControlID;
149 pGlobalData->volumeStep = (pGlobalData->volumeMaximum - pGlobalData->volumeMinimum) / (VOLUME_MAX - VOLUME_MIN);
150
151 pGlobalData->volumeInitialValues = HeapAlloc(GetProcessHeap(),
152 0,
153 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
154 if (pGlobalData->volumeInitialValues == NULL)
155 return;
156
157 pGlobalData->volumePreviousValues = HeapAlloc(GetProcessHeap(),
158 0,
159 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
160 if (pGlobalData->volumePreviousValues == NULL)
161 return;
162
163 pGlobalData->volumeCurrentValues = HeapAlloc(GetProcessHeap(),
164 0,
165 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
166 if (pGlobalData->volumeCurrentValues == NULL)
167 return;
168}
169
170
171VOID
172GetVolumeValue(
173 PGLOBAL_DATA pGlobalData,
174 BOOL bInit)
175{
176 MIXERCONTROLDETAILS mxcd;
177 DWORD i;
178
179 if (pGlobalData->hMixer == NULL)
180 return;
181
182 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
183 mxcd.dwControlID = pGlobalData->volumeControlID;
184 mxcd.cChannels = pGlobalData->volumeChannels;
185 mxcd.cMultipleItems = 0;
186 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
187 mxcd.paDetails = pGlobalData->volumePreviousValues;
188
189 if (mixerGetControlDetailsW((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE)
190 != MMSYSERR_NOERROR)
191 return;
192
193 pGlobalData->maxVolume = 0;
194 for (i = 0; i < pGlobalData->volumeChannels; i++)
195 {
196 pGlobalData->volumeCurrentValues[i].dwValue = pGlobalData->volumePreviousValues[i].dwValue;
197
198 if (pGlobalData->volumePreviousValues[i].dwValue > pGlobalData->maxVolume)
199 pGlobalData->maxVolume = pGlobalData->volumePreviousValues[i].dwValue;
200
201 if (bInit)
202 pGlobalData->volumeInitialValues[i].dwValue = pGlobalData->volumeCurrentValues[i].dwValue;
203 }
204}
205
206
207VOID
208SetVolumeValue(PGLOBAL_DATA pGlobalData,
209 DWORD dwPosition)
210{
211 MIXERCONTROLDETAILS mxcd;
212 DWORD dwVolume, i;
213
214 if (pGlobalData->hMixer == NULL)
215 return;
216
217 if (dwPosition == VOLUME_MIN)
218 dwVolume = pGlobalData->volumeMinimum;
219 else if (dwPosition == VOLUME_MAX)
220 dwVolume = pGlobalData->volumeMaximum;
221 else
222 dwVolume = (dwPosition * pGlobalData->volumeStep) + pGlobalData->volumeMinimum;
223
224 for (i = 0; i < pGlobalData->volumeChannels; i++)
225 {
226 if (pGlobalData->volumePreviousValues[i].dwValue == pGlobalData->maxVolume)
227 {
228 pGlobalData->volumeCurrentValues[i].dwValue = dwVolume;
229 }
230 else
231 {
232 pGlobalData->volumeCurrentValues[i].dwValue =
233 pGlobalData->volumePreviousValues[i].dwValue * dwVolume / pGlobalData->maxVolume;
234 }
235 }
236
237 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
238 mxcd.dwControlID = pGlobalData->volumeControlID;
239 mxcd.cChannels = pGlobalData->volumeChannels;
240 mxcd.cMultipleItems = 0;
241 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
242 mxcd.paDetails = pGlobalData->volumeCurrentValues;
243
244 if (mixerSetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)
245 != MMSYSERR_NOERROR)
246 return;
247}
248
249
250static
251VOID
252RestoreVolumeValue(
253 PGLOBAL_DATA pGlobalData)
254{
255 MIXERCONTROLDETAILS mxcd;
256
257 if (pGlobalData->hMixer == NULL)
258 return;
259
260 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
261 mxcd.dwControlID = pGlobalData->volumeControlID;
262 mxcd.cChannels = pGlobalData->volumeChannels;
263 mxcd.cMultipleItems = 0;
264 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
265 mxcd.paDetails = pGlobalData->volumeInitialValues;
266
267 mixerSetControlDetails((HMIXEROBJ)pGlobalData->hMixer,
268 &mxcd,
269 MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
270}
271
272
273static
274VOID
275SetSystrayVolumeIconState(BOOL bEnabled)
276{
277 HWND hwndTaskBar;
278
279 hwndTaskBar = FindWindowW(L"SystemTray_Main", NULL);
280 if (hwndTaskBar == NULL)
281 return;
282
283 SendMessageW(hwndTaskBar, WM_USER + 220, 4, bEnabled);
284}
285
286static
287BOOL
288GetSystrayVolumeIconState(VOID)
289{
290 HWND hwndTaskBar;
291
292 hwndTaskBar = FindWindowW(L"SystemTray_Main", NULL);
293 if (hwndTaskBar == NULL)
294 {
295 return FALSE;
296 }
297
298 return (BOOL)SendMessageW(hwndTaskBar, WM_USER + 221, 4, 0);
299}
300
301VOID
302InitVolumeControls(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
303{
304 UINT NumMixers;
305 MIXERCAPSW mxc;
306 WCHAR szNoDevices[256];
307
308 LoadStringW(hApplet, IDS_NO_DEVICES, szNoDevices, _countof(szNoDevices));
309
310 SendDlgItemMessageW(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
311 SendDlgItemMessageW(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETTICFREQ, VOLUME_TICFREQ, 0);
312 SendDlgItemMessageW(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPAGESIZE, 0, VOLUME_PAGESIZE);
313
314 NumMixers = mixerGetNumDevs();
315 if (!NumMixers)
316 {
317 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_TRACKBAR), FALSE);
318 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_LOW), FALSE);
319 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_HIGH), FALSE);
320 EnableWindow(GetDlgItem(hwndDlg, IDC_MUTE_CHECKBOX), FALSE);
321 EnableWindow(GetDlgItem(hwndDlg, IDC_ICON_IN_TASKBAR), FALSE);
322 EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED_BTN), FALSE);
323 EnableWindow(GetDlgItem(hwndDlg, IDC_SPEAKER_VOL_BTN), FALSE);
324 EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED2_BTN), FALSE);
325 SendDlgItemMessageW(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconNoHW);
326 SetDlgItemTextW(hwndDlg, IDC_DEVICE_NAME, szNoDevices);
327 return;
328 }
329
330 if (mixerOpen(&pGlobalData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR)
331 {
332 MessageBoxW(hwndDlg, L"Cannot open mixer", NULL, MB_OK);
333 return;
334 }
335
336 ZeroMemory(&mxc, sizeof(MIXERCAPSW));
337 if (mixerGetDevCapsW(PtrToUint(pGlobalData->hMixer), &mxc, sizeof(MIXERCAPSW)) != MMSYSERR_NOERROR)
338 {
339 MessageBoxW(hwndDlg, L"mixerGetDevCaps failed", NULL, MB_OK);
340 return;
341 }
342
343 CheckDlgButton(hwndDlg,
344 IDC_ICON_IN_TASKBAR,
345 GetSystrayVolumeIconState() ? BST_CHECKED : BST_UNCHECKED);
346
347 GetMuteControl(pGlobalData);
348 GetMuteState(pGlobalData);
349 if (pGlobalData->muteVal)
350 {
351 SendDlgItemMessageW(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
352 SendDlgItemMessageW(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted);
353 }
354 else
355 {
356 SendDlgItemMessageW(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
357 SendDlgItemMessageW(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconUnMuted);
358 }
359
360 GetVolumeControl(pGlobalData);
361 GetVolumeValue(pGlobalData, TRUE);
362
363 SendDlgItemMessageW(hwndDlg, IDC_DEVICE_NAME, WM_SETTEXT, 0, (LPARAM)mxc.szPname);
364 SendDlgItemMessageW(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(pGlobalData->maxVolume - pGlobalData->volumeMinimum) / pGlobalData->volumeStep);
365}
366
367VOID
368SaveData(HWND hwndDlg)
369{
370 BOOL bShowIcon;
371
372 bShowIcon = (IsDlgButtonChecked(hwndDlg, IDC_ICON_IN_TASKBAR) == BST_CHECKED);
373
374 SetSystrayVolumeIconState(bShowIcon);
375}
376
377VOID
378LaunchSoundControl(HWND hwndDlg)
379{
380 if ((INT_PTR)ShellExecuteW(NULL, L"open", L"sndvol32.exe", NULL, NULL, SW_SHOWNORMAL) > 32)
381 return;
382 MessageBoxW(hwndDlg, L"Cannot run sndvol32.exe", NULL, MB_OK);
383}
384
385/* Volume property page dialog callback */
386//static INT_PTR CALLBACK
387INT_PTR CALLBACK
388VolumeDlgProc(HWND hwndDlg,
389 UINT uMsg,
390 WPARAM wParam,
391 LPARAM lParam)
392{
393 static const INT speakImgSize[] = {72, 72};
394 PGLOBAL_DATA pGlobalData;
395
396 pGlobalData = (PGLOBAL_DATA)GetWindowLongPtrW(hwndDlg, DWLP_USER);
397
398 switch (uMsg)
399 {
400 case MM_MIXM_LINE_CHANGE:
401 {
402 GetMuteState(pGlobalData);
403 if (pGlobalData->muteVal)
404 {
405 SendDlgItemMessageW(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
406 SendDlgItemMessageW(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted);
407 }
408 else
409 {
410 SendDlgItemMessageW(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
411 SendDlgItemMessageW(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconUnMuted);
412 }
413 break;
414 }
415 case MM_MIXM_CONTROL_CHANGE:
416 {
417 GetVolumeValue(pGlobalData, FALSE);
418 SendDlgItemMessageW(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(pGlobalData->maxVolume - pGlobalData->volumeMinimum) / pGlobalData->volumeStep);
419 break;
420 }
421 case WM_INITDIALOG:
422 {
423 pGlobalData = (PGLOBAL_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBAL_DATA));
424 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
425
426 pGlobalData->hIconUnMuted = LoadImageW(hApplet, MAKEINTRESOURCEW(IDI_CPLICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
427 pGlobalData->hIconMuted = LoadImageW(hApplet, MAKEINTRESOURCEW(IDI_MUTED_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
428 pGlobalData->hIconNoHW = LoadImageW(hApplet, MAKEINTRESOURCEW(IDI_NO_HW), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
429 pGlobalData->hIconSpeakImg = LoadImageW(hApplet,
430 MAKEINTRESOURCEW(IDI_SPEAKIMG),
431 IMAGE_ICON,
432 speakImgSize[0],
433 speakImgSize[1],
434 LR_DEFAULTCOLOR);
435
436 InitVolumeControls(hwndDlg, pGlobalData);
437 break;
438 }
439
440 case WM_DRAWITEM:
441 {
442 LPDRAWITEMSTRUCT lpDrawItem;
443 lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
444 if (lpDrawItem->CtlID == IDC_SPEAKIMG)
445 {
446 LONG left;
447
448 /* Position image in centre of dialog */
449 left = (lpDrawItem->rcItem.right - speakImgSize[0]) / 2;
450
451 DrawIconEx(lpDrawItem->hDC,
452 left,
453 lpDrawItem->rcItem.top,
454 pGlobalData->hIconSpeakImg,
455 speakImgSize[0],
456 speakImgSize[1],
457 0,
458 NULL,
459 DI_NORMAL);
460 }
461 break;
462 }
463
464 case WM_COMMAND:
465 {
466 switch (LOWORD(wParam))
467 {
468 case IDC_MUTE_CHECKBOX:
469 if (HIWORD(wParam) == BN_CLICKED)
470 {
471 SwitchMuteState(pGlobalData);
472 if (pGlobalData->muteVal)
473 {
474 SendDlgItemMessageW(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted);
475 }
476 else
477 {
478 SendDlgItemMessageW(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconUnMuted);
479 }
480
481 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
482 }
483 break;
484
485 case IDC_ICON_IN_TASKBAR:
486 if (HIWORD(wParam) == BN_CLICKED)
487 {
488 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
489 }
490 break;
491
492 case IDC_ADVANCED_BTN:
493 LaunchSoundControl(hwndDlg);
494 break;
495
496 case IDC_SPEAKER_VOL_BTN:
497 SpeakerVolume(hwndDlg);
498 break;
499 }
500 break;
501 }
502
503 case WM_HSCROLL:
504 {
505 HWND hVolumeTrackbar = GetDlgItem(hwndDlg, IDC_VOLUME_TRACKBAR);
506 if (hVolumeTrackbar == (HWND)lParam)
507 {
508 switch (LOWORD(wParam))
509 {
510 case TB_THUMBPOSITION:
511 break;
512
513 case TB_ENDTRACK:
514 PlaySoundW((LPCWSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ALIAS_ID | SND_ASYNC);
515 break;
516
517 default:
518 SetVolumeValue(pGlobalData,
519 (DWORD)SendDlgItemMessageW(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_GETPOS, 0, 0));
520 break;
521 }
522 }
523 break;
524 }
525
526 case WM_DESTROY:
527 if (pGlobalData)
528 {
529 HeapFree(GetProcessHeap(), 0, pGlobalData->volumeCurrentValues);
530 HeapFree(GetProcessHeap(), 0, pGlobalData->volumePreviousValues);
531 HeapFree(GetProcessHeap(), 0, pGlobalData->volumeInitialValues);
532 mixerClose(pGlobalData->hMixer);
533
534 if (pGlobalData->hIconSpeakImg)
535 DestroyIcon(pGlobalData->hIconSpeakImg);
536
537 if (pGlobalData->hIconNoHW)
538 DestroyIcon(pGlobalData->hIconNoHW);
539
540 if (pGlobalData->hIconMuted)
541 DestroyIcon(pGlobalData->hIconMuted);
542
543 if (pGlobalData->hIconUnMuted)
544 DestroyIcon(pGlobalData->hIconUnMuted);
545
546 HeapFree(GetProcessHeap(), 0, pGlobalData);
547 }
548 break;
549
550 case WM_NOTIFY:
551 switch (((LPNMHDR)lParam)->code)
552 {
553 case PSN_APPLY:
554 SaveData(hwndDlg);
555 break;
556
557 case PSN_RESET:
558 RestoreVolumeValue(pGlobalData);
559 break;
560 }
561 return TRUE;
562 }
563
564 return FALSE;
565}