|
|
//==========================================================================;
//
// 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 (c) 1992 - 1994 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
//
// acmapp.c
//
// Description:
// This is a sample application that demonstrates how to use the
// Audio Compression Manager API's in Windows. This application is
// also useful as an ACM driver test.
//
//==========================================================================;
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <commdlg.h>
#include <shellapi.h>
#include <stdarg.h>
#include <memory.h>
#include <mmreg.h>
#include <msacm.h>
#include "appport.h"
#include "acmapp.h"
#include "debug.h"
//
// globals, no less
//
HINSTANCE ghinst; BOOL gfAcmAvailable; UINT gfuAppOptions = APP_OPTIONSF_AUTOOPEN; HFONT ghfontApp; HACMDRIVERID ghadidNotify;
UINT guWaveInId = (UINT)WAVE_MAPPER; UINT guWaveOutId = (UINT)WAVE_MAPPER;
TCHAR gszNull[] = TEXT(""); TCHAR gszAppProfile[] = TEXT("acmapp.ini"); TCHAR gszYes[] = TEXT("Yes"); TCHAR gszNo[] = TEXT("No");
TCHAR gszAppName[APP_MAX_APP_NAME_CHARS]; TCHAR gszFileUntitled[APP_MAX_FILE_TITLE_CHARS];
TCHAR gszInitialDirOpen[APP_MAX_FILE_PATH_CHARS]; TCHAR gszInitialDirSave[APP_MAX_FILE_PATH_CHARS];
TCHAR gszLastSaveFile[APP_MAX_FILE_PATH_CHARS];
ACMAPPFILEDESC gaafd;
//==========================================================================;
//
// Application helper functions
//
//
//==========================================================================;
//--------------------------------------------------------------------------;
//
// 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.
//
//--------------------------------------------------------------------------;
int FNCGLOBAL AppMsgBox ( HWND hwnd, UINT fuStyle, PTSTR pszFormat, ... ) { va_list va; TCHAR ach[1024]; int n;
//
// format and display the message..
//
va_start(va, pszFormat); #ifdef WIN32
wvsprintf(ach, pszFormat, va); #else
wvsprintf(ach, pszFormat, (LPSTR)va); #endif
va_end(va);
n = MessageBox(hwnd, ach, gszAppName, fuStyle);
return (n); } // AppMsgBox()
//--------------------------------------------------------------------------;
//
// int AppMsgBoxId
//
// Description:
// This function displays a message for the application. The message
// text is retrieved from the string resource table using LoadString.
//
// 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().
//
// UINT uIdsFormat: String resource id to be loaded with LoadString()
// and used a the format string for wvsprintf().
//
// Return (int):
// The return value is the result of MessageBox() if the string
// resource specified by uIdsFormat is valid. The return value is zero
// if the string resource failed to load.
//
//--------------------------------------------------------------------------;
int FNCGLOBAL AppMsgBoxId ( HWND hwnd, UINT fuStyle, UINT uIdsFormat, ... ) { va_list va; TCHAR szFormat[APP_MAX_STRING_RC_CHARS]; TCHAR ach[APP_MAX_STRING_ERROR_CHARS]; int n;
n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat)); if (0 != n) { //
// format and display the message..
//
va_start(va, uIdsFormat); #ifdef WIN32
wvsprintf(ach, szFormat, va); #else
wvsprintf(ach, szFormat, (LPSTR)va); #endif
va_end(va);
n = MessageBox(hwnd, ach, gszAppName, fuStyle); }
return (n); } // AppMsgBoxId()
//--------------------------------------------------------------------------;
//
// 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.
//
//--------------------------------------------------------------------------;
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()
//--------------------------------------------------------------------------;
//
// BOOL AppYield
//
// Description:
// This function yields by dispatching all messages stacked up in the
// application queue.
//
// Arguments:
// HWND hwnd: Handle to main window of application if not yielding
// for a dialog. Handle to dialog box if yielding for a dialog box.
//
// BOOL fIsDialog: TRUE if being called to yield for a dialog box.
//
// Return (BOOL):
// The return value is always TRUE.
//
//--------------------------------------------------------------------------;
BOOL FNGLOBAL AppYield ( HWND hwnd, BOOL fIsDialog ) { MSG msg;
if (fIsDialog) { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if ((NULL == hwnd) || !IsDialogMessage(hwnd, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } else { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
return (TRUE); } // AppYield()
//--------------------------------------------------------------------------;
//
// 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.
//
//--------------------------------------------------------------------------;
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); #ifdef WIN32
n = wvsprintf(ach, pszFormat, va); #else
n = wvsprintf(ach, pszFormat, (LPSTR)va); #endif
va_end(va);
SetWindowText(hwnd, ach);
return (n); } // AppSetWindowText()
//--------------------------------------------------------------------------;
//
// int AppSetWindowTextId
//
// Description:
// This function formats a string and sets the specified window text
// to the result. The format string is extracted from the string
// table using LoadString() on the uIdsFormat argument.
//
// Arguments:
// HWND hwnd: Handle to window to receive the new text.
//
// UINT uIdsFormat: String resource id to be loaded with LoadString()
// and used a the format string for wvsprintf().
//
// Return (int):
// The return value is the number of bytes that the resulting window
// text was. This value is zero if the LoadString() function fails
// for the uIdsFormat argument.
//
//--------------------------------------------------------------------------;
int FNCGLOBAL AppSetWindowTextId ( HWND hwnd, UINT uIdsFormat, ... ) { va_list va; TCHAR szFormat[APP_MAX_STRING_RC_CHARS]; TCHAR ach[APP_MAX_STRING_ERROR_CHARS]; int n;
n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat)); if (0 != n) { //
// format and display the string in the window...
//
va_start(va, uIdsFormat); #ifdef WIN32
n = wvsprintf(ach, szFormat, va); #else
n = wvsprintf(ach, szFormat, (LPSTR)va); #endif
va_end(va);
SetWindowText(hwnd, ach); }
return (n); } // AppSetWindowTextId()
//--------------------------------------------------------------------------;
//
// BOOL AppFormatBigNumber
//
// Description:
//
//
// Arguments:
// LPTSTR pszNumber:
//
// DWORD dw:
//
// Return (BOOL):
//
//--------------------------------------------------------------------------;
BOOL FNGLOBAL AppFormatBigNumber ( LPTSTR pszNumber, DWORD dw ) { //
// this is ugly...
//
//
if (dw >= 1000000000L) { wsprintf(pszNumber, TEXT("%u,%03u,%03u,%03u"), (WORD)(dw / 1000000000L), (WORD)((dw % 1000000000L) / 1000000L), (WORD)((dw % 1000000L) / 1000), (WORD)(dw % 1000)); } else if (dw >= 1000000L) { wsprintf(pszNumber, TEXT("%u,%03u,%03u"), (WORD)(dw / 1000000L), (WORD)((dw % 1000000L) / 1000), (WORD)(dw % 1000)); } else if (dw >= 1000) { wsprintf(pszNumber, TEXT("%u,%03u"), (WORD)(dw / 1000), (WORD)(dw % 1000)); } else { wsprintf(pszNumber, TEXT("%lu"), dw); }
return (TRUE); } // AppFormatBigNumber()
//--------------------------------------------------------------------------;
//
// BOOL AppFormatDosDateTime
//
// Description:
//
//
// Arguments:
// LPTSTR pszDateTime:
//
// UINT uDosDate:
//
// UINT uDosTime:
//
// Return (BOOL):
//
//--------------------------------------------------------------------------;
BOOL FNGLOBAL AppFormatDosDateTime ( LPTSTR pszDateTime, UINT uDosDate, UINT uDosTime ) { static TCHAR szFormatDateTime[] = TEXT("%.02u/%.02u/%.02u %.02u:%.02u:%.02u");
UINT uDateMonth; UINT uDateDay; UINT uDateYear; UINT uTimeHour; UINT uTimeMinute; UINT uTimeSecond;
//
//
//
uTimeHour = uDosTime >> 11; uTimeMinute = (uDosTime & 0x07E0) >> 5; uTimeSecond = (uDosTime & 0x001F) << 1;
uDateMonth = (uDosDate & 0x01E0) >> 5; uDateDay = (uDosDate & 0x001F); uDateYear = (uDosDate >> 9) + 80;
//
//
//
//
wsprintf(pszDateTime, szFormatDateTime, uDateMonth, uDateDay, uDateYear, uTimeHour, uTimeMinute, uTimeSecond);
return (TRUE); } // AppFormatDosDateTime()
//--------------------------------------------------------------------------;
//
// void AcmAppDebugLog
//
// 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.
//
//--------------------------------------------------------------------------;
void FNCGLOBAL AcmAppDebugLog ( PTSTR pszFormat, ... ) { static TCHAR szDebugLogSeparator[] = TEXT("=============================================================================\r\n");
va_list va; TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
//
// !!! UNICODE !!!
//
//
if (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions)) { if (NULL == pszFormat) { OutputDebugString(szDebugLogSeparator); return; }
//
// format and display the string in a message box...
//
va_start(va, pszFormat); #ifdef WIN32
wvsprintf(ach, pszFormat, va); #else
wvsprintf(ach, pszFormat, (LPSTR)va); #endif
va_end(va);
OutputDebugString(ach); } } // AcmAppDebugLog()
//--------------------------------------------------------------------------;
//
// 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).
//
//
//--------------------------------------------------------------------------;
int FNCGLOBAL MEditPrintF ( HWND hedit, PTSTR pszFormat, ... ) { static TCHAR szCRLF[] = TEXT("\r\n");
va_list va; TCHAR ach[APP_MAX_STRING_RC_CHARS]; int n; BOOL fCRLF; BOOL fDebugLog;
//
// default the escapes
//
fCRLF = TRUE; fDebugLog = TRUE;
//
// if the pszFormat argument is NULL, then just clear all text in
// the edit control..
//
if (NULL == pszFormat) { SetWindowText(hedit, gszNull);
AcmAppDebugLog(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); #ifdef WIN32
n = wvsprintf(ach, pszFormat, va); #else
n = wvsprintf(ach, pszFormat, (LPSTR)va); #endif
va_end(va);
Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1); Edit_ReplaceSel(hedit, ach);
if (fDebugLog) { AcmAppDebugLog(ach); }
if (fCRLF) { Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1); Edit_ReplaceSel(hedit, szCRLF);
if (fDebugLog) { AcmAppDebugLog(szCRLF); } }
return (n); } // MEditPrintF()
//--------------------------------------------------------------------------;
//
// BOOL AppGetFileTitle
//
// Description:
// This function extracts the file title from a file path and returns
// it in the caller's specified buffer.
//
// Arguments:
// PTSTR pszFilePath: Pointer to null terminated file path.
//
// PTSTR pszFileTitle: Pointer to buffer to receive the file title.
//
// Return (BOOL):
// Always returns TRUE. But should return FALSE if this function
// checked for bogus values, etc.
//
//
//--------------------------------------------------------------------------;
BOOL FNGLOBAL AppGetFileTitle ( PTSTR pszFilePath, PTSTR pszFileTitle ) { #define IS_SLASH(c) ('/' == (c) || '\\' == (c))
PTSTR pch;
//
// scan to the end of the file path string..
//
for (pch = pszFilePath; '\0' != *pch; pch++) ;
//
// now scan back toward the beginning of the string until a slash (\),
// colon, or start of the string is encountered.
//
while ((pch >= pszFilePath) && !IS_SLASH(*pch) && (':' != *pch)) { pch--; }
//
// finally, copy the 'title' into the destination buffer.. skip ahead
// one char since the above loop steps back one too many chars...
//
lstrcpy(pszFileTitle, ++pch);
return (TRUE); } // AppGetFileTitle()
//--------------------------------------------------------------------------;
//
// BOOL AppGetFileName
//
// Description:
// This function is a wrapper for the Get[Open/Save]FileName commdlg
// chooser dialogs. Based on the fuFlags argument, this function will
// display the appropriate chooser dialog and return the result.
//
// Arguments:
// HWND hwnd: Handle to parent window for chooser dialog.
//
// PTSTR pszFilePath: Pointer to buffer to receive the file path.
//
// PTSTR pszFileTitle: Pointer to buffer to receive the file title.
// This argument may be NULL, in which case no title will be returned.
//
// UINT fuFlags:
//
// Return (BOOL):
// The return value is TRUE if a file was chosen. It is FALSE if the
// user canceled the operation.
//
//
//--------------------------------------------------------------------------;
BOOL FNGLOBAL AppGetFileName ( HWND hwnd, PTSTR pszFilePath, PTSTR pszFileTitle, UINT fuFlags ) { #define APP_OFN_FLAGS_SAVE (OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT)
#define APP_OFN_FLAGS_OPEN (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST)
TCHAR szExtDefault[APP_MAX_EXT_DEFAULT_CHARS]; TCHAR szExtFilter[APP_MAX_EXT_FILTER_CHARS]; OPENFILENAME ofn; BOOL f; PTCHAR pch;
//
// get the extension filter and default extension for this application
//
LoadString(ghinst, IDS_OFN_EXT_DEF, szExtDefault, SIZEOF(szExtDefault)); LoadString(ghinst, IDS_OFN_EXT_FILTER, szExtFilter, SIZEOF(szExtFilter));
//
// NOTE! building the filter string for the OPENFILENAME structure
// is a bit more difficult when dealing with Unicode and C8's new
// optimizer. it joyfully removes literal '\0' characters from
// strings that are concatted together. if you try making each
// string separate (array of pointers to strings), the compiler
// will dword align them... etc, etc.
//
// if you can think of a better way to build the filter string
// for common dialogs and still work in Win 16 and Win 32 [Unicode]
// i'd sure like to hear about it...
//
for (pch = &szExtFilter[0]; '\0' != *pch; pch++) { if ('!' == *pch) *pch = '\0'; }
//
// initialize the OPENFILENAME members
//
memset(&ofn, 0, sizeof(OPENFILENAME));
pszFilePath[0] = '\0'; if (pszFileTitle) pszFileTitle[0] = '\0';
ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = szExtFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0L; ofn.nFilterIndex = 1L; ofn.lpstrFile = pszFilePath; ofn.nMaxFile = APP_MAX_FILE_PATH_CHARS; ofn.lpstrFileTitle = pszFileTitle; ofn.nMaxFileTitle = pszFileTitle ? APP_MAX_FILE_TITLE_CHARS : 0; if (fuFlags & APP_GETFILENAMEF_SAVE) { ofn.lpstrInitialDir = gszInitialDirSave; } else { ofn.lpstrInitialDir = gszInitialDirOpen; } ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = szExtDefault;
//
// if the fuFlags.APP_GETFILENAMEF_SAVE bit is set, then call
// GetSaveFileName() otherwise call GetOpenFileName(). why commdlg was
// designed with two separate functions for save and open only clark
// knows.
//
if (fuFlags & APP_GETFILENAMEF_SAVE) { ofn.Flags = APP_OFN_FLAGS_SAVE; f = GetSaveFileName(&ofn); if (f) { if (NULL != pszFilePath) { lstrcpy(gszInitialDirSave, pszFilePath);
pch = &gszInitialDirSave[lstrlen(gszInitialDirSave) - 1]; for ( ; gszInitialDirSave != pch; pch--) { if ('\\' == *pch) { *pch = '\0'; break; } } } } } else { ofn.Flags = APP_OFN_FLAGS_OPEN; f = GetOpenFileName(&ofn); if (f) { if (NULL != pszFilePath) { lstrcpy(gszInitialDirOpen, pszFilePath);
pch = &gszInitialDirOpen[lstrlen(gszInitialDirOpen) - 1]; for ( ; gszInitialDirOpen != pch; pch--) { if ('\\' == *pch) { *pch = '\0'; break; } } } } }
return (f); } // AppGetFileName()
//--------------------------------------------------------------------------;
//
// BOOL AppTitle
//
// Description:
// This function formats and sets the title text of the application's
// window.
//
// Arguments:
// HWND hwnd: Handle to application window to set title text for.
//
// PTSTR pszFileTitle: Pointer to file title to display.
//
// Return (BOOL):
// The return value is always TRUE.
//
//
//--------------------------------------------------------------------------;
BOOL FNGLOBAL AppTitle ( HWND hwnd, PTSTR pszFileTitle ) { static TCHAR szFormatTitle[] = TEXT("%s - %s");
TCHAR ach[APP_MAX_FILE_PATH_CHARS];
//
// format the title text as 'AppName - FileTitle'
//
wsprintf(ach, szFormatTitle, (LPSTR)gszAppName, (LPSTR)pszFileTitle); SetWindowText(hwnd, ach);
return (TRUE); } // AppTitle()
//--------------------------------------------------------------------------;
//
// BOOL AppFileNew
//
// Description:
// This function is called to handle the IDM_FILE_NEW message. It is
// responsible for clearing the working area for a new unnamed file.
//
// Arguments:
// HWND hwnd: Handle to application window.
//
// PACMAPPFILEDESC paafd: Pointer to current file descriptor.
//
// Return (BOOL):
// The return value is TRUE if the working area was cleared and is
// ready for new stuff. The return value is FALSE if the user canceled
// the operation.
//
//--------------------------------------------------------------------------;
BOOL FNGLOBAL AppFileNew ( HWND hwnd, PACMAPPFILEDESC paafd, BOOL fCreate ) { BOOL f;
if (fCreate) { f = AcmAppFileNew(hwnd, paafd); if (!f) return (FALSE); } else { //
// if there is currently a file path, then we have to do some real
// work...
//
if ('\0' != paafd->szFilePath[0]) { f = AcmAppFileNew(hwnd, paafd); if (!f) return (FALSE); }
//
// blow away the old file path and title; set the window title
// and return success
//
lstrcpy(paafd->szFilePath, gszFileUntitled); lstrcpy(paafd->szFileTitle, gszFileUntitled); }
AppTitle(hwnd, paafd->szFileTitle);
AcmAppDisplayFileProperties(hwnd, paafd);
return (TRUE); } // AppFileNew()
//--------------------------------------------------------------------------;
//
// BOOL AppFileOpen
//
// Description:
// This function handles the IDM_FILE_OPEN message. It is responsible
// for getting a new file name from the user and opening that file
// if possible.
//
// Arguments:
// HWND hwnd: Handle to application window.
//
// PACMAPPFILEDESC paafd: Pointer to current file descriptor.
//
// Return (BOOL):
// The return value is TRUE if a new file was selected and opened.
// It is FALSE if the user canceled the operation.
//
//--------------------------------------------------------------------------;
BOOL FNLOCAL AppFileOpen ( HWND hwnd, PACMAPPFILEDESC paafd ) { TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS]; TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; BOOL f;
//
// first test for a modified file that has not been saved. if the
// return value is FALSE we should cancel the File.Open operation.
//
f = AcmAppFileSaveModified(hwnd, paafd); if (!f) return (FALSE);
//
// get the file name of the new file into temporary buffers (so
// if we fail to open it we can back out cleanly).
//
f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_OPEN); if (!f) return (FALSE);
//!!!
// read the new file...
//
lstrcpy(paafd->szFilePath, szFilePath); lstrcpy(paafd->szFileTitle, szFileTitle);
f = AcmAppFileOpen(hwnd, paafd); if (f) { //
// set the window title text...
//
AppTitle(hwnd, szFileTitle); AcmAppDisplayFileProperties(hwnd, paafd); }
return (f); } // AppFileOpen()
//--------------------------------------------------------------------------;
//
// BOOL AppFileSave
//
// Description:
// This function handles the IDM_FILE_SAVE[AS] messages. It is
// responsible for saving the current file. If a file name needs
// to be specified then the save file dialog is displayed.
//
// Arguments:
// HWND hwnd: Handle to application window.
//
// PACMAPPFILEDESC paafd: Pointer to current file descriptor.
//
// BOOL fSaveAs: TRUE if the save file chooser should be displayed
// before saving the file. FALSE if should operate like File.Save.
//
// Return (BOOL):
// The return value is TRUE if the file was saved. It is FALSE if the
// user canceled the operation or the file does not need saved.
//
//--------------------------------------------------------------------------;
BOOL FNGLOBAL AppFileSave ( HWND hwnd, PACMAPPFILEDESC paafd, BOOL fSaveAs ) { TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS]; TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; BOOL f;
//
//
//
lstrcpy(szFilePath, paafd->szFilePath); lstrcpy(szFileTitle, paafd->szFileTitle);
//
// check if we should bring up the save file chooser dialog...
//
if (fSaveAs || (0 == lstrcmp(paafd->szFileTitle, gszFileUntitled))) { //
// get the file name for saving the data to into temporary
// buffers (so if we fail to save it we can back out cleanly).
//
f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_SAVE); if (!f) return (FALSE); }
//
// save the file...
//
f = AcmAppFileSave(hwnd, paafd, szFilePath, szFileTitle, 0); if (f) { //
// changes have been saved, so clear the modified bit...
//
paafd->fdwState &= ~ACMAPPFILEDESC_STATEF_MODIFIED;
AppTitle(hwnd, paafd->szFileTitle);
AcmAppDisplayFileProperties(hwnd, paafd); }
return (f); } // AppFileSave()
//==========================================================================;
//
// 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.
//
//--------------------------------------------------------------------------;
LRESULT FNLOCAL AppInitMenuPopup ( HWND hwnd, HMENU hmenu, int nItem, BOOL fSysMenu ) { BOOL f; int nSelStart; int nSelEnd; HWND hedit;
DPF(4, "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: EnableMenuItem(hmenu, IDM_FILE_NEW, (UINT)(gfAcmAvailable ? MF_ENABLED : MF_GRAYED));
f = (NULL != gaafd.pwfx); EnableMenuItem(hmenu, IDM_FILE_SNDPLAYSOUND_PLAY, (UINT)(f ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(hmenu, IDM_FILE_SNDPLAYSOUND_STOP, (UINT)(f ? MF_ENABLED : MF_GRAYED));
f = (NULL != gaafd.pwfx) && gfAcmAvailable; EnableMenuItem(hmenu, IDM_FILE_CONVERT, (UINT)(f ? MF_ENABLED : MF_GRAYED));
//
// if the file has been modified, then enable the File.Save
// menu
//
f = (0 != (gaafd.fdwState & ACMAPPFILEDESC_STATEF_MODIFIED)); EnableMenuItem(hmenu, IDM_FILE_SAVE, (UINT)(f ? MF_ENABLED : MF_GRAYED));
// f = (NULL != gaafd.pwfx);
EnableMenuItem(hmenu, IDM_FILE_SAVEAS, (UINT)(f ? MF_ENABLED : MF_GRAYED)); break;
case APP_MENU_ITEM_EDIT: //
// check to see if something is selected in the display
// window and enable/disable Edit menu options appropriately
//
hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY); Edit_GetSelEx(hedit, &nSelStart, &nSelEnd);
f = (nSelStart != nSelEnd); EnableMenuItem(hmenu, WM_COPY, (UINT)(f ? MF_ENABLED : MF_GRAYED)); break;
case APP_MENU_ITEM_VIEW: EnableMenuItem(hmenu, IDM_VIEW_ACM_DRIVERS, (UINT)(gfAcmAvailable ? MF_ENABLED : MF_GRAYED)); break;
case APP_MENU_ITEM_OPTIONS: f = (0 != waveInGetNumDevs()); EnableMenuItem(hmenu, IDM_OPTIONS_WAVEINDEVICE, (UINT)(f ? MF_ENABLED : MF_GRAYED));
f = (0 != waveOutGetNumDevs()); EnableMenuItem(hmenu, IDM_OPTIONS_WAVEOUTDEVICE, (UINT)(f ? MF_ENABLED : MF_GRAYED));
//
// make sure the options that need a checkmark are checked..
//
f = (0 != (APP_OPTIONSF_AUTOOPEN & gfuAppOptions)); CheckMenuItem(hmenu, IDM_OPTIONS_AUTOOPEN, (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
f = (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions)); CheckMenuItem(hmenu, IDM_OPTIONS_DEBUGLOG, (UINT)(f ? MF_CHECKED : MF_UNCHECKED)); 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.
//
//--------------------------------------------------------------------------;
LRESULT FNLOCAL AppCommand ( HWND hwnd, int nId, HWND hwndCtl, UINT uCode ) { BOOL f; DWORD dw; UINT uDevId;
switch (nId) { case IDM_FILE_NEW: AppFileNew(hwnd, &gaafd, TRUE); break;
case IDM_FILE_OPEN: AppFileOpen(hwnd, &gaafd); break;
case IDM_FILE_SAVE: AppFileSave(hwnd, &gaafd, FALSE); break;
case IDM_FILE_SAVEAS: AppFileSave(hwnd, &gaafd, TRUE); break;
case IDM_FILE_SNDPLAYSOUND_PLAY: if (NULL == gaafd.pwfx) { MessageBeep((UINT)-1); break; }
AppHourGlass(TRUE); dw = timeGetTime(); f = sndPlaySound(gaafd.szFilePath, SND_ASYNC | SND_NODEFAULT); dw = timeGetTime() - dw; AppHourGlass(FALSE);
if (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions)) { AcmAppDebugLog(NULL); AcmAppDebugLog(TEXT("sndPlaySound(%s) took %lu milliseconds to %s.\r\n"), (LPTSTR)gaafd.szFilePath, dw, f ? (LPTSTR)TEXT("succeed") : (LPTSTR)TEXT("fail")); } if (!f) { AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION, TEXT("The file '%s' cannot be played by sndPlaySound."), (LPSTR)gaafd.szFilePath); } break;
case IDM_FILE_SNDPLAYSOUND_STOP: sndPlaySound(NULL, 0L); break;
case IDM_FILE_CONVERT: AcmAppFileConvert(hwnd, &gaafd); break;
case IDM_FILE_ABOUT: DialogBox(ghinst, DLG_ABOUT, hwnd, AboutDlgProc); break;
case IDM_FILE_EXIT: FORWARD_WM_CLOSE(hwnd, SendMessage); break;
case WM_COPY: //
// pass on edit messages received to the display window
//
SendMessage(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), nId, 0, 0L); break;
case IDM_EDIT_SELECTALL: Edit_SetSel(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), 0, -1); break;
case IDM_UPDATE: AcmAppFileOpen(hwnd, &gaafd);
AcmAppDisplayFileProperties(hwnd, &gaafd); break;
case IDM_VIEW_SYSTEMINFO: DialogBox(ghinst, DLG_AADETAILS, hwnd, AcmAppSystemInfoDlgProc); break;
case IDM_VIEW_ACM_DRIVERS: DialogBox(ghinst, DLG_AADRIVERS, hwnd, AcmAppDriversDlgProc); break;
case IDM_OPTIONS_WAVEINDEVICE: uDevId = DialogBoxParam(ghinst, DLG_AAWAVEDEVICE, hwnd, AcmAppWaveDeviceDlgProc, MAKELONG((WORD)guWaveInId, TRUE));
if (uDevId != guWaveInId) { guWaveInId = uDevId; AcmAppDisplayFileProperties(hwnd, &gaafd); } break;
case IDM_OPTIONS_WAVEOUTDEVICE: uDevId = DialogBoxParam(ghinst, DLG_AAWAVEDEVICE, hwnd, AcmAppWaveDeviceDlgProc, MAKELONG((WORD)guWaveOutId, FALSE));
if (uDevId != guWaveOutId) { guWaveOutId = uDevId; AcmAppDisplayFileProperties(hwnd, &gaafd); } break;
case IDM_OPTIONS_AUTOOPEN: gfuAppOptions ^= APP_OPTIONSF_AUTOOPEN; break;
case IDM_OPTIONS_DEBUGLOG: gfuAppOptions ^= APP_OPTIONSF_DEBUGLOG; break;
case IDM_OPTIONS_FONT: AcmAppChooseFont(hwnd); break;
case IDM_PLAYRECORD: if (NULL == gaafd.pwfx) { f = AppFileNew(hwnd, &gaafd, TRUE); if (!f) break;
if (NULL == gaafd.pwfx) break; }
f = DialogBoxParam(ghinst, DLG_AAPLAYRECORD, hwnd, AcmAppPlayRecord, (LPARAM)(LPVOID)&gaafd); if (f) { AcmAppFileOpen(hwnd, &gaafd);
AcmAppDisplayFileProperties(hwnd, &gaafd); } break; }
return (0L); } // AppCommand()
//--------------------------------------------------------------------------;
//
// BOOL AcmAppDlgProcDragDropContinue
//
// Description:
//
// 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 (BOOL):
// The return value is specific to the message that was received. For
// the most part, it is FALSE if this dialog procedure does not handle
// a message.
//
//--------------------------------------------------------------------------;
BOOL FNEXPORT AcmAppDlgProcDragDropContinue ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { UINT uId;
switch (uMsg) { case WM_INITDIALOG: AppSetWindowText(hwnd, TEXT("File %u of %u"), LOWORD(lParam), HIWORD(lParam)); return (TRUE);
case WM_COMMAND: uId = GET_WM_COMMAND_ID(wParam, lParam); if ((IDOK == uId) || (IDCANCEL == uId)) { EndDialog(hwnd, uId); } break; }
return (FALSE); } // AcmAppDlgProcDragDropContinue()
//--------------------------------------------------------------------------;
//
// LRESULT AppDropFiles
//
// Description:
// This function handles the WM_DROPFILES message. This message is
// sent when files are 'dropped' on the window from file manager
// (or other drag/drop servers made by ISV's that figured out the
// undocumented internal workings of the SHELL).
//
// A window must be registered to receive these messages either by
// called DragAcceptFiles() or using CreateWindowEx() with the
// WS_EX_ACCEPTFILES style bit.
//
// Arguments:
// HWND hwnd: Handle to window receiving the message.
//
// HDROP hdrop: Handle to drop structure.
//
// Return (LRESULT):
// Returns 0 if the message is processed.
//
//--------------------------------------------------------------------------;
LRESULT FNLOCAL AppDropFiles ( HWND hwnd, HDROP hdrop ) { TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS]; UINT cFiles; UINT u; BOOL f; int n;
//
// first test for a file that has not been saved. if the return
// value is FALSE we should cancel the drop operation.
//
f = AcmAppFileSaveModified(hwnd, &gaafd); if (!f) { goto App_Drop_Files_Exit; }
//
// get number of files dropped on our window
//
cFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
DPF(4, "AppDropFiles(hwnd=%Xh, hdrop=%Xh)--cFiles=%u", hwnd, hdrop, cFiles);
//
// step through each file and stop on the one the user wants or
// the last file (whichever comes first).
//
for (u = 0; u < cFiles; u++) { //
// get the next file name and try to open it--if not a valid
// file, then skip to the next one (if there is one).
//
DragQueryFile(hdrop, u, szFilePath, SIZEOF(szFilePath));
//
// !!! destructive !!!
//
// attempt to open the file
//
lstrcpy(gaafd.szFilePath, szFilePath); lstrcpy(gaafd.szFileTitle, gszNull);
f = AcmAppFileOpen(hwnd, &gaafd); if (!f) { continue; }
AppTitle(hwnd, gaafd.szFileTitle); AcmAppDisplayFileProperties(hwnd, &gaafd);
//
// if this is NOT the last file in the list of files that are
// being dropped on us, then bring up a box asking if we should
// continue or stop where we are..
//
if ((cFiles - 1) != u) { n = DialogBoxParam(ghinst, DLG_AADRAGDROP, hwnd, AcmAppDlgProcDragDropContinue, MAKELPARAM((WORD)(u + 1), (WORD)cFiles)); if (IDCANCEL == n) break; } }
//
// tell the shell to release the memory it allocated for beaming
// the file name(s) over to us... return 0 to show we processed
// the message.
//
App_Drop_Files_Exit:
DragFinish(hdrop); return (0L); } // AppDropFiles()
//--------------------------------------------------------------------------;
//
// 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.
//
//--------------------------------------------------------------------------;
LRESULT FNLOCAL AppSize ( HWND hwnd, UINT fuSizeType, int nWidth, int nHeight ) { HWND hedit; RECT rc;
DPF(4, "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);
//
//
//
GetClientRect(hwnd, &rc); InflateRect(&rc, 1, 1);
hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY); SetWindowPos(hedit, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER);
//
// we processed the message..
//
return (0L); } // AppSize()
//--------------------------------------------------------------------------;
//
// LRESULT AcmAppNotify
//
// Description:
//
//
// Arguments:
//
// Return (LRESULT):
//
//
//--------------------------------------------------------------------------;
LRESULT FNLOCAL AcmAppNotify ( HWND hwnd, WPARAM wParam, LPARAM lParam ) { HWND hwndNext;
DPF(1, "AcmAppNotify: hwnd=%.04Xh, wParam=%.04Xh, lParam2=%.08lXh", hwnd, wParam, lParam);
//
//
//
hwndNext = GetWindow(hwnd, GW_HWNDFIRST); while (NULL != hwndNext) { if (GetParent(hwndNext) == hwnd) { SendMessage(hwndNext, WM_ACMAPP_ACM_NOTIFY, wParam, lParam); }
hwndNext = GetWindow(hwndNext, GW_HWNDNEXT); }
//
// now force an update to our display in case driver [dis/en]able
// changed what is playable/recordable.
//
AcmAppDisplayFileProperties(hwnd, &gaafd);
//
//
//
return (1L); } // AcmAppNotify()
//--------------------------------------------------------------------------;
//
// 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.
//
//--------------------------------------------------------------------------;
LRESULT FNEXPORT 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_WININICHANGE: HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, AppWinIniChange); return (0L);
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_DROPFILES: //
// some windowsx.h files have a messed up message cracker for
// WM_DROPFILES. because this is a sample app, i don't want
// people having trouble with bogus windowsx.h files, so crack
// the message manually... you should use the message cracker
// if you know your windowsx.h file is good.
//
// lr = HANDLE_WM_DROPFILES(hwnd, wParam, lParam, AppDropFiles);
//
lr = AppDropFiles(hwnd, (HDROP)wParam); 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_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 WM_ACMAPP_ACM_NOTIFY: AcmAppNotify(hwnd, wParam, lParam); return (0L); }
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.
//
//--------------------------------------------------------------------------;
int PASCAL WinMain ( HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR pszCmdLine, int nCmdShow ) { int nResult; HWND hwnd; MSG msg; HACCEL haccl;
DbgInitialize(TRUE);
//
// 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()
|