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