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