mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
9393fc320e
Excluded: 3rd-party code (incl. wine) and most of the win32ss.
1540 lines
52 KiB
C
1540 lines
52 KiB
C
/*
|
|
* ReactOS Sound Volume Control
|
|
* Copyright (C) 2004-2005 Thomas Weidenmueller
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Sound Volume Control
|
|
* FILE: base/applications/sndvol32/sndvol32.c
|
|
* PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com>
|
|
*/
|
|
|
|
#include "sndvol32.h"
|
|
|
|
#include <shellapi.h>
|
|
|
|
HINSTANCE hAppInstance;
|
|
ATOM MainWindowClass;
|
|
HWND hMainWnd;
|
|
HANDLE hAppHeap;
|
|
LPTSTR lpAppTitle;
|
|
PREFERENCES_CONTEXT Preferences;
|
|
|
|
#define GetDialogData(hwndDlg, type) \
|
|
( P##type )GetWindowLongPtr((hwndDlg), DWLP_USER)
|
|
#define GetWindowData(hwnd, type) \
|
|
( P##type )GetWindowLongPtr((hwnd), GWL_USERDATA)
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
typedef struct _PREFERENCES_FILL_DEVICES
|
|
{
|
|
PPREFERENCES_CONTEXT PrefContext;
|
|
HWND hComboBox;
|
|
UINT Selected;
|
|
} PREFERENCES_FILL_DEVICES, *PPREFERENCES_FILL_DEVICES;
|
|
|
|
static BOOL CALLBACK
|
|
FillDeviceComboBox(PSND_MIXER Mixer,
|
|
UINT Id,
|
|
LPCTSTR ProductName,
|
|
PVOID Context)
|
|
{
|
|
LRESULT lres;
|
|
PPREFERENCES_FILL_DEVICES FillContext = (PPREFERENCES_FILL_DEVICES)Context;
|
|
|
|
UNREFERENCED_PARAMETER(Mixer);
|
|
|
|
lres = SendMessage(FillContext->hComboBox,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(LPARAM)ProductName);
|
|
if (lres != CB_ERR)
|
|
{
|
|
/* save the index so we don't screw stuff when the combobox is sorted... */
|
|
SendMessage(FillContext->hComboBox,
|
|
CB_SETITEMDATA,
|
|
(WPARAM)lres,
|
|
Id);
|
|
|
|
if (Id == FillContext->Selected)
|
|
{
|
|
SendMessage(FillContext->hComboBox,
|
|
CB_SETCURSEL,
|
|
(WPARAM)lres,
|
|
0);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL CALLBACK
|
|
PrefDlgAddLine(PSND_MIXER Mixer,
|
|
LPMIXERLINE Line,
|
|
UINT DisplayControls,
|
|
PVOID Context)
|
|
{
|
|
PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
|
|
|
|
UNREFERENCED_PARAMETER(Mixer);
|
|
UNREFERENCED_PARAMETER(DisplayControls);
|
|
|
|
switch (Line->dwComponentType)
|
|
{
|
|
case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
|
|
if (PrefContext->PlaybackID == (DWORD)-1)
|
|
{
|
|
PrefContext->PlaybackID = Line->dwLineID;
|
|
|
|
if (PrefContext->SelectedLine == (DWORD)-1)
|
|
{
|
|
PrefContext->SelectedLine = Line->dwLineID;
|
|
}
|
|
}
|
|
else
|
|
goto AddToOthersLines;
|
|
|
|
break;
|
|
|
|
case MIXERLINE_COMPONENTTYPE_DST_WAVEIN:
|
|
if (PrefContext->RecordingID == (DWORD)-1)
|
|
{
|
|
PrefContext->RecordingID = Line->dwLineID;
|
|
|
|
if (PrefContext->SelectedLine == (DWORD)-1)
|
|
{
|
|
PrefContext->SelectedLine = Line->dwLineID;
|
|
}
|
|
}
|
|
else
|
|
goto AddToOthersLines;
|
|
|
|
break;
|
|
|
|
default:
|
|
{
|
|
LRESULT lres;
|
|
HWND hwndCbOthers;
|
|
|
|
if (PrefContext->SelectedLine == (DWORD)-1)
|
|
{
|
|
PrefContext->SelectedLine = Line->dwLineID;
|
|
}
|
|
|
|
AddToOthersLines:
|
|
hwndCbOthers = GetDlgItem(PrefContext->hwndDlg,
|
|
IDC_LINE);
|
|
|
|
lres = SendMessage(hwndCbOthers,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(LPARAM)Line->szName);
|
|
if (lres != CB_ERR)
|
|
{
|
|
SendMessage(hwndCbOthers,
|
|
CB_SETITEMDATA,
|
|
(WPARAM)lres,
|
|
Line->dwLineID);
|
|
|
|
PrefContext->OtherLines++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL CALLBACK
|
|
PrefDlgAddConnection(PSND_MIXER Mixer,
|
|
DWORD LineID,
|
|
LPMIXERLINE Line,
|
|
PVOID Context)
|
|
{
|
|
PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
|
|
HWND hwndControls;
|
|
LVITEM lvi;
|
|
UINT i;
|
|
|
|
UNREFERENCED_PARAMETER(Mixer);
|
|
UNREFERENCED_PARAMETER(LineID);
|
|
|
|
if (Line->cControls != 0)
|
|
{
|
|
hwndControls = GetDlgItem(PrefContext->hwndDlg,
|
|
IDC_CONTROLS);
|
|
|
|
lvi.mask = LVIF_TEXT | LVIF_PARAM;
|
|
lvi.iItem = PrefContext->tmp++;
|
|
lvi.iSubItem = 0;
|
|
lvi.pszText = Line->szName;
|
|
lvi.lParam = (LPARAM)Line->dwSource;
|
|
|
|
i = SendMessage(hwndControls,
|
|
LVM_INSERTITEM,
|
|
0,
|
|
(LPARAM)&lvi);
|
|
if (i != (UINT)-1)
|
|
{
|
|
TCHAR LineName[MIXER_LONG_NAME_CHARS];
|
|
DWORD Flags;
|
|
BOOL SelLine = FALSE;
|
|
|
|
if (SndMixerGetLineName(PrefContext->Mixer,
|
|
PrefContext->SelectedLine,
|
|
LineName,
|
|
MIXER_LONG_NAME_CHARS,
|
|
TRUE) == -1)
|
|
{
|
|
LineName[0] = TEXT('\0');
|
|
}
|
|
|
|
if (ReadLineConfig(PrefContext->DeviceName,
|
|
LineName,
|
|
Line->szName,
|
|
&Flags))
|
|
{
|
|
if (Flags != 0x4)
|
|
{
|
|
SelLine = TRUE;
|
|
}
|
|
}
|
|
|
|
ListView_SetCheckState(hwndControls,
|
|
i,
|
|
SelLine);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static VOID
|
|
UpdatePrefDlgControls(PPREFERENCES_CONTEXT Context,
|
|
DWORD LineID)
|
|
{
|
|
INT OldID, MixerID = 0;
|
|
INT DeviceCbIndex;
|
|
|
|
/* select the mixer */
|
|
DeviceCbIndex = SendDlgItemMessage(Context->hwndDlg,
|
|
IDC_MIXERDEVICE,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0);
|
|
if (DeviceCbIndex != CB_ERR)
|
|
{
|
|
MixerID = SendDlgItemMessage(Context->hwndDlg,
|
|
IDC_MIXERDEVICE,
|
|
CB_GETITEMDATA,
|
|
DeviceCbIndex,
|
|
0);
|
|
if (MixerID == CB_ERR)
|
|
{
|
|
MixerID = 0;
|
|
}
|
|
}
|
|
|
|
OldID = Context->Selected;
|
|
if (MixerID != OldID &&
|
|
SndMixerSelect(Context->Mixer,
|
|
MixerID))
|
|
{
|
|
Context->Selected = SndMixerGetSelection(Context->Mixer);
|
|
|
|
/* update the controls */
|
|
Context->PlaybackID = (DWORD)-1;
|
|
Context->RecordingID = (DWORD)-1;
|
|
Context->OtherLines = 0;
|
|
Context->SelectedLine = (DWORD)-1;
|
|
|
|
SndMixerGetProductName(Context->Mixer,
|
|
Context->DeviceName,
|
|
sizeof(Context->DeviceName) / sizeof(Context->DeviceName[0]));
|
|
|
|
if (SndMixerEnumLines(Context->Mixer,
|
|
PrefDlgAddLine,
|
|
Context))
|
|
{
|
|
UINT SelBox = 0;
|
|
|
|
/* enable/disable controls and make default selection */
|
|
EnableWindow(GetDlgItem(Context->hwndDlg,
|
|
IDC_PLAYBACK),
|
|
Context->PlaybackID != (DWORD)-1);
|
|
CheckDlgButton(Context->hwndDlg,
|
|
IDC_PLAYBACK,
|
|
(Context->PlaybackID != (DWORD)-1 && SelBox++ == 0) ?
|
|
BST_CHECKED : BST_UNCHECKED);
|
|
|
|
EnableWindow(GetDlgItem(Context->hwndDlg,
|
|
IDC_RECORDING),
|
|
Context->RecordingID != (DWORD)-1);
|
|
CheckDlgButton(Context->hwndDlg,
|
|
IDC_RECORDING,
|
|
(Context->RecordingID != (DWORD)-1 && SelBox++ == 0) ?
|
|
BST_CHECKED : BST_UNCHECKED);
|
|
|
|
if (Context->OtherLines != 0)
|
|
{
|
|
/* select the first item in the other lines combo box by default */
|
|
SendDlgItemMessage(Context->hwndDlg,
|
|
IDC_LINE,
|
|
CB_SETCURSEL,
|
|
0,
|
|
0);
|
|
}
|
|
EnableWindow(GetDlgItem(Context->hwndDlg,
|
|
IDC_LINE),
|
|
FALSE);
|
|
EnableWindow(GetDlgItem(Context->hwndDlg,
|
|
IDC_OTHER),
|
|
Context->OtherLines != 0);
|
|
CheckDlgButton(Context->hwndDlg,
|
|
IDC_LINE,
|
|
(Context->OtherLines != 0 && SelBox++ == 0) ?
|
|
BST_CHECKED : BST_UNCHECKED);
|
|
|
|
/* disable the OK button if the device doesn't have any lines */
|
|
EnableWindow(GetDlgItem(Context->hwndDlg,
|
|
IDOK),
|
|
Context->PlaybackID != (DWORD)-1 ||
|
|
Context->RecordingID != (DWORD)-1 ||
|
|
Context->OtherLines != 0);
|
|
|
|
LineID = Context->SelectedLine;
|
|
}
|
|
}
|
|
|
|
/* update the line sources list */
|
|
if ((MixerID != OldID && Context->SelectedLine != (DWORD)-1) ||
|
|
(Context->SelectedLine != LineID && LineID != (DWORD)-1))
|
|
{
|
|
Context->SelectedLine = LineID;
|
|
|
|
(void)ListView_DeleteAllItems(GetDlgItem(Context->hwndDlg,
|
|
IDC_CONTROLS));
|
|
|
|
Context->tmp = 0;
|
|
SndMixerEnumConnections(Context->Mixer,
|
|
LineID,
|
|
PrefDlgAddConnection,
|
|
Context);
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID
|
|
WriteLineSettings(PPREFERENCES_CONTEXT Context, HWND hwndDlg)
|
|
{
|
|
HWND hwndControls;
|
|
INT Count, Index;
|
|
WCHAR LineName[MIXER_LONG_NAME_CHARS];
|
|
WCHAR DestinationName[MIXER_LONG_NAME_CHARS];
|
|
DWORD Flags;
|
|
PSNDVOL_REG_LINESTATE LineStates;
|
|
|
|
/* get list view */
|
|
hwndControls = GetDlgItem(hwndDlg, IDC_CONTROLS);
|
|
|
|
/* get list item count */
|
|
Count = ListView_GetItemCount(hwndControls);
|
|
|
|
/* sanity check */
|
|
assert(Count);
|
|
|
|
if (SndMixerGetLineName(Context->Mixer, Context->SelectedLine, DestinationName, MIXER_LONG_NAME_CHARS, TRUE) == -1)
|
|
{
|
|
/* failed to get destination line name */
|
|
return;
|
|
}
|
|
|
|
/* allocate line states array */
|
|
LineStates = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SNDVOL_REG_LINESTATE) * Count);
|
|
if (LineStates == NULL)
|
|
{
|
|
/* failed to allocate line states array */
|
|
return;
|
|
}
|
|
|
|
|
|
for(Index = 0; Index < Count; Index++)
|
|
{
|
|
/* set to empty */
|
|
LineName[0] = L'\0';
|
|
|
|
/* get item text */
|
|
ListView_GetItemText(hwndControls, Index, 0, LineName, MIXER_LONG_NAME_CHARS);
|
|
|
|
/* make sure it is null terminated */
|
|
LineName[MIXER_LONG_NAME_CHARS-1] = L'\0';
|
|
|
|
/* get check state */
|
|
Flags = (ListView_GetCheckState(hwndControls, Index) == 0 ? 0x4 : 0);
|
|
|
|
/* copy line name */
|
|
wcscpy(LineStates[Index].LineName, LineName);
|
|
|
|
/* store flags */
|
|
LineStates[Index].Flags = Flags;
|
|
}
|
|
|
|
/* now write the line config */
|
|
WriteLineConfig(Context->DeviceName, DestinationName, LineStates, sizeof(SNDVOL_REG_LINESTATE) * Count);
|
|
|
|
/* free line states */
|
|
HeapFree(GetProcessHeap(), 0, LineStates);
|
|
}
|
|
|
|
static INT_PTR CALLBACK
|
|
DlgPreferencesProc(HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PPREFERENCES_CONTEXT Context;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_COMMAND:
|
|
{
|
|
Context = GetDialogData(hwndDlg,
|
|
PREFERENCES_CONTEXT);
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_MIXERDEVICE:
|
|
{
|
|
if (HIWORD(wParam) == CBN_SELCHANGE)
|
|
{
|
|
UpdatePrefDlgControls(Context,
|
|
(DWORD)-1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_LINE:
|
|
{
|
|
if (HIWORD(wParam) == CBN_SELCHANGE)
|
|
{
|
|
INT LineID;
|
|
INT Index;
|
|
|
|
Index = SendDlgItemMessage(hwndDlg,
|
|
IDC_LINE,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0);
|
|
if (Index != CB_ERR)
|
|
{
|
|
LineID = SendDlgItemMessage(hwndDlg,
|
|
IDC_LINE,
|
|
CB_GETITEMDATA,
|
|
Index,
|
|
0);
|
|
if (LineID != CB_ERR)
|
|
{
|
|
UpdatePrefDlgControls(Context,
|
|
LineID);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_PLAYBACK:
|
|
{
|
|
UpdatePrefDlgControls(Context,
|
|
Context->PlaybackID);
|
|
EnableWindow(GetDlgItem(hwndDlg,
|
|
IDC_LINE),
|
|
FALSE);
|
|
break;
|
|
}
|
|
|
|
case IDC_RECORDING:
|
|
{
|
|
UpdatePrefDlgControls(Context,
|
|
Context->RecordingID);
|
|
EnableWindow(GetDlgItem(hwndDlg,
|
|
IDC_LINE),
|
|
FALSE);
|
|
break;
|
|
}
|
|
|
|
case IDC_OTHER:
|
|
{
|
|
INT LineCbIndex;
|
|
INT LineID;
|
|
|
|
EnableWindow(GetDlgItem(hwndDlg,
|
|
IDC_LINE),
|
|
TRUE);
|
|
|
|
LineCbIndex = SendDlgItemMessage(hwndDlg,
|
|
IDC_LINE,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0);
|
|
if (LineCbIndex != CB_ERR)
|
|
{
|
|
LineID = SendDlgItemMessage(hwndDlg,
|
|
IDC_LINE,
|
|
CB_GETITEMDATA,
|
|
LineCbIndex,
|
|
0);
|
|
if (LineID != CB_ERR)
|
|
{
|
|
UpdatePrefDlgControls(Context,
|
|
LineID);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDOK:
|
|
{
|
|
/* write line settings */
|
|
WriteLineSettings(Context, hwndDlg);
|
|
|
|
/* fall through */
|
|
}
|
|
case IDCANCEL:
|
|
{
|
|
EndDialog(hwndDlg,
|
|
LOWORD(wParam));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
PREFERENCES_FILL_DEVICES FillDevContext;
|
|
LVCOLUMN lvc;
|
|
RECT rcClient;
|
|
HWND hwndControls;
|
|
|
|
SetWindowLongPtr(hwndDlg,
|
|
DWLP_USER,
|
|
(LONG_PTR)lParam);
|
|
Context = (PPREFERENCES_CONTEXT)((LONG_PTR)lParam);
|
|
Context->hwndDlg = hwndDlg;
|
|
Context->Mixer = SndMixerCreate(hwndDlg, Context->MixerWindow->MixerId);
|
|
Context->Selected = (UINT)-1;
|
|
|
|
FillDevContext.PrefContext = Context;
|
|
FillDevContext.hComboBox = GetDlgItem(hwndDlg,
|
|
IDC_MIXERDEVICE);
|
|
FillDevContext.Selected = SndMixerGetSelection(Context->Mixer);
|
|
SndMixerEnumProducts(Context->Mixer,
|
|
FillDeviceComboBox,
|
|
&FillDevContext);
|
|
|
|
/* initialize the list view control */
|
|
hwndControls = GetDlgItem(hwndDlg,
|
|
IDC_CONTROLS);
|
|
(void)ListView_SetExtendedListViewStyle(hwndControls,
|
|
LVS_EX_CHECKBOXES);
|
|
|
|
GetClientRect(hwndControls,
|
|
&rcClient);
|
|
lvc.mask = LVCF_TEXT | LVCF_WIDTH;
|
|
lvc.pszText = TEXT("");
|
|
lvc.cx = rcClient.right;
|
|
SendMessage(hwndControls,
|
|
LVM_INSERTCOLUMN,
|
|
0,
|
|
(LPARAM)&lvc);
|
|
|
|
/* update all controls */
|
|
UpdatePrefDlgControls(Context,
|
|
(DWORD)Context->SelectedLine);
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_CLOSE:
|
|
{
|
|
EndDialog(hwndDlg,
|
|
IDCANCEL);
|
|
break;
|
|
}
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
{
|
|
HWND hwndControls;
|
|
|
|
/* Forward WM_SYSCOLORCHANGE */
|
|
hwndControls = GetDlgItem(hwndDlg, IDC_CONTROLS);
|
|
SendMessage(hwndControls, WM_SYSCOLORCHANGE, 0, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
static VOID
|
|
DeleteMixerWindowControls(PMIXER_WINDOW MixerWindow)
|
|
{
|
|
DWORD Index;
|
|
|
|
for(Index = 0; Index < MixerWindow->WindowCount; Index++)
|
|
{
|
|
/* destroys the window */
|
|
DestroyWindow(MixerWindow->Window[Index]);
|
|
}
|
|
|
|
/* free memory */
|
|
HeapFree(GetProcessHeap(), 0, MixerWindow->Window);
|
|
|
|
/* set to null */
|
|
MixerWindow->Window = NULL;
|
|
MixerWindow->WindowCount = 0;
|
|
}
|
|
|
|
static BOOL
|
|
RebuildMixerWindowControls(PPREFERENCES_CONTEXT PrefContext)
|
|
{
|
|
/* delete existing mixer controls */
|
|
DeleteMixerWindowControls(PrefContext->MixerWindow);
|
|
|
|
/* load new mixer controls */
|
|
LoadDialogCtrls(PrefContext);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
CALLBACK
|
|
SetVolumeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Ctx)
|
|
{
|
|
UINT ControlCount = 0, Index;
|
|
LPMIXERCONTROL Control = NULL;
|
|
PMIXERCONTROLDETAILS_UNSIGNED puDetails = NULL;
|
|
MIXERCONTROLDETAILS_BOOLEAN bDetails;
|
|
PSET_VOLUME_CONTEXT Context = (PSET_VOLUME_CONTEXT)Ctx;
|
|
|
|
/* check if the line name is equal */
|
|
if (wcsicmp(Line->szName, Context->LineName))
|
|
{
|
|
/* it is not */
|
|
return TRUE;
|
|
}
|
|
|
|
/* query controls */
|
|
if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) == FALSE)
|
|
{
|
|
/* failed to query for controls */
|
|
return FALSE;
|
|
}
|
|
|
|
puDetails = HeapAlloc(GetProcessHeap(), 0, Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
|
|
if (puDetails == NULL)
|
|
return FALSE;
|
|
|
|
/* now go through all controls and compare control ids */
|
|
for (Index = 0; Index < ControlCount; Index++)
|
|
{
|
|
if (Context->bVertical)
|
|
{
|
|
if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
|
|
{
|
|
DWORD LineOffset, volumePosition, balancePosition;
|
|
DWORD volumeStep, balanceStep;
|
|
|
|
LineOffset = Context->SliderPos;
|
|
|
|
volumePosition = (DWORD)SendDlgItemMessage(Preferences.MixerWindow->hWnd, LineOffset * IDC_LINE_SLIDER_VERT, TBM_GETPOS, 0, 0);
|
|
volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
|
|
|
|
if (Line->cChannels == 1)
|
|
{
|
|
/* set up details */
|
|
puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
|
|
}
|
|
else if (Line->cChannels == 2)
|
|
{
|
|
balancePosition = (DWORD)SendDlgItemMessage(Preferences.MixerWindow->hWnd, LineOffset * IDC_LINE_SLIDER_HORZ, TBM_GETPOS, 0, 0);
|
|
if (balancePosition == BALANCE_CENTER)
|
|
{
|
|
puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
|
|
puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
|
|
}
|
|
else if (balancePosition == BALANCE_LEFT)
|
|
{
|
|
puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
|
|
puDetails[1].dwValue = Control[Index].Bounds.dwMinimum;
|
|
}
|
|
else if (balancePosition == BALANCE_RIGHT)
|
|
{
|
|
puDetails[0].dwValue = Control[Index].Bounds.dwMinimum;
|
|
puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
|
|
}
|
|
else if (balancePosition < BALANCE_CENTER) // Left
|
|
{
|
|
puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
|
|
|
|
balanceStep = (puDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
|
|
|
|
puDetails[1].dwValue = (balancePosition * balanceStep) + Control[Index].Bounds.dwMinimum;
|
|
}
|
|
else if (balancePosition > BALANCE_CENTER) // Right
|
|
{
|
|
puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
|
|
|
|
balanceStep = (puDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
|
|
|
|
puDetails[0].dwValue = ((BALANCE_RIGHT - balancePosition) * balanceStep) + Control[Index].Bounds.dwMinimum;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)puDetails);
|
|
|
|
/* FIXME */
|
|
}
|
|
|
|
/* set volume */
|
|
SndMixerSetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)puDetails);
|
|
|
|
/* done */
|
|
break;
|
|
}
|
|
}
|
|
else if (Context->bSwitch)
|
|
{
|
|
if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
|
|
{
|
|
/* set up details */
|
|
bDetails.fValue = Context->SliderPos;
|
|
|
|
/* set volume */
|
|
SndMixerSetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&bDetails);
|
|
|
|
/* done */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (puDetails != NULL)
|
|
HeapFree(GetProcessHeap(), 0, puDetails);
|
|
|
|
/* free controls */
|
|
HeapFree(GetProcessHeap(), 0, Control);
|
|
|
|
|
|
/* done */
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
CALLBACK
|
|
MixerControlChangeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Context)
|
|
{
|
|
PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails = NULL;
|
|
UINT ControlCount = 0, Index;
|
|
LPMIXERCONTROL Control = NULL;
|
|
|
|
/* check if the line has controls */
|
|
if (Line->cControls == 0)
|
|
{
|
|
/* no controls */
|
|
return TRUE;
|
|
}
|
|
|
|
/* query controls */
|
|
if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) == FALSE)
|
|
{
|
|
/* failed to query for controls */
|
|
return FALSE;
|
|
}
|
|
|
|
pVolumeDetails = HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
|
|
if (pVolumeDetails == NULL)
|
|
goto done;
|
|
|
|
/* now go through all controls and compare control ids */
|
|
for (Index = 0; Index < ControlCount; Index++)
|
|
{
|
|
if (Control[Index].dwControlID == PtrToUlong(Context))
|
|
{
|
|
if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
|
|
{
|
|
MIXERCONTROLDETAILS_BOOLEAN Details;
|
|
|
|
/* get volume control details */
|
|
if (SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
|
|
{
|
|
/* update dialog control */
|
|
UpdateDialogLineSwitchControl(&Preferences, Line, Details.fValue);
|
|
}
|
|
}
|
|
else if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
|
|
{
|
|
/* get volume control details */
|
|
if (SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)pVolumeDetails) != -1)
|
|
{
|
|
/* update dialog control */
|
|
DWORD volumePosition, volumeStep, maxVolume, i;
|
|
DWORD balancePosition, balanceStep;
|
|
|
|
volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
|
|
|
|
maxVolume = 0;
|
|
for (i = 0; i < Line->cChannels; i++)
|
|
{
|
|
if (pVolumeDetails[i].dwValue > maxVolume)
|
|
maxVolume = pVolumeDetails[i].dwValue;
|
|
}
|
|
|
|
volumePosition = (maxVolume - Control[Index].Bounds.dwMinimum) / volumeStep;
|
|
|
|
if (Line->cChannels == 1)
|
|
{
|
|
balancePosition = BALANCE_CENTER;
|
|
}
|
|
else if (Line->cChannels == 2)
|
|
{
|
|
if (pVolumeDetails[0].dwValue == pVolumeDetails[1].dwValue)
|
|
{
|
|
balancePosition = BALANCE_CENTER;
|
|
}
|
|
else if (pVolumeDetails[0].dwValue == Control[Index].Bounds.dwMinimum)
|
|
{
|
|
balancePosition = BALANCE_RIGHT;
|
|
}
|
|
else if (pVolumeDetails[1].dwValue == Control[Index].Bounds.dwMinimum)
|
|
{
|
|
balancePosition = BALANCE_LEFT;
|
|
}
|
|
else
|
|
{
|
|
balanceStep = (maxVolume - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
|
|
|
|
if (pVolumeDetails[0].dwValue < pVolumeDetails[1].dwValue)
|
|
{
|
|
balancePosition = (pVolumeDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
|
|
balancePosition = BALANCE_RIGHT - balancePosition;
|
|
}
|
|
else if (pVolumeDetails[1].dwValue < pVolumeDetails[0].dwValue)
|
|
{
|
|
balancePosition = (pVolumeDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
|
|
balancePosition = BALANCE_LEFT + balancePosition;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update the volume control slider */
|
|
UpdateDialogLineSliderControl(&Preferences, Line, IDC_LINE_SLIDER_VERT, VOLUME_MAX - volumePosition);
|
|
|
|
/* Update the balance control slider */
|
|
UpdateDialogLineSliderControl(&Preferences, Line, IDC_LINE_SLIDER_HORZ, balancePosition);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
done:
|
|
/* Free the volume details */
|
|
if (pVolumeDetails)
|
|
HeapFree(GetProcessHeap(), 0, pVolumeDetails);
|
|
|
|
/* free controls */
|
|
HeapFree(GetProcessHeap(), 0, Control);
|
|
|
|
/* done */
|
|
return TRUE;
|
|
}
|
|
|
|
static LRESULT CALLBACK
|
|
MainWindowProc(HWND hwnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PMIXER_WINDOW MixerWindow;
|
|
DWORD CtrlID, LineOffset;
|
|
BOOL bRet;
|
|
LRESULT Result = 0;
|
|
SET_VOLUME_CONTEXT Context;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_COMMAND:
|
|
{
|
|
MixerWindow = GetWindowData(hwnd,
|
|
MIXER_WINDOW);
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDM_PROPERTIES:
|
|
{
|
|
PREFERENCES_CONTEXT Pref;
|
|
|
|
Pref.MixerWindow = MixerWindow;
|
|
Pref.Mixer = NULL;
|
|
Pref.SelectedLine = Preferences.SelectedLine;
|
|
|
|
if (DialogBoxParam(hAppInstance,
|
|
MAKEINTRESOURCE(IDD_PREFERENCES),
|
|
hwnd,
|
|
DlgPreferencesProc,
|
|
(LPARAM)&Pref) == IDOK)
|
|
{
|
|
/* update window */
|
|
TCHAR szProduct[MAXPNAMELEN];
|
|
|
|
/* get mixer product name */
|
|
if (SndMixerGetProductName(Pref.Mixer,
|
|
szProduct,
|
|
sizeof(szProduct) / sizeof(szProduct[0])) == -1)
|
|
{
|
|
/* failed to get name */
|
|
szProduct[0] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
/* copy product */
|
|
wcscpy(Preferences.DeviceName, szProduct);
|
|
}
|
|
|
|
/* destroy old status bar */
|
|
if (MixerWindow->Mode == NORMAL_MODE)
|
|
DestroyWindow(MixerWindow->hStatusBar);
|
|
|
|
/* update details */
|
|
Preferences.SelectedLine = Pref.SelectedLine;
|
|
|
|
/* destroy old mixer */
|
|
SndMixerDestroy(Preferences.MixerWindow->Mixer);
|
|
|
|
/* use new selected mixer */
|
|
Preferences.MixerWindow->Mixer = Pref.Mixer;
|
|
|
|
/* create status window */
|
|
if (MixerWindow->Mode == NORMAL_MODE)
|
|
{
|
|
MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
|
|
NULL,
|
|
hwnd,
|
|
0);
|
|
if (MixerWindow->hStatusBar)
|
|
{
|
|
/* Set status bar */
|
|
SendMessage(MixerWindow->hStatusBar,
|
|
WM_SETTEXT,
|
|
0,
|
|
(LPARAM)szProduct);
|
|
}
|
|
}
|
|
|
|
/* rebuild dialog controls */
|
|
RebuildMixerWindowControls(&Preferences);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDM_ADVANCED_CONTROLS:
|
|
MixerWindow->bShowExtendedControls = !MixerWindow->bShowExtendedControls;
|
|
CheckMenuItem(GetMenu(hwnd),
|
|
IDM_ADVANCED_CONTROLS,
|
|
MF_BYCOMMAND | (MixerWindow->bShowExtendedControls ? MF_CHECKED : MF_UNCHECKED));
|
|
RebuildMixerWindowControls(&Preferences);
|
|
break;
|
|
|
|
case IDM_EXIT:
|
|
{
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
|
|
case IDM_ABOUT:
|
|
{
|
|
HICON hAppIcon = (HICON)GetClassLongPtrW(hwnd,
|
|
GCLP_HICON);
|
|
ShellAbout(hwnd,
|
|
lpAppTitle,
|
|
NULL,
|
|
hAppIcon);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
/* get button id */
|
|
CtrlID = LOWORD(wParam);
|
|
|
|
/* check if the message is from the line switch */
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
{
|
|
if (CtrlID % IDC_LINE_SWITCH == 0)
|
|
{
|
|
/* compute line offset */
|
|
LineOffset = CtrlID / IDC_LINE_SWITCH;
|
|
|
|
/* compute window id of line name static control */
|
|
CtrlID = LineOffset * IDC_LINE_NAME;
|
|
|
|
if (Preferences.MixerWindow->Mixer->MixerId == PLAY_MIXER)
|
|
{
|
|
/* get line name */
|
|
if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0)
|
|
{
|
|
/* setup context */
|
|
Context.SliderPos = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0);
|
|
Context.bVertical = FALSE;
|
|
Context.bSwitch = TRUE;
|
|
|
|
/* set volume */
|
|
SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context);
|
|
}
|
|
}
|
|
else if (Preferences.MixerWindow->Mixer->MixerId == RECORD_MIXER)
|
|
{
|
|
UINT i;
|
|
|
|
for (i = 0; i < Preferences.MixerWindow->DialogCount; i++)
|
|
{
|
|
SendDlgItemMessageW(hwnd, (i + 1) * IDC_LINE_SWITCH, BM_SETCHECK, (WPARAM)((i + 1) == LineOffset), 0);
|
|
}
|
|
}
|
|
}
|
|
else if (CtrlID % IDC_LINE_ADVANCED == 0)
|
|
{
|
|
ADVANCED_CONTEXT AdvancedContext;
|
|
|
|
/* compute line offset */
|
|
LineOffset = CtrlID / IDC_LINE_ADVANCED;
|
|
|
|
/* compute window id of line name static control */
|
|
CtrlID = LineOffset * IDC_LINE_NAME;
|
|
|
|
/* get line name */
|
|
if (GetDlgItemTextW(hwnd, CtrlID, AdvancedContext.LineName, MIXER_LONG_NAME_CHARS) != 0)
|
|
{
|
|
AdvancedContext.MixerWindow = Preferences.MixerWindow;
|
|
AdvancedContext.Mixer = Preferences.MixerWindow->Mixer;
|
|
AdvancedContext.Line = SndMixerGetLineByName(Preferences.MixerWindow->Mixer,
|
|
Preferences.SelectedLine,
|
|
AdvancedContext.LineName);
|
|
if (AdvancedContext.Line)
|
|
{
|
|
DialogBoxParam(hAppInstance,
|
|
MAKEINTRESOURCE(IDD_ADVANCED),
|
|
hwnd,
|
|
AdvancedDlgProc,
|
|
(LPARAM)&AdvancedContext);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MM_MIXM_LINE_CHANGE:
|
|
{
|
|
DPRINT("MM_MIXM_LINE_CHANGE\n");
|
|
break;
|
|
}
|
|
|
|
case MM_MIXM_CONTROL_CHANGE:
|
|
{
|
|
DPRINT("MM_MIXM_CONTROL_CHANGE\n");
|
|
|
|
/* get mixer window */
|
|
MixerWindow = GetWindowData(hwnd,
|
|
MIXER_WINDOW);
|
|
|
|
/* sanity checks */
|
|
assert(MixerWindow);
|
|
assert(MixerWindow->Mixer->hmx == (HMIXER)wParam);
|
|
|
|
SndMixerEnumConnections(MixerWindow->Mixer, Preferences.SelectedLine, MixerControlChangeCallback, (PVOID)lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_VSCROLL:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case TB_THUMBTRACK:
|
|
/* get dialog item ctrl */
|
|
CtrlID = GetDlgCtrlID((HWND)lParam);
|
|
|
|
/* get line index */
|
|
LineOffset = CtrlID / IDC_LINE_SLIDER_VERT;
|
|
|
|
/* compute window id of line name static control */
|
|
CtrlID = LineOffset * IDC_LINE_NAME;
|
|
|
|
/* get line name */
|
|
if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0)
|
|
{
|
|
/* setup context */
|
|
Context.SliderPos = LineOffset;
|
|
Context.bVertical = TRUE;
|
|
Context.bSwitch = FALSE;
|
|
|
|
/* set volume */
|
|
SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context);
|
|
}
|
|
break;
|
|
|
|
case TB_ENDTRACK:
|
|
MixerWindow = GetWindowData(hwnd,
|
|
MIXER_WINDOW);
|
|
|
|
/* get dialog item ctrl */
|
|
CtrlID = GetDlgCtrlID((HWND)lParam);
|
|
|
|
/* get line index */
|
|
LineOffset = CtrlID / IDC_LINE_SLIDER_VERT;
|
|
|
|
if (LineOffset == 1 && MixerWindow->Mixer->MixerId == 0)
|
|
PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_HSCROLL:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case TB_THUMBTRACK:
|
|
/* get dialog item ctrl */
|
|
CtrlID = GetDlgCtrlID((HWND)lParam);
|
|
|
|
/* get line index */
|
|
LineOffset = CtrlID / IDC_LINE_SLIDER_HORZ;
|
|
|
|
/* compute window id of line name static control */
|
|
CtrlID = LineOffset * IDC_LINE_NAME;
|
|
|
|
/* get line name */
|
|
if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0)
|
|
{
|
|
/* setup context */
|
|
Context.SliderPos = LineOffset;
|
|
Context.bVertical = TRUE;
|
|
Context.bSwitch = FALSE;
|
|
|
|
/* set volume */
|
|
SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context);
|
|
}
|
|
break;
|
|
|
|
case TB_ENDTRACK:
|
|
MixerWindow = GetWindowData(hwnd,
|
|
MIXER_WINDOW);
|
|
|
|
/* get dialog item ctrl */
|
|
CtrlID = GetDlgCtrlID((HWND)lParam);
|
|
|
|
/* get line index */
|
|
LineOffset = CtrlID / IDC_LINE_SLIDER_HORZ;
|
|
|
|
if (LineOffset == 1 && MixerWindow->Mixer->MixerId == 0)
|
|
PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_CREATE:
|
|
{
|
|
MixerWindow = ((LPCREATESTRUCT)lParam)->lpCreateParams;
|
|
SetWindowLongPtr(hwnd,
|
|
GWL_USERDATA,
|
|
(LONG_PTR)MixerWindow);
|
|
MixerWindow->hWnd = hwnd;
|
|
MixerWindow->Mixer = SndMixerCreate(MixerWindow->hWnd, MixerWindow->MixerId);
|
|
if (MixerWindow->Mixer != NULL)
|
|
{
|
|
TCHAR szProduct[MAXPNAMELEN];
|
|
|
|
/* get mixer product name */
|
|
if (SndMixerGetProductName(MixerWindow->Mixer,
|
|
szProduct,
|
|
sizeof(szProduct) / sizeof(szProduct[0])) == -1)
|
|
{
|
|
/* failed to get name */
|
|
szProduct[0] = L'\0';
|
|
}
|
|
|
|
|
|
/* initialize preferences */
|
|
ZeroMemory(&Preferences, sizeof(Preferences));
|
|
|
|
/* store mixer */
|
|
Preferences.Mixer = MixerWindow->Mixer;
|
|
|
|
/* store mixer window */
|
|
Preferences.MixerWindow = MixerWindow;
|
|
|
|
/* first destination line id */
|
|
Preferences.SelectedLine = 0xFFFF0000;
|
|
|
|
/* copy product */
|
|
wcscpy(Preferences.DeviceName, szProduct);
|
|
|
|
/* Disable the 'Advanced Controls' menu item */
|
|
EnableMenuItem(GetMenu(hwnd), IDM_ADVANCED_CONTROLS, MF_BYCOMMAND | MF_GRAYED);
|
|
|
|
/* Load the placement coordinate data of the window */
|
|
bRet = LoadXYCoordWnd(&Preferences);
|
|
if (bRet)
|
|
{
|
|
/*
|
|
* LoadXYCoordWnd() might fail for the first time of opening the application which is normal as
|
|
* the Sound Control's applet settings haven't been saved yet to the Registry. At this point SetWindowPos()
|
|
* call is skipped.
|
|
*/
|
|
SetWindowPos(hwnd, NULL, MixerWindow->WndPosX, MixerWindow->WndPosY, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
|
}
|
|
|
|
/* create status window */
|
|
if (MixerWindow->Mode == NORMAL_MODE)
|
|
{
|
|
MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
|
|
NULL,
|
|
hwnd,
|
|
0);
|
|
if (MixerWindow->hStatusBar)
|
|
{
|
|
SendMessage(MixerWindow->hStatusBar,
|
|
WM_SETTEXT,
|
|
0,
|
|
(LPARAM)szProduct);
|
|
}
|
|
}
|
|
|
|
if (!RebuildMixerWindowControls(&Preferences))
|
|
{
|
|
DPRINT("Rebuilding mixer window controls failed!\n");
|
|
SndMixerDestroy(MixerWindow->Mixer);
|
|
MixerWindow->Mixer = NULL;
|
|
Result = -1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
MixerWindow = GetWindowData(hwnd,
|
|
MIXER_WINDOW);
|
|
if (MixerWindow != NULL)
|
|
{
|
|
if (MixerWindow->Mixer != NULL)
|
|
{
|
|
SndMixerDestroy(MixerWindow->Mixer);
|
|
}
|
|
if (MixerWindow->hFont)
|
|
DeleteObject(MixerWindow->hFont);
|
|
HeapFree(hAppHeap, 0, MixerWindow);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_CLOSE:
|
|
{
|
|
SaveXYCoordWnd(hwnd, &Preferences);
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Result = DefWindowProc(hwnd,
|
|
uMsg,
|
|
wParam,
|
|
lParam);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static BOOL
|
|
RegisterApplicationClasses(VOID)
|
|
{
|
|
WNDCLASSEX wc;
|
|
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = MainWindowProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(PMIXER_WINDOW);
|
|
wc.hInstance = hAppInstance;
|
|
wc.hIcon = LoadIcon(hAppInstance,
|
|
MAKEINTRESOURCE(IDI_MAINAPP));
|
|
wc.hCursor = LoadCursor(NULL,
|
|
IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = SZ_APP_CLASS;
|
|
wc.hIconSm = NULL;
|
|
MainWindowClass = RegisterClassEx(&wc);
|
|
|
|
return MainWindowClass != 0;
|
|
}
|
|
|
|
static VOID
|
|
UnregisterApplicationClasses(VOID)
|
|
{
|
|
UnregisterClass(SZ_APP_CLASS,
|
|
hAppInstance);
|
|
}
|
|
|
|
static HWND
|
|
CreateApplicationWindow(
|
|
WINDOW_MODE WindowMode,
|
|
UINT MixerId)
|
|
{
|
|
HWND hWnd;
|
|
|
|
PMIXER_WINDOW MixerWindow = HeapAlloc(hAppHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(MIXER_WINDOW));
|
|
if (MixerWindow == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
MixerWindow->Mode = WindowMode;
|
|
MixerWindow->MixerId = MixerId;
|
|
|
|
if (mixerGetNumDevs() > 0)
|
|
{
|
|
hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT,
|
|
SZ_APP_CLASS,
|
|
lpAppTitle,
|
|
WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
|
|
0, 0, 300, 315,
|
|
NULL,
|
|
LoadMenu(hAppInstance,
|
|
MAKEINTRESOURCE(IDM_MAINMENU)),
|
|
hAppInstance,
|
|
MixerWindow);
|
|
}
|
|
else
|
|
{
|
|
LPTSTR lpErrMessage;
|
|
|
|
/*
|
|
* no mixer devices are available!
|
|
*/
|
|
|
|
hWnd = NULL;
|
|
if (AllocAndLoadString(&lpErrMessage,
|
|
hAppInstance,
|
|
IDS_NOMIXERDEVICES))
|
|
{
|
|
MessageBox(NULL,
|
|
lpErrMessage,
|
|
lpAppTitle,
|
|
MB_ICONINFORMATION);
|
|
LocalFree(lpErrMessage);
|
|
}
|
|
}
|
|
|
|
if (hWnd == NULL)
|
|
{
|
|
HeapFree(hAppHeap,
|
|
0,
|
|
MixerWindow);
|
|
}
|
|
|
|
return hWnd;
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
HandleCommandLine(LPTSTR cmdline,
|
|
DWORD dwStyle,
|
|
PWINDOW_MODE pMode,
|
|
PUINT pMixerId)
|
|
{
|
|
TCHAR option;
|
|
|
|
*pMixerId = PLAY_MIXER;
|
|
*pMode = (dwStyle & 0x20) ? SMALL_MODE : NORMAL_MODE;
|
|
|
|
while (*cmdline == _T(' ') || *cmdline == _T('-') || *cmdline == _T('/'))
|
|
{
|
|
if (*cmdline++ == _T(' '))
|
|
continue;
|
|
|
|
option = *cmdline;
|
|
if (option)
|
|
cmdline++;
|
|
while (*cmdline == _T(' '))
|
|
cmdline++;
|
|
|
|
switch (option)
|
|
{
|
|
case 'd': /* Device */
|
|
case 'D':
|
|
break;
|
|
|
|
case 'n': /* Small size */
|
|
case 'N':
|
|
*pMode = NORMAL_MODE;
|
|
break;
|
|
|
|
case 's': /* Small size */
|
|
case 'S':
|
|
*pMode = SMALL_MODE;
|
|
break;
|
|
|
|
case 't': /* Tray size */
|
|
case 'T':
|
|
*pMode = TRAY_MODE;
|
|
break;
|
|
|
|
case 'p': /* Play mode */
|
|
case 'P':
|
|
*pMixerId = PLAY_MIXER;
|
|
break;
|
|
|
|
case 'r': /* Record mode */
|
|
case 'R':
|
|
*pMixerId = RECORD_MIXER;
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int WINAPI
|
|
_tWinMain(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPTSTR lpszCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
MSG Msg;
|
|
int Ret = 1;
|
|
INITCOMMONCONTROLSEX Controls;
|
|
WINDOW_MODE WindowMode = SMALL_MODE;
|
|
UINT MixerId = 0;
|
|
DWORD dwStyle;
|
|
|
|
UNREFERENCED_PARAMETER(hPrevInstance);
|
|
UNREFERENCED_PARAMETER(nCmdShow);
|
|
|
|
hAppInstance = hInstance;
|
|
hAppHeap = GetProcessHeap();
|
|
|
|
if (InitAppConfig())
|
|
{
|
|
dwStyle = GetStyleValue();
|
|
HandleCommandLine(lpszCmdLine, dwStyle, &WindowMode, &MixerId);
|
|
|
|
/* load the application title */
|
|
if (!AllocAndLoadString(&lpAppTitle,
|
|
hAppInstance,
|
|
IDS_SNDVOL32))
|
|
{
|
|
lpAppTitle = NULL;
|
|
}
|
|
|
|
Controls.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
|
Controls.dwICC = ICC_BAR_CLASSES | ICC_STANDARD_CLASSES;
|
|
|
|
InitCommonControlsEx(&Controls);
|
|
|
|
if (WindowMode == TRAY_MODE)
|
|
{
|
|
DialogBoxParam(hAppInstance,
|
|
MAKEINTRESOURCE(IDD_TRAY_MASTER),
|
|
NULL,
|
|
TrayDlgProc,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
if (RegisterApplicationClasses())
|
|
{
|
|
hMainWnd = CreateApplicationWindow(WindowMode, MixerId);
|
|
if (hMainWnd != NULL)
|
|
{
|
|
BOOL bRet;
|
|
while ((bRet =GetMessage(&Msg,
|
|
NULL,
|
|
0,
|
|
0)) != 0)
|
|
{
|
|
if (bRet != -1)
|
|
{
|
|
TranslateMessage(&Msg);
|
|
DispatchMessage(&Msg);
|
|
}
|
|
}
|
|
|
|
DestroyWindow(hMainWnd);
|
|
Ret = 0;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Failed to create application window (LastError: %d)!\n", GetLastError());
|
|
}
|
|
|
|
UnregisterApplicationClasses();
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Failed to register application classes (LastError: %d)!\n", GetLastError());
|
|
}
|
|
}
|
|
|
|
if (lpAppTitle != NULL)
|
|
{
|
|
LocalFree(lpAppTitle);
|
|
}
|
|
|
|
CloseAppConfig();
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Unable to open the Volume Control registry key!\n");
|
|
}
|
|
|
|
return Ret;
|
|
}
|