MIXAPP.C

//==========================================================================; 
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright 1993 - 1998 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
//
// mixapp.c
//
//==========================================================================;

#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdarg.h>

#include "mixapp.h"

#include "debug.h"


//
// globals, no less
//
HINSTANCE ghinst;
UINT gfuAppOptions;

TCHAR gszNull[] = TEXT("");
TCHAR gszCRLF[] = TEXT("\r\n");

TCHAR gszAppName[APP_MAX_APP_NAME_CHARS];




//
//
//
PTABBEDLISTBOX gptlbLines;
HMIXER ghmx;



BOOL gfDisplayingControl = FALSE;
DWORD gdwControlID;
HWND ghdlgControl;
MIXERLINE gmxl;
MIXERCONTROL gmxctrl;



//==========================================================================;
//
// Application helper functions
//
//
//==========================================================================;

//--------------------------------------------------------------------------;
//
// void AppHourGlass
//
// Description:
// This function changes the cursor to that of the hour glass or
// back to the previous cursor.
//
// This function can be called recursively.
//
// Arguments:
// BOOL fHourGlass: TRUE if we need the hour glass. FALSE if we need
// the arrow back.
//
// Return (void):
// On return, the cursor will be what was requested.
//
// History:
// 11/ 8/92
//
//--------------------------------------------------------------------------;

void FNGLOBAL AppHourGlass
(
BOOL fHourGlass
)
{
static HCURSOR hcur;
static UINT uWaiting = 0;

if (fHourGlass)
{
if (!uWaiting)
{
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
ShowCursor(TRUE);
}

uWaiting++;
}
else
{
--uWaiting;

if (!uWaiting)
{
ShowCursor(FALSE);
SetCursor(hcur);
}
}
} // AppHourGlass()


//--------------------------------------------------------------------------;
//
// int AppMsgBox
//
// Description:
// This function displays a message for the application in a standard
// message box.
//
// Note that this function takes any valid argument list that can
// be passed to wsprintf. Because of this, the application must
// remember to cast near string pointers to FAR when built for Win 16.
// You will get a nice GP fault if you do not cast them correctly.
//
// Arguments:
// HWND hwnd: Handle to parent window for message box holding the
// message.
//
// UINT fuStyle: Style flags for MessageBox().
//
// PTSTR pszFormat: Format string used for wvsprintf().
//
// Return (int):
// The return value is the result of MessageBox() function.
//
// History:
// 2/13/93
//
//--------------------------------------------------------------------------;

int FNCGLOBAL AppMsgBox
(
HWND hwnd,
UINT fuStyle,
PTSTR pszFormat,
...
)
{
va_list va;
TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
int n;

//
// format and display the message..
//
va_start(va, pszFormat);
wvsprintf(ach, pszFormat, va);
va_end(va);

n = MessageBox(hwnd, ach, gszAppName, fuStyle);

return (n);
} // AppMsgBox()


//--------------------------------------------------------------------------;
//
// int AppSetWindowText
//
// Description:
// This function formats a string and sets the specified window text
// to the result.
//
// Arguments:
// HWND hwnd: Handle to window to receive the new text.
//
// PTSTR pszFormat: Pointer to any valid format for wsprintf.
//
// Return (int):
// The return value is the number of bytes that the resulting window
// text was.
//
// History:
// 2/ 7/93
//
//--------------------------------------------------------------------------;

int FNCGLOBAL AppSetWindowText
(
HWND hwnd,
PTSTR pszFormat,
...
)
{
va_list va;
TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
int n;

//
// format and display the string in the window...
//
va_start(va, pszFormat);
n = wvsprintf(ach, pszFormat, va);
va_end(va);

SetWindowText(hwnd, ach);

return (n);
} // AppSetWindowText()


//--------------------------------------------------------------------------;
//
// void MixAppDebugLog
//
// Description:
// This function logs information to the debugger if the Debug Log
// option is set. You can then run DBWin (or something similar)
// to redirect the output whereever you want. Very useful for debugging
// ACM drivers.
//
// Arguments:
// PTSTR pszFormat: Pointer to any valid format for wsprintf.
//
// Return (void):
// None.
//
// History:
// 2/ 7/93
//
//--------------------------------------------------------------------------;

void FNCGLOBAL MixAppDebugLog
(
PTSTR pszFormat,
...
)
{
static TCHAR szDebugLogSeparator[] = TEXT("=============================================================================\r\n");

va_list va;
TCHAR ach[APP_MAX_STRING_ERROR_CHARS];


//
// !!! UNICODE !!!
//
//
if (0 != (APP_OPTF_DEBUGLOG & gfuAppOptions))
{
if (NULL == pszFormat)
{
OutputDebugString(szDebugLogSeparator);
return;
}

//
// format and display the string in a message box...
//
va_start(va, pszFormat);
wvsprintf(ach, pszFormat, va);
va_end(va);

OutputDebugString(ach);
}
} // MixAppDebugLog()


//--------------------------------------------------------------------------;
//
// int MEditPrintF
//
// Description:
// This function is used to print formatted text into a Multiline
// Edit Control as if it were a standard console display. This is
// a very easy way to display small amounts of text information
// that can be scrolled and copied to the clip-board.
//
// Arguments:
// HWND hedit: Handle to a Multiline Edit control.
//
// PTSTR pszFormat: Pointer to any valid format for wsprintf. If
// this argument is NULL, then the Multiline Edit Control is cleared
// of all text.
//
//
// Return (int):
// Returns the number of characters written into the edit control.
//
// Notes:
// The pszFormat string can contain combinations of escapes that
// modify the default behaviour of this function. Escapes are single
// character codes placed at the _beginning_ of the format string.
//
// Current escapes defined are:
//
// ~ : Suppresses the default CR/LF added to the end of the
// printed line. Since the most common use of this function
// is to output a whole line of text with a CR/LF, that is
// the default.
//
// ` : Suppresses logging to the debug terminal (regardless of
// the global debug log options flag).
//
// History:
// 05/16/93
//
//--------------------------------------------------------------------------;

int FNCGLOBAL MEditPrintF
(
HWND hedit,
PTSTR pszFormat,
...
)
{
va_list va;
TCHAR ach[APP_MAX_STRING_RC_CHARS];
int n;
BOOL fCRLF;
BOOL fDebugLog;

//
// default the escapes
//
fCRLF = TRUE;
fDebugLog = (0 != (APP_OPTF_DEBUGLOG & gfuAppOptions));


//
// if the pszFormat argument is NULL, then just clear all text in
// the edit control..
//
if (NULL == pszFormat)
{
SetWindowText(hedit, gszNull);

if (fDebugLog)
MixAppDebugLog(NULL);

return (0);
}

//
// format and display the string in the window... first search for
// escapes to modify default behaviour.
//
for (;;)
{
switch (*pszFormat)
{
case '~':
fCRLF = FALSE;
pszFormat++;
continue;

case '`':
fDebugLog = FALSE;
pszFormat++;
continue;
}

break;
}

va_start(va, pszFormat);
n = wvsprintf(ach, pszFormat, va);
va_end(va);

Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1);
Edit_ReplaceSel(hedit, ach);

if (fDebugLog)
MixAppDebugLog(ach);

if (fCRLF)
{
Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1);
Edit_ReplaceSel(hedit, gszCRLF);

if (fDebugLog)
MixAppDebugLog(gszCRLF);
}

return (n);
} // MEditPrintF()


//==========================================================================;
//
//
//
//
//==========================================================================;

//--------------------------------------------------------------------------;
//
// HMIXER MixAppNewDevice
//
// Description:
//
//
// Arguments:
// HWND hwnd:
//
// HMIXER hmxCur:
//
// UINT uMxId:
//
// Return (HMIXER):
//
// History:
// 09/25/93
//
//--------------------------------------------------------------------------;

HMIXER FNGLOBAL MixAppNewDevice
(
HWND hwnd,
HMIXER hmxCur,
UINT uMxId
)
{
MMRESULT mmr;
HMIXER hmx;
MIXERCAPS mxcaps;


//
//
//
mmr = mixerGetDevCaps(uMxId, &mxcaps, sizeof(mxcaps));
if (MMSYSERR_NOERROR != mmr)
{
AppMsgBox(NULL, MB_OK | MB_ICONEXCLAMATION,
"mixerGetDevCaps() failed on uMxId=%u, mmr=%u!",
uMxId, mmr);
return (hmxCur);
}


//
//
//
mmr = mixerOpen(&hmx, uMxId, (DWORD)(UINT)hwnd, 0L, CALLBACK_WINDOW);
if (MMSYSERR_NOERROR != mmr)
{
AppMsgBox(NULL, MB_OK | MB_ICONEXCLAMATION,
"mixerOpen() failed on uMxId=%u, mmr=%u!",
uMxId, mmr);
return (hmxCur);
}


if (NULL != hmxCur)
{
mmr = mixerClose(hmxCur);
if (MMSYSERR_NOERROR != mmr)
{
AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
"mixerClose() failed on hmx=%.04Xh, mmr=%u!",
hmxCur, mmr);
}

hmxCur = NULL;
}


AppSetWindowText(hwnd, "Mixer Device: %s", (LPSTR)mxcaps.szPname);

return (hmx);
} // MixAppNewDevice()


//--------------------------------------------------------------------------;
//
// BOOL MixAppDisplayDevCaps
//
// Description:
//
//
// Arguments:
// HWND hedit:
//
// UINT uMxId:
//
// LPMIXERCAPS pmxcaps:
//
// Return (BOOL):
//
// History:
// 09/25/93
//
//--------------------------------------------------------------------------;

BOOL FNLOCAL MixAppDisplayDevCaps
(
HWND hedit,
UINT uMxId,
LPMIXERCAPS pmxcaps
)
{
static TCHAR szDisplayTitle[] = TEXT("[Mixer Device Capabilities]\r\n");

SetWindowRedraw(hedit, FALSE);

//
//
//
MEditPrintF(hedit, NULL);
MEditPrintF(hedit, szDisplayTitle);

MEditPrintF(hedit, "%18s: %u", (LPTSTR)"Device Id", uMxId);

MEditPrintF(hedit, "%18s: %u", (LPTSTR)"Manufacturer Id", pmxcaps->wMid);
MEditPrintF(hedit, "%18s: %u", (LPTSTR)"Product Id", pmxcaps->wPid);
MEditPrintF(hedit, "%18s: %u.%.02u", (LPTSTR)"Driver Version",
(pmxcaps->vDriverVersion >> 8),
(pmxcaps->vDriverVersion & 0x00FF));
MEditPrintF(hedit, "%18s: '%s'", (LPTSTR)"Device Name", (LPSTR)pmxcaps->szPname);
MEditPrintF(hedit, "%18s: %.08lXh", (LPTSTR)"Support Flags", pmxcaps->fdwSupport);
MEditPrintF(hedit, "%18s: %lu", (LPTSTR)"Destinations", pmxcaps->cDestinations);

SetWindowRedraw(hedit, TRUE);

return (TRUE);
} // MixAppDisplayDevCaps()


//--------------------------------------------------------------------------;
//
// BOOL MixAppDlgProcDevice
//
// Description:
//
//
// Arguments:
// HWND hwnd:
//
// UINT uMsg:
//
// WPARAM wParam:
//
// LPARAM lParam:
//
// Return (BOOL):
//
// History:
// 09/25/93
//
//--------------------------------------------------------------------------;

BOOL CALLBACK MixAppDlgProcDevice
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
UINT cMixerDevs;
UINT u;
UINT uMxId;
UINT uId;
UINT uCmd;
HWND hcb;
HWND hedit;
MIXERCAPS mxcaps;

//
//
//
switch (uMsg)
{
case WM_INITDIALOG:
hedit = GetDlgItem(hwnd, IDD_MADEVICE_EDIT_CAPABILITIES);
SetWindowFont(hedit, GetStockFont(SYSTEM_FIXED_FONT), FALSE);

SetWindowLong(hwnd, DWL_USER, lParam);

uMxId = (UINT)lParam;

//
//
//
hcb = GetDlgItem(hwnd, IDD_MADEVICE_COMBO_DEVICE);

cMixerDevs = mixerGetNumDevs();
for (u = 0; u < cMixerDevs; u++)
{
mixerGetDevCaps(u, &mxcaps, sizeof(mxcaps));
ComboBox_AddString(hcb, mxcaps.szPname);

if (uMxId == u)
{
hedit = GetDlgItem(hwnd, IDD_MADEVICE_EDIT_CAPABILITIES);
MixAppDisplayDevCaps(hedit, uMxId, &mxcaps);
}
}

ComboBox_SetCurSel(hcb, uMxId);
return (TRUE);


case WM_COMMAND:
uId = GET_WM_COMMAND_ID(wParam, lParam);

switch (uId)
{
case IDOK:
hcb = GetDlgItem(hwnd, IDD_MADEVICE_COMBO_DEVICE);
uMxId = ComboBox_GetCurSel(hcb);
if (CB_ERR != uMxId)
{
EndDialog(hwnd, uMxId);
break;
}

// -- fall through -- //

case IDCANCEL:
uMxId = (UINT)GetWindowLong(hwnd, DWL_USER);
EndDialog(hwnd, uMxId);
break;


case IDD_MADEVICE_COMBO_DEVICE:
uCmd = GET_WM_COMMAND_CMD(wParam, lParam);
hcb = GET_WM_COMMAND_HWND(wParam, lParam);
switch (uCmd)
{
case CBN_SELCHANGE:
uMxId = ComboBox_GetCurSel(hcb);
if (CB_ERR == uMxId)
break;

mixerGetDevCaps(uMxId, &mxcaps, sizeof(mxcaps));

hedit = GetDlgItem(hwnd, IDD_MADEVICE_EDIT_CAPABILITIES);
MixAppDisplayDevCaps(hedit, uMxId, &mxcaps);
break;
}
}
return (TRUE);
}

return (FALSE);
} // MixAppDlgProcDevice()



//==========================================================================;
//
// Main application window handling code...
//
//
//==========================================================================;

//--------------------------------------------------------------------------;
//
// LRESULT AppInitMenuPopup
//
// Description:
// This function handles the WM_INITMENUPOPUP message. This message
// is sent to the window owning the menu that is going to become
// active. This gives an application the ability to modify the menu
// before it is displayed (disable/add items, etc).
//
// Arguments:
// HWND hwnd: Handle to window that generated the WM_INITMENUPOPUP
// message.
//
// HMENU hmenu: Handle to the menu that is to become active.
//
// int nItem: Specifies the zero-based relative position of the menu
// item that invoked the popup menu.
//
// BOOL fSysMenu: Specifies whether the popup menu is a System menu
// (TRUE) or it is not a System menu (FALSE).
//
// Return (LRESULT):
// Returns zero if the message is processed.
//
// History:
// 1/ 2/93
//
//--------------------------------------------------------------------------;

LRESULT FNLOCAL AppInitMenuPopup
(
HWND hwnd,
HMENU hmenu,
int nItem,
BOOL fSysMenu
)
{
int n;
BOOL f;

DPF(1, "AppInitMenuPopup(hwnd=%Xh, hmenu=%Xh, nItem=%d, fSysMenu=%d)",
hwnd, hmenu, nItem, fSysMenu);

//
// if the system menu is what got hit, succeed immediately... this
// application has no stuff in the system menu.
//
if (fSysMenu)
return (0L);

//
// initialize the menu that is being 'popped up'
//
switch (nItem)
{
case APP_MENU_ITEM_FILE:
f = (0 != mixerGetNumDevs());
EnableMenuItem(hmenu, IDM_FILE_MIXER_DEVICE, (UINT)(f ? MF_ENABLED : MF_GRAYED));

f = (0 != (gfuAppOptions & APP_OPTF_DEBUGLOG));
CheckMenuItem(hmenu, IDM_FILE_DEBUG_LOG, (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
break;

case APP_MENU_ITEM_VIEW:
n = ListBox_GetCurSel(gptlbLines->hlb);
f = (LB_ERR != n);

EnableMenuItem(hmenu, IDM_VIEW_LINE_INFO, (UINT)(f ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hmenu, IDM_VIEW_LINE_CONTROLS, (UINT)(f ? MF_ENABLED : MF_GRAYED));
break;
}

//
// we processed the message--return 0...
//
return (0L);
} // AppInitMenuPopup()


//--------------------------------------------------------------------------;
//
// LRESULT AppCommand
//
// Description:
// This function handles the WM_COMMAND message.
//
// Arguments:
// HWND hwnd: Handle to window receiving the WM_COMMAND message.
//
// int nId: Control or menu item identifier.
//
// HWND hwndCtl: Handle of control if the message is from a control.
// This argument is NULL if the message was not generated by a control.
//
// UINT uCode: Notification code. This argument is 1 if the message
// was generated by an accelerator. If the message is from a menu,
// this argument is 0.
//
// Return (LRESULT):
// Returns zero if the message is processed.
//
// History:
// 11/ 8/92
//
//--------------------------------------------------------------------------;

LRESULT FNLOCAL AppCommand
(
HWND hwnd,
int nId,
HWND hwndCtl,
UINT uCode
)
{
int n;
UINT uMxId;
LRESULT lr;

switch (nId)
{
case IDM_FILE_MIXER_DEVICE:
mixerGetID((HMIXEROBJ)ghmx, &uMxId, MIXER_OBJECTF_HMIXER);
n = DialogBoxParam(ghinst, DLG_MIXAPP_DEVICE, hwnd, (DLGPROC)MixAppDlgProcDevice, uMxId);
if ((UINT)n != uMxId)
{
uMxId = (UINT)n;
ghmx = MixAppNewDevice(hwnd, ghmx, uMxId);

MixAppRefreshLineList(hwnd, gptlbLines);
}
break;

case IDM_FILE_FONT:
MixAppChooseFont(hwnd);
break;

case IDM_FILE_DEBUG_LOG:
gfuAppOptions ^= APP_OPTF_DEBUGLOG;
break;

case IDM_FILE_ABOUT:
DialogBox(ghinst, DLG_ABOUT, hwnd, (DLGPROC)AboutDlgProc);
break;

case IDM_FILE_EXIT:
FORWARD_WM_CLOSE(hwnd, SendMessage);
break;


case IDM_VIEW_LINE_INFO:
n = ListBox_GetCurSel(gptlbLines->hlb);
if (LB_ERR == n)
break;

lr = ListBox_GetItemData(gptlbLines->hlb, n);
DialogBoxParam(ghinst, DLG_LINEINFO, hwnd, (DLGPROC)MixAppDlgProcLineInfo, lr);
break;

case IDM_VIEW_LINE_CONTROLS:
n = ListBox_GetCurSel(gptlbLines->hlb);
if (LB_ERR == n)
break;

lr = ListBox_GetItemData(gptlbLines->hlb, n);
DialogBoxParam(ghinst, DLG_LINECONTROLS, hwnd, (DLGPROC)MixAppDlgProcLineControls, lr);
break;


case IDM_UPDATE:
MixAppRefreshLineList(hwnd, gptlbLines);
break;


case IDD_APP_LIST_LINES:
switch (uCode)
{
case LBN_SELCHANGE:
break;

case LBN_DBLCLK:
n = ListBox_GetCurSel(hwndCtl);
if (LB_ERR == n)
break;

lr = ListBox_GetItemData(hwndCtl, n);
if (GetKeyState(VK_CONTROL) < 0)
{
DialogBoxParam(ghinst, DLG_LINEINFO, hwnd, (DLGPROC)MixAppDlgProcLineInfo, lr);
}
else
{
DialogBoxParam(ghinst, DLG_LINECONTROLS, hwnd, (DLGPROC)MixAppDlgProcLineControls, lr);
}
break;
}
break;
}

return (0L);
} // AppCommand()


//--------------------------------------------------------------------------;
//
// LRESULT AppSize
//
// Description:
// This function handles the WM_SIZE message for the application's
// window. This message is sent to the application window after the
// size has changed (but before it is painted).
//
// Arguments:
// HWND hwnd: Handle to window that generated the WM_SIZE message.
//
// UINT fuSizeType: Specifies the type of resizing requested. This
// argument is one of the following: SIZE_MAXIMIZED, SIZE_MINIMIZED,
// SIZE_RESTORED, SIZE_MAXHIDE, or SIZE_MAXSHOW.
//
// int nWidth: Width of the new client area for the window.
//
// int nHeight: Height of the new client area for the window.
//
// Return (LRESULT):
// Returns zero if the application processes the message.
//
// History:
// 2/ 5/93
//
//--------------------------------------------------------------------------;

LRESULT FNLOCAL AppSize
(
HWND hwnd,
UINT fuSizeType,
int nWidth,
int nHeight
)
{
RECT rc;

DPF(1, "AppSize(hwnd=%Xh, fuSizeType=%u, nWidth=%d, nHeight=%d)",
hwnd, fuSizeType, nWidth, nHeight);

//
// unless this application is the one being resized then don't waste
// time computing stuff that doesn't matter. this applies to being
// minimized also because this application does not have a custom
// minimized state.
//
if ((SIZE_RESTORED != fuSizeType) && (SIZE_MAXIMIZED != fuSizeType))
return (0L);


//
// size the devices listbox to be the total size of the client area--
// inflate the rect by one so borders are not visible. note that
// we need to leave room at the top for the title text which is one
// line of text in height...
//
GetClientRect(hwnd, &rc);
InflateRect(&rc, 1, 1);


TlbMove(gptlbLines, &rc, FALSE);


//
// we processed the message..
//
return (0L);
} // AppSize()


//--------------------------------------------------------------------------;
//
// LRESULT AppPaint
//
// Description:
//
//
// Arguments:
// HWND hwnd:
//
// Return (LRESULT):
//
// History:
// 05/11/93
//
//--------------------------------------------------------------------------;

LRESULT FNLOCAL AppPaint
(
HWND hwnd
)
{
PAINTSTRUCT ps;

//
//
//
BeginPaint(hwnd, &ps);

TlbPaint(gptlbLines, hwnd, ps.hdc);

EndPaint(hwnd, &ps);

//
// we processed the message
//
return (0L);
} // AppPaint()


//--------------------------------------------------------------------------;
//
// LRESULT AppWndProc
//
// Description:
// This is the main application window procedure.
//
// Arguments:
// HWND hwnd: Handle to window.
//
// UINT uMsg: Message being sent to the window.
//
// WPARAM wParam: Specific argument to message.
//
// LPARAM lParam: Specific argument to message.
//
// Return (LRESULT):
// The return value depends on the message that is being processed.
//
// History:
// 11/ 8/92
//
//--------------------------------------------------------------------------;

LRESULT CALLBACK AppWndProc
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
LRESULT lr;

switch (uMsg)
{
case WM_CREATE:
lr = HANDLE_WM_CREATE(hwnd, wParam, lParam, AppCreate);
return (lr);

case WM_INITMENUPOPUP:
HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, AppInitMenuPopup);
return (0L);

case WM_COMMAND:
lr = HANDLE_WM_COMMAND(hwnd, wParam, lParam, AppCommand);
return (lr);

case WM_SIZE:
//
// handle what we want for sizing, and then always call the
// default handler...
//
HANDLE_WM_SIZE(hwnd, wParam, lParam, AppSize);
break;

case WM_PAINT:
HANDLE_WM_PAINT(hwnd, wParam, lParam, AppPaint);
break;

case WM_QUERYENDSESSION:
lr = HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, AppQueryEndSession);
return (lr);

case WM_ENDSESSION:
HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, AppEndSession);
return (0L);

case WM_CLOSE:
HANDLE_WM_CLOSE(hwnd, wParam, lParam, AppClose);
return (0L);

case WM_DESTROY:
PostQuitMessage(0);
return (0L);


case MM_MIXM_LINE_CHANGE:
lr = MixAppLineChange(hwnd, (HMIXER)wParam, lParam);
return (lr);

case MM_MIXM_CONTROL_CHANGE:
lr = MixAppControlChange(hwnd, (HMIXER)wParam, lParam);
return (lr);
}

return (DefWindowProc(hwnd, uMsg, wParam, lParam));
} // AppWndProc()


//==========================================================================;
//
// Main entry and message dispatching code
//
//
//==========================================================================;

//--------------------------------------------------------------------------;
//
// int WinMain
//
// Description:
// This function is called by the system as the initial entry point
// for a Windows application.
//
// Arguments:
// HINSTANCE hinst: Identifies the current instance of the
// application.
//
// HINSTANCE hinstPrev: Identifies the previous instance of the
// application (NULL if first instance). For Win 32, this argument
// is _always_ NULL.
//
// LPSTR pszCmdLine: Points to null-terminated unparsed command line.

//      This string is strictly ANSI regardless of whether the application 
// is built for Unicode. To get the Unicode equivalent call the
// GetCommandLine() function (Win 32 only).
//
// int nCmdShow: How the main window for the application is to be
// shown by default.
//
// Return (int):
// Returns result from WM_QUIT message (in wParam of MSG structure) if
// the application is able to enter its message loop. Returns 0 if
// the application is not able to enter its message loop.
//
// History:
// 11/ 8/92
//
//--------------------------------------------------------------------------;

int PASCAL WinMain
(
HINSTANCE hinst,
HINSTANCE hinstPrev,
LPSTR pszCmdLine,
int nCmdShow
)
{
int nResult;
HWND hwnd;
MSG msg;
HACCEL haccl;

// * * * temp bodge * * *
{
HKEY htemp;
RegOpenKey(HKEY_LOCAL_MACHINE, "A Value That Does Not Exist", &htemp);
}
// * * * * * * * * * * * *

//
// our documentation states that WinMain is supposed to return 0 if
// we do not enter our message loop--so assume the worst...
//
nResult = 0;

//
// make our instance handle global for convenience..
//
ghinst = hinst;

//
// init some stuff, create window, etc.. note the explicit cast of
// pszCmdLine--this is to mute a warning (and an ugly ifdef) when
// compiling for Unicode. see AppInit() for more details.
//
hwnd = AppInit(hinst, hinstPrev, (LPTSTR)pszCmdLine, nCmdShow);
if (hwnd)
{
haccl = LoadAccelerators(hinst, ACCEL_APP);

//
// dispatch messages
//
while (GetMessage(&msg, NULL, 0, 0))
{
//
// do all the special stuff required for this application
// when dispatching messages..
//
if (!TranslateAccelerator(hwnd, haccl, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

//
// return result of WM_QUIT message.
//
nResult = (int)msg.wParam;
}

//
// shut things down, clean up, etc.
//
nResult = AppExit(hinst, nResult);

return (nResult);
} // WinMain()