//==========================================================================; // // 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 #include #include #include #include #include #include #include #include #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()