|
|
/*****************************************************************************
* * Component: sndvol32.exe * File: volume.c * Purpose: main application module * * Copyright (c) 1985-1999 Microsoft Corporation * *****************************************************************************/ #include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <commctrl.h>
#include <shellapi.h>
#include <dbt.h>
#include <htmlhelp.h>
#include <regstr.h>
#include "vu.h"
#include "dlg.h"
#include "volids.h"
#include "volumei.h"
#include "utils.h"
#include "stdlib.h"
#include "helpids.h"
#if(WINVER >= 0x040A)
//Support for new WM_DEVICECHANGE behaviour in NT5
/////////////////////////////////////////////////
#include <objbase.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <initguid.h>
#include <devguid.h>
#include <mmddkp.h>
#include <ks.h>
#include <ksmedia.h>
#include <wchar.h>
#define STRSAFE_LIB
#include <strsafe.h>
#define HMIXER_INDEX(i) ((HMIXER)IntToPtr(i))
HDEVNOTIFY DeviceEventContext = NULL; BOOL bUseHandle = FALSE; //Indicates whether a handle is being used for device notification,
//instead of the general KSCATEGORY_AUDIO
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
#endif /* WINVER >= 0x040A */
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); HRESULT GetDestLineID(int mxid, DWORD *piDest); HRESULT GetSrcLineID(int mxid, DWORD *piDest); HRESULT GetDestination(DWORD mxid, int *piDest); HICON GetAppIcon (HINSTANCE hInst, UINT uiMixID); void FreeAppIcon (); HKEY OpenDeviceRegKey (UINT uiMixID, REGSAM sam); PTCHAR GetInterfaceName (DWORD dwMixerID); HKEY OpenDeviceBrandRegKey (UINT uiMixID);
/* string declarations */ const TCHAR gszParentClass[] = TEXT( "SNDVOL32" );
const TCHAR gszAppClassName[] = TEXT( "Volume Control" ); const TCHAR gszTrayClassName[] = TEXT( "Tray Volume" );
#ifdef DEBUG
static void _dlout(LPSTR szExp, LPSTR szFile, UINT uLine) { char sz[256]; StringCchPrintfA(sz, SIZEOF(sz), "%s, file %s, line %u\r\n", szExp, szFile, uLine); OutputDebugStringA(sz); } #define dlout(exp) (void)(_dlout(exp, __FILE__, __LINE__), 0)
#else
#define dlout(exp) ((void)0)
#endif
/* app global
* */ TCHAR gszHelpFileName[MAX_PATH]; TCHAR gszHtmlHelpFileName[MAX_PATH]; BOOL gfIsRTL; BOOL fCanDismissWindow = FALSE; BOOL gfRecord = FALSE; HICON ghiconApp = NULL; static HHOOK fpfnOldMsgFilter; static HOOKPROC fpfnMsgHook; //Data used for supporting context menu help
BOOL bF1InMenu=FALSE; //If true F1 was pressed on a menu item.
UINT currMenuItem=0; //The current selected menu item if any.
static HWND ghwndApp=NULL;
/*
* 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: SendMessage(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); if (hmenu) { 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; case IDC_MULTICHANNEL: Volume_SetControl(pmxud, hctl, iMixerLine, MIXUI_MULTICHANNEL); 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_PTR dwUser, DWORD_PTR dwReserved1, DWORD_PTR 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); }
#if(WINVER >= 0x040A)
void DeviceChange_Cleanup() { if (DeviceEventContext) { UnregisterDeviceNotification(DeviceEventContext); DeviceEventContext = 0; }
bUseHandle = FALSE;
return; }
/*
************************************************************************************************** GetDeviceHandle()
given a mixerID this functions opens its corresponding device handle. This handle can be used to register for DeviceNotifications.
dwMixerID -- The mixer ID phDevice -- a pointer to a handle. This pointer will hold the handle value if the function is successful
return values -- If the handle could be obtained successfully the return vlaue is TRUE.
************************************************************************************************** */ BOOL GetDeviceHandle(DWORD dwMixerID, HANDLE *phDevice) { MMRESULT mmr; ULONG cbSize=0; TCHAR *szInterfaceName=NULL;
//Query for the Device interface name
mmr = mixerMessage((HMIXER)ULongToPtr(dwMixerID), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&cbSize, 0L); if(MMSYSERR_NOERROR == mmr) { szInterfaceName = (TCHAR *)GlobalAllocPtr(GHND, (cbSize+1)*sizeof(TCHAR)); if(!szInterfaceName) { return FALSE; }
mmr = mixerMessage((HMIXER)ULongToPtr(dwMixerID), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)szInterfaceName, cbSize); if(MMSYSERR_NOERROR != mmr) { GlobalFreePtr(szInterfaceName); return FALSE; } } else { return FALSE; }
//Get an handle on the device interface name.
*phDevice = CreateFile(szInterfaceName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
GlobalFreePtr(szInterfaceName); if(INVALID_HANDLE_VALUE == *phDevice) { return FALSE; }
return TRUE; }
/* DeviceChange_Init()
* First time initialization for WM_DEVICECHANGE messages * * On NT 5.0, you have to register for device notification */ BOOL DeviceChange_Init(HWND hWnd, DWORD dwMixerID) {
DEV_BROADCAST_HANDLE DevBrodHandle; DEV_BROADCAST_DEVICEINTERFACE dbi; HANDLE hMixerDevice;
//If we had registered already for device notifications, unregister ourselves.
DeviceChange_Cleanup();
//If we get the device handle register for device notifications on it.
if(GetDeviceHandle(dwMixerID, &hMixerDevice)) { memset(&DevBrodHandle, 0, sizeof(DEV_BROADCAST_HANDLE));
DevBrodHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE); DevBrodHandle.dbch_devicetype = DBT_DEVTYP_HANDLE; DevBrodHandle.dbch_handle = hMixerDevice;
DeviceEventContext = RegisterDeviceNotification(hWnd, &DevBrodHandle, DEVICE_NOTIFY_WINDOW_HANDLE);
if(hMixerDevice) { CloseHandle(hMixerDevice); hMixerDevice = NULL; }
if(DeviceEventContext) { bUseHandle = TRUE; return TRUE; } }
if(!DeviceEventContext) { //Register for notifications from all audio devices. KSCATEGORY_AUDIO gives notifications
//on device arrival and removal. We cannot identify which device the notification has arrived for
//but we can take some precautionary measures on these messages so that we do not crash.
dbi.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; dbi.dbcc_reserved = 0; dbi.dbcc_classguid = KSCATEGORY_AUDIO; dbi.dbcc_name[0] = TEXT('\0');
DeviceEventContext = RegisterDeviceNotification(hWnd, (PVOID)&dbi, DEVICE_NOTIFY_WINDOW_HANDLE); if(!DeviceEventContext) return FALSE; }
return TRUE; }
#endif /* WINVER >= 0x040A */
//fixes bug where controls are lopped off on high-contract extra-large modes
void AdjustForStatusBar(PMIXUIDIALOG pmxud) { RECT statusrect, windowrect; statusrect.bottom = 0; statusrect.top = 0;
if (pmxud) { if (pmxud->hStatus) { GetClientRect(pmxud->hStatus,&statusrect); GetWindowRect(pmxud->hwnd,&windowrect);
if (statusrect.bottom - statusrect.top > 20) { int y_adjustment = (statusrect.bottom - statusrect.top) - 20;
MoveWindow(pmxud->hwnd, windowrect.left, windowrect.top, windowrect.right - windowrect.left, (windowrect.bottom - windowrect.top) + y_adjustment, FALSE );
GetClientRect(pmxud->hwnd,&windowrect);
MoveWindow(pmxud->hStatus, statusrect.left, windowrect.bottom - (statusrect.bottom - statusrect.top), statusrect.right - statusrect.left, statusrect.bottom - statusrect.top, FALSE ); } } //end if hStatus is valid
} //end if pmxud is not null
}
/*
* * */ 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; HMONITOR hMonitor; MONITORINFO monitorInfo;
if (GetWindowRect(pmxud->hwnd, &rcWnd)) { if (pmxud->cmxul == 1) { // Adjust size if small
if (pmxud->dwStyle & MXUD_STYLEF_SMALL) 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; } else { // Check if the rect is visible is any of the monitors
if (!MonitorFromRect(&rc, MONITOR_DEFAULTTONULL)) { //The window is not visible. Let's center it in the nearest monitor.
//Note: the window could be in this state if (1) the display mode was changed from
//a high-resolution to a lower resolution, with the mixer in the corner. Or,
//(2) the multi-mon configuration was rearranged.
hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST); if (hMonitor) { monitorInfo.cbSize = sizeof(MONITORINFO); if (GetMonitorInfo(hMonitor, &monitorInfo)) { rc.left = ((monitorInfo.rcWork.right - monitorInfo.rcWork.left) - (rcWnd.right - rcWnd.left)) / 2; //center in x
rc.top = ((monitorInfo.rcWork.bottom - monitorInfo.rcWork.top) - (rcWnd.bottom - rcWnd.top)) / 3; //and a little towards the top
} } } //else, the window is visible, so let's leave the (x,y) as read from the settings
} //
// 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)) { MapWindowPoints(NULL, pmxud->hwnd, (LPPOINT)&rcBorder, 2); pos.x = rcBorder.left; pos.y = rcBorder.top; 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
//
//init status bar hwnd variable
pmxud->hStatus = NULL;
if (pmxud->dwStyle & MXUD_STYLEF_STATUS) { MapWindowPoints(NULL, pmxud->hwnd, (LPPOINT)&rcWnd, 2); pos.x = rcWnd.left; pos.y = rcWnd.bottom;
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; }
AdjustForStatusBar(pmxud);
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_PTR)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); } }
#if(WINVER >= 0x040A)
//Register for WM_DEVICECHANGE messages
DeviceChange_Init(pmxud->hwnd, pmxud->mxid); #endif /* WINVER >= 0x040A */
return TRUE; }
/*
* Volume_OnInitDialog * * - Process WM_INITDIALOG * * */ BOOL Volume_OnInitDialog( HWND hwnd, HWND hwndFocus, LPARAM lParam) { PMIXUIDIALOG pmxud; RECT rc;
//
// 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 so big that we need a scroll bar, then make one.
//
rc.top = rc.bottom = 0; rc.left = 60; // typical width of a dialog template
rc.right = Dlg_HorizSize(pmxud->lpDialog); MapDialogRect(hwnd, &rc); pmxud->cxDlgContent = rc.right; pmxud->cxScroll = rc.left; pmxud->xOffset = 0;
GetClientRect(hwnd, &rc); pmxud->xOffset = 0; pmxud->cxDlgWidth = rc.right; if (rc.right < pmxud->cxDlgContent) { RECT rcWindow; SCROLLINFO si; LONG lStyle = GetWindowStyle(hwnd); SetWindowLong(hwnd, GWL_STYLE, lStyle | WS_HSCROLL);
si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_RANGE; si.nMin = 0; si.nMax = pmxud->cxDlgContent - 1; // endpoint is inclusive
si.nPage = rc.right; SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
// Grow the dialog to accomodate the scrollbar
GetWindowRect(hwnd, &rcWindow); SetWindowPos(hwnd, NULL, 0, 0, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top + GetSystemMetrics(SM_CYHSCROLL), SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); }
//
// 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);
DeviceChange_Cleanup();
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); }
extern DWORD GetWaveOutID(BOOL *pfPreferred); /*
* Volume_PlayDefaultSound * * Play the default sound on the current mixer * * */ void Volume_PlayDefaultSound (PMIXUIDIALOG pmxud) { /*
// TODO: Implement for all master volumes. Convert mixerid to wave id then
// use wave API to play the file
TCHAR szDefSnd[MAX_PATH]; long lcb = sizeof (szDefSnd);
// Get the default sound filename
if (ERROR_SUCCESS != RegQueryValue (HKEY_CURRENT_USER, REGSTR_PATH_APPS_DEFAULT TEXT("\\.Default\\.Current"), szDefSnd, &lcb) || 0 >= lstrlen (szDefSnd)) return; */
DWORD dwWave = GetWaveOutID (NULL); UINT uiMixID;
// Check Parameter
if (!pmxud) return;
// Play the sound only if we are on the default mixer...
if (MMSYSERR_NOERROR == mixerGetID (ULongToPtr(dwWave), &uiMixID, MIXER_OBJECTF_WAVEOUT) && pmxud -> mxid == uiMixID) {
static const TCHAR cszDefSnd[] = TEXT(".Default"); PlaySound(cszDefSnd, NULL, SND_ASYNC | SND_ALIAS); } }
/*
* Volume_ScrollTo * * Move the scrollbar position. */ void Volume_ScrollTo( PMIXUIDIALOG pmxud, int pos ) { RECT rc;
/*
* Keep in range. */ pos = max(pos, 0); pos = min(pos, pmxud->cxDlgContent - pmxud->cxDlgWidth);
/*
* Scroll the window contents accordingly. But don't scroll * the status bar. */
GetClientRect(pmxud->hwnd, &rc); if (pmxud->hStatus) { RECT rcStatus; GetWindowRect(pmxud->hStatus, &rcStatus); MapWindowRect(NULL, pmxud->hwnd, &rcStatus); SubtractRect(&rc, &rc, &rcStatus); }
rc.left = -pmxud->cxDlgContent; rc.right = pmxud->cxDlgContent;
ScrollWindowEx(pmxud->hwnd, pmxud->xOffset - pos, 0, &rc, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN); pmxud->xOffset = pos;
/*
* Move the scrollbar to match. */ SetScrollPos(pmxud->hwnd, SB_HORZ, pos, TRUE); }
/*
* Volume_ScrollContent * * Process scroll bar messages for the dialog itself. */
void Volume_ScrollContent( PMIXUIDIALOG pmxud, UINT code, int pos ) { switch (code) { case SB_LINELEFT: Volume_ScrollTo(pmxud, pmxud->xOffset - pmxud->cxScroll); break;
case SB_LINERIGHT: Volume_ScrollTo(pmxud, pmxud->xOffset + pmxud->cxScroll); break;
case SB_PAGELEFT: Volume_ScrollTo(pmxud, pmxud->xOffset - pmxud->cxDlgWidth); break;
case SB_PAGERIGHT: Volume_ScrollTo(pmxud, pmxud->xOffset + pmxud->cxDlgWidth); break;
case SB_LEFT: Volume_ScrollTo(pmxud, 0); break;
case SB_RIGHT: Volume_ScrollTo(pmxud, MAXLONG); break;
case SB_THUMBPOSITION: case SB_THUMBTRACK: Volume_ScrollTo(pmxud, pos); break; } }
/*
* 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;
// If this is a scroll message from the dialog itself, then we need
// to scroll our content.
if (hwndCtl == NULL) { Volume_ScrollContent(pmxud, code, pos); return; }
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;
// Play a sound on for the master volume or balance slider when the
// user ends the scroll and we are still in focus and the topmost app.
if (code == SB_ENDSCROLL && pmxud && !(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER) && pmxud->amxul[iline].pvcd && (MXUL_STYLEF_DESTINATION & pmxud->amxul[iline].dwStyle) && hwndCtl == GetFocus() && hwnd == GetForegroundWindow ()) { Volume_PlayDefaultSound (pmxud); } }
/*
* 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;
if (! (pmxc->state == MIXUI_CONTROL_ENABLED) ) { if (ctrl) ShowWindow(ctrl, SW_HIDE); } else if (ctrl) { HWND hvol;
SendMessage(ctrl, VU_SETRANGEMAX, 0, VOLUME_TICS); SendMessage(ctrl, VU_SETRANGEMIN, 0, 0);
hvol = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_VOLUME); if (hvol) { RECT rc; POINT pos;
GetWindowRect(hvol, &rc); MapWindowPoints(NULL, pmxud->hwnd, (LPPOINT)&rc, 2); pos.x = rc.left; pos.y = rc.top;
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->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->hwnd = ctrl;
if (ctrl) { SendMessage(ctrl, TBM_SETRANGE, 0, MAKELONG(0, VOLUME_TICS)); SendMessage(ctrl, TBM_SETTICFREQ, (VOLUME_TICS + 5)/6, 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;
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) { PostMessage(hwnd, WM_CLOSE, 0, 0L); /*
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; 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);
MapWindowPoints(NULL, hwnd, (LPPOINT)&rc, 2);
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; PDEV_BROADCAST_DEVICEINTERFACE bdi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam; PDEV_BROADCAST_HANDLE bh = (PDEV_BROADCAST_HANDLE)lParam;
//
// Determine if this is our event.
//
if(!DeviceEventContext) return;
//If we have an handle on the device then we get a DEV_BROADCAST_HDR structure as the lParam.
//Or else it means that we have registered for the general audio category KSCATEGORY_AUDIO.
if(bUseHandle) { if(!bh || bh->dbch_devicetype != DBT_DEVTYP_HANDLE) { return; } } else if (!bdi || bdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE || !IsEqualGUID(&KSCATEGORY_AUDIO, &bdi->dbcc_classguid) || !(*bdi->dbcc_name) ) { return; }
switch (wParam) { case DBT_DEVICEQUERYREMOVE: //The mixer has to be shutdown now.
//Posting a WM_CLOSE message as Volume_EndDialog does will not help.
if (pmxud->dwFlags & MXUD_FLAGSF_MIXER) Mixer_Shutdown(pmxud); else Nonmixer_Shutdown(pmxud);
// Don't attempt restart, just exit. The wavemapper is not
// updated with the new default device, so do not know what
// to restart as and we should NOT hardcode device #0!
// pmxud->mxid = (DWORD) 0;
// GetDestination(pmxud->mxid, &pmxud->iDest);
Volume_EndDialog(pmxud, MIXUI_EXIT, 0); return;
case DBT_DEVICEQUERYREMOVEFAILED: // The query failed, the device will not be removed, so lets reopen it.
mmr = Volume_GetDefaultMixerID(&uMxID, gfRecord); pmxud->mxid = (mmr == MMSYSERR_NOERROR)?uMxID:0; GetDestination(pmxud->mxid, &pmxud->iDest); Volume_EndDialog(pmxud, MIXUI_RESTART, 0); return;
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: //The mixer has to be shutdown now.
//Posting a WM_CLOSE message as Volume_EndDialog does will not help.
if (pmxud->dwFlags & MXUD_FLAGSF_MIXER) Mixer_Shutdown(pmxud); else Nonmixer_Shutdown(pmxud);
//A DBT_DEVICEQUERYREMOVE is not guaranteed before a DBT_DEVICEREMOVECOMPLETE.
//There should be a check here to see if this message is meant for this device.
//We do not know a way of doing that right now.
// Don't attempt restart, just exit. The wavemapper is not
// updated with the new default device, so do not know what
// to restart as and we should NOT hardcode device #0!
// pmxud->mxid = (DWORD) 0;
// GetDestination(pmxud->mxid, &pmxud->iDest);
Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
pmxud->dwDeviceState = V_DC_STATEF_PENDING | V_DC_STATEF_REMOVING; return; case DBT_DEVICEARRIVAL: //
// A devnode is being added to the system
//
pmxud->dwDeviceState = V_DC_STATEF_PENDING | V_DC_STATEF_ARRIVING; return;
default: return; }
mmr = Volume_GetDefaultMixerID(&uMxID, gfRecord);
if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER) { if ( mmr == MMSYSERR_NOERROR && (pmxud->dwDeviceState & V_DC_STATEF_ARRIVING)) { DWORD dwDevNode; if (!mixerMessage((HMIXER)UIntToPtr(uMxID), DRV_QUERYDEVNODE , (DWORD_PTR)&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) { //
// Restart with the default mixer if we can.
//
pmxud->mxid = (mmr == MMSYSERR_NOERROR)?uMxID:0; GetDestination(pmxud->mxid, &pmxud->iDest); Volume_EndDialog(pmxud, MIXUI_RESTART, 0); } pmxud->dwDeviceState = 0L; }
void Volume_OnWakeup( HWND hwnd, WPARAM wParam) { POINT pos; RECT rc, rcPopup; LONG w,h; HWND hTrack; HMONITOR hMonitor; MONITORINFO moninfo;
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.
//
//Get the current position.
GetCursorPos(&pos);
//Get the width and height of the popup.
GetWindowRect(hwnd, &rc); w = rc.right - rc.left; //This value will always be positive as left is always lesser than right.
h = rc.bottom - rc.top; //This value will always be positive as top is always lesser than bottom.
//Initialize the rectangle for the popup. Position it so that the popup appears to the right,
//bottom of the cursor.
rcPopup.left = pos.x; rcPopup.right = pos.x + w; rcPopup.top = pos.y; rcPopup.bottom = pos.y+h;
//Get the rectangle for the monitor.
hMonitor = MonitorFromPoint(pos, MONITOR_DEFAULTTONEAREST); moninfo.cbSize = sizeof(moninfo); GetMonitorInfo(hMonitor,&moninfo);
//If the popup rectangle is leaking off from the right of the screen. Make it appear on the
//left of the cursor.
if(rcPopup.right > moninfo.rcWork.right) { OffsetRect(&rcPopup, -w, 0); }
//If the popup rectangle is leaking off from the bottom of the screen. Make it appear on top
//of the cursor.
if(rcPopup.bottom > moninfo.rcWork.bottom) { OffsetRect(&rcPopup, 0, -h); }
SetWindowPos(hwnd , HWND_TOPMOST , rcPopup.left , rcPopup.top , w , h , SWP_SHOWWINDOW);
// make us come to the front
SetForegroundWindow(hwnd); fCanDismissWindow = TRUE;
hTrack = GetDlgItem(hwnd, IDC_VOLUME); if (hTrack) SetFocus(hTrack); }
/*
* VolumeProc * * */ INT_PTR 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 WM_MENUSELECT: //Keep track of which menu bar item is currently popped up.
//This will be used for displaying the appropriate help from the mplayer.hlp file
//when the user presses the F1 key.
currMenuItem = (UINT)LOWORD(wparam); 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;
FreeAppIcon (); }
/*
* 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; BOOL fAddLine = TRUE;
wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = GetAppIcon (pmxud->hInstance, pmxud->mxid); 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) { HMIXER hmx; MMRESULT mmr;
//
// Mixer API's work much more efficiently with a mixer handle...
//
mmr = mixerOpen(&hmx, pmxud->mxid, 0L, 0L, MIXER_OBJECTF_MIXER);
if(MMSYSERR_NOERROR == mmr) { avcd = Mixer_CreateVolumeDescription((HMIXEROBJ)hmx , pmxud->iDest , &cvcd);
mixerClose(hmx); } else { avcd = Mixer_CreateVolumeDescription((HMIXEROBJ)ULongToPtr(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) { if (!Volume_AddLine(pmxud , lpMaster , cbMaster , MXUL_STYLEF_DESTINATION , &avcd[0])) { return FALSE; } } 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 ) fAddLine = Volume_AddLine(pmxud , lpDst , cbDst , MXUL_STYLEF_DESTINATION , &avcd[ivcd]); else fAddLine = Volume_AddLine(pmxud , lpSrc , cbSrc , MXUL_STYLEF_SOURCE , &avcd[ivcd]);
if (!fAddLine) { return FALSE; } }
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;
if(NULL == pmxud->lpDialog) { Volume_Cleanup(pmxud); return MIXUI_ERROR; }
hdlg = CreateDialogIndirectParam(pmxud->hInstance , (DLGTEMPLATE *)pmxud->lpDialog , NULL , VolumeProc , (LPARAM)(LPVOID)pmxud );
if (!hdlg) { Volume_Cleanup(pmxud); return MIXUI_ERROR; } else { // Unfortunately, re-registering the winclass does not re-apply any
// new icon correctly, so we must explicitly apply it here.
SendMessage (hdlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) GetAppIcon (pmxud->hInstance, pmxud->mxid)); }
ShowWindow(hdlg, pmxud->nShowCmd); } else { return MIXUI_ERROR; }
return (DWORD)(-1); }
void DoHtmlHelp() { //note, using ANSI version of function because UNICODE is foobar in NT5 builds
char chDst[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, gszHtmlHelpFileName, -1, chDst, MAX_PATH, NULL, NULL); HtmlHelpA(GetDesktopWindow(), chDst, HH_DISPLAY_TOPIC, 0); }
void ProcessHelp(HWND hwnd) { static TCHAR HelpFile[] = TEXT("SNDVOL32.HLP");
//Handle context menu help
if(bF1InMenu) { switch(currMenuItem) { case IDM_PROPERTIES: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_OPTIONS_PROPERTIES); break; case IDM_ADVANCED: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_OPTIONS_ADVANCED_CONTROLS); break; case IDM_EXIT: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_OPTIONS_EXIT); break; case IDM_HELPTOPICS: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_HELP_HELP_TOPICS); break; case IDM_HELPABOUT: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_HELP_ABOUT); break; default://In the default case just display the HTML Help.
DoHtmlHelp(); } bF1InMenu = FALSE; //This flag will be set again if F1 is pressed in a menu.
} else DoHtmlHelp(); }
/*
* 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;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)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)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (!(pmxud->dwStyle & MXUD_STYLEF_NOHELP)) WinHelp(hwnd, gszHelpFileName, HELP_QUIT, 0L);
PostQuitMessage(0);
return 0;
case MYWM_HELPTOPICS: //
// F1 Help
//
pmxud = (PMIXUIDIALOG)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (!(pmxud->dwStyle & MXUD_STYLEF_NOHELP)) { ProcessHelp(hwnd); } 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)GetWindowLongPtr(hwnd, GWLP_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; }
return (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; }
/*
* Determines if what the recording destination ID */
HRESULT GetRecordingDestID(int mxid, DWORD *piDest) { HRESULT hr = E_FAIL; DWORD cDest; int iDest; MMRESULT mmr; MIXERCAPS mxcaps;
if (piDest) { *piDest = 0;
mmr = mixerGetDevCaps(mxid, &mxcaps, sizeof(MIXERCAPS));
if (mmr == MMSYSERR_NOERROR) { cDest = mxcaps.cDestinations;
for (iDest = cDest - 1; iDest >= 0; iDest--) { MIXERLINE mlDst;
mlDst.cbStruct = sizeof ( mlDst ); mlDst.dwDestination = iDest;
if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_DESTINATION) != MMSYSERR_NOERROR) continue;
if (Mixer_IsValidRecordingDestination ((HMIXEROBJ)IntToPtr(mxid), &mlDst)) { *piDest = iDest; hr = S_OK; break; } } } }
return(hr);
}
/*------------------------------------------------------+
| HelpMsgFilter - filter for F1 key in dialogs | | | +------------------------------------------------------*/
DWORD FAR PASCAL HelpMsgFilter(int nCode, UINT wParam, DWORD_PTR lParam) { if (nCode >= 0) { LPMSG msg = (LPMSG)lParam;
if (ghwndApp && (msg->message == WM_KEYDOWN) && (msg->wParam == VK_F1)) { if(nCode == MSGF_MENU) bF1InMenu = TRUE; SendMessage(ghwndApp, WM_COMMAND, (WPARAM)IDM_HELPTOPICS, 0L); } } return 0; }
/*
* Returns the correct Destination ID for the specified device ID */
HRESULT GetDestination(DWORD mxid, int *piDest) { if (gfRecord) { return GetDestLineID(mxid,piDest); } else { return GetSrcLineID(mxid,piDest); } }
/*
* Determines line ID */
HRESULT GetDestLineID(int mxid, DWORD *piDest) { HRESULT hr = E_FAIL; MIXERLINE mlDst;
if (piDest) { hr = S_OK; *piDest = 0;
mlDst.cbStruct = sizeof ( mlDst ); mlDst.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR) { *piDest = mlDst.dwDestination; } }
return(hr); }
/*
* Determines line ID */
HRESULT GetSrcLineID(int mxid, DWORD *piDest) { HRESULT hr = E_FAIL; MIXERLINE mlDst;
if (piDest) { hr = S_OK; *piDest = 0;
mlDst.cbStruct = sizeof ( mlDst ); mlDst.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_COMPONENTTYPE ) == MMSYSERR_NOERROR) { *piDest = mlDst.dwDestination; } else { mlDst.cbStruct = sizeof ( mlDst ); mlDst.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_HEADPHONES;
if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_COMPONENTTYPE ) == MMSYSERR_NOERROR) { *piDest = mlDst.dwDestination; } else { mlDst.cbStruct = sizeof ( mlDst ); mlDst.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_COMPONENTTYPE ) == MMSYSERR_NOERROR) { *piDest = mlDst.dwDestination; } } } }
return(hr); }
/* - - - - - - - - - */
/*
* 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]; UINT u; BOOL fGotDevice = FALSE; UINT uDeviceID;
ach[0] = '\0'; // PREFIX complains if we do not init this.
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;
/* setup the message filter to handle grabbing F1 for this task */ fpfnMsgHook = (HOOKPROC)MakeProcInstance((FARPROC)HelpMsgFilter, ghInst); fpfnOldMsgFilter = (HHOOK)SetWindowsHook(WH_MSGFILTER, fpfnMsgHook);
//
// parse the command line for "/T"
//
u = 0;
while (lpCmdLine[u] != '\0') { switch (lpCmdLine[u]) { case TEXT('-'): case TEXT('/'): { u++;
if (lpCmdLine[u] != '\0') { switch (lpCmdLine[u]) { case TEXT('T'): case TEXT('t'): mxud.dwStyle |= MXUD_STYLEF_TRAYMASTER; u++; break;
case TEXT('S'): case TEXT('s'): mxud.dwStyle |= MXUD_STYLEF_SMALL; u++; break;
case TEXT('R'): // Should run in Record mode, not Playback (default)
case TEXT('r'): gfRecord = TRUE; u++; break;
case TEXT('X'): case TEXT('x'): mxud.dwStyle |= MXUD_STYLEF_TRAYMASTER | MXUD_STYLEF_CLOSE; break;
case TEXT('D'): // Should use the specified device
case TEXT('d'): { u++; // Skip "d" and any following spaces
while (lpCmdLine[u] != '\0' && isspace(lpCmdLine[u])) { u++; }
if (lpCmdLine[u] != '\0') { char szDeviceID[255]; UINT uDev = 0;
while ((uDev < 2) && lpCmdLine[u] != '\0' && !isalpha(lpCmdLine[u]) && !isspace(lpCmdLine[u])) { szDeviceID[uDev] = lpCmdLine[u]; u++; uDev++; }
szDeviceID[uDev] = '\0';
uDeviceID = strtoul(szDeviceID,NULL,10);
fGotDevice = TRUE; } } break;
default: // Unknown Command, just ignore it.
u++; break; } } } break;
default: { u++; } 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
//
if (fGotDevice) { UINT cWaves;
if (gfRecord) { cWaves = waveInGetNumDevs(); } else { cWaves = waveOutGetNumDevs(); }
if (uDeviceID >= cWaves) { fGotDevice = FALSE; } }
if (!fGotDevice) { mmr = Volume_GetDefaultMixerID(&mxud.mxid, gfRecord); } else { mxud.mxid = uDeviceID; }
if (gfRecord) { if (FAILED(GetRecordingDestID(mxud.mxid,&mxud.iDest))) { goto mxendapp; } } else { if (FAILED(GetDestination(mxud.mxid,&mxud.iDest))) { goto mxendapp; } }
//
// 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;
if (!LoadString(hInst , IDS_HTMLHELPFILENAME , gszHtmlHelpFileName , SIZEOF(gszHtmlHelpFileName))) 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);
//Initialize the handle which the hook for F1 help will use.
ghwndApp = mxud.hwnd;
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: /* if the message hook was installed, remove it and free */ /* up our proc instance for it. */ if (fpfnOldMsgFilter){ UnhookWindowsHook(WH_MSGFILTER, fpfnMsgHook); } return err; }
void FreeAppIcon () { if (ghiconApp) { DestroyIcon (ghiconApp); ghiconApp = NULL; } }
// TODO: Move to "regstr.h"
#define REGSTR_KEY_BRANDING TEXT("Branding")
#define REGSTR_VAL_AUDIO_BITMAP TEXT("bitmap")
#define REGSTR_VAL_AUDIO_ICON TEXT("icon")
#define REGSTR_VAL_AUDIO_URL TEXT("url")
HKEY OpenDeviceBrandRegKey (UINT uiMixID) {
HKEY hkeyBrand = NULL; HKEY hkeyDevice = OpenDeviceRegKey (uiMixID, KEY_READ);
if (hkeyDevice) { if (ERROR_SUCCESS != RegOpenKeyEx (hkeyDevice, REGSTR_KEY_BRANDING, 0, KEY_READ, &hkeyBrand)) hkeyBrand = NULL; // Make sure NULL on failure
// Close the Device key
RegCloseKey (hkeyDevice); }
return hkeyBrand;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Microsoft Confidential - DO NOT COPY THIS METHOD INTO ANY APPLICATION, THIS MEANS YOU!!!
///////////////////////////////////////////////////////////////////////////////////////////
PTCHAR GetInterfaceName (DWORD dwMixerID) { MMRESULT mmr; ULONG cbSize=0; TCHAR *szInterfaceName=NULL;
//Query for the Device interface name
mmr = mixerMessage(HMIXER_INDEX(dwMixerID), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&cbSize, 0L); if(MMSYSERR_NOERROR == mmr) { szInterfaceName = (TCHAR *)GlobalAllocPtr(GHND, (cbSize+1)*sizeof(TCHAR)); if(!szInterfaceName) { return NULL; }
mmr = mixerMessage(HMIXER_INDEX(dwMixerID), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)szInterfaceName, cbSize); if(MMSYSERR_NOERROR != mmr) { GlobalFreePtr(szInterfaceName); return NULL; } }
return szInterfaceName; }
HKEY OpenDeviceRegKey (UINT uiMixID, REGSAM sam) {
HKEY hkeyDevice = NULL; PTCHAR szInterfaceName = GetInterfaceName (uiMixID);
if (szInterfaceName) { HDEVINFO DeviceInfoSet = SetupDiCreateDeviceInfoList (NULL, NULL);
if (INVALID_HANDLE_VALUE != DeviceInfoSet) { SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; DeviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
if (SetupDiOpenDeviceInterface (DeviceInfoSet, szInterfaceName, 0, &DeviceInterfaceData)) { DWORD dwRequiredSize; SP_DEVINFO_DATA DeviceInfoData; DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
// Ignore error, it always returns "ERROR_INSUFFICIENT_BUFFER" even though
// the "SP_DEVICE_INTERFACE_DETAIL_DATA" parameter is supposed to be optional.
(void) SetupDiGetDeviceInterfaceDetail (DeviceInfoSet, &DeviceInterfaceData, NULL, 0, &dwRequiredSize, &DeviceInfoData); // Open device reg key
hkeyDevice = SetupDiOpenDevRegKey (DeviceInfoSet, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, sam);
} SetupDiDestroyDeviceInfoList (DeviceInfoSet); } GlobalFreePtr (szInterfaceName); }
return hkeyDevice;
}
HICON GetAppIcon (HINSTANCE hInst, UINT uiMixID) {
HKEY hkeyBrand = OpenDeviceBrandRegKey (uiMixID);
FreeAppIcon ();
if (hkeyBrand) { WCHAR szBuffer[MAX_PATH]; DWORD dwType = REG_SZ; DWORD cb = sizeof (szBuffer);
if (ERROR_SUCCESS == RegQueryValueEx (hkeyBrand, REGSTR_VAL_AUDIO_ICON, NULL, &dwType, (LPBYTE)szBuffer, &cb)) { if (REG_SZ == dwType) { WCHAR* pszComma = wcschr (szBuffer, L','); if (pszComma) { WCHAR* pszResourceID = pszComma + 1; HANDLE hResource;
// Remove comma delimeter
*pszComma = L'\0';
// Should be a resource module and a resource ID
hResource = LoadLibrary (szBuffer); if (!hResource) { TCHAR szDriversPath[MAX_PATH];
// If we didn't find it on the normal search path, try looking
// in the "drivers" directory.
if (GetSystemDirectory (szDriversPath, MAX_PATH)) { HRESULT hr = StringCchCat(szDriversPath, SIZEOF(szDriversPath), TEXT("\\drivers\\")); if( hr == S_OK ) { hr = StringCchCat(szDriversPath, SIZEOF(szDriversPath), szBuffer); if( hr == S_OK ) { hResource = LoadLibrary (szDriversPath); } } }
} if (hResource) { ghiconApp = LoadImage (hResource, MAKEINTRESOURCE(_wtoi (pszResourceID)), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); FreeLibrary (hResource); } } else // Should be an *.ico file
ghiconApp = LoadImage (NULL, szBuffer, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); } } RegCloseKey (hkeyBrand);
// Return the custom icon
if (ghiconApp) return ghiconApp; }
return (LoadIcon (hInst, MAKEINTRESOURCE (IDI_MIXER)));
}
|