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 = LoadImage(hApplet, 55 MAKEINTRESOURCE(IDB_SPEAKIMG), 56 IMAGE_BITMAP, 57 0, 58 0, 59 LR_DEFAULTCOLOR); 60 61 if (ImgInfo->hBitmap != NULL) 62 { 63 GetObject(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 MIXERLINE mxln; 75 MIXERCONTROL mxc; 76 MIXERLINECONTROLS mxlctrl; 77 78 if (pGlobalData->hMixer == NULL) 79 return; 80 81 mxln.cbStruct = sizeof(MIXERLINE); 82 mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; 83 84 if (mixerGetLineInfo((HMIXEROBJ)pGlobalData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) 85 != MMSYSERR_NOERROR) return; 86 87 mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS); 88 mxlctrl.dwLineID = mxln.dwLineID; 89 mxlctrl.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; 90 mxlctrl.cControls = 1; 91 mxlctrl.cbmxctrl = sizeof(MIXERCONTROL); 92 mxlctrl.pamxctrl = &mxc; 93 94 if (mixerGetLineControls((HMIXEROBJ)pGlobalData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) 95 != MMSYSERR_NOERROR) return; 96 97 pGlobalData->muteControlID = mxc.dwControlID; 98 } 99 100 101 VOID 102 GetMuteState(PGLOBAL_DATA pGlobalData) 103 { 104 MIXERCONTROLDETAILS_BOOLEAN mxcdMute; 105 MIXERCONTROLDETAILS mxcd; 106 107 if (pGlobalData->hMixer == NULL) 108 return; 109 110 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 111 mxcd.dwControlID = pGlobalData->muteControlID; 112 mxcd.cChannels = 1; 113 mxcd.cMultipleItems = 0; 114 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); 115 mxcd.paDetails = &mxcdMute; 116 117 if (mixerGetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) 118 != MMSYSERR_NOERROR) 119 return; 120 121 pGlobalData->muteVal = mxcdMute.fValue; 122 } 123 124 125 VOID 126 SwitchMuteState(PGLOBAL_DATA pGlobalData) 127 { 128 MIXERCONTROLDETAILS_BOOLEAN mxcdMute; 129 MIXERCONTROLDETAILS mxcd; 130 131 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 132 mxcd.dwControlID = pGlobalData->muteControlID; 133 mxcd.cChannels = 1; 134 mxcd.cMultipleItems = 0; 135 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); 136 mxcd.paDetails = &mxcdMute; 137 138 mxcdMute.fValue = !pGlobalData->muteVal; 139 if (mixerSetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) 140 != MMSYSERR_NOERROR) 141 return; 142 143 pGlobalData->muteVal = mxcdMute.fValue; 144 } 145 146 147 VOID 148 GetVolumeControl(PGLOBAL_DATA pGlobalData) 149 { 150 MIXERLINE mxln; 151 MIXERCONTROL mxc; 152 MIXERLINECONTROLS mxlc; 153 154 if (pGlobalData->hMixer == NULL) 155 return; 156 157 mxln.cbStruct = sizeof(MIXERLINE); 158 mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; 159 if (mixerGetLineInfo((HMIXEROBJ)pGlobalData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) 160 != MMSYSERR_NOERROR) 161 return; 162 163 pGlobalData->volumeChannels = mxln.cChannels; 164 165 mxlc.cbStruct = sizeof(MIXERLINECONTROLS); 166 mxlc.dwLineID = mxln.dwLineID; 167 mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; 168 mxlc.cControls = 1; 169 mxlc.cbmxctrl = sizeof(MIXERCONTROL); 170 mxlc.pamxctrl = &mxc; 171 if (mixerGetLineControls((HMIXEROBJ)pGlobalData->hMixer, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) 172 != MMSYSERR_NOERROR) 173 return; 174 175 pGlobalData->volumeMinimum = mxc.Bounds.dwMinimum; 176 pGlobalData->volumeMaximum = mxc.Bounds.dwMaximum; 177 pGlobalData->volumeControlID = mxc.dwControlID; 178 pGlobalData->volumeStep = (pGlobalData->volumeMaximum - pGlobalData->volumeMinimum) / (VOLUME_MAX - VOLUME_MIN); 179 180 pGlobalData->volumeInitialValues = HeapAlloc(GetProcessHeap(), 181 0, 182 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED)); 183 if (pGlobalData->volumeInitialValues == NULL) 184 return; 185 186 pGlobalData->volumePreviousValues = HeapAlloc(GetProcessHeap(), 187 0, 188 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED)); 189 if (pGlobalData->volumePreviousValues == NULL) 190 return; 191 192 pGlobalData->volumeCurrentValues = HeapAlloc(GetProcessHeap(), 193 0, 194 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED)); 195 if (pGlobalData->volumeCurrentValues == NULL) 196 return; 197 } 198 199 200 VOID 201 GetVolumeValue( 202 PGLOBAL_DATA pGlobalData, 203 BOOL bInit) 204 { 205 MIXERCONTROLDETAILS mxcd; 206 DWORD i; 207 208 if (pGlobalData->hMixer == NULL) 209 return; 210 211 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 212 mxcd.dwControlID = pGlobalData->volumeControlID; 213 mxcd.cChannels = pGlobalData->volumeChannels; 214 mxcd.cMultipleItems = 0; 215 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 216 mxcd.paDetails = pGlobalData->volumePreviousValues; 217 218 if (mixerGetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) 219 != MMSYSERR_NOERROR) 220 return; 221 222 pGlobalData->maxVolume = 0; 223 for (i = 0; i < pGlobalData->volumeChannels; i++) 224 { 225 pGlobalData->volumeCurrentValues[i].dwValue = pGlobalData->volumePreviousValues[i].dwValue; 226 227 if (pGlobalData->volumePreviousValues[i].dwValue > pGlobalData->maxVolume) 228 pGlobalData->maxVolume = pGlobalData->volumePreviousValues[i].dwValue; 229 230 if (bInit) 231 pGlobalData->volumeInitialValues[i].dwValue = pGlobalData->volumeCurrentValues[i].dwValue; 232 } 233 } 234 235 236 VOID 237 SetVolumeValue(PGLOBAL_DATA pGlobalData, 238 DWORD dwPosition) 239 { 240 MIXERCONTROLDETAILS mxcd; 241 DWORD dwVolume, i; 242 243 if (pGlobalData->hMixer == NULL) 244 return; 245 246 if (dwPosition == VOLUME_MIN) 247 dwVolume = pGlobalData->volumeMinimum; 248 else if (dwPosition == VOLUME_MAX) 249 dwVolume = pGlobalData->volumeMaximum; 250 else 251 dwVolume = (dwPosition * pGlobalData->volumeStep) + pGlobalData->volumeMinimum; 252 253 for (i = 0; i < pGlobalData->volumeChannels; i++) 254 { 255 if (pGlobalData->volumePreviousValues[i].dwValue == pGlobalData->maxVolume) 256 { 257 pGlobalData->volumeCurrentValues[i].dwValue = dwVolume; 258 } 259 else 260 { 261 pGlobalData->volumeCurrentValues[i].dwValue = 262 pGlobalData->volumePreviousValues[i].dwValue * dwVolume / pGlobalData-> maxVolume; 263 } 264 } 265 266 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 267 mxcd.dwControlID = pGlobalData->volumeControlID; 268 mxcd.cChannels = pGlobalData->volumeChannels; 269 mxcd.cMultipleItems = 0; 270 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 271 mxcd.paDetails = pGlobalData->volumeCurrentValues; 272 273 if (mixerSetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) 274 != MMSYSERR_NOERROR) 275 return; 276 } 277 278 279 static 280 VOID 281 RestoreVolumeValue( 282 PGLOBAL_DATA pGlobalData) 283 { 284 MIXERCONTROLDETAILS mxcd; 285 286 if (pGlobalData->hMixer == NULL) 287 return; 288 289 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 290 mxcd.dwControlID = pGlobalData->volumeControlID; 291 mxcd.cChannels = pGlobalData->volumeChannels; 292 mxcd.cMultipleItems = 0; 293 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 294 mxcd.paDetails = pGlobalData->volumeInitialValues; 295 296 mixerSetControlDetails((HMIXEROBJ)pGlobalData->hMixer, 297 &mxcd, 298 MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE); 299 } 300 301 302 static 303 VOID 304 SetSystrayVolumeIconState(BOOL bEnabled) 305 { 306 HWND hwndTaskBar; 307 308 hwndTaskBar = FindWindowW(L"SystemTray_Main", NULL); 309 if (hwndTaskBar == NULL) 310 return; 311 312 SendMessageW(hwndTaskBar, WM_USER + 220, 4, bEnabled); 313 } 314 315 static 316 BOOL 317 GetSystrayVolumeIconState(VOID) 318 { 319 HWND hwndTaskBar; 320 321 hwndTaskBar = FindWindowW(L"SystemTray_Main", NULL); 322 if (hwndTaskBar == NULL) 323 { 324 return FALSE; 325 } 326 327 return (BOOL)SendMessageW(hwndTaskBar, WM_USER + 221, 4, 0); 328 } 329 330 VOID 331 InitVolumeControls(HWND hwndDlg, PGLOBAL_DATA pGlobalData) 332 { 333 UINT NumMixers; 334 MIXERCAPS mxc; 335 TCHAR szNoDevices[256]; 336 337 LoadString(hApplet, IDS_NO_DEVICES, szNoDevices, _countof(szNoDevices)); 338 339 SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX)); 340 SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETTICFREQ, VOLUME_TICFREQ, 0); 341 SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPAGESIZE, 0, VOLUME_PAGESIZE); 342 343 NumMixers = mixerGetNumDevs(); 344 if (!NumMixers) 345 { 346 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_TRACKBAR), FALSE); 347 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_LOW), FALSE); 348 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_HIGH), FALSE); 349 EnableWindow(GetDlgItem(hwndDlg, IDC_MUTE_CHECKBOX), FALSE); 350 EnableWindow(GetDlgItem(hwndDlg, IDC_ICON_IN_TASKBAR), FALSE); 351 EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED_BTN), FALSE); 352 EnableWindow(GetDlgItem(hwndDlg, IDC_SPEAKER_VOL_BTN), FALSE); 353 EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED2_BTN), FALSE); 354 SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconNoHW); 355 SetDlgItemText(hwndDlg, IDC_DEVICE_NAME, szNoDevices); 356 return; 357 } 358 359 if (mixerOpen(&pGlobalData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR) 360 { 361 MessageBox(hwndDlg, _T("Cannot open mixer"), NULL, MB_OK); 362 return; 363 } 364 365 ZeroMemory(&mxc, sizeof(MIXERCAPS)); 366 if (mixerGetDevCaps(PtrToUint(pGlobalData->hMixer), &mxc, sizeof(MIXERCAPS)) != MMSYSERR_NOERROR) 367 { 368 MessageBox(hwndDlg, _T("mixerGetDevCaps failed"), NULL, MB_OK); 369 return; 370 } 371 372 CheckDlgButton(hwndDlg, 373 IDC_ICON_IN_TASKBAR, 374 GetSystrayVolumeIconState() ? BST_CHECKED : BST_UNCHECKED); 375 376 GetMuteControl(pGlobalData); 377 GetMuteState(pGlobalData); 378 if (pGlobalData->muteVal) 379 { 380 SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0); 381 SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted); 382 } 383 else 384 { 385 SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0); 386 SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconUnMuted); 387 } 388 389 GetVolumeControl(pGlobalData); 390 GetVolumeValue(pGlobalData, TRUE); 391 392 SendDlgItemMessage(hwndDlg, IDC_DEVICE_NAME, WM_SETTEXT, 0, (LPARAM)mxc.szPname); 393 SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(pGlobalData->maxVolume - pGlobalData->volumeMinimum) / pGlobalData->volumeStep); 394 } 395 396 VOID 397 SaveData(HWND hwndDlg) 398 { 399 BOOL bShowIcon; 400 401 bShowIcon = (IsDlgButtonChecked(hwndDlg, IDC_ICON_IN_TASKBAR) == BST_CHECKED); 402 403 SetSystrayVolumeIconState(bShowIcon); 404 } 405 406 VOID 407 LaunchSoundControl(HWND hwndDlg) 408 { 409 if ((INT_PTR)ShellExecuteW(NULL, L"open", L"sndvol32.exe", NULL, NULL, SW_SHOWNORMAL) > 32) 410 return; 411 MessageBox(hwndDlg, _T("Cannot run sndvol32.exe"), NULL, MB_OK); 412 } 413 414 /* Volume property page dialog callback */ 415 //static INT_PTR CALLBACK 416 INT_PTR CALLBACK 417 VolumeDlgProc(HWND hwndDlg, 418 UINT uMsg, 419 WPARAM wParam, 420 LPARAM lParam) 421 { 422 static IMGINFO ImgInfo; 423 PGLOBAL_DATA pGlobalData; 424 UNREFERENCED_PARAMETER(lParam); 425 UNREFERENCED_PARAMETER(wParam); 426 427 pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER); 428 429 switch(uMsg) 430 { 431 case MM_MIXM_LINE_CHANGE: 432 { 433 GetMuteState(pGlobalData); 434 if (pGlobalData->muteVal) 435 { 436 SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0); 437 SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted); 438 } 439 else 440 { 441 SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0); 442 SendDlgItemMessage(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 SendDlgItemMessage(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 = (GLOBAL_DATA*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBAL_DATA)); 455 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData); 456 457 pGlobalData->hIconUnMuted = LoadImage(hApplet, MAKEINTRESOURCE(IDI_CPLICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); 458 pGlobalData->hIconMuted = LoadImage(hApplet, MAKEINTRESOURCE(IDI_MUTED_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); 459 pGlobalData->hIconNoHW = LoadImage(hApplet, MAKEINTRESOURCE(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 SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted); 508 } 509 else 510 { 511 SendDlgItemMessage(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 PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ALIAS_ID | SND_ASYNC); 548 break; 549 550 default: 551 SetVolumeValue(pGlobalData, 552 (DWORD)SendDlgItemMessage(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