1 /* 2 * ReactOS Sound Volume Control 3 * Copyright (C) 2004-2005 Thomas Weidenmueller 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 /* 20 * COPYRIGHT: See COPYING in the top level directory 21 * PROJECT: ReactOS Sound Volume Control 22 * FILE: base/applications/sndvol32/sndvol32.c 23 * PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com> 24 */ 25 26 #include "sndvol32.h" 27 28 #include <shellapi.h> 29 30 HINSTANCE hAppInstance; 31 ATOM MainWindowClass; 32 HWND hMainWnd; 33 HANDLE hAppHeap; 34 LPTSTR lpAppTitle; 35 PREFERENCES_CONTEXT Preferences; 36 37 #define GetDialogData(hwndDlg, type) \ 38 ( P##type )GetWindowLongPtr((hwndDlg), DWLP_USER) 39 #define GetWindowData(hwnd, type) \ 40 ( P##type )GetWindowLongPtr((hwnd), GWL_USERDATA) 41 42 /******************************************************************************/ 43 44 45 46 typedef struct _PREFERENCES_FILL_DEVICES 47 { 48 PPREFERENCES_CONTEXT PrefContext; 49 HWND hComboBox; 50 UINT Selected; 51 } PREFERENCES_FILL_DEVICES, *PPREFERENCES_FILL_DEVICES; 52 53 static BOOL CALLBACK 54 FillDeviceComboBox(PSND_MIXER Mixer, 55 UINT Id, 56 LPCTSTR ProductName, 57 PVOID Context) 58 { 59 LRESULT lres; 60 PPREFERENCES_FILL_DEVICES FillContext = (PPREFERENCES_FILL_DEVICES)Context; 61 62 UNREFERENCED_PARAMETER(Mixer); 63 64 lres = SendMessage(FillContext->hComboBox, 65 CB_ADDSTRING, 66 0, 67 (LPARAM)ProductName); 68 if (lres != CB_ERR) 69 { 70 /* save the index so we don't screw stuff when the combobox is sorted... */ 71 SendMessage(FillContext->hComboBox, 72 CB_SETITEMDATA, 73 (WPARAM)lres, 74 Id); 75 76 if (Id == FillContext->Selected) 77 { 78 SendMessage(FillContext->hComboBox, 79 CB_SETCURSEL, 80 (WPARAM)lres, 81 0); 82 } 83 } 84 85 return TRUE; 86 } 87 88 static BOOL CALLBACK 89 PrefDlgAddLine(PSND_MIXER Mixer, 90 LPMIXERLINE Line, 91 UINT DisplayControls, 92 PVOID Context) 93 { 94 PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context; 95 96 UNREFERENCED_PARAMETER(Mixer); 97 UNREFERENCED_PARAMETER(DisplayControls); 98 99 switch (Line->dwComponentType) 100 { 101 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: 102 if (PrefContext->PlaybackID == (DWORD)-1) 103 { 104 PrefContext->PlaybackID = Line->dwLineID; 105 106 if (PrefContext->SelectedLine == (DWORD)-1) 107 { 108 PrefContext->SelectedLine = Line->dwLineID; 109 } 110 } 111 else 112 goto AddToOthersLines; 113 114 break; 115 116 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN: 117 if (PrefContext->RecordingID == (DWORD)-1) 118 { 119 PrefContext->RecordingID = Line->dwLineID; 120 121 if (PrefContext->SelectedLine == (DWORD)-1) 122 { 123 PrefContext->SelectedLine = Line->dwLineID; 124 } 125 } 126 else 127 goto AddToOthersLines; 128 129 break; 130 131 default: 132 { 133 LRESULT lres; 134 HWND hwndCbOthers; 135 136 if (PrefContext->SelectedLine == (DWORD)-1) 137 { 138 PrefContext->SelectedLine = Line->dwLineID; 139 } 140 141 AddToOthersLines: 142 hwndCbOthers = GetDlgItem(PrefContext->hwndDlg, 143 IDC_LINE); 144 145 lres = SendMessage(hwndCbOthers, 146 CB_ADDSTRING, 147 0, 148 (LPARAM)Line->szName); 149 if (lres != CB_ERR) 150 { 151 SendMessage(hwndCbOthers, 152 CB_SETITEMDATA, 153 (WPARAM)lres, 154 Line->dwLineID); 155 156 PrefContext->OtherLines++; 157 } 158 break; 159 } 160 } 161 162 return TRUE; 163 } 164 165 static BOOL CALLBACK 166 PrefDlgAddConnection(PSND_MIXER Mixer, 167 DWORD LineID, 168 LPMIXERLINE Line, 169 PVOID Context) 170 { 171 PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context; 172 HWND hwndControls; 173 LVITEM lvi; 174 UINT i; 175 176 UNREFERENCED_PARAMETER(Mixer); 177 UNREFERENCED_PARAMETER(LineID); 178 179 if (Line->cControls != 0) 180 { 181 hwndControls = GetDlgItem(PrefContext->hwndDlg, 182 IDC_CONTROLS); 183 184 lvi.mask = LVIF_TEXT | LVIF_PARAM; 185 lvi.iItem = PrefContext->tmp++; 186 lvi.iSubItem = 0; 187 lvi.pszText = Line->szName; 188 lvi.lParam = (LPARAM)Line->dwSource; 189 190 i = SendMessage(hwndControls, 191 LVM_INSERTITEM, 192 0, 193 (LPARAM)&lvi); 194 if (i != (UINT)-1) 195 { 196 TCHAR LineName[MIXER_LONG_NAME_CHARS]; 197 DWORD Flags; 198 BOOL SelLine = FALSE; 199 200 if (SndMixerGetLineName(PrefContext->Mixer, 201 PrefContext->SelectedLine, 202 LineName, 203 MIXER_LONG_NAME_CHARS, 204 TRUE) == -1) 205 { 206 LineName[0] = TEXT('\0'); 207 } 208 209 if (ReadLineConfig(PrefContext->DeviceName, 210 LineName, 211 Line->szName, 212 &Flags)) 213 { 214 if (Flags != 0x4) 215 { 216 SelLine = TRUE; 217 } 218 } 219 220 ListView_SetCheckState(hwndControls, 221 i, 222 SelLine); 223 } 224 } 225 226 return TRUE; 227 } 228 229 static VOID 230 UpdatePrefDlgControls(PPREFERENCES_CONTEXT Context, 231 DWORD LineID) 232 { 233 INT OldID, MixerID = 0; 234 INT DeviceCbIndex; 235 236 /* select the mixer */ 237 DeviceCbIndex = SendDlgItemMessage(Context->hwndDlg, 238 IDC_MIXERDEVICE, 239 CB_GETCURSEL, 240 0, 241 0); 242 if (DeviceCbIndex != CB_ERR) 243 { 244 MixerID = SendDlgItemMessage(Context->hwndDlg, 245 IDC_MIXERDEVICE, 246 CB_GETITEMDATA, 247 DeviceCbIndex, 248 0); 249 if (MixerID == CB_ERR) 250 { 251 MixerID = 0; 252 } 253 } 254 255 OldID = Context->Selected; 256 if (MixerID != OldID && 257 SndMixerSelect(Context->Mixer, 258 MixerID)) 259 { 260 Context->Selected = SndMixerGetSelection(Context->Mixer); 261 262 /* update the controls */ 263 Context->PlaybackID = (DWORD)-1; 264 Context->RecordingID = (DWORD)-1; 265 Context->OtherLines = 0; 266 Context->SelectedLine = (DWORD)-1; 267 268 SndMixerGetProductName(Context->Mixer, 269 Context->DeviceName, 270 sizeof(Context->DeviceName) / sizeof(Context->DeviceName[0])); 271 272 if (SndMixerEnumLines(Context->Mixer, 273 PrefDlgAddLine, 274 Context)) 275 { 276 UINT SelBox = 0; 277 278 /* enable/disable controls and make default selection */ 279 EnableWindow(GetDlgItem(Context->hwndDlg, 280 IDC_PLAYBACK), 281 Context->PlaybackID != (DWORD)-1); 282 CheckDlgButton(Context->hwndDlg, 283 IDC_PLAYBACK, 284 (Context->PlaybackID != (DWORD)-1 && SelBox++ == 0) ? 285 BST_CHECKED : BST_UNCHECKED); 286 287 EnableWindow(GetDlgItem(Context->hwndDlg, 288 IDC_RECORDING), 289 Context->RecordingID != (DWORD)-1); 290 CheckDlgButton(Context->hwndDlg, 291 IDC_RECORDING, 292 (Context->RecordingID != (DWORD)-1 && SelBox++ == 0) ? 293 BST_CHECKED : BST_UNCHECKED); 294 295 if (Context->OtherLines != 0) 296 { 297 /* select the first item in the other lines combo box by default */ 298 SendDlgItemMessage(Context->hwndDlg, 299 IDC_LINE, 300 CB_SETCURSEL, 301 0, 302 0); 303 } 304 EnableWindow(GetDlgItem(Context->hwndDlg, 305 IDC_LINE), 306 FALSE); 307 EnableWindow(GetDlgItem(Context->hwndDlg, 308 IDC_OTHER), 309 Context->OtherLines != 0); 310 CheckDlgButton(Context->hwndDlg, 311 IDC_LINE, 312 (Context->OtherLines != 0 && SelBox++ == 0) ? 313 BST_CHECKED : BST_UNCHECKED); 314 315 /* disable the OK button if the device doesn't have any lines */ 316 EnableWindow(GetDlgItem(Context->hwndDlg, 317 IDOK), 318 Context->PlaybackID != (DWORD)-1 || 319 Context->RecordingID != (DWORD)-1 || 320 Context->OtherLines != 0); 321 322 LineID = Context->SelectedLine; 323 } 324 } 325 326 /* update the line sources list */ 327 if ((MixerID != OldID && Context->SelectedLine != (DWORD)-1) || 328 (Context->SelectedLine != LineID && LineID != (DWORD)-1)) 329 { 330 Context->SelectedLine = LineID; 331 332 (void)ListView_DeleteAllItems(GetDlgItem(Context->hwndDlg, 333 IDC_CONTROLS)); 334 335 Context->tmp = 0; 336 SndMixerEnumConnections(Context->Mixer, 337 LineID, 338 PrefDlgAddConnection, 339 Context); 340 } 341 } 342 343 static 344 VOID 345 WriteLineSettings(PPREFERENCES_CONTEXT Context, HWND hwndDlg) 346 { 347 HWND hwndControls; 348 INT Count, Index; 349 WCHAR LineName[MIXER_LONG_NAME_CHARS]; 350 WCHAR DestinationName[MIXER_LONG_NAME_CHARS]; 351 DWORD Flags; 352 PSNDVOL_REG_LINESTATE LineStates; 353 354 /* get list view */ 355 hwndControls = GetDlgItem(hwndDlg, IDC_CONTROLS); 356 357 /* get list item count */ 358 Count = ListView_GetItemCount(hwndControls); 359 360 /* sanity check */ 361 assert(Count); 362 363 if (SndMixerGetLineName(Context->Mixer, Context->SelectedLine, DestinationName, MIXER_LONG_NAME_CHARS, TRUE) == -1) 364 { 365 /* failed to get destination line name */ 366 return; 367 } 368 369 /* allocate line states array */ 370 LineStates = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SNDVOL_REG_LINESTATE) * Count); 371 if (LineStates == NULL) 372 { 373 /* failed to allocate line states array */ 374 return; 375 } 376 377 378 for(Index = 0; Index < Count; Index++) 379 { 380 /* set to empty */ 381 LineName[0] = L'\0'; 382 383 /* get item text */ 384 ListView_GetItemText(hwndControls, Index, 0, LineName, MIXER_LONG_NAME_CHARS); 385 386 /* make sure it is null terminated */ 387 LineName[MIXER_LONG_NAME_CHARS-1] = L'\0'; 388 389 /* get check state */ 390 Flags = (ListView_GetCheckState(hwndControls, Index) == 0 ? 0x4 : 0); 391 392 /* copy line name */ 393 wcscpy(LineStates[Index].LineName, LineName); 394 395 /* store flags */ 396 LineStates[Index].Flags = Flags; 397 } 398 399 /* now write the line config */ 400 WriteLineConfig(Context->DeviceName, DestinationName, LineStates, sizeof(SNDVOL_REG_LINESTATE) * Count); 401 402 /* free line states */ 403 HeapFree(GetProcessHeap(), 0, LineStates); 404 } 405 406 static INT_PTR CALLBACK 407 DlgPreferencesProc(HWND hwndDlg, 408 UINT uMsg, 409 WPARAM wParam, 410 LPARAM lParam) 411 { 412 PPREFERENCES_CONTEXT Context; 413 414 switch (uMsg) 415 { 416 case WM_COMMAND: 417 { 418 Context = GetDialogData(hwndDlg, 419 PREFERENCES_CONTEXT); 420 switch (LOWORD(wParam)) 421 { 422 case IDC_MIXERDEVICE: 423 { 424 if (HIWORD(wParam) == CBN_SELCHANGE) 425 { 426 UpdatePrefDlgControls(Context, 427 (DWORD)-1); 428 } 429 break; 430 } 431 432 case IDC_LINE: 433 { 434 if (HIWORD(wParam) == CBN_SELCHANGE) 435 { 436 INT LineID; 437 INT Index; 438 439 Index = SendDlgItemMessage(hwndDlg, 440 IDC_LINE, 441 CB_GETCURSEL, 442 0, 443 0); 444 if (Index != CB_ERR) 445 { 446 LineID = SendDlgItemMessage(hwndDlg, 447 IDC_LINE, 448 CB_GETITEMDATA, 449 Index, 450 0); 451 if (LineID != CB_ERR) 452 { 453 UpdatePrefDlgControls(Context, 454 LineID); 455 } 456 } 457 } 458 break; 459 } 460 461 case IDC_PLAYBACK: 462 { 463 UpdatePrefDlgControls(Context, 464 Context->PlaybackID); 465 EnableWindow(GetDlgItem(hwndDlg, 466 IDC_LINE), 467 FALSE); 468 break; 469 } 470 471 case IDC_RECORDING: 472 { 473 UpdatePrefDlgControls(Context, 474 Context->RecordingID); 475 EnableWindow(GetDlgItem(hwndDlg, 476 IDC_LINE), 477 FALSE); 478 break; 479 } 480 481 case IDC_OTHER: 482 { 483 INT LineCbIndex; 484 INT LineID; 485 486 EnableWindow(GetDlgItem(hwndDlg, 487 IDC_LINE), 488 TRUE); 489 490 LineCbIndex = SendDlgItemMessage(hwndDlg, 491 IDC_LINE, 492 CB_GETCURSEL, 493 0, 494 0); 495 if (LineCbIndex != CB_ERR) 496 { 497 LineID = SendDlgItemMessage(hwndDlg, 498 IDC_LINE, 499 CB_GETITEMDATA, 500 LineCbIndex, 501 0); 502 if (LineID != CB_ERR) 503 { 504 UpdatePrefDlgControls(Context, 505 LineID); 506 } 507 } 508 break; 509 } 510 511 case IDOK: 512 { 513 /* write line settings */ 514 WriteLineSettings(Context, hwndDlg); 515 516 /* fall through */ 517 } 518 case IDCANCEL: 519 { 520 EndDialog(hwndDlg, 521 LOWORD(wParam)); 522 break; 523 } 524 } 525 break; 526 } 527 528 case WM_INITDIALOG: 529 { 530 PREFERENCES_FILL_DEVICES FillDevContext; 531 LVCOLUMN lvc; 532 RECT rcClient; 533 HWND hwndControls; 534 535 SetWindowLongPtr(hwndDlg, 536 DWLP_USER, 537 (LONG_PTR)lParam); 538 Context = (PPREFERENCES_CONTEXT)((LONG_PTR)lParam); 539 Context->hwndDlg = hwndDlg; 540 Context->Mixer = SndMixerCreate(hwndDlg, Context->MixerWindow->MixerId); 541 Context->Selected = (UINT)-1; 542 543 FillDevContext.PrefContext = Context; 544 FillDevContext.hComboBox = GetDlgItem(hwndDlg, 545 IDC_MIXERDEVICE); 546 FillDevContext.Selected = SndMixerGetSelection(Context->Mixer); 547 SndMixerEnumProducts(Context->Mixer, 548 FillDeviceComboBox, 549 &FillDevContext); 550 551 /* initialize the list view control */ 552 hwndControls = GetDlgItem(hwndDlg, 553 IDC_CONTROLS); 554 (void)ListView_SetExtendedListViewStyle(hwndControls, 555 LVS_EX_CHECKBOXES); 556 557 GetClientRect(hwndControls, 558 &rcClient); 559 lvc.mask = LVCF_TEXT | LVCF_WIDTH; 560 lvc.pszText = TEXT(""); 561 lvc.cx = rcClient.right; 562 SendMessage(hwndControls, 563 LVM_INSERTCOLUMN, 564 0, 565 (LPARAM)&lvc); 566 567 /* update all controls */ 568 UpdatePrefDlgControls(Context, 569 (DWORD)Context->SelectedLine); 570 return TRUE; 571 } 572 573 case WM_CLOSE: 574 { 575 EndDialog(hwndDlg, 576 IDCANCEL); 577 break; 578 } 579 580 case WM_SYSCOLORCHANGE: 581 { 582 HWND hwndControls; 583 584 /* Forward WM_SYSCOLORCHANGE */ 585 hwndControls = GetDlgItem(hwndDlg, IDC_CONTROLS); 586 SendMessage(hwndControls, WM_SYSCOLORCHANGE, 0, 0); 587 break; 588 } 589 } 590 591 return 0; 592 } 593 594 /******************************************************************************/ 595 596 static VOID 597 DeleteMixerWindowControls(PMIXER_WINDOW MixerWindow) 598 { 599 DWORD Index; 600 601 for(Index = 0; Index < MixerWindow->WindowCount; Index++) 602 { 603 /* destroys the window */ 604 DestroyWindow(MixerWindow->Window[Index]); 605 } 606 607 /* free memory */ 608 HeapFree(GetProcessHeap(), 0, MixerWindow->Window); 609 610 /* set to null */ 611 MixerWindow->Window = NULL; 612 MixerWindow->WindowCount = 0; 613 } 614 615 static BOOL 616 RebuildMixerWindowControls(PPREFERENCES_CONTEXT PrefContext) 617 { 618 /* delete existing mixer controls */ 619 DeleteMixerWindowControls(PrefContext->MixerWindow); 620 621 /* load new mixer controls */ 622 LoadDialogCtrls(PrefContext); 623 624 return TRUE; 625 } 626 627 static 628 BOOL 629 CALLBACK 630 SetVolumeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Ctx) 631 { 632 UINT ControlCount = 0, Index; 633 LPMIXERCONTROL Control = NULL; 634 PMIXERCONTROLDETAILS_UNSIGNED puDetails = NULL; 635 MIXERCONTROLDETAILS_BOOLEAN bDetails; 636 PSET_VOLUME_CONTEXT Context = (PSET_VOLUME_CONTEXT)Ctx; 637 638 /* check if the line name is equal */ 639 if (wcsicmp(Line->szName, Context->LineName)) 640 { 641 /* it is not */ 642 return TRUE; 643 } 644 645 /* query controls */ 646 if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) == FALSE) 647 { 648 /* failed to query for controls */ 649 return FALSE; 650 } 651 652 puDetails = HeapAlloc(GetProcessHeap(), 0, Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED)); 653 if (puDetails == NULL) 654 return FALSE; 655 656 /* now go through all controls and compare control ids */ 657 for (Index = 0; Index < ControlCount; Index++) 658 { 659 if (Context->bVertical) 660 { 661 if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) 662 { 663 DWORD LineOffset, volumePosition, balancePosition; 664 DWORD volumeStep, balanceStep; 665 666 LineOffset = Context->SliderPos; 667 668 volumePosition = (DWORD)SendDlgItemMessage(Preferences.MixerWindow->hWnd, LineOffset * IDC_LINE_SLIDER_VERT, TBM_GETPOS, 0, 0); 669 volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN); 670 671 if (Line->cChannels == 1) 672 { 673 /* set up details */ 674 puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum; 675 } 676 else if (Line->cChannels == 2) 677 { 678 balancePosition = (DWORD)SendDlgItemMessage(Preferences.MixerWindow->hWnd, LineOffset * IDC_LINE_SLIDER_HORZ, TBM_GETPOS, 0, 0); 679 if (balancePosition == BALANCE_CENTER) 680 { 681 puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum; 682 puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum; 683 } 684 else if (balancePosition == BALANCE_LEFT) 685 { 686 puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum; 687 puDetails[1].dwValue = Control[Index].Bounds.dwMinimum; 688 } 689 else if (balancePosition == BALANCE_RIGHT) 690 { 691 puDetails[0].dwValue = Control[Index].Bounds.dwMinimum; 692 puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum; 693 } 694 else if (balancePosition < BALANCE_CENTER) // Left 695 { 696 puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum; 697 698 balanceStep = (puDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2); 699 700 puDetails[1].dwValue = (balancePosition * balanceStep) + Control[Index].Bounds.dwMinimum; 701 } 702 else if (balancePosition > BALANCE_CENTER) // Right 703 { 704 puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum; 705 706 balanceStep = (puDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2); 707 708 puDetails[0].dwValue = ((BALANCE_RIGHT - balancePosition) * balanceStep) + Control[Index].Bounds.dwMinimum; 709 } 710 } 711 else 712 { 713 SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)puDetails); 714 715 /* FIXME */ 716 } 717 718 /* set volume */ 719 SndMixerSetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)puDetails); 720 721 /* done */ 722 break; 723 } 724 } 725 else if (Context->bSwitch) 726 { 727 if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) 728 { 729 /* set up details */ 730 bDetails.fValue = Context->SliderPos; 731 732 /* set volume */ 733 SndMixerSetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&bDetails); 734 735 /* done */ 736 break; 737 } 738 } 739 } 740 741 if (puDetails != NULL) 742 HeapFree(GetProcessHeap(), 0, puDetails); 743 744 /* free controls */ 745 HeapFree(GetProcessHeap(), 0, Control); 746 747 748 /* done */ 749 return TRUE; 750 } 751 752 static 753 BOOL 754 CALLBACK 755 MixerControlChangeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Context) 756 { 757 PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails = NULL; 758 UINT ControlCount = 0, Index; 759 LPMIXERCONTROL Control = NULL; 760 761 /* check if the line has controls */ 762 if (Line->cControls == 0) 763 { 764 /* no controls */ 765 return TRUE; 766 } 767 768 /* query controls */ 769 if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) == FALSE) 770 { 771 /* failed to query for controls */ 772 return FALSE; 773 } 774 775 pVolumeDetails = HeapAlloc(GetProcessHeap(), 776 0, 777 Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED)); 778 if (pVolumeDetails == NULL) 779 goto done; 780 781 /* now go through all controls and compare control ids */ 782 for (Index = 0; Index < ControlCount; Index++) 783 { 784 if (Control[Index].dwControlID == PtrToUlong(Context)) 785 { 786 if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) 787 { 788 MIXERCONTROLDETAILS_BOOLEAN Details; 789 790 /* get volume control details */ 791 if (SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1) 792 { 793 /* update dialog control */ 794 UpdateDialogLineSwitchControl(&Preferences, Line, Details.fValue); 795 } 796 } 797 else if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) 798 { 799 /* get volume control details */ 800 if (SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)pVolumeDetails) != -1) 801 { 802 /* update dialog control */ 803 DWORD volumePosition, volumeStep, maxVolume, i; 804 DWORD balancePosition, balanceStep; 805 806 volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN); 807 808 maxVolume = 0; 809 for (i = 0; i < Line->cChannels; i++) 810 { 811 if (pVolumeDetails[i].dwValue > maxVolume) 812 maxVolume = pVolumeDetails[i].dwValue; 813 } 814 815 volumePosition = (maxVolume - Control[Index].Bounds.dwMinimum) / volumeStep; 816 817 if (Line->cChannels == 1) 818 { 819 balancePosition = BALANCE_CENTER; 820 } 821 else if (Line->cChannels == 2) 822 { 823 if (pVolumeDetails[0].dwValue == pVolumeDetails[1].dwValue) 824 { 825 balancePosition = BALANCE_CENTER; 826 } 827 else if (pVolumeDetails[0].dwValue == Control[Index].Bounds.dwMinimum) 828 { 829 balancePosition = BALANCE_RIGHT; 830 } 831 else if (pVolumeDetails[1].dwValue == Control[Index].Bounds.dwMinimum) 832 { 833 balancePosition = BALANCE_LEFT; 834 } 835 else 836 { 837 balanceStep = (maxVolume - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2); 838 839 if (pVolumeDetails[0].dwValue < pVolumeDetails[1].dwValue) 840 { 841 balancePosition = (pVolumeDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep; 842 balancePosition = BALANCE_RIGHT - balancePosition; 843 } 844 else if (pVolumeDetails[1].dwValue < pVolumeDetails[0].dwValue) 845 { 846 balancePosition = (pVolumeDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep; 847 balancePosition = BALANCE_LEFT + balancePosition; 848 } 849 } 850 } 851 852 /* Update the volume control slider */ 853 UpdateDialogLineSliderControl(&Preferences, Line, IDC_LINE_SLIDER_VERT, VOLUME_MAX - volumePosition); 854 855 /* Update the balance control slider */ 856 UpdateDialogLineSliderControl(&Preferences, Line, IDC_LINE_SLIDER_HORZ, balancePosition); 857 } 858 } 859 break; 860 } 861 } 862 863 done: 864 /* Free the volume details */ 865 if (pVolumeDetails) 866 HeapFree(GetProcessHeap(), 0, pVolumeDetails); 867 868 /* free controls */ 869 HeapFree(GetProcessHeap(), 0, Control); 870 871 /* done */ 872 return TRUE; 873 } 874 875 static LRESULT CALLBACK 876 MainWindowProc(HWND hwnd, 877 UINT uMsg, 878 WPARAM wParam, 879 LPARAM lParam) 880 { 881 PMIXER_WINDOW MixerWindow; 882 DWORD CtrlID, LineOffset; 883 BOOL bRet; 884 LRESULT Result = 0; 885 SET_VOLUME_CONTEXT Context; 886 887 switch (uMsg) 888 { 889 case WM_COMMAND: 890 { 891 MixerWindow = GetWindowData(hwnd, 892 MIXER_WINDOW); 893 894 switch (LOWORD(wParam)) 895 { 896 case IDM_PROPERTIES: 897 { 898 PREFERENCES_CONTEXT Pref; 899 900 Pref.MixerWindow = MixerWindow; 901 Pref.Mixer = NULL; 902 Pref.SelectedLine = Preferences.SelectedLine; 903 904 if (DialogBoxParam(hAppInstance, 905 MAKEINTRESOURCE(IDD_PREFERENCES), 906 hwnd, 907 DlgPreferencesProc, 908 (LPARAM)&Pref) == IDOK) 909 { 910 /* update window */ 911 TCHAR szProduct[MAXPNAMELEN]; 912 913 /* get mixer product name */ 914 if (SndMixerGetProductName(Pref.Mixer, 915 szProduct, 916 sizeof(szProduct) / sizeof(szProduct[0])) == -1) 917 { 918 /* failed to get name */ 919 szProduct[0] = L'\0'; 920 } 921 else 922 { 923 /* copy product */ 924 wcscpy(Preferences.DeviceName, szProduct); 925 } 926 927 /* destroy old status bar */ 928 if (MixerWindow->Mode == NORMAL_MODE) 929 DestroyWindow(MixerWindow->hStatusBar); 930 931 /* update details */ 932 Preferences.SelectedLine = Pref.SelectedLine; 933 934 /* destroy old mixer */ 935 SndMixerDestroy(Preferences.MixerWindow->Mixer); 936 937 /* use new selected mixer */ 938 Preferences.MixerWindow->Mixer = Pref.Mixer; 939 940 /* create status window */ 941 if (MixerWindow->Mode == NORMAL_MODE) 942 { 943 MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS, 944 NULL, 945 hwnd, 946 0); 947 if (MixerWindow->hStatusBar) 948 { 949 /* Set status bar */ 950 SendMessage(MixerWindow->hStatusBar, 951 WM_SETTEXT, 952 0, 953 (LPARAM)szProduct); 954 } 955 } 956 957 /* rebuild dialog controls */ 958 RebuildMixerWindowControls(&Preferences); 959 } 960 break; 961 } 962 963 case IDM_ADVANCED_CONTROLS: 964 MixerWindow->bShowExtendedControls = !MixerWindow->bShowExtendedControls; 965 CheckMenuItem(GetMenu(hwnd), 966 IDM_ADVANCED_CONTROLS, 967 MF_BYCOMMAND | (MixerWindow->bShowExtendedControls ? MF_CHECKED : MF_UNCHECKED)); 968 RebuildMixerWindowControls(&Preferences); 969 break; 970 971 case IDM_EXIT: 972 { 973 PostQuitMessage(0); 974 break; 975 } 976 977 case IDM_ABOUT: 978 { 979 HICON hAppIcon = (HICON)GetClassLongPtrW(hwnd, 980 GCLP_HICON); 981 ShellAbout(hwnd, 982 lpAppTitle, 983 NULL, 984 hAppIcon); 985 break; 986 } 987 988 default: 989 { 990 /* get button id */ 991 CtrlID = LOWORD(wParam); 992 993 /* check if the message is from the line switch */ 994 if (HIWORD(wParam) == BN_CLICKED) 995 { 996 if (CtrlID % IDC_LINE_SWITCH == 0) 997 { 998 /* compute line offset */ 999 LineOffset = CtrlID / IDC_LINE_SWITCH; 1000 1001 /* compute window id of line name static control */ 1002 CtrlID = LineOffset * IDC_LINE_NAME; 1003 1004 if (Preferences.MixerWindow->Mixer->MixerId == PLAY_MIXER) 1005 { 1006 /* get line name */ 1007 if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0) 1008 { 1009 /* setup context */ 1010 Context.SliderPos = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0); 1011 Context.bVertical = FALSE; 1012 Context.bSwitch = TRUE; 1013 1014 /* set volume */ 1015 SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context); 1016 } 1017 } 1018 else if (Preferences.MixerWindow->Mixer->MixerId == RECORD_MIXER) 1019 { 1020 UINT i; 1021 1022 for (i = 0; i < Preferences.MixerWindow->DialogCount; i++) 1023 { 1024 SendDlgItemMessageW(hwnd, (i + 1) * IDC_LINE_SWITCH, BM_SETCHECK, (WPARAM)((i + 1) == LineOffset), 0); 1025 } 1026 } 1027 } 1028 else if (CtrlID % IDC_LINE_ADVANCED == 0) 1029 { 1030 ADVANCED_CONTEXT AdvancedContext; 1031 1032 /* compute line offset */ 1033 LineOffset = CtrlID / IDC_LINE_ADVANCED; 1034 1035 /* compute window id of line name static control */ 1036 CtrlID = LineOffset * IDC_LINE_NAME; 1037 1038 /* get line name */ 1039 if (GetDlgItemTextW(hwnd, CtrlID, AdvancedContext.LineName, MIXER_LONG_NAME_CHARS) != 0) 1040 { 1041 AdvancedContext.MixerWindow = Preferences.MixerWindow; 1042 AdvancedContext.Mixer = Preferences.MixerWindow->Mixer; 1043 AdvancedContext.Line = SndMixerGetLineByName(Preferences.MixerWindow->Mixer, 1044 Preferences.SelectedLine, 1045 AdvancedContext.LineName); 1046 if (AdvancedContext.Line) 1047 { 1048 DialogBoxParam(hAppInstance, 1049 MAKEINTRESOURCE(IDD_ADVANCED), 1050 hwnd, 1051 AdvancedDlgProc, 1052 (LPARAM)&AdvancedContext); 1053 } 1054 } 1055 } 1056 } 1057 } 1058 } 1059 break; 1060 } 1061 1062 case MM_MIXM_LINE_CHANGE: 1063 { 1064 DPRINT("MM_MIXM_LINE_CHANGE\n"); 1065 break; 1066 } 1067 1068 case MM_MIXM_CONTROL_CHANGE: 1069 { 1070 DPRINT("MM_MIXM_CONTROL_CHANGE\n"); 1071 1072 /* get mixer window */ 1073 MixerWindow = GetWindowData(hwnd, 1074 MIXER_WINDOW); 1075 1076 /* sanity checks */ 1077 assert(MixerWindow); 1078 assert(MixerWindow->Mixer->hmx == (HMIXER)wParam); 1079 1080 SndMixerEnumConnections(MixerWindow->Mixer, Preferences.SelectedLine, MixerControlChangeCallback, (PVOID)lParam); 1081 break; 1082 } 1083 1084 case WM_VSCROLL: 1085 switch (LOWORD(wParam)) 1086 { 1087 case TB_THUMBTRACK: 1088 /* get dialog item ctrl */ 1089 CtrlID = GetDlgCtrlID((HWND)lParam); 1090 1091 /* get line index */ 1092 LineOffset = CtrlID / IDC_LINE_SLIDER_VERT; 1093 1094 /* compute window id of line name static control */ 1095 CtrlID = LineOffset * IDC_LINE_NAME; 1096 1097 /* get line name */ 1098 if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0) 1099 { 1100 /* setup context */ 1101 Context.SliderPos = LineOffset; 1102 Context.bVertical = TRUE; 1103 Context.bSwitch = FALSE; 1104 1105 /* set volume */ 1106 SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context); 1107 } 1108 break; 1109 1110 case TB_ENDTRACK: 1111 MixerWindow = GetWindowData(hwnd, 1112 MIXER_WINDOW); 1113 1114 /* get dialog item ctrl */ 1115 CtrlID = GetDlgCtrlID((HWND)lParam); 1116 1117 /* get line index */ 1118 LineOffset = CtrlID / IDC_LINE_SLIDER_VERT; 1119 1120 if (LineOffset == 1 && MixerWindow->Mixer->MixerId == 0) 1121 PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID); 1122 break; 1123 1124 default: 1125 break; 1126 } 1127 break; 1128 1129 case WM_HSCROLL: 1130 switch (LOWORD(wParam)) 1131 { 1132 case TB_THUMBTRACK: 1133 /* get dialog item ctrl */ 1134 CtrlID = GetDlgCtrlID((HWND)lParam); 1135 1136 /* get line index */ 1137 LineOffset = CtrlID / IDC_LINE_SLIDER_HORZ; 1138 1139 /* compute window id of line name static control */ 1140 CtrlID = LineOffset * IDC_LINE_NAME; 1141 1142 /* get line name */ 1143 if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0) 1144 { 1145 /* setup context */ 1146 Context.SliderPos = LineOffset; 1147 Context.bVertical = TRUE; 1148 Context.bSwitch = FALSE; 1149 1150 /* set volume */ 1151 SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context); 1152 } 1153 break; 1154 1155 case TB_ENDTRACK: 1156 MixerWindow = GetWindowData(hwnd, 1157 MIXER_WINDOW); 1158 1159 /* get dialog item ctrl */ 1160 CtrlID = GetDlgCtrlID((HWND)lParam); 1161 1162 /* get line index */ 1163 LineOffset = CtrlID / IDC_LINE_SLIDER_HORZ; 1164 1165 if (LineOffset == 1 && MixerWindow->Mixer->MixerId == 0) 1166 PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID); 1167 break; 1168 1169 default: 1170 break; 1171 } 1172 break; 1173 1174 1175 case WM_CREATE: 1176 { 1177 MixerWindow = ((LPCREATESTRUCT)lParam)->lpCreateParams; 1178 SetWindowLongPtr(hwnd, 1179 GWL_USERDATA, 1180 (LONG_PTR)MixerWindow); 1181 MixerWindow->hWnd = hwnd; 1182 MixerWindow->Mixer = SndMixerCreate(MixerWindow->hWnd, MixerWindow->MixerId); 1183 if (MixerWindow->Mixer != NULL) 1184 { 1185 TCHAR szProduct[MAXPNAMELEN]; 1186 1187 /* get mixer product name */ 1188 if (SndMixerGetProductName(MixerWindow->Mixer, 1189 szProduct, 1190 sizeof(szProduct) / sizeof(szProduct[0])) == -1) 1191 { 1192 /* failed to get name */ 1193 szProduct[0] = L'\0'; 1194 } 1195 1196 1197 /* initialize preferences */ 1198 ZeroMemory(&Preferences, sizeof(Preferences)); 1199 1200 /* store mixer */ 1201 Preferences.Mixer = MixerWindow->Mixer; 1202 1203 /* store mixer window */ 1204 Preferences.MixerWindow = MixerWindow; 1205 1206 /* first destination line id */ 1207 Preferences.SelectedLine = 0xFFFF0000; 1208 1209 /* copy product */ 1210 wcscpy(Preferences.DeviceName, szProduct); 1211 1212 /* Disable the 'Advanced Controls' menu item */ 1213 EnableMenuItem(GetMenu(hwnd), IDM_ADVANCED_CONTROLS, MF_BYCOMMAND | MF_GRAYED); 1214 1215 /* Load the placement coordinate data of the window */ 1216 bRet = LoadXYCoordWnd(&Preferences); 1217 if (bRet) 1218 { 1219 /* 1220 * LoadXYCoordWnd() might fail for the first time of opening the application which is normal as 1221 * the Sound Control's applet settings haven't been saved yet to the Registry. At this point SetWindowPos() 1222 * call is skipped. 1223 */ 1224 SetWindowPos(hwnd, NULL, MixerWindow->WndPosX, MixerWindow->WndPosY, 0, 0, SWP_NOSIZE | SWP_NOZORDER); 1225 } 1226 1227 /* create status window */ 1228 if (MixerWindow->Mode == NORMAL_MODE) 1229 { 1230 MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS, 1231 NULL, 1232 hwnd, 1233 0); 1234 if (MixerWindow->hStatusBar) 1235 { 1236 SendMessage(MixerWindow->hStatusBar, 1237 WM_SETTEXT, 1238 0, 1239 (LPARAM)szProduct); 1240 } 1241 } 1242 1243 if (!RebuildMixerWindowControls(&Preferences)) 1244 { 1245 DPRINT("Rebuilding mixer window controls failed!\n"); 1246 SndMixerDestroy(MixerWindow->Mixer); 1247 MixerWindow->Mixer = NULL; 1248 Result = -1; 1249 } 1250 } 1251 break; 1252 } 1253 1254 case WM_DESTROY: 1255 { 1256 MixerWindow = GetWindowData(hwnd, 1257 MIXER_WINDOW); 1258 if (MixerWindow != NULL) 1259 { 1260 if (MixerWindow->Mixer != NULL) 1261 { 1262 SndMixerDestroy(MixerWindow->Mixer); 1263 } 1264 if (MixerWindow->hFont) 1265 DeleteObject(MixerWindow->hFont); 1266 HeapFree(hAppHeap, 0, MixerWindow); 1267 } 1268 break; 1269 } 1270 1271 case WM_CLOSE: 1272 { 1273 SaveXYCoordWnd(hwnd, &Preferences); 1274 PostQuitMessage(0); 1275 break; 1276 } 1277 1278 default: 1279 { 1280 Result = DefWindowProc(hwnd, 1281 uMsg, 1282 wParam, 1283 lParam); 1284 break; 1285 } 1286 } 1287 1288 return Result; 1289 } 1290 1291 static BOOL 1292 RegisterApplicationClasses(VOID) 1293 { 1294 WNDCLASSEX wc; 1295 1296 wc.cbSize = sizeof(WNDCLASSEX); 1297 wc.style = CS_HREDRAW | CS_VREDRAW; 1298 wc.lpfnWndProc = MainWindowProc; 1299 wc.cbClsExtra = 0; 1300 wc.cbWndExtra = sizeof(PMIXER_WINDOW); 1301 wc.hInstance = hAppInstance; 1302 wc.hIcon = LoadIcon(hAppInstance, 1303 MAKEINTRESOURCE(IDI_MAINAPP)); 1304 wc.hCursor = LoadCursor(NULL, 1305 IDC_ARROW); 1306 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 1307 wc.lpszMenuName = NULL; 1308 wc.lpszClassName = SZ_APP_CLASS; 1309 wc.hIconSm = NULL; 1310 MainWindowClass = RegisterClassEx(&wc); 1311 1312 return MainWindowClass != 0; 1313 } 1314 1315 static VOID 1316 UnregisterApplicationClasses(VOID) 1317 { 1318 UnregisterClass(SZ_APP_CLASS, 1319 hAppInstance); 1320 } 1321 1322 static HWND 1323 CreateApplicationWindow( 1324 WINDOW_MODE WindowMode, 1325 UINT MixerId) 1326 { 1327 HWND hWnd; 1328 1329 PMIXER_WINDOW MixerWindow = HeapAlloc(hAppHeap, 1330 HEAP_ZERO_MEMORY, 1331 sizeof(MIXER_WINDOW)); 1332 if (MixerWindow == NULL) 1333 { 1334 return NULL; 1335 } 1336 1337 MixerWindow->Mode = WindowMode; 1338 MixerWindow->MixerId = MixerId; 1339 1340 if (mixerGetNumDevs() > 0) 1341 { 1342 hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT, 1343 SZ_APP_CLASS, 1344 lpAppTitle, 1345 WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, 1346 0, 0, 300, 315, 1347 NULL, 1348 LoadMenu(hAppInstance, 1349 MAKEINTRESOURCE(IDM_MAINMENU)), 1350 hAppInstance, 1351 MixerWindow); 1352 } 1353 else 1354 { 1355 LPTSTR lpErrMessage; 1356 1357 /* 1358 * no mixer devices are available! 1359 */ 1360 1361 hWnd = NULL; 1362 if (AllocAndLoadString(&lpErrMessage, 1363 hAppInstance, 1364 IDS_NOMIXERDEVICES)) 1365 { 1366 MessageBox(NULL, 1367 lpErrMessage, 1368 lpAppTitle, 1369 MB_ICONINFORMATION); 1370 LocalFree(lpErrMessage); 1371 } 1372 } 1373 1374 if (hWnd == NULL) 1375 { 1376 HeapFree(hAppHeap, 1377 0, 1378 MixerWindow); 1379 } 1380 1381 return hWnd; 1382 } 1383 1384 static 1385 BOOL 1386 HandleCommandLine(LPTSTR cmdline, 1387 DWORD dwStyle, 1388 PWINDOW_MODE pMode, 1389 PUINT pMixerId) 1390 { 1391 TCHAR option; 1392 1393 *pMixerId = PLAY_MIXER; 1394 *pMode = (dwStyle & 0x20) ? SMALL_MODE : NORMAL_MODE; 1395 1396 while (*cmdline == _T(' ') || *cmdline == _T('-') || *cmdline == _T('/')) 1397 { 1398 if (*cmdline++ == _T(' ')) 1399 continue; 1400 1401 option = *cmdline; 1402 if (option) 1403 cmdline++; 1404 while (*cmdline == _T(' ')) 1405 cmdline++; 1406 1407 switch (option) 1408 { 1409 case 'd': /* Device */ 1410 case 'D': 1411 break; 1412 1413 case 'n': /* Small size */ 1414 case 'N': 1415 *pMode = NORMAL_MODE; 1416 break; 1417 1418 case 's': /* Small size */ 1419 case 'S': 1420 *pMode = SMALL_MODE; 1421 break; 1422 1423 case 't': /* Tray size */ 1424 case 'T': 1425 *pMode = TRAY_MODE; 1426 break; 1427 1428 case 'p': /* Play mode */ 1429 case 'P': 1430 *pMixerId = PLAY_MIXER; 1431 break; 1432 1433 case 'r': /* Record mode */ 1434 case 'R': 1435 *pMixerId = RECORD_MIXER; 1436 break; 1437 1438 default: 1439 return FALSE; 1440 } 1441 } 1442 1443 return TRUE; 1444 } 1445 1446 int WINAPI 1447 _tWinMain(HINSTANCE hInstance, 1448 HINSTANCE hPrevInstance, 1449 LPTSTR lpszCmdLine, 1450 int nCmdShow) 1451 { 1452 MSG Msg; 1453 int Ret = 1; 1454 INITCOMMONCONTROLSEX Controls; 1455 WINDOW_MODE WindowMode = SMALL_MODE; 1456 UINT MixerId = 0; 1457 DWORD dwStyle; 1458 1459 UNREFERENCED_PARAMETER(hPrevInstance); 1460 UNREFERENCED_PARAMETER(nCmdShow); 1461 1462 hAppInstance = hInstance; 1463 hAppHeap = GetProcessHeap(); 1464 1465 if (InitAppConfig()) 1466 { 1467 dwStyle = GetStyleValue(); 1468 HandleCommandLine(lpszCmdLine, dwStyle, &WindowMode, &MixerId); 1469 1470 /* load the application title */ 1471 if (!AllocAndLoadString(&lpAppTitle, 1472 hAppInstance, 1473 IDS_SNDVOL32)) 1474 { 1475 lpAppTitle = NULL; 1476 } 1477 1478 Controls.dwSize = sizeof(INITCOMMONCONTROLSEX); 1479 Controls.dwICC = ICC_BAR_CLASSES | ICC_STANDARD_CLASSES; 1480 1481 InitCommonControlsEx(&Controls); 1482 1483 if (WindowMode == TRAY_MODE) 1484 { 1485 DialogBoxParam(hAppInstance, 1486 MAKEINTRESOURCE(IDD_TRAY_MASTER), 1487 NULL, 1488 TrayDlgProc, 1489 0); 1490 } 1491 else 1492 { 1493 if (RegisterApplicationClasses()) 1494 { 1495 hMainWnd = CreateApplicationWindow(WindowMode, MixerId); 1496 if (hMainWnd != NULL) 1497 { 1498 BOOL bRet; 1499 while ((bRet =GetMessage(&Msg, 1500 NULL, 1501 0, 1502 0)) != 0) 1503 { 1504 if (bRet != -1) 1505 { 1506 TranslateMessage(&Msg); 1507 DispatchMessage(&Msg); 1508 } 1509 } 1510 1511 DestroyWindow(hMainWnd); 1512 Ret = 0; 1513 } 1514 else 1515 { 1516 DPRINT("Failed to create application window (LastError: %d)!\n", GetLastError()); 1517 } 1518 1519 UnregisterApplicationClasses(); 1520 } 1521 else 1522 { 1523 DPRINT("Failed to register application classes (LastError: %d)!\n", GetLastError()); 1524 } 1525 } 1526 1527 if (lpAppTitle != NULL) 1528 { 1529 LocalFree(lpAppTitle); 1530 } 1531 1532 CloseAppConfig(); 1533 } 1534 else 1535 { 1536 DPRINT("Unable to open the Volume Control registry key!\n"); 1537 } 1538 1539 return Ret; 1540 } 1541