NT4/private/windows/media/mixerapp/volume.c
2020-09-30 17:12:29 +02:00

1938 lines
41 KiB
C

/*****************************************************************************
*
* Component: sndvol32.exe
* File: volume.c
* Purpose: main application module
*
* Copyright (C) Microsoft Corporation 1985-1995. All rights reserved.
*
*****************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <commctrl.h>
#include <shellapi.h>
#include <dbt.h>
#include "vu.h"
#include "dlg.h"
#include "volids.h"
#include "volumei.h"
#include "utils.h"
void Volume_SetControl(PMIXUIDIALOG pmxud, HWND hctl, int iLine, int iCtl);
void Volume_GetControl(PMIXUIDIALOG pmxud, HWND hctl, int iLine, int iCtl);
DWORD Volume_DialogBox(PMIXUIDIALOG pmxud);
void Volume_Cleanup(PMIXUIDIALOG pmxud);
void Volume_InitLine(PMIXUIDIALOG pmxud, DWORD iLine);
/* stubs for NT */
typedef void (FAR PASCAL *PENWINREGISTERPROC)(UINT, BOOL);
/* string declarations */
const TCHAR gszParentClass[] = TEXT( "SNDVOL32" );
const CHAR gszRegisterPenApp[] = "RegisterPenApp";
const TCHAR gszAppClassName[] = TEXT( "Volume Control" );
const TCHAR gszTrayClassName[] = TEXT( "Tray Volume" );
/* app global
* */
TCHAR gszHelpFileName[MAX_PATH];
BOOL gfIsRTL;
BOOL fCanDismissWindow = FALSE;
/*
* Number of uniquely supported devices.
*
* */
int Volume_NumDevs()
{
int cNumDevs = 0;
#pragma message("----Nonmixer issue here.")
// cNumDevs = Nonmixer_GetNumDevs();
cNumDevs += Mixer_GetNumDevs();
return cNumDevs;
}
/*
* Volume_EndDialog
*
* */
void Volume_EndDialog(
PMIXUIDIALOG pmxud,
DWORD dwErr,
MMRESULT mmr)
{
pmxud->dwReturn = dwErr;
if (dwErr == MIXUI_MMSYSERR)
pmxud->mmr = mmr;
if (IsWindow(pmxud->hwnd))
PostMessage(pmxud->hwnd, WM_CLOSE, 0, 0);
}
/*
* Volume_OnMenuCommand
*
* */
BOOL Volume_OnMenuCommand(
HWND hwnd,
int id,
HWND hctl,
UINT unotify)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
switch(id)
{
case IDM_PROPERTIES:
if (Properties(pmxud, hwnd))
{
Volume_GetSetStyle(&pmxud->dwStyle, SET);
Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
}
break;
case IDM_HELPTOPICS:
PostMessage(pmxud->hParent, MYWM_HELPTOPICS, 0, 0L);
break;
case IDM_HELPABOUT:
{
TCHAR ach[256];
GetWindowText(hwnd, ach, SIZEOF(ach));
ShellAbout(hwnd
, ach
, NULL
, (HICON)SendMessage(hwnd, WM_QUERYDRAGICON, 0, 0L));
break;
}
case IDM_ADVANCED:
{
HMENU hmenu;
pmxud->dwStyle ^= MXUD_STYLEF_ADVANCED;
hmenu = GetMenu(hwnd);
CheckMenuItem(hmenu, IDM_ADVANCED, MF_BYCOMMAND
| ((pmxud->dwStyle & MXUD_STYLEF_ADVANCED)?MF_CHECKED:MF_UNCHECKED));
Volume_GetSetStyle(&pmxud->dwStyle, SET);
Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
break;
}
case IDM_SMALLMODESWITCH:
if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
{
pmxud->dwStyle ^= MXUD_STYLEF_SMALL;
if (pmxud->dwStyle & MXUD_STYLEF_SMALL)
{
pmxud->dwStyle &= ~MXUD_STYLEF_STATUS;
}
else
pmxud->dwStyle |= MXUD_STYLEF_STATUS;
Volume_GetSetStyle(&pmxud->dwStyle, SET);
Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
}
break;
case IDM_EXIT:
Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
return TRUE;
}
return FALSE;
}
/*
* Volume_OnCommand
*
* - Process WM_COMMAND
*
* Note: We need a 2 way mapping. Dialog control -> Mixer control
* and Mixer control -> Dialog control.
*
* */
void Volume_OnCommand(
HWND hdlg,
int id,
HWND hctl,
UINT unotify)
{
int iMixerLine;
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hdlg);
//
// Filter menu messages
//
if (Volume_OnMenuCommand(hdlg, id, hctl, unotify))
return;
// Each control is offset from the original template control by IDOFFSET.
// e.g.
// IDC_VOLUME, IDC_VOLUME+IDOFFSET, .. IDC_VOLUME+(IDOFFSET*cMixerLines)
//
iMixerLine = id/IDOFFSET - 1;
switch ((id % IDOFFSET) + IDC_MIXERCONTROLS)
{
case IDC_SWITCH:
Volume_SetControl(pmxud, hctl, iMixerLine, MIXUI_SWITCH);
break;
case IDC_ADVANCED:
if (MXUD_ADVANCED(pmxud) &&
!(pmxud->dwStyle & MXUD_STYLEF_SMALL))
Volume_SetControl(pmxud, hctl, iMixerLine, MIXUI_ADVANCED);
break;
}
}
/*
* Volume_GetLineItem
*
* - Helper function.
* */
HWND Volume_GetLineItem(
HWND hdlg,
DWORD iLine,
DWORD idCtrl)
{
HWND hwnd;
DWORD id;
id = (iLine * IDOFFSET) + idCtrl;
hwnd = GetDlgItem(hdlg, id);
return hwnd;
}
/* - - - - - - - - - */
/*
* Volume_TimeProc
*
* This is the callback for the periodic timer that does updates for
* controls that need to be polled. We only allocate one per app to keep
* the number of callbacks down.
*/
void CALLBACK Volume_TimeProc(
UINT idEvent,
UINT uReserved,
DWORD dwUser,
DWORD dwReserved1,
DWORD dwReserved2)
{
PMIXUIDIALOG pmxud = (PMIXUIDIALOG)dwUser;
if (!(pmxud->dwFlags & MXUD_FLAGSF_USETIMER))
return;
if (pmxud->cTimeInQueue < 5)
{
pmxud->cTimeInQueue++;
PostMessage(pmxud->hwnd, MYWM_TIMER, 0, 0L);
}
}
#define PROPATOM TEXT("dingprivprop")
const TCHAR gszDingPropAtom[] = PROPATOM;
#define SETPROP(x,y) SetProp((x), gszDingPropAtom, (HANDLE)(y))
#define GETPROP(x) (PMIXUIDIALOG)GetProp((x), gszDingPropAtom)
#define REMOVEPROP(x) RemoveProp(x,gszDingPropAtom)
LRESULT CALLBACK Volume_TrayVolProc(
HWND hwnd,
UINT umsg,
WPARAM wParam,
LPARAM lParam)
{
PMIXUIDIALOG pmxud = (PMIXUIDIALOG)GETPROP(hwnd);
static const TCHAR cszDefSnd[] = TEXT(".Default");
if (umsg == WM_KILLFOCUS)
{
//
// if we've just been made inactive via keyboard, clear the signal
//
pmxud->dwTrayInfo &= ~MXUD_TRAYINFOF_SIGNAL;
}
if (umsg == WM_KEYUP && (pmxud->dwTrayInfo & MXUD_TRAYINFOF_SIGNAL))
{
if (wParam == VK_UP || wParam == VK_DOWN || wParam == VK_END ||
wParam == VK_HOME || wParam == VK_LEFT || wParam == VK_RIGHT ||
wParam == VK_PRIOR || wParam == VK_NEXT || wParam == VK_SPACE)
{
PlaySound(cszDefSnd, NULL, SND_ASYNC | SND_ALIAS);
pmxud->dwTrayInfo &= ~MXUD_TRAYINFOF_SIGNAL;
}
}
if (umsg == WM_LBUTTONUP && (pmxud->dwTrayInfo & MXUD_TRAYINFOF_SIGNAL))
{
PlaySound(cszDefSnd, NULL, SND_ASYNC | SND_ALIAS);
pmxud->dwTrayInfo &= ~MXUD_TRAYINFOF_SIGNAL;
}
return CallWindowProc(pmxud->lpfnTrayVol, hwnd, umsg, wParam, lParam);
}
/*
*
* */
BOOL Volume_Init(
PMIXUIDIALOG pmxud)
{
DWORD iLine, ictrl;
RECT rc, rcWnd;
if (!Mixer_Init(pmxud) && !Nonmixer_Init(pmxud))
Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
//
// For all line controls, make sure we initialize the values.
//
for (iLine = 0; iLine < pmxud->cmxul; iLine++)
{
//
// init the ui control
//
Volume_InitLine(pmxud, iLine);
for (ictrl = MIXUI_FIRST; ictrl <= MIXUI_LAST; ictrl++)
{
PMIXUICTRL pmxc = &pmxud->amxul[iLine].acr[ictrl];
//
// set initial settings
//
if (pmxc->state == MIXUI_CONTROL_INITIALIZED)
Volume_GetControl(pmxud, pmxc->hwnd, iLine, ictrl);
}
}
if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
{
RECT rcBase;
HWND hBase;
RECT rcAdv,rcBorder;
HWND hAdv,hBorder;
DWORD i;
LONG lPrev;
POINT pos;
HMENU hmenu;
if (GetWindowRect(pmxud->hwnd, &rcWnd))
{
if (pmxud->cmxul == 1)
{
rcWnd.right -= 20;
ShowWindow(GetDlgItem(pmxud->hwnd, IDC_BORDER), SW_HIDE);
}
if (!Volume_GetSetRegistryRect(pmxud->szMixer
, pmxud->szDestination
, &rc
, GET))
{
rc.left = rcWnd.left;
rc.top = rcWnd.top;
}
//
// Adjusted bottom to match switch bottom
//
if (!(pmxud->dwStyle & MXUD_STYLEF_SMALL))
{
hBase = GetDlgItem(pmxud->hwnd, IDC_SWITCH);
if (hBase && GetWindowRect(hBase, &rcBase))
{
rcWnd.bottom = rcBase.bottom;
}
//
// Adjusted bottom to match "Advanced" bottom
//
if (MXUD_ADVANCED(pmxud))
{
hAdv = GetDlgItem(pmxud->hwnd, IDC_ADVANCED);
if (hAdv && GetWindowRect(hAdv, &rcAdv))
{
lPrev = rcWnd.bottom;
rcWnd.bottom = rcAdv.bottom;
//
// Adjust height of all border lines
//
lPrev = rcWnd.bottom - lPrev;
for (i = 0; i < pmxud->cmxul; i++)
{
hBorder = GetDlgItem(pmxud->hwnd,
IDC_BORDER+(IDOFFSET*i));
if (hBorder && GetWindowRect(hBorder, &rcBorder))
{
pos.x = rcBorder.left;
pos.y = rcBorder.top;
ScreenToClient(pmxud->hwnd, &pos);
MoveWindow(hBorder
, pos.x
, pos.y
, rcBorder.right - rcBorder.left
, (rcBorder.bottom - rcBorder.top) + lPrev
, TRUE );
}
}
}
}
//
// Allocate some more space.
//
rcWnd.bottom += 28;
}
MoveWindow(pmxud->hwnd, rc.left, rc.top, rcWnd.right - rcWnd.left,
rcWnd.bottom - rcWnd.top, FALSE );
//
// Tack on the status bar after resizing the dialog
//
if (pmxud->dwStyle & MXUD_STYLEF_STATUS)
{
pos.x = rcWnd.left;
pos.y = rcWnd.bottom;
ScreenToClient(pmxud->hwnd, &pos);
pmxud->hStatus = CreateWindowEx ( gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0
, STATUSCLASSNAME
, TEXT ("X")
, WS_VISIBLE | WS_CHILD
, 0
, pos.y
, rcWnd.right - rcWnd.left
, 14
, pmxud->hwnd
, NULL
, pmxud->hInstance
, NULL);
if (pmxud->hStatus)
{
SendMessage(pmxud->hStatus, WM_SETTEXT, 0,
(LPARAM)(LPVOID)(LPTSTR)pmxud->szMixer);
}
else
pmxud->dwStyle ^= MXUD_STYLEF_STATUS;
}
hmenu = GetMenu(pmxud->hwnd);
CheckMenuItem(hmenu, IDM_ADVANCED, MF_BYCOMMAND
| ((pmxud->dwStyle & MXUD_STYLEF_ADVANCED)?MF_CHECKED:MF_UNCHECKED));
if (pmxud->dwStyle & MXUD_STYLEF_SMALL ||
pmxud->dwFlags & MXUD_FLAGSF_NOADVANCED)
EnableMenuItem(hmenu, IDM_ADVANCED, MF_BYCOMMAND | MF_GRAYED);
}
if (pmxud->dwFlags & MXUD_FLAGSF_USETIMER)
{
pmxud->cTimeInQueue = 0;
pmxud->uTimerID = timeSetEvent(100
, 50
, Volume_TimeProc
, (DWORD)pmxud
, TIME_PERIODIC);
if (!pmxud->uTimerID)
pmxud->dwFlags &= ~MXUD_FLAGSF_USETIMER;
}
}
else
{
WNDPROC lpfnOldTrayVol;
HWND hVol;
hVol = pmxud->amxul[0].acr[MIXUI_VOLUME].hwnd;
lpfnOldTrayVol = SubclassWindow(hVol, Volume_TrayVolProc);
if (lpfnOldTrayVol)
{
pmxud->lpfnTrayVol = lpfnOldTrayVol;
SETPROP(hVol, pmxud);
}
}
return TRUE;
}
/*
* Volume_OnInitDialog
*
* - Process WM_INITDIALOG
*
* */
BOOL Volume_OnInitDialog(
HWND hwnd,
HWND hwndFocus,
LPARAM lParam)
{
PMIXUIDIALOG pmxud;
//
// set app instance data
//
SETMIXUIDIALOG(hwnd, lParam);
pmxud = (PMIXUIDIALOG)(LPVOID)lParam;
pmxud->hwnd = hwnd;
if (!Volume_Init(pmxud))
{
Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
}
else
{
if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
PostMessage(hwnd, MYWM_WAKEUP, 0, 0);
}
//
// If we are the tray master, don't ask to set focus
//
return (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER));
}
/*
* Volume_OnDestroy
*
* Shut down this dialog. DO NOT TOUCH the hmixer!
*
* */
void Volume_OnDestroy(
HWND hwnd)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
if (!pmxud)
return;
if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
{
HWND hVol;
hVol = pmxud->amxul[0].acr[MIXUI_VOLUME].hwnd;
SubclassWindow(hVol, pmxud->lpfnTrayVol);
REMOVEPROP(hVol);
}
Volume_Cleanup(pmxud);
if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
{
//
// save window position
//
if (!IsIconic(hwnd))
{
RECT rc;
GetWindowRect(hwnd, &rc);
Volume_GetSetRegistryRect(pmxud->szMixer
, pmxud->szDestination
, &rc
, SET);
}
}
if (pmxud->dwReturn == MIXUI_RESTART)
{
PostMessage(pmxud->hParent, MYWM_RESTART, 0, (LPARAM)pmxud);
}
else
PostMessage(pmxud->hParent, WM_CLOSE, 0, 0L);
}
/*
* Volume_SetControl
*
* Update system controls from visual controls
*
* */
void Volume_SetControl(
PMIXUIDIALOG pmxud,
HWND hctl,
int imxul,
int itype)
{
if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
Mixer_SetControl(pmxud, hctl, imxul, itype);
else
Nonmixer_SetControl(pmxud, hctl, imxul, itype);
}
/*
* Volume_GetControl
*
* Update visual controls from system controls
* */
void Volume_GetControl(
PMIXUIDIALOG pmxud,
HWND hctl,
int imxul,
int itype)
{
if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
Mixer_GetControl(pmxud, hctl, imxul, itype);
else
Nonmixer_GetControl(pmxud, hctl, imxul, itype);
}
/*
* Volume_OnXScroll
*
* Process Scroll bar messages
*
* */
void Volume_OnXScroll(
HWND hwnd,
HWND hwndCtl,
UINT code,
int pos)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
UINT id;
int ictl;
int iline;
id = GetDlgCtrlID(hwndCtl);
iline = id/IDOFFSET - 1;
ictl = ((id % IDOFFSET) + IDC_MIXERCONTROLS == IDC_BALANCE)
? MIXUI_BALANCE : MIXUI_VOLUME;
Volume_SetControl(pmxud, hwndCtl, iline, ictl);
//
// Make sure a note gets played
//
if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
pmxud->dwTrayInfo |= MXUD_TRAYINFOF_SIGNAL;
}
/*
* Volume_OnMyTimer
*
* Frequent update timer for meters
* */
void Volume_OnMyTimer(
HWND hwnd)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
if (!pmxud)
return;
if (pmxud->cTimeInQueue > 0)
pmxud->cTimeInQueue--;
if (!(pmxud->dwFlags & MXUD_FLAGSF_USETIMER))
return;
if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
Mixer_PollingUpdate(pmxud);
else
Nonmixer_PollingUpdate(pmxud);
}
/*
* Volume_OnTimer
*
* Infrequent update timer for tray shutdown
* */
void Volume_OnTimer(
HWND hwnd,
UINT id)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
KillTimer(hwnd, VOLUME_TRAYSHUTDOWN_ID);
Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
}
/*
* Volume_OnMixmControlChange
*
* Handle control changes
*
* */
void Volume_OnMixmControlChange(
HWND hwnd,
HMIXER hmx,
DWORD dwControlID)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
Mixer_GetControlFromID(pmxud, dwControlID);
}
/*
* Volume_EnableLine
*
* Enable/Disable a line
*
* */
void Volume_EnableLine(
PMIXUIDIALOG pmxud,
DWORD iLine,
BOOL fEnable)
{
DWORD iCtrl;
PMIXUICTRL pmxc;
for (iCtrl = MIXUI_FIRST; iCtrl <= MIXUI_LAST; iCtrl++ )
{
pmxc = &pmxud->amxul[iLine].acr[iCtrl];
if (pmxc->state == MIXUI_CONTROL_INITIALIZED)
EnableWindow(pmxc->hwnd, fEnable);
}
pmxud->amxul[iLine].dwStyle ^= MXUL_STYLEF_DISABLED;
}
/*
* Volume_InitLine
*
* Initialize the UI controls for the dialog
*
* */
void Volume_InitLine(
PMIXUIDIALOG pmxud,
DWORD iLine)
{
HWND ctrl;
PMIXUICTRL pmxc;
//
// Peakmeter control
//
pmxc = &pmxud->amxul[iLine].acr[MIXUI_VUMETER];
ctrl = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_VUMETER);
pmxc->hwnd = ctrl;
pmxc->noset = 0;
if (! (pmxc->state == MIXUI_CONTROL_ENABLED) )
{
if (ctrl)
ShowWindow(ctrl, SW_HIDE);
}
else if (ctrl)
{
HWND hvol;
SendMessage(ctrl, VU_SETRANGEMAX, 0, 255);
SendMessage(ctrl, VU_SETRANGEMIN, 0, 0);
hvol = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_VOLUME);
if (hvol)
{
RECT rc;
POINT pos;
//bugbug: must base this on an invisible frame we can destroy
GetWindowRect(hvol, &rc);
pos.x = rc.left;
pos.y = rc.top;
ScreenToClient(pmxud->hwnd,&pos);
MoveWindow(hvol
, pos.x - 15
, pos.y
, rc.right - rc.left
, rc.bottom - rc.top
, FALSE);
}
//
// Signal use of update timer
//
pmxud->dwFlags |= MXUD_FLAGSF_USETIMER;
pmxc->state = MIXUI_CONTROL_INITIALIZED;
}
else
pmxc->state = MIXUI_CONTROL_UNINITIALIZED;
//
// Balance control
//
pmxc = &pmxud->amxul[iLine].acr[MIXUI_BALANCE];
ctrl = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_BALANCE);
pmxc->noset = 0;
pmxc->hwnd = ctrl;
if (ctrl)
{
SendMessage(ctrl, TBM_SETRANGE, 0, MAKELONG(0, 64));
SendMessage(ctrl, TBM_SETTICFREQ, 32, 0 );
SendMessage(ctrl, TBM_SETPOS, TRUE, 32);
if (pmxc->state != MIXUI_CONTROL_ENABLED)
{
EnableWindow(ctrl, FALSE);
}
else
pmxc->state = MIXUI_CONTROL_INITIALIZED;
}
else
pmxc->state = MIXUI_CONTROL_UNINITIALIZED;
//
// Volume control
//
pmxc = &pmxud->amxul[iLine].acr[MIXUI_VOLUME];
ctrl = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_VOLUME);
pmxc->noset = 0;
pmxc->hwnd = ctrl;
if (ctrl)
{
SendMessage(ctrl, TBM_SETRANGE, 0, MAKELONG(0, 255));
SendMessage(ctrl, TBM_SETTICFREQ, 43, 0 );
if (pmxc->state != MIXUI_CONTROL_ENABLED)
{
SendMessage(ctrl, TBM_SETPOS, TRUE, 128);
EnableWindow(ctrl, FALSE);
}
else
pmxc->state = MIXUI_CONTROL_INITIALIZED;
}
else
pmxc->state = MIXUI_CONTROL_UNINITIALIZED;
//
// Switch
//
pmxc = &pmxud->amxul[iLine].acr[MIXUI_SWITCH];
ctrl = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_SWITCH);
pmxc->hwnd = ctrl;
pmxc->noset = 0;
if (ctrl)
{
if (pmxc->state != MIXUI_CONTROL_ENABLED)
EnableWindow(ctrl, FALSE);
else
pmxc->state = MIXUI_CONTROL_INITIALIZED;
}
else
pmxc->state = MIXUI_CONTROL_UNINITIALIZED;
}
/*
* Volume_OnMixmLineChange
*
* */
void Volume_OnMixmLineChange(
HWND hwnd,
HMIXER hmx,
DWORD dwLineID)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
DWORD iLine;
for (iLine = 0; iLine < pmxud->cmxul; iLine++)
{
if ( dwLineID == pmxud->amxul[iLine].pvcd->dwLineID )
{
MIXERLINE ml;
MMRESULT mmr;
BOOL fEnable;
ml.cbStruct = sizeof(ml);
ml.dwLineID = dwLineID;
mmr = mixerGetLineInfo((HMIXEROBJ)hmx, &ml, MIXER_GETLINEINFOF_LINEID);
if (mmr != MMSYSERR_NOERROR)
{
fEnable = !(ml.fdwLine & MIXERLINE_LINEF_DISCONNECTED);
Volume_EnableLine(pmxud, iLine, fEnable);
}
}
}
}
/*
* Volume_OnActivate
*
* Important for tray volume only. Dismisses the dialog and starts an
* expiration timer.
*
* */
void Volume_OnActivate(
HWND hwnd,
UINT state,
HWND hwndActDeact,
BOOL fMinimized)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
return;
if (state != WA_INACTIVE)
{
fCanDismissWindow = TRUE;
}
else if (fCanDismissWindow)
{
DWORD dwTimeout = 5 * 60 * 1000;
fCanDismissWindow = FALSE;
ShowWindow(hwnd, SW_HIDE);
//
// Set expiration timer. If no one adjusts the volume, make the
// application go away after 5 minutes.
//
dwTimeout = Volume_GetTrayTimeout(dwTimeout);
SetTimer(hwnd, VOLUME_TRAYSHUTDOWN_ID, dwTimeout, NULL);
}
}
/*
* Volume_PropogateMessage
*
* WM_SYSCOLORCHANGE needs to be send to all child windows (esp. trackbars)
*/
void Volume_PropagateMessage(
HWND hwnd,
UINT uMessage,
WPARAM wParam,
LPARAM lParam)
{
HWND hwndChild;
for (hwndChild = GetWindow(hwnd, GW_CHILD); hwndChild != NULL;
hwndChild = GetWindow(hwndChild, GW_HWNDNEXT))
{
SendMessage(hwndChild, uMessage, wParam, lParam);
}
}
/*
* Volume_OnPaint
*
* Handle custom painting
* */
void Volume_OnPaint(HWND hwnd)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
RECT rc;
POINT pos;
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
//
// for all styles other than the tray master, draw an etched
// line to delinate the menu area
//
if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
{
GetClientRect(hwnd, &rc);
rc.bottom = 0;
DrawEdge(hdc, &rc, EDGE_ETCHED, BF_TOP);
EndPaint(hwnd, &ps);
return;
}
//
// for the tray master, draw some significant icon to indicate
// volume
//
GetWindowRect(GetDlgItem(hwnd, IDC_VOLUMECUE), &rc);
pos.x = rc.left;
pos.y = rc.top;
ScreenToClient(hwnd, &pos);
rc.left = pos.x;
rc.top = pos.y;
pos.x = rc.right;
pos.y = rc.bottom;
ScreenToClient(hwnd, &pos);
rc.right = pos.x;
rc.bottom = pos.y;
DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_DIAGONAL|BF_TOP|BF_LEFT);
DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_TOP);
rc.bottom -= 8;
DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_RIGHT);
EndPaint(hwnd, &ps);
}
/*
* Volume_OnClose
*
* */
void Volume_OnClose(
HWND hwnd)
{
DestroyWindow(hwnd);
}
/*
* Volume_OnEndSession
*
* */
void Volume_OnEndSession(
HWND hwnd,
BOOL fEnding)
{
if (!fEnding)
return;
//
// Be sure to call the close code to free open handles
//
Volume_OnClose(hwnd);
}
#define V_DC_STATEF_PENDING 0x00000001
#define V_DC_STATEF_REMOVING 0x00000002
#define V_DC_STATEF_ARRIVING 0x00000004
/*
* Volume_OnDeviceChange
*
* */
void Volume_OnDeviceChange(
HWND hwnd,
WPARAM wParam,
LPARAM lParam)
{
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
MMRESULT mmr;
UINT uMxID;
switch (wParam)
{
case DBT_DEVNODES_CHANGED:
//
// We cannot reliably determine the final state of the devices in
// the system until this message is broadcast.
//
if (pmxud->dwDeviceState & V_DC_STATEF_PENDING)
{
pmxud->dwDeviceState ^= V_DC_STATEF_PENDING;
break;
}
return;
case DBT_DEVICEREMOVECOMPLETE:
//
// This is our devnode and it's being removed.
//
if (((struct _DEV_BROADCAST_HEADER *)lParam)->dbcd_devicetype
== DBT_DEVTYP_DEVNODE)
{
if (((struct _DEV_BROADCAST_DEVNODE *)lParam)->dbcd_devnode
== pmxud->dwDevNode)
{
pmxud->dwDeviceState = V_DC_STATEF_PENDING
| V_DC_STATEF_REMOVING;
}
}
return;
case DBT_DEVICEARRIVAL:
//
// A devnode is being added to the system
//
if (((struct _DEV_BROADCAST_HEADER *)lParam)->dbcd_devicetype
== DBT_DEVTYP_DEVNODE)
{
pmxud->dwDeviceState = V_DC_STATEF_PENDING
| V_DC_STATEF_ARRIVING;
}
return;
default:
return;
}
mmr = Volume_GetDefaultMixerID(&uMxID);
if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
{
if ( mmr == MMSYSERR_NOERROR
&& (pmxud->dwDeviceState & V_DC_STATEF_ARRIVING))
{
DWORD dwDevNode;
if (!mixerMessage((HMIXER)uMxID, DRV_QUERYDEVNODE
, (DWORD)&dwDevNode, 0L))
{
if (dwDevNode == pmxud->dwDevNode)
{
//
// ignore this device, it doesn't affect us
//
pmxud->dwDeviceState = 0L;
return;
}
}
}
//
// Our device state has changed. Just go away.
//
Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
}
else if (pmxud->dwDeviceState & V_DC_STATEF_REMOVING)
{
//
// Our device is gone. Restart with the default mixer if we can.
// We don't care about arrivals.
//
pmxud->mxid = (mmr == MMSYSERR_NOERROR)?uMxID:0;
pmxud->iDest = 0;
Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
}
pmxud->dwDeviceState = 0L;
}
void Volume_OnWakeup(
HWND hwnd,
WPARAM wParam)
{
POINT pos;
RECT rc;
LONG w,h;
LONG scrw, scrh;
HWND hTrack;
PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
return;
KillTimer(hwnd, VOLUME_TRAYSHUTDOWN_ID);
if (wParam != 0)
{
Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
return;
}
//
// Make the tray volume come up.
//
GetCursorPos(&pos);
GetWindowRect(hwnd, &rc);
w = rc.right - rc.left;
h = rc.bottom - rc.top;
scrw = GetSystemMetrics(SM_CXSCREEN);
scrh = GetSystemMetrics(SM_CYSCREEN);
// menu like behavior.
// show up on the left of the cursor if you're too far to the
// right.
if (pos.x + w > scrw)
pos.x -= w;
if (pos.y + h > scrh)
pos.y = scrh - h;
SetWindowPos(hwnd
, HWND_TOPMOST
, pos.x
, pos.y
, w
, h
, SWP_SHOWWINDOW);
// make us come to the front
SetForegroundWindow(hwnd);
fCanDismissWindow = TRUE;
hTrack = GetDlgItem(hwnd, IDC_VOLUME);
if (hTrack)
SetFocus(hTrack);
}
/*
* VolumeProc
*
* */
BOOL CALLBACK VolumeProc(
HWND hdlg,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
switch (msg)
{
case WM_INITDIALOG:
return HANDLE_WM_INITDIALOG(hdlg, wparam, lparam, Volume_OnInitDialog);
case WM_COMMAND:
HANDLE_WM_COMMAND(hdlg, wparam, lparam, Volume_OnCommand);
break;
case WM_CLOSE:
HANDLE_WM_CLOSE(hdlg, wparam, lparam, Volume_OnClose);
break;
case WM_DESTROY:
HANDLE_WM_DESTROY(hdlg, wparam, lparam, Volume_OnDestroy);
break;
case WM_HSCROLL:
case WM_VSCROLL:
//
// balance and volume are essentially the same
//
HANDLE_WM_XSCROLL(hdlg, wparam, lparam, Volume_OnXScroll);
break;
case MM_MIXM_LINE_CHANGE:
HANDLE_MM_MIXM_LINE_CHANGE(hdlg
, wparam
, lparam
, Volume_OnMixmLineChange);
return FALSE;
case MM_MIXM_CONTROL_CHANGE:
HANDLE_MM_MIXM_CONTROL_CHANGE(hdlg
, wparam
, lparam
, Volume_OnMixmControlChange);
return FALSE;
case WM_ACTIVATE:
HANDLE_WM_ACTIVATE(hdlg, wparam, lparam, Volume_OnActivate);
break;
case MYWM_TIMER:
HANDLE_MYWM_TIMER(hdlg, wparam, lparam, Volume_OnMyTimer);
break;
case WM_TIMER:
HANDLE_WM_TIMER(hdlg, wparam, lparam, Volume_OnTimer);
break;
case WM_PAINT:
HANDLE_WM_PAINT(hdlg, wparam, lparam, Volume_OnPaint);
break;
case WM_SYSCOLORCHANGE:
Volume_PropagateMessage(hdlg, msg, wparam, lparam);
break;
case WM_DEVICECHANGE:
HANDLE_WM_IDEVICECHANGE(hdlg, wparam, lparam, Volume_OnDeviceChange);
break;
case MYWM_WAKEUP:
HANDLE_MYWM_WAKEUP(hdlg, wparam, lparam, Volume_OnWakeup);
break;
case WM_ENDSESSION:
HANDLE_WM_ENDSESSION(hdlg, wparam, lparam, Volume_OnEndSession);
break;
default:
break;
}
return FALSE;
}
/*
* Volume_AddLine
*
* */
BOOL Volume_AddLine(
PMIXUIDIALOG pmxud,
LPBYTE lpAdd,
DWORD cbAdd,
DWORD dwStyle,
PVOLCTRLDESC pvcd)
{
LPBYTE pbNew;
DWORD cbNew;
PMIXUILINE pmxul;
if (pmxud->amxul)
{
pmxul = (PMIXUILINE)GlobalReAllocPtr(pmxud->amxul
, (pmxud->cmxul+1)*sizeof(MIXUILINE)
, GHND);
}
else
{
pmxul = (PMIXUILINE)GlobalAllocPtr(GHND, sizeof(MIXUILINE));
}
if (!pmxul)
return FALSE;
pbNew = Dlg_HorizAttach(pmxud->lpDialog
, pmxud->cbDialog
, lpAdd
, cbAdd
, (WORD)(IDOFFSET * pmxud->cmxul)
, &cbNew );
if (!pbNew)
{
if (!pmxud->amxul)
GlobalFreePtr(pmxul);
return FALSE;
}
pmxul[pmxud->cmxul].dwStyle = dwStyle;
pmxul[pmxud->cmxul].pvcd = pvcd;
pmxud->amxul = pmxul;
pmxud->lpDialog = pbNew;
pmxud->cbDialog = cbNew;
pmxud->cmxul ++;
return TRUE;
}
/*
* Volume_Cleanup
*
* */
void Volume_Cleanup(
PMIXUIDIALOG pmxud)
{
if (pmxud->dwFlags & MXUD_FLAGSF_USETIMER)
{
timeKillEvent(pmxud->uTimerID);
pmxud->dwFlags ^= MXUD_FLAGSF_USETIMER;
}
if (pmxud->dwFlags & MXUD_FLAGSF_BADDRIVER)
{
pmxud->dwFlags ^= MXUD_FLAGSF_BADDRIVER;
}
if (pmxud->dwFlags & MXUD_FLAGSF_NOADVANCED)
{
pmxud->dwFlags ^= MXUD_FLAGSF_NOADVANCED;
}
if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
Mixer_Shutdown(pmxud);
else
Nonmixer_Shutdown(pmxud);
if (pmxud->lpDialog)
GlobalFreePtr(pmxud->lpDialog);
if (pmxud->amxul)
GlobalFreePtr(pmxud->amxul);
if (pmxud->avcd)
GlobalFreePtr(pmxud->avcd);
pmxud->amxul = NULL;
pmxud->lpDialog = NULL;
pmxud->cbDialog = 0;
pmxud->cmxul = 0;
pmxud->hwnd = NULL;
pmxud->hStatus = NULL;
pmxud->uTimerID = 0;
pmxud->dwDevNode = 0L;
}
/*
* Volume_CreateVolume
* */
BOOL Volume_CreateVolume(
PMIXUIDIALOG pmxud)
{
WNDCLASS wc;
LPBYTE lpDst = NULL, lpSrc = NULL, lpMaster = NULL;
DWORD cbDst, cbSrc, cbMaster;
PVOLCTRLDESC avcd;
DWORD cvcd;
DWORD ivcd;
DWORD imxul;
DWORD dwSupport = 0L;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(pmxud->hInstance, MAKEINTRESOURCE(IDI_MIXER));
wc.lpszMenuName = NULL;
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.hInstance = pmxud->hInstance;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefDlgProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.lpszClassName = (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
? gszTrayClassName : gszAppClassName;
RegisterClass(&wc);
if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
{
lpMaster = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
, MAKEINTRESOURCE(IDD_TRAYMASTER)
, &cbMaster);
if (!lpMaster)
return FALSE;
}
else
{
if (pmxud->dwStyle & MXUD_STYLEF_SMALL)
{
lpDst = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
, MAKEINTRESOURCE(IDD_SMDST)
, &cbDst);
lpSrc = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
, MAKEINTRESOURCE(IDD_SMSRC)
, &cbSrc);
}
else
{
lpDst = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
, MAKEINTRESOURCE(IDD_DESTINATION)
, &cbDst);
lpSrc = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
, MAKEINTRESOURCE(IDD_SOURCE)
, &cbSrc);
}
if (!lpDst || !lpSrc)
return FALSE;
}
pmxud->lpDialog = NULL;
pmxud->cbDialog = 0;
pmxud->amxul = NULL;
pmxud->cmxul = 0;
pmxud->avcd = NULL;
pmxud->cvcd = 0;
//
// Create the volume description
//
if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
{
avcd = Mixer_CreateVolumeDescription((HMIXEROBJ)pmxud->mxid
, pmxud->iDest
, &cvcd);
if (!Mixer_GetDeviceName(pmxud))
{
GlobalFreePtr(avcd);
avcd = NULL;
}
}
else
{
avcd = Nonmixer_CreateVolumeDescription(pmxud->iDest
, &cvcd);
if (!Nonmixer_GetDeviceName(pmxud));
{
GlobalFreePtr(avcd);
avcd = NULL;
}
}
//
// Create the dialog box to go along with it
//
if (avcd)
{
pmxud->avcd = avcd;
pmxud->cvcd = cvcd;
if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
{
Volume_AddLine(pmxud
, lpMaster
, cbMaster
, MXUL_STYLEF_DESTINATION
, &avcd[0]);
}
else
{
BOOL fFirstRun;
//
// Restore HIDDEN flags.
//
// On first run, be sure to re-save state so there's something
// there.
//
fFirstRun = !Volume_GetSetRegistryLineStates(pmxud->szMixer
, pmxud->avcd[0].szShortName
, avcd
, cvcd
, GET);
for (ivcd = 0; ivcd < cvcd; ivcd++)
{
//
// Lines are marked hidden if a state has been saved in the
// registry or no state has been saved and there are too many
// unnecessary lines.
//
if (avcd[ivcd].dwSupport & VCD_SUPPORTF_HIDDEN)
continue;
//
// Lines are marked VISIBLE if they have sufficient controls
// to be useful.
//
if (!(avcd[ivcd].dwSupport & VCD_SUPPORTF_VISIBLE))
continue;
//
// Show only defaults on first run.
//
if (fFirstRun && !(avcd[ivcd].dwSupport & VCD_SUPPORTF_DEFAULT))
{
avcd[ivcd].dwSupport |= VCD_SUPPORTF_HIDDEN;
continue;
}
//
// For those lines that have important controls, add them to
// the UI.
//
if ((pmxud->dwFlags & MXUD_FLAGSF_MIXER) && ivcd == 0 )
Volume_AddLine(pmxud
, lpDst
, cbDst
, MXUL_STYLEF_DESTINATION
, &avcd[ivcd]);
else
Volume_AddLine(pmxud
, lpSrc
, cbSrc
, MXUL_STYLEF_SOURCE
, &avcd[ivcd]);
}
if (fFirstRun)
Volume_GetSetRegistryLineStates(pmxud->szMixer
, pmxud->avcd[0].szShortName
, avcd
, cvcd
, SET);
}
//
// Now that both arrays are now fixed, set back pointers for
// the vcd's to ui lines.
//
for (imxul = 0; imxul < pmxud->cmxul; imxul++)
{
pmxud->amxul[imxul].pvcd->pmxul = &pmxud->amxul[imxul];
//
// Accumulate support bits
//
dwSupport |= pmxud->amxul[imxul].pvcd->dwSupport;
}
//
// Support bits say we have no advanced controls, so don't make
// them available.
//
if (!(dwSupport & VCD_SUPPORTF_MIXER_ADVANCED))
{
pmxud->dwFlags |= MXUD_FLAGSF_NOADVANCED;
}
//
// Propogate bad driver bit to be app global. A bad driver was
// detected during the construction of a volume description.
//
for (ivcd = 0; ivcd < pmxud->cvcd; ivcd++)
{
if (pmxud->avcd[ivcd].dwSupport & VCD_SUPPORTF_BADDRIVER)
{
dlout("Bad Control->Line mapping. Marking bad driver.");
pmxud->dwFlags |= MXUD_FLAGSF_BADDRIVER;
break;
}
}
}
//
// Note: it isn't necessary to free/unlock the lpMaster/lpDst/lpSrc
// because they are ptr's to resources and Win32 is smart about resources
//
return (avcd != NULL);
}
/*
* Volume_DialogBox
*
* */
DWORD Volume_DialogBox(
PMIXUIDIALOG pmxud)
{
pmxud->dwReturn = MIXUI_EXIT;
if (Volume_CreateVolume(pmxud))
{
HWND hdlg;
hdlg = CreateDialogIndirectParam(pmxud->hInstance
, (DLGTEMPLATE *)pmxud->lpDialog
, NULL
, VolumeProc
, (LONG)(LPVOID)pmxud );
if (!hdlg)
{
Volume_Cleanup(pmxud);
return MIXUI_ERROR;
}
ShowWindow(hdlg, pmxud->nShowCmd);
}
else
return MIXUI_ERROR;
}
/*
* VolumeParent_WndProc
*
* A generic invisible parent window.
*
* */
LRESULT CALLBACK VolumeParent_WndProc(
HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
PMIXUIDIALOG pmxud;
switch (msg)
{
case WM_CREATE:
{
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lparam;
pmxud = (PMIXUIDIALOG)lpcs->lpCreateParams;
SetWindowLong(hwnd, GWL_USERDATA, (LONG)pmxud);
pmxud->hParent = hwnd;
if (Volume_DialogBox(pmxud) == MIXUI_ERROR)
{
if ( !(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
{
if ( Volume_NumDevs() == 0 )
Volume_ErrorMessageBox(NULL, pmxud->hInstance, IDS_ERR_NODEV);
else
Volume_ErrorMessageBox(NULL, pmxud->hInstance, IDS_ERR_HARDWARE);
}
PostMessage(hwnd, WM_CLOSE, 0, 0L);
}
return 0;
}
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
case WM_DESTROY:
//
// Post-close cleanup
//
pmxud = (PMIXUIDIALOG)GetWindowLong(hwnd, GWL_USERDATA);
if (!(pmxud->dwStyle & MXUD_STYLEF_NOHELP))
WinHelp(hwnd, gszHelpFileName, HELP_QUIT, 0L);
PostQuitMessage(0);
return 0;
case MYWM_HELPTOPICS:
//
// F1 Help
//
pmxud = (PMIXUIDIALOG)GetWindowLong(hwnd, GWL_USERDATA);
if (!(pmxud->dwStyle & MXUD_STYLEF_NOHELP))
WinHelp(hwnd, gszHelpFileName, HELP_FINDER, 0);
break;
case MYWM_RESTART:
//
// A device change or other user property change caused a UI
// change. Sending a restart to the parent prevents ugly stuff
// like WinHelp shutting down and exiting our primary message
// loop.
//
pmxud = (PMIXUIDIALOG)GetWindowLong(hwnd, GWL_USERDATA);
if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
{
if (Volume_NumDevs() == 0)
{
Volume_ErrorMessageBox(NULL
, pmxud->hInstance
, IDS_ERR_NODEV);
PostMessage(hwnd, WM_CLOSE, 0, 0L);
}
else if (Volume_DialogBox((PMIXUIDIALOG)lparam) == MIXUI_ERROR)
{
Volume_ErrorMessageBox(NULL
, pmxud->hInstance
, IDS_ERR_HARDWARE);
PostMessage(hwnd, WM_CLOSE, 0, 0L);
}
}
else
{
if (Mixer_GetNumDevs() == 0
|| Volume_DialogBox((PMIXUIDIALOG)lparam) == MIXUI_ERROR)
PostMessage(hwnd, WM_CLOSE, 0, 0L);
}
break;
default:
break;
}
DefWindowProc(hwnd, msg, wparam, lparam);
}
const TCHAR szNull[] = TEXT ("");
/*
* Parent Dialog
* */
HWND VolumeParent_DialogMain(
PMIXUIDIALOG pmxud)
{
WNDCLASS wc;
HWND hwnd;
wc.lpszClassName = gszParentClass;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.hbrBackground = NULL;
wc.hInstance = pmxud->hInstance;
wc.style = 0;
wc.lpfnWndProc = VolumeParent_WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
if (!RegisterClass(&wc))
return NULL;
hwnd = CreateWindow(gszParentClass
, szNull
, 0
, 0
, 0
, 0
, 0
, NULL
, NULL
, pmxud->hInstance
, (LPVOID)pmxud );
return hwnd;
}
/* - - - - - - - - - */
/*
* entry point
* */
int WINAPI WinMain(
HINSTANCE hInst,
HINSTANCE hPrev,
LPSTR lpCmdLine,
int nShowCmd)
{
int err = 0;
MIXUIDIALOG mxud;
MSG msg;
HWND hwnd;
HANDLE hAccel;
MMRESULT mmr;
TCHAR ach[2];
PENWINREGISTERPROC lpfnRegisterPenApp;
HINSTANCE hinstPen;
if (hinstPen = (HINSTANCE)GetSystemMetrics(SM_PENWINDOWS))
lpfnRegisterPenApp = (PENWINREGISTERPROC)GetProcAddress(hinstPen
, gszRegisterPenApp);
else
lpfnRegisterPenApp = NULL;
if (lpfnRegisterPenApp)
(*lpfnRegisterPenApp)(1, TRUE);
LoadString(hInst, IDS_IS_RTL, ach, SIZEOF(ach));
gfIsRTL = ach[0] == TEXT('1');
//
// initialize the app instance data
//
ZeroMemory(&mxud, sizeof(mxud));
mxud.hInstance = hInst;
mxud.dwFlags = MXUD_FLAGSF_MIXER;
//
// parse the command line for "/Tray"
//
switch (lpCmdLine[0])
{
case TEXT('-'):
case TEXT('/'):
switch (lpCmdLine[1])
{
case TEXT('T'):
case TEXT('t'):
mxud.dwStyle |= MXUD_STYLEF_TRAYMASTER;
break;
case TEXT('S'):
case TEXT('s'):
mxud.dwStyle |= MXUD_STYLEF_SMALL;
break;
case TEXT('X'):
case TEXT('x'):
mxud.dwStyle |= MXUD_STYLEF_TRAYMASTER | MXUD_STYLEF_CLOSE;
break;
}
break;
default:
break;
}
//
// Restore last style
//
if (!(mxud.dwStyle & (MXUD_STYLEF_TRAYMASTER|MXUD_STYLEF_SMALL)))
{
Volume_GetSetStyle(&mxud.dwStyle, GET);
}
if (mxud.dwStyle & MXUD_STYLEF_TRAYMASTER)
{
HWND hwndSV;
//
// Locate a waiting instance of the tray volume and wake it up
//
hwndSV = FindWindow(gszTrayClassName, NULL);
if (hwndSV) {
SendMessage(hwndSV, MYWM_WAKEUP,
(mxud.dwStyle & MXUD_STYLEF_CLOSE), 0);
goto mxendapp;
}
}
if (mxud.dwStyle & MXUD_STYLEF_CLOSE) {
goto mxendapp;
}
//
// Init to the default mixer
//
mmr = Volume_GetDefaultMixerID(&mxud.mxid);
//
// For the tray master, get the mix id associated with the default
// wave device. If this fails, go away.
//
if (mxud.dwStyle & MXUD_STYLEF_TRAYMASTER)
{
if (mmr != MMSYSERR_NOERROR)
goto mxendapp;
mxud.dwStyle |= MXUD_STYLEF_NOHELP;
mxud.nShowCmd = SW_HIDE;
}
else
{
if (!Volume_NumDevs())
{
Volume_ErrorMessageBox(NULL, hInst, IDS_ERR_NODEV);
goto mxendapp;
}
InitVUControl(hInst);
if (!LoadString(hInst
, IDS_HELPFILENAME
, gszHelpFileName
, SIZEOF(gszHelpFileName)))
mxud.dwStyle |= MXUD_STYLEF_NOHELP;
mxud.nShowCmd = (nShowCmd == SW_SHOWMAXIMIZED)
? SW_SHOWNORMAL:nShowCmd;
if (!(mxud.dwStyle & MXUD_STYLEF_SMALL))
mxud.dwStyle |= MXUD_STYLEF_STATUS; // has status bar
}
//
// Use the common controls
//
InitCommonControls();
hAccel = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_VOLUMEACCEL));
hwnd = VolumeParent_DialogMain(&mxud);
if (hwnd)
{
while (GetMessage(&msg, NULL, 0, 0))
{
if (mxud.hwnd) {
if (hAccel && TranslateAccelerator(mxud.hwnd, hAccel, &msg))
continue;
if (IsDialogMessage(mxud.hwnd,&msg))
continue;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
mxendapp:
return err;
}