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 UnregisterHotKey(hwnd, HOTKEY_CTRL_S); 975 break; 976 } 977 978 case IDM_ABOUT: 979 { 980 HICON hAppIcon = (HICON)GetClassLongPtrW(hwnd, 981 GCLP_HICON); 982 ShellAbout(hwnd, 983 lpAppTitle, 984 NULL, 985 hAppIcon); 986 break; 987 } 988 989 default: 990 { 991 /* get button id */ 992 CtrlID = LOWORD(wParam); 993 994 /* check if the message is from the line switch */ 995 if (HIWORD(wParam) == BN_CLICKED) 996 { 997 if (CtrlID % IDC_LINE_SWITCH == 0) 998 { 999 /* compute line offset */ 1000 LineOffset = CtrlID / IDC_LINE_SWITCH; 1001 1002 /* compute window id of line name static control */ 1003 CtrlID = LineOffset * IDC_LINE_NAME; 1004 1005 if (Preferences.MixerWindow->Mixer->MixerId == PLAY_MIXER) 1006 { 1007 /* get line name */ 1008 if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0) 1009 { 1010 /* setup context */ 1011 Context.SliderPos = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0); 1012 Context.bVertical = FALSE; 1013 Context.bSwitch = TRUE; 1014 1015 /* set volume */ 1016 SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context); 1017 } 1018 } 1019 else if (Preferences.MixerWindow->Mixer->MixerId == RECORD_MIXER) 1020 { 1021 UINT i; 1022 1023 for (i = 0; i < Preferences.MixerWindow->DialogCount; i++) 1024 { 1025 SendDlgItemMessageW(hwnd, (i + 1) * IDC_LINE_SWITCH, BM_SETCHECK, (WPARAM)((i + 1) == LineOffset), 0); 1026 } 1027 } 1028 } 1029 else if (CtrlID % IDC_LINE_ADVANCED == 0) 1030 { 1031 ADVANCED_CONTEXT AdvancedContext; 1032 1033 /* compute line offset */ 1034 LineOffset = CtrlID / IDC_LINE_ADVANCED; 1035 1036 /* compute window id of line name static control */ 1037 CtrlID = LineOffset * IDC_LINE_NAME; 1038 1039 /* get line name */ 1040 if (GetDlgItemTextW(hwnd, CtrlID, AdvancedContext.LineName, MIXER_LONG_NAME_CHARS) != 0) 1041 { 1042 AdvancedContext.MixerWindow = Preferences.MixerWindow; 1043 AdvancedContext.Mixer = Preferences.MixerWindow->Mixer; 1044 AdvancedContext.Line = SndMixerGetLineByName(Preferences.MixerWindow->Mixer, 1045 Preferences.SelectedLine, 1046 AdvancedContext.LineName); 1047 if (AdvancedContext.Line) 1048 { 1049 DialogBoxParam(hAppInstance, 1050 MAKEINTRESOURCE(IDD_ADVANCED), 1051 hwnd, 1052 AdvancedDlgProc, 1053 (LPARAM)&AdvancedContext); 1054 } 1055 } 1056 } 1057 } 1058 } 1059 } 1060 break; 1061 } 1062 1063 case MM_MIXM_LINE_CHANGE: 1064 { 1065 DPRINT("MM_MIXM_LINE_CHANGE\n"); 1066 break; 1067 } 1068 1069 case MM_MIXM_CONTROL_CHANGE: 1070 { 1071 DPRINT("MM_MIXM_CONTROL_CHANGE\n"); 1072 1073 /* get mixer window */ 1074 MixerWindow = GetWindowData(hwnd, 1075 MIXER_WINDOW); 1076 1077 /* sanity checks */ 1078 assert(MixerWindow); 1079 assert(MixerWindow->Mixer->hmx == (HMIXER)wParam); 1080 1081 SndMixerEnumConnections(MixerWindow->Mixer, Preferences.SelectedLine, MixerControlChangeCallback, (PVOID)lParam); 1082 break; 1083 } 1084 1085 case WM_VSCROLL: 1086 switch (LOWORD(wParam)) 1087 { 1088 case TB_THUMBTRACK: 1089 /* get dialog item ctrl */ 1090 CtrlID = GetDlgCtrlID((HWND)lParam); 1091 1092 /* get line index */ 1093 LineOffset = CtrlID / IDC_LINE_SLIDER_VERT; 1094 1095 /* compute window id of line name static control */ 1096 CtrlID = LineOffset * IDC_LINE_NAME; 1097 1098 /* get line name */ 1099 if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0) 1100 { 1101 /* setup context */ 1102 Context.SliderPos = LineOffset; 1103 Context.bVertical = TRUE; 1104 Context.bSwitch = FALSE; 1105 1106 /* set volume */ 1107 SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context); 1108 } 1109 break; 1110 1111 case TB_ENDTRACK: 1112 MixerWindow = GetWindowData(hwnd, 1113 MIXER_WINDOW); 1114 1115 /* get dialog item ctrl */ 1116 CtrlID = GetDlgCtrlID((HWND)lParam); 1117 1118 /* get line index */ 1119 LineOffset = CtrlID / IDC_LINE_SLIDER_VERT; 1120 1121 if (LineOffset == 1 && MixerWindow->Mixer->MixerId == 0) 1122 PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID); 1123 break; 1124 1125 default: 1126 break; 1127 } 1128 break; 1129 1130 case WM_HSCROLL: 1131 switch (LOWORD(wParam)) 1132 { 1133 case TB_THUMBTRACK: 1134 /* get dialog item ctrl */ 1135 CtrlID = GetDlgCtrlID((HWND)lParam); 1136 1137 /* get line index */ 1138 LineOffset = CtrlID / IDC_LINE_SLIDER_HORZ; 1139 1140 /* compute window id of line name static control */ 1141 CtrlID = LineOffset * IDC_LINE_NAME; 1142 1143 /* get line name */ 1144 if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0) 1145 { 1146 /* setup context */ 1147 Context.SliderPos = LineOffset; 1148 Context.bVertical = TRUE; 1149 Context.bSwitch = FALSE; 1150 1151 /* set volume */ 1152 SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context); 1153 } 1154 break; 1155 1156 case TB_ENDTRACK: 1157 MixerWindow = GetWindowData(hwnd, 1158 MIXER_WINDOW); 1159 1160 /* get dialog item ctrl */ 1161 CtrlID = GetDlgCtrlID((HWND)lParam); 1162 1163 /* get line index */ 1164 LineOffset = CtrlID / IDC_LINE_SLIDER_HORZ; 1165 1166 if (LineOffset == 1 && MixerWindow->Mixer->MixerId == 0) 1167 PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID); 1168 break; 1169 1170 default: 1171 break; 1172 } 1173 break; 1174 1175 1176 case WM_CREATE: 1177 { 1178 MixerWindow = ((LPCREATESTRUCT)lParam)->lpCreateParams; 1179 SetWindowLongPtr(hwnd, 1180 GWL_USERDATA, 1181 (LONG_PTR)MixerWindow); 1182 MixerWindow->hWnd = hwnd; 1183 MixerWindow->Mixer = SndMixerCreate(MixerWindow->hWnd, MixerWindow->MixerId); 1184 if (MixerWindow->Mixer != NULL) 1185 { 1186 TCHAR szProduct[MAXPNAMELEN]; 1187 1188 /* get mixer product name */ 1189 if (SndMixerGetProductName(MixerWindow->Mixer, 1190 szProduct, 1191 sizeof(szProduct) / sizeof(szProduct[0])) == -1) 1192 { 1193 /* failed to get name */ 1194 szProduct[0] = L'\0'; 1195 } 1196 1197 1198 /* initialize preferences */ 1199 ZeroMemory(&Preferences, sizeof(Preferences)); 1200 1201 /* store mixer */ 1202 Preferences.Mixer = MixerWindow->Mixer; 1203 1204 /* store mixer window */ 1205 Preferences.MixerWindow = MixerWindow; 1206 1207 /* first destination line id */ 1208 Preferences.SelectedLine = 0xFFFF0000; 1209 1210 /* copy product */ 1211 wcscpy(Preferences.DeviceName, szProduct); 1212 1213 /* Disable the 'Advanced Controls' menu item */ 1214 EnableMenuItem(GetMenu(hwnd), IDM_ADVANCED_CONTROLS, MF_BYCOMMAND | MF_GRAYED); 1215 1216 /* Load the placement coordinate data of the window */ 1217 bRet = LoadXYCoordWnd(&Preferences); 1218 if (bRet) 1219 { 1220 /* 1221 * LoadXYCoordWnd() might fail for the first time of opening the application which is normal as 1222 * the Sound Control's applet settings haven't been saved yet to the Registry. At this point SetWindowPos() 1223 * call is skipped. 1224 */ 1225 SetWindowPos(hwnd, NULL, MixerWindow->WndPosX, MixerWindow->WndPosY, 0, 0, SWP_NOSIZE | SWP_NOZORDER); 1226 } 1227 1228 /* create status window */ 1229 if (MixerWindow->Mode == NORMAL_MODE) 1230 { 1231 MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS, 1232 NULL, 1233 hwnd, 1234 0); 1235 if (MixerWindow->hStatusBar) 1236 { 1237 SendMessage(MixerWindow->hStatusBar, 1238 WM_SETTEXT, 1239 0, 1240 (LPARAM)szProduct); 1241 } 1242 } 1243 1244 if (!RebuildMixerWindowControls(&Preferences)) 1245 { 1246 DPRINT("Rebuilding mixer window controls failed!\n"); 1247 SndMixerDestroy(MixerWindow->Mixer); 1248 MixerWindow->Mixer = NULL; 1249 Result = -1; 1250 } 1251 } 1252 1253 RegisterHotKey(hwnd, HOTKEY_CTRL_S, MOD_CONTROL, 'S'); 1254 break; 1255 } 1256 1257 case WM_DESTROY: 1258 { 1259 MixerWindow = GetWindowData(hwnd, 1260 MIXER_WINDOW); 1261 if (MixerWindow != NULL) 1262 { 1263 if (MixerWindow->Mixer != NULL) 1264 { 1265 SndMixerDestroy(MixerWindow->Mixer); 1266 } 1267 if (MixerWindow->hFont) 1268 DeleteObject(MixerWindow->hFont); 1269 HeapFree(hAppHeap, 0, MixerWindow); 1270 } 1271 break; 1272 } 1273 1274 case WM_CLOSE: 1275 { 1276 SaveXYCoordWnd(hwnd, &Preferences); 1277 PostQuitMessage(0); 1278 break; 1279 } 1280 1281 case WM_HOTKEY: 1282 { 1283 if (wParam == HOTKEY_CTRL_S) 1284 { 1285 Preferences.MixerWindow->Mode = (Preferences.MixerWindow->Mode == NORMAL_MODE ? SMALL_MODE : NORMAL_MODE); 1286 RebuildMixerWindowControls(&Preferences); 1287 } 1288 break; 1289 } 1290 1291 default: 1292 { 1293 Result = DefWindowProc(hwnd, 1294 uMsg, 1295 wParam, 1296 lParam); 1297 break; 1298 } 1299 } 1300 1301 return Result; 1302 } 1303 1304 static BOOL 1305 RegisterApplicationClasses(VOID) 1306 { 1307 WNDCLASSEX wc; 1308 1309 wc.cbSize = sizeof(WNDCLASSEX); 1310 wc.style = CS_HREDRAW | CS_VREDRAW; 1311 wc.lpfnWndProc = MainWindowProc; 1312 wc.cbClsExtra = 0; 1313 wc.cbWndExtra = sizeof(PMIXER_WINDOW); 1314 wc.hInstance = hAppInstance; 1315 wc.hIcon = LoadIcon(hAppInstance, 1316 MAKEINTRESOURCE(IDI_MAINAPP)); 1317 wc.hCursor = LoadCursor(NULL, 1318 IDC_ARROW); 1319 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 1320 wc.lpszMenuName = NULL; 1321 wc.lpszClassName = SZ_APP_CLASS; 1322 wc.hIconSm = NULL; 1323 MainWindowClass = RegisterClassEx(&wc); 1324 1325 return MainWindowClass != 0; 1326 } 1327 1328 static VOID 1329 UnregisterApplicationClasses(VOID) 1330 { 1331 UnregisterClass(SZ_APP_CLASS, 1332 hAppInstance); 1333 } 1334 1335 static HWND 1336 CreateApplicationWindow( 1337 WINDOW_MODE WindowMode, 1338 UINT MixerId) 1339 { 1340 HWND hWnd; 1341 1342 PMIXER_WINDOW MixerWindow = HeapAlloc(hAppHeap, 1343 HEAP_ZERO_MEMORY, 1344 sizeof(MIXER_WINDOW)); 1345 if (MixerWindow == NULL) 1346 { 1347 return NULL; 1348 } 1349 1350 MixerWindow->Mode = WindowMode; 1351 MixerWindow->MixerId = MixerId; 1352 1353 if (mixerGetNumDevs() > 0) 1354 { 1355 hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT, 1356 SZ_APP_CLASS, 1357 lpAppTitle, 1358 WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, 1359 0, 0, 300, 315, 1360 NULL, 1361 LoadMenu(hAppInstance, 1362 MAKEINTRESOURCE(IDM_MAINMENU)), 1363 hAppInstance, 1364 MixerWindow); 1365 } 1366 else 1367 { 1368 LPTSTR lpErrMessage; 1369 1370 /* 1371 * no mixer devices are available! 1372 */ 1373 1374 hWnd = NULL; 1375 if (AllocAndLoadString(&lpErrMessage, 1376 hAppInstance, 1377 IDS_NOMIXERDEVICES)) 1378 { 1379 MessageBox(NULL, 1380 lpErrMessage, 1381 lpAppTitle, 1382 MB_ICONINFORMATION); 1383 LocalFree(lpErrMessage); 1384 } 1385 } 1386 1387 if (hWnd == NULL) 1388 { 1389 HeapFree(hAppHeap, 1390 0, 1391 MixerWindow); 1392 } 1393 1394 return hWnd; 1395 } 1396 1397 static 1398 BOOL 1399 HandleCommandLine(LPTSTR cmdline, 1400 DWORD dwStyle, 1401 PWINDOW_MODE pMode, 1402 PUINT pMixerId) 1403 { 1404 TCHAR option; 1405 1406 *pMixerId = PLAY_MIXER; 1407 *pMode = (dwStyle & 0x20) ? SMALL_MODE : NORMAL_MODE; 1408 1409 while (*cmdline == _T(' ') || *cmdline == _T('-') || *cmdline == _T('/')) 1410 { 1411 if (*cmdline++ == _T(' ')) 1412 continue; 1413 1414 option = *cmdline; 1415 if (option) 1416 cmdline++; 1417 while (*cmdline == _T(' ')) 1418 cmdline++; 1419 1420 switch (option) 1421 { 1422 case 'd': /* Device */ 1423 case 'D': 1424 break; 1425 1426 case 'n': /* Small size */ 1427 case 'N': 1428 *pMode = NORMAL_MODE; 1429 break; 1430 1431 case 's': /* Small size */ 1432 case 'S': 1433 *pMode = SMALL_MODE; 1434 break; 1435 1436 case 't': /* Tray size */ 1437 case 'T': 1438 *pMode = TRAY_MODE; 1439 break; 1440 1441 case 'p': /* Play mode */ 1442 case 'P': 1443 *pMixerId = PLAY_MIXER; 1444 break; 1445 1446 case 'r': /* Record mode */ 1447 case 'R': 1448 *pMixerId = RECORD_MIXER; 1449 break; 1450 1451 default: 1452 return FALSE; 1453 } 1454 } 1455 1456 return TRUE; 1457 } 1458 1459 int WINAPI 1460 _tWinMain(HINSTANCE hInstance, 1461 HINSTANCE hPrevInstance, 1462 LPTSTR lpszCmdLine, 1463 int nCmdShow) 1464 { 1465 MSG Msg; 1466 int Ret = 1; 1467 INITCOMMONCONTROLSEX Controls; 1468 WINDOW_MODE WindowMode = SMALL_MODE; 1469 UINT MixerId = 0; 1470 DWORD dwStyle; 1471 1472 UNREFERENCED_PARAMETER(hPrevInstance); 1473 UNREFERENCED_PARAMETER(nCmdShow); 1474 1475 hAppInstance = hInstance; 1476 hAppHeap = GetProcessHeap(); 1477 1478 if (InitAppConfig()) 1479 { 1480 dwStyle = GetStyleValue(); 1481 HandleCommandLine(lpszCmdLine, dwStyle, &WindowMode, &MixerId); 1482 1483 /* load the application title */ 1484 if (!AllocAndLoadString(&lpAppTitle, 1485 hAppInstance, 1486 IDS_SNDVOL32)) 1487 { 1488 lpAppTitle = NULL; 1489 } 1490 1491 Controls.dwSize = sizeof(INITCOMMONCONTROLSEX); 1492 Controls.dwICC = ICC_BAR_CLASSES | ICC_STANDARD_CLASSES; 1493 1494 InitCommonControlsEx(&Controls); 1495 1496 if (WindowMode == TRAY_MODE) 1497 { 1498 DialogBoxParam(hAppInstance, 1499 MAKEINTRESOURCE(IDD_TRAY_MASTER), 1500 NULL, 1501 TrayDlgProc, 1502 0); 1503 } 1504 else 1505 { 1506 if (RegisterApplicationClasses()) 1507 { 1508 hMainWnd = CreateApplicationWindow(WindowMode, MixerId); 1509 if (hMainWnd != NULL) 1510 { 1511 BOOL bRet; 1512 while ((bRet =GetMessage(&Msg, 1513 NULL, 1514 0, 1515 0)) != 0) 1516 { 1517 if (bRet != -1) 1518 { 1519 TranslateMessage(&Msg); 1520 DispatchMessage(&Msg); 1521 } 1522 } 1523 1524 DestroyWindow(hMainWnd); 1525 Ret = 0; 1526 } 1527 else 1528 { 1529 DPRINT("Failed to create application window (LastError: %d)!\n", GetLastError()); 1530 } 1531 1532 UnregisterApplicationClasses(); 1533 } 1534 else 1535 { 1536 DPRINT("Failed to register application classes (LastError: %d)!\n", GetLastError()); 1537 } 1538 } 1539 1540 if (lpAppTitle != NULL) 1541 { 1542 LocalFree(lpAppTitle); 1543 } 1544 1545 CloseAppConfig(); 1546 } 1547 else 1548 { 1549 DPRINT("Unable to open the Volume Control registry key!\n"); 1550 } 1551 1552 return Ret; 1553 } 1554