windows-nt/Source/XPSP1/NT/multimedia/media/sndrec32/soundrec/soundrec.c
2020-09-26 16:20:57 +08:00

1519 lines
36 KiB
C

/* (C) Copyright Microsoft Corporation 1991-1994. All Rights Reserved */
/* SoundRec.c
*
* SoundRec main loop etc.
* Revision History.
* 4/2/91 LaurieGr (AKA LKG) Ported to WIN32 / WIN16 common code
* 21/2/94 LaurieGr Merged Daytona and Motown versions
* LaurieGr Merged common button and trackbar code from StephenE
*/
#undef NOWH // Allow SetWindowsHook and WH_*
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <htmlhelp.h>
#ifdef USE_MMCNTRLS
#include "mmcntrls.h"
#else
#include <commctrl.h>
#include "buttons.h"
#endif
#include <mmreg.h>
#define INCLUDE_OLESTUBS
#include "soundrec.h"
#include "srecids.h"
#include "fixreg.h"
#include "reg.h"
#include "convert.h"
#include "helpids.h"
#include <stdarg.h>
#include <stdio.h>
/* globals */
BOOL gfUserClose; // user-driven shutdown
HWND ghwndApp; // main application window
HINSTANCE ghInst; // program instance handle
TCHAR gachFileName[_MAX_PATH];// current file name (or UNTITLED)
BOOL gfDirty; // file was modified and not saved?
BOOL gfClipboard; // we have data in clipboard
int gfErrorBox; // TRUE if we have a message box active
HICON ghiconApp; // app's icon
HWND ghwndWaveDisplay; // waveform display window handle
HWND ghwndScroll; // scroll bar control window handle
HWND ghwndPlay; // Play button window handle
HWND ghwndStop; // Stop button window handle
HWND ghwndRecord; // Record button window handle
#ifdef THRESHOLD
HWND ghwndSkipStart; // Needed to enable/disable...
HWND ghwndSkipEnd; // ...the skip butons
#endif //THRESHOLD
HWND ghwndForward; // [>>] button
HWND ghwndRewind; // [<<] button
BOOL gfWasPlaying; // was playing before scroll, fwd, etc.
BOOL gfWasRecording; // was recording before scroll etc.
BOOL gfPaused; // are we paused now?
BOOL gfPausing; // are we stopping into a paused state?
HWAVE ghPausedWave; // holder for the paused wave handle
int gidDefaultButton; // which button should have input focus
BOOL gfEmbeddedObject; // Are we editing an embedded object?
BOOL gfRunWithEmbeddingFlag; // TRUE if we are run with "-Embedding"
BOOL gfHideAfterPlaying;
BOOL gfShowWhilePlaying;
BOOL gfInUserDestroy = FALSE;
TCHAR chDecimal = TEXT('.');
BOOL gfLZero = 1; // do we use leading zeros?
BOOL gfIsRTL = 0; // no compile BIDI
UINT guiACMHlpMsg = 0; // help message from ACM, none == 0
//Data used for supporting context menu help
BOOL bF1InMenu=FALSE; //If true F1 was pressed on a menu item.
UINT currMenuItem=0; //The current selected menu item if any.
BITMAPBTN tbPlaybar[] = {
{ ID_REWINDBTN - ID_BTN_BASE, ID_REWINDBTN, 0 }, /* index 0 */
{ ID_FORWARDBTN - ID_BTN_BASE, ID_FORWARDBTN,0 }, /* index 1 */
{ ID_PLAYBTN - ID_BTN_BASE, ID_PLAYBTN, 0 }, /* index 2 */
{ ID_STOPBTN - ID_BTN_BASE, ID_STOPBTN, 0 }, /* index 3 */
{ ID_RECORDBTN - ID_BTN_BASE, ID_RECORDBTN, 0 } /* index 4 */
};
#include <msacmdlg.h>
#ifdef CHICAGO
/* these id's are part of the main windows help file */
#define IDH_AUDIO_CUST_ATTRIB 2403
#define IDH_AUDIO_CUST_FORMAT 2404
#define IDH_AUDIO_CUST_NAME 2405
#define IDH_AUDIO_CUST_REMOVE 2406
#define IDH_AUDIO_CUST_SAVEAS 2407
const DWORD aChooserHelpIds[] = {
IDD_ACMFORMATCHOOSE_CMB_FORMAT, IDH_AUDIO_CUST_ATTRIB,
IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, IDH_AUDIO_CUST_FORMAT,
IDD_ACMFORMATCHOOSE_CMB_CUSTOM, IDH_AUDIO_CUST_NAME,
IDD_ACMFORMATCHOOSE_BTN_DELNAME, IDH_AUDIO_CUST_REMOVE,
IDD_ACMFORMATCHOOSE_BTN_SETNAME, IDH_AUDIO_CUST_SAVEAS,
0, 0
};
UINT guChooserContextMenu = 0;
UINT guChooserContextHelp = 0;
#endif
/*
* constants
*/
SZCODE aszNULL[] = TEXT("");
SZCODE aszClassKey[] = TEXT(".wav");
SZCODE aszIntl[] = TEXT("Intl");
/*
* statics
*/
static HHOOK hMsgHook;
/*
* functions
*/
BOOL SoundRec_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
BOOL SoundRec_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT *lpdis);
void SoundRec_ControlPanel(HINSTANCE hinst, HWND hwnd);
BOOL NEAR PASCAL FreeWaveHeaders(void);
/*
* HelpMsgFilter - filter for F1 key in dialogs
*/
LRESULT CALLBACK
HelpMsgFilter(
int nCode,
WPARAM wParam,
LPARAM lParam)
{
LPMSG msg;
if (nCode >= 0){
msg = (LPMSG)lParam;
if ((msg->message == WM_KEYDOWN) && (LOWORD(msg->wParam) == VK_F1))
{
// testing for <0 tests MSB whether int is 16 or 32 bits
// MSB set means key is down
if (( GetAsyncKeyState(VK_SHIFT)
| GetAsyncKeyState(VK_CONTROL)
| GetAsyncKeyState(VK_MENU)) < 0 )
//
// do nothing
//
;
else
{
if(nCode == MSGF_MENU)
{
bF1InMenu = TRUE;
SendMessage(ghwndApp, WM_COMMAND, IDM_HELPTOPICS, 0L);
}
}
}
}
return CallNextHookEx(hMsgHook, nCode, wParam, lParam);
}
/* WinMain(hInst, hPrev, lpszCmdLine, cmdShow)
*
* The main procedure for the App. After initializing, it just goes
* into a message-processing loop until it gets a WM_QUIT message
* (meaning the app was closed).
*/
int WINAPI // returns exit code specified in WM_QUIT
WinMain(
HINSTANCE hInst, // instance handle of current instance
HINSTANCE hPrev, // instance handle of previous instance
LPSTR lpszCmdLine, // null-terminated command line
int iCmdShow) // how window should be initially displayed
{
HWND hDlg;
MSG rMsg;
//
// save instance handle for dialog boxes
//
ghInst = hInst;
DPF(TEXT("AppInit ...\n"));
//
// call initialization procedure
//
if (!AppInit(hInst, hPrev))
{
DPF(TEXT("AppInit failed\n"));
return FALSE;
}
//
// setup the message filter to handle grabbing F1 for this task
//
hMsgHook = SetWindowsHookEx(WH_MSGFILTER, HelpMsgFilter, ghInst, GetCurrentThreadId());
//
// display "SoundRec" dialog box
//
hDlg = CreateDialogParam( ghInst
, MAKEINTRESOURCE(IDD_SOUNDRECBOX)
, NULL
, SoundRecDlgProc
, iCmdShow );
if (hDlg)
{
//
// Polling messages from event queue
//
while (GetMessage(&rMsg, NULL, 0, 0))
{
if (ghwndApp) {
if (TranslateAccelerator(ghwndApp, ghAccel, &rMsg))
continue;
if (IsDialogMessage(ghwndApp,&rMsg))
continue;
}
TranslateMessage(&rMsg);
DispatchMessage(&rMsg);
}
}
//
// free the current document
//
DestroyWave();
//
// if the message hook was installed, remove it and free
// up our proc instance for it.
//
if (hMsgHook)
{
UnhookWindowsHookEx(hMsgHook);
}
//
// random cleanup
//
DeleteObject(ghbrPanel);
if(gfOleInitialized)
{
FlushOleClipboard();
OleUninitialize();
gfOleInitialized = FALSE;
}
return TRUE;
}
/*
* Process file drop/drag options.
*/
void SoundRec_OnDropFiles(
HWND hwnd,
HDROP hdrop)
{
TCHAR szPath[_MAX_PATH];
if (DragQueryFile(hdrop, (UINT)(-1), NULL, 0) > 0)
{
//
// If user dragged/dropped a file regardless of keys pressed
// at the time, open the first selected file from file
// manager.
//
DragQueryFile(hdrop,0,szPath,SIZEOF(szPath));
SetActiveWindow(hwnd);
ResolveIfLink(szPath);
if (FileOpen(szPath))
{
gfHideAfterPlaying = FALSE;
//
// This is a bit hacked. The Ole caption should just never change.
//
if (gfEmbeddedObject && !gfLinked)
{
LPTSTR lpszObj, lpszApp;
extern void SetOleCaption(LPTSTR lpsz);
DoOleSave();
AdviseSaved();
OleObjGetHostNames(&lpszApp,&lpszObj);
lpszObj = (LPTSTR)FileName((LPCTSTR)lpszObj);
SetOleCaption(lpszObj);
}
PostMessage(ghwndApp, WM_COMMAND, ID_PLAYBTN, 0L);
}
}
DragFinish(hdrop); // Delete structure alocated
}
/* Pause(BOOL fBeginPause)
*
* If <fBeginPause>, then if user is playing or recording do a StopWave().
* The next call to Pause() should have <fBeginPause> be FALSE -- this will
* cause the playing or recording to be resumed (possibly at a new position
* if <glWavePosition> changed.
*/
void
Pause(BOOL fBeginPause)
{
if (fBeginPause) {
if (ghWaveOut != NULL) {
#ifdef NEWPAUSE
gfPausing = TRUE;
gfPaused = FALSE;
ghPausedWave = (HWAVE)ghWaveOut;
#endif
gfWasPlaying = TRUE;
// User intentionally stopped us. Don't go away.
if (gfCloseAtEndOfPlay && IsWindowVisible(ghwndApp))
gfCloseAtEndOfPlay = FALSE;
StopWave();
}
else if (ghWaveIn != NULL) {
#ifdef NEWPAUSE
gfPausing = TRUE;
gfPaused = FALSE;
ghPausedWave = (HWAVE)ghWaveIn;
#endif
gfWasRecording = TRUE;
// User intentionally stopped us. Don't go away.
if (gfCloseAtEndOfPlay && IsWindowVisible(ghwndApp))
gfCloseAtEndOfPlay = FALSE;
StopWave();
}
}
else {
if (gfWasPlaying) {
gfWasPlaying = FALSE;
PlayWave();
#ifdef NEWPAUSE
gfPausing = FALSE;
gfPaused = FALSE;
#endif
}
else if (gfWasRecording) {
gfWasRecording = FALSE;
RecordWave();
#ifdef NEWPAUSE
gfPausing = FALSE;
gfPaused = FALSE;
#endif
}
}
}
void DoHtmlHelp()
{
//note, using ANSI version of function because UNICODE is foobar in NT5 builds
char chDst[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, gachHtmlHelpFile,
-1, chDst, MAX_PATH, NULL, NULL);
HtmlHelpA(GetDesktopWindow(), chDst, HH_DISPLAY_TOPIC, 0L);
}
void ProcessHelp(HWND hwnd)
{
static TCHAR HelpFile[] = TEXT("SOUNDREC.HLP");
//Handle context menu help
if(bF1InMenu)
{
switch(currMenuItem)
{
case IDM_NEW:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_FILE_NEW);
break;
case IDM_OPEN:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_FILE_OPEN);
break;
case IDM_SAVE:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_FILE_SAVE);
break;
case IDM_SAVEAS:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_FILE_SAVE_AS);
break;
case IDM_REVERT:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_FILE_REVERT);
break;
case IDM_PROPERTIES:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_FILE_PROPERTIES);
break;
case IDM_EXIT:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_FILE_EXIT);
break;
case IDM_COPY:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EDIT_COPY);
break;
case IDM_PASTE_INSERT:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EDIT_PASTE_INSERT);
break;
case IDM_PASTE_MIX:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EDIT_PASTE_MIX);
break;
case IDM_INSERTFILE:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EDIT_INSERT_FILE);
break;
case IDM_MIXWITHFILE:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EDIT_MIX_WITH_FILE);
break;
case IDM_DELETEBEFORE:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EDIT_DELETE_BEFORE_CURRENT_POSITION);
break;
case IDM_DELETEAFTER:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EDIT_DELETE_AFTER_CURRENT_POSITION);
break;
case IDM_VOLUME:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EDIT_AUDIO_PROPERTIES);
break;
case IDM_INCREASEVOLUME:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EFFECTS_INCREASE_VOLUME);
break;
case IDM_DECREASEVOLUME:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EFFECTS_DECREASE_VOLUME);
break;
case IDM_MAKEFASTER:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EFFECTS_INCREASE_SPEED);
break;
case IDM_MAKESLOWER:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EFFECTS_DECREASE_SPEED);
break;
case IDM_ADDECHO:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EFFECTS_ADD_ECHO);
break;
case IDM_REVERSE:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_EFFECTS_REVERSE);
break;
case IDM_HELPTOPICS:
case IDM_INDEX:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_HELP_HELP_TOPICS);
break;
case IDM_ABOUT:
WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SOUNDREC_SNDRC_CS_HELP_ABOUT);
break;
default://In the default case just display the HTML Help.
DoHtmlHelp();
}
bF1InMenu = FALSE; //This flag will be set again if F1 is pressed in a menu.
}
else
DoHtmlHelp();
}
/*
* SoundRec_OnCommand
*/
BOOL
SoundRec_OnCommand(
HWND hwnd,
int id,
HWND hwndCtl,
UINT codeNotify)
{
if (gfHideAfterPlaying && id != ID_PLAYBTN)
{
DPF(TEXT("Resetting HideAfterPlaying\n"));
gfHideAfterPlaying = FALSE;
}
switch (id)
{
case IDM_NEW:
if (PromptToSave(FALSE, FALSE) == enumCancel)
return FALSE;
#ifdef CHICAGO
if (FileNew(FMT_DEFAULT,TRUE,FALSE))
#else
if (FileNew(FMT_DEFAULT,TRUE,TRUE))
#endif
{
/* return to being a standalone */
gfHideAfterPlaying = FALSE;
}
break;
case IDM_OPEN:
if (FileOpen(NULL)) {
/* return to being a standalone */
gfHideAfterPlaying = FALSE;
}
if (IsWindowEnabled(ghwndPlay))
{
SetDlgFocus(ghwndPlay);
}
break;
case IDM_SAVE: // also OLE UPDATE
if (!gfEmbeddedObject || gfLinked)
{
if (!FileSave(FALSE))
break;
}
else
{
DoOleSave();
gfDirty = FALSE;
}
break;
case IDM_SAVEAS:
if (FileSave(TRUE))
{
/* return to being a standalone */
gfHideAfterPlaying = FALSE;
}
break;
case IDM_REVERT:
UpdateWindow(hwnd);
// User intentionally stopped us. Don't go away.
if (gfCloseAtEndOfPlay && IsWindowVisible(ghwndApp))
gfCloseAtEndOfPlay = FALSE;
StopWave();
SnapBack();
if (FileRevert())
{
/* return to being a standalone */
gfHideAfterPlaying = FALSE;
}
break;
case IDM_EXIT:
PostMessage(hwnd, WM_CLOSE, 0, 0L);
return TRUE;
case IDCANCEL:
// User intentionally stopped us. Don't go away.
if (gfCloseAtEndOfPlay && IsWindowVisible(ghwndApp))
gfCloseAtEndOfPlay = FALSE;
StopWave();
SnapBack();
break;
case IDM_COPY:
if (!gfOleInitialized)
{
InitializeOle(ghInst);
if (gfStandalone && gfOleInitialized)
CreateStandaloneObject();
}
TransferToClipboard();
gfClipboard = TRUE;
break;
case IDM_PASTE_INSERT:
case IDM_INSERTFILE:
UpdateWindow(hwnd);
// User intentionally stopped us. Don't go away.
if (gfCloseAtEndOfPlay && IsWindowVisible(ghwndApp))
gfCloseAtEndOfPlay = FALSE;
StopWave();
SnapBack();
InsertFile(id == IDM_PASTE_INSERT);
break;
case IDM_PASTE_MIX:
case IDM_MIXWITHFILE:
UpdateWindow(hwnd);
// User intentionally stopped us. Don't go away.
if (gfCloseAtEndOfPlay && IsWindowVisible(ghwndApp))
gfCloseAtEndOfPlay = FALSE;
StopWave();
SnapBack();
MixWithFile(id == IDM_PASTE_MIX);
break;
case IDM_DELETEBEFORE:
UpdateWindow(hwnd);
Pause(TRUE);
DeleteBefore();
Pause(FALSE);
break;
case IDM_DELETE:
if (glWaveSamplesValid == 0L)
return 0L;
glWavePosition = 0L;
// fall through to delete after.
case IDM_DELETEAFTER:
UpdateWindow(hwnd);
Pause(TRUE);
DeleteAfter();
Pause(FALSE);
break;
#ifdef THRESHOLD
// Threshold was an experiment to allow facilities to skip to the start
// of the sound or to the end of the sound. The trouble was that it
// required the ability to detect silence and different sound cards in
// different machines with different background noises gave quite different
// ideas of what counted as silence. Manual control over the threshold level
// did sort-of work but was just too complicated. It really wanted to be
// intuitive or intelligent (or both).
case IDM_SKIPTOSTART:
case ID_SKIPSTARTBTN:
UpdateWindow(hwnd);
Pause(TRUE);
SkipToStart();
Pause(FALSE);
break;
case ID_SKIPENDBTN:
case IDM_SKIPTOEND:
UpdateWindow(hwnd);
Pause(TRUE);
SkipToEnd();
Pause(FALSE);
break;
case IDM_INCREASETHRESH:
IncreaseThresh();
break;
case IDM_DECREASETHRESH:
DecreaseThresh();
break;
#endif //THRESHOLD
case IDM_INCREASEVOLUME:
UpdateWindow(hwnd);
Pause(TRUE);
ChangeVolume(TRUE);
Pause(FALSE);
break;
case IDM_DECREASEVOLUME:
UpdateWindow(hwnd);
Pause(TRUE);
ChangeVolume(FALSE);
Pause(FALSE);
break;
case IDM_MAKEFASTER:
UpdateWindow(hwnd);
Pause(TRUE);
MakeFaster();
Pause(FALSE);
break;
case IDM_MAKESLOWER:
UpdateWindow(hwnd);
Pause(TRUE);
MakeSlower();
Pause(FALSE);
break;
case IDM_ADDECHO:
UpdateWindow(hwnd);
Pause(TRUE);
AddEcho();
Pause(FALSE);
break;
#if defined(REVERB)
case IDM_ADDREVERB:
UpdateWindow(hwnd);
Pause(TRUE);
AddReverb();
Pause(FALSE);
break;
#endif //REVERB
case IDM_REVERSE:
UpdateWindow(hwnd);
Pause(TRUE);
Reverse();
Pause(FALSE);
break;
case IDM_VOLUME:
SoundRec_ControlPanel(ghInst, hwnd);
break;
case IDM_PROPERTIES:
{
WAVEDOC wd;
SGLOBALS sg;
DWORD dw;
wd.pwfx = gpWaveFormat;
wd.pbdata = gpWaveSamples;
wd.cbdata = wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid);
wd.fChanged = FALSE;
wd.pszFileName = (LPTSTR)FileName(gachFileName);
//
// Need to extract these from the file
//
wd.hIcon = NULL;
wd.pszCopyright = gpszInfo;
wd.lpv = &sg;
//
// modify globals w/o returning from prop dialog
//
sg.ppwfx = &gpWaveFormat;
sg.pcbwfx = &gcbWaveFormat;
sg.pcbdata = &dw;
sg.ppbdata = &gpWaveSamples;
sg.plSamplesValid = &glWaveSamplesValid;
sg.plSamples = &glWaveSamples;
sg.plWavePosition = &dw;
SoundRec_Properties(hwnd, ghInst, &wd);
break;
}
#ifndef CHICAGO
case IDM_INDEX:
WinHelp(hwnd, gachHelpFile, HELP_INDEX, 0L);
break;
case IDM_SEARCH:
WinHelp(hwnd, gachHelpFile, HELP_PARTIALKEY,
(DWORD)(LPTSTR)aszNULL);
break;
#else
case IDM_HELPTOPICS:
ProcessHelp(hwnd);
break;
#endif
case IDM_USINGHELP:
WinHelp(hwnd, (LPTSTR)NULL, HELP_HELPONHELP, 0L);
break;
case IDM_ABOUT:
{
LPTSTR lpAbout = NULL;
lpAbout = SoundRec_GetFormatName(gpWaveFormat);
ShellAbout(hwnd,
gachAppTitle,
lpAbout,
(HICON)SendMessage(hwnd, WM_QUERYDRAGICON, 0, 0L));
// , ghiconApp
if (lpAbout)
GlobalFreePtr(lpAbout);
break;
}
case ID_REWINDBTN:
#if 1
//Related to BombayBug 1609
Pause(TRUE);
glWavePosition = 0L;
Pause(FALSE);
UpdateDisplay(FALSE);
#else
//Behave as if the user pressed the 'Home' key
//Call the handler directly
SoundRec_OnHScroll(hwnd,ghwndScroll,SB_TOP,0);
#endif
break;
case ID_PLAYBTN:
// checks for empty file moved to PlayWave in wave.c
// if at end of file, go back to beginning.
if (glWavePosition == glWaveSamplesValid)
glWavePosition = 0;
PlayWave();
break;
case ID_STOPBTN:
// User intentionally stopped us. Don't go away.
if (gfCloseAtEndOfPlay && IsWindowVisible(ghwndApp))
gfCloseAtEndOfPlay = FALSE;
StopWave();
// I added this update because StopWave doesn't call it and
// if you hit stop too quickly, the buttons aren't updated
// Should StopWave() be calling UpdateDisplay()?
UpdateDisplay(TRUE);
SnapBack();
break;
case ID_RECORDBTN:
/* Never let us be forced to quit after recording. */
gfHideAfterPlaying = FALSE;
RecordWave();
break;
case ID_FORWARDBTN:
#if 1
//Bombay bug 1610
//Behave as if the user pressed the 'End' key
Pause(TRUE);
glWavePosition = glWaveSamplesValid;
Pause(FALSE);
UpdateDisplay(FALSE);
#else
//Call the handler directly
SoundRec_OnHScroll(hwnd,ghwndScroll,SB_BOTTOM,0);
#endif
break;
default:
return FALSE;
}
return TRUE;
} /* SoundRec_OnCommand */
/*
* handle WM_INIT from SoundRecDlgProc
*/
void
SoundRec_OnInitMenu(HWND hwnd, HMENU hMenu)
{
BOOL fUntitled; // file is untitled?
UINT mf;
//
// see if we can insert/mix into this file.
//
mf = (glWaveSamplesValid == 0 || IsWaveFormatPCM(gpWaveFormat))
? MF_ENABLED : MF_GRAYED;
EnableMenuItem(hMenu, IDM_INSERTFILE , mf);
EnableMenuItem(hMenu, IDM_MIXWITHFILE , mf);
//
// see if any CF_WAVE data is in the clipboard
//
mf = ( (mf == MF_ENABLED)
&& IsClipboardFormatAvailable(CF_WAVE) //DOWECARE (|| IsClipboardNative())
) ? MF_ENABLED : MF_GRAYED;
EnableMenuItem(hMenu, IDM_PASTE_INSERT, mf);
EnableMenuItem(hMenu, IDM_PASTE_MIX , mf);
//
// see if we can delete before or after the current position.
//
EnableMenuItem(hMenu, IDM_DELETEBEFORE, glWavePosition > 0 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hMenu, IDM_DELETEAFTER, (glWaveSamplesValid-glWavePosition) > 0 ? MF_ENABLED : MF_GRAYED);
//
// see if we can do editing operations on the file.
//
mf = IsWaveFormatPCM(gpWaveFormat) ? MF_ENABLED : MF_GRAYED;
EnableMenuItem(hMenu, IDM_INCREASEVOLUME , mf);
EnableMenuItem(hMenu, IDM_DECREASEVOLUME , mf);
EnableMenuItem(hMenu, IDM_MAKEFASTER , mf);
EnableMenuItem(hMenu, IDM_MAKESLOWER , mf);
EnableMenuItem(hMenu, IDM_ADDECHO , mf);
EnableMenuItem(hMenu, IDM_REVERSE , mf);
/* enable "Revert..." if the file was opened or saved
* (not created using "New") and is currently dirty
* and we're not using an embedded object
*/
fUntitled = (lstrcmp(gachFileName, aszUntitled) == 0);
EnableMenuItem( hMenu,
IDM_REVERT,
(!fUntitled && gfDirty && !gfEmbeddedObject)
? MF_ENABLED : MF_GRAYED);
if (gfHideAfterPlaying) {
DPF(TEXT("Resetting HideAfterPlaying"));
gfHideAfterPlaying = FALSE;
}
} /* SoundRec_OnInitMenu() */
/*
* Handle WM_HSCROLL from SoundRecDlgProc
* */
BOOL
SoundRec_OnHScroll(
HWND hwnd,
HWND hwndCtl,
UINT code,
int pos)
{
BOOL fFineControl;
long lNewPosition; // new position in wave buffer
LONG l;
LONG lBlockInc;
LONG lInc;
fFineControl = (0 > GetKeyState(VK_SHIFT));
if (gfHideAfterPlaying) {
DPF(TEXT("Resetting HideAfterPlaying"));
gfHideAfterPlaying = FALSE;
}
lBlockInc = wfBytesToSamples(gpWaveFormat,gpWaveFormat->nBlockAlign);
switch (code)
{
case SB_LINEUP: // left-arrow
// This is a mess. NT implemented SHIFT and Motown implemented CTRL
// To do about the same thing!!
if (fFineControl)
lNewPosition = glWavePosition - 1;
else {
l = (GetKeyState(VK_CONTROL) < 0) ?
(SCROLL_LINE_MSEC/10) : SCROLL_LINE_MSEC;
lNewPosition = glWavePosition -
MulDiv(l, (long) gpWaveFormat->nSamplesPerSec, 1000L);
}
break;
case SB_PAGEUP: // left-page
// NEEDS SOMETHING SENSIBLE !!! ???
if (fFineControl)
lNewPosition = glWavePosition - 10;
else
lNewPosition = glWavePosition -
MulDiv((long) SCROLL_PAGE_MSEC,
(long) gpWaveFormat->nSamplesPerSec, 1000L);
break;
case SB_LINEDOWN: // right-arrow
if (fFineControl)
lNewPosition = glWavePosition + 1;
else {
l = (GetKeyState(VK_CONTROL) & 0x8000) ?
(SCROLL_LINE_MSEC/10) : SCROLL_LINE_MSEC;
lInc = MulDiv(l, (long) gpWaveFormat->nSamplesPerSec, 1000L);
lInc = (lInc < lBlockInc)?lBlockInc:lInc;
lNewPosition = glWavePosition + lInc;
}
break;
case SB_PAGEDOWN: // right-page
if (fFineControl)
lNewPosition = glWavePosition + 10;
else {
lInc = MulDiv((long) SCROLL_PAGE_MSEC,
(long) gpWaveFormat->nSamplesPerSec, 1000L);
lInc = (lInc < lBlockInc)?lBlockInc:lInc;
lNewPosition = glWavePosition + lInc;
}
break;
case SB_THUMBTRACK: // thumb has been positioned
case SB_THUMBPOSITION: // thumb has been positioned
lNewPosition = MulDiv(glWaveSamplesValid, pos, SCROLL_RANGE);
break;
case SB_TOP: // Home
lNewPosition = 0L;
break;
case SB_BOTTOM: // End
lNewPosition = glWaveSamplesValid;
break;
case SB_ENDSCROLL: // user released mouse button
/* resume playing, if necessary */
Pause(FALSE);
return TRUE;
default:
return TRUE;
}
//
// snap position to nBlockAlign
//
if (lNewPosition != glWaveSamplesValid)
lNewPosition = wfSamplesToSamples(gpWaveFormat,lNewPosition);
if (lNewPosition < 0)
lNewPosition = 0;
if (lNewPosition > glWaveSamplesValid)
lNewPosition = glWaveSamplesValid;
/* if user is playing or recording, pause until scrolling
* is complete
*/
Pause(TRUE);
glWavePosition = lNewPosition;
UpdateDisplay(FALSE);
return TRUE;
} /* SoundRec_OnHScroll() */
/*
* WM_SYSCOLORCHANGE needs to be send to all child windows (esp. trackbars)
*/
void SoundRec_PropagateMessage(
HWND hwnd,
UINT uMessage,
WPARAM wParam,
LPARAM lParam)
{
HWND hwndChild;
for (hwndChild = GetWindow(hwnd, GW_CHILD); hwndChild != NULL;
hwndChild = GetWindow(hwndChild, GW_HWNDNEXT))
{
SendMessage(hwndChild, uMessage, wParam, lParam);
}
}
/* SoundRecDlgProc(hwnd, wMsg, wParam, lParam)
*
* This function handles messages belonging to the main window dialog box.
*/
INT_PTR CALLBACK
SoundRecDlgProc(
HWND hwnd,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (wMsg)
{
case WM_BADREG:
//
// Bad registry entries detected. Clean it up.
//
FixReg(hwnd);
return TRUE;
case WM_COMMAND:
return HANDLE_WM_COMMAND( hwnd, wParam, lParam
, SoundRec_OnCommand );
case WM_INITDIALOG:
//
// Start async registry check.
//
if (!IgnoreRegCheck())
BackgroundRegCheck(hwnd);
//
// restore window position
//
SoundRec_GetSetRegistryRect(hwnd, SGSRR_GET);
return SoundDialogInit(hwnd, (int)lParam);
case WM_SIZE:
return FALSE; // let dialog manager do whatever else it wants
case WM_WININICHANGE:
if (!lParam || !lstrcmpi((LPTSTR)lParam, aszIntl))
if (GetIntlSpecs())
UpdateDisplay(TRUE);
return (TRUE);
case WM_INITMENU:
HANDLE_WM_INITMENU(hwnd, wParam, lParam, SoundRec_OnInitMenu);
return (TRUE);
case WM_PASTE:
UpdateWindow(hwnd);
// User intentionally stopped us. Don't go away.
if (gfCloseAtEndOfPlay && IsWindowVisible(ghwndApp))
gfCloseAtEndOfPlay = FALSE;
StopWave();
SnapBack();
InsertFile(TRUE);
break;
case WM_DRAWITEM:
return HANDLE_WM_DRAWITEM( hwnd, wParam, lParam, SoundRec_OnDrawItem );
case WM_NOTIFY:
{
LPNMHDR pnmhdr;
pnmhdr = (LPNMHDR)lParam;
//
// tooltips notifications
//
switch (pnmhdr->code)
{
case TTN_NEEDTEXT:
{
LPTOOLTIPTEXT lpTt;
lpTt = (LPTOOLTIPTEXT)lParam;
LoadString( ghInst, (UINT)lpTt->hdr.idFrom, lpTt->szText
, SIZEOF(lpTt->szText) );
break;
}
default:
break;
}
break;
}
case WM_HSCROLL:
HANDLE_WM_HSCROLL(hwnd, wParam, lParam, SoundRec_OnHScroll);
return (TRUE);
case WM_SYSCOMMAND:
if (gfHideAfterPlaying)
{
DPF(TEXT("Resetting HideAfterPlaying"));
gfHideAfterPlaying = FALSE;
}
switch (wParam & 0xFFF0)
{
case SC_CLOSE:
PostMessage(hwnd, WM_CLOSE, 0, 0L);
return TRUE;
}
break;
case WM_QUERYENDSESSION:
if (PromptToSave(FALSE, TRUE) == enumCancel)
return TRUE;
SoundRec_GetSetRegistryRect(hwnd, SGSRR_SET);
#if 0 // this is bogus if someone else cancels the shutdown!
ShowWindow(hwnd, SW_HIDE);
#endif
return FALSE;
case WM_SYSCOLORCHANGE:
if (ghbrPanel)
DeleteObject(ghbrPanel);
ghbrPanel = CreateSolidBrush(RGB_PANEL);
SoundRec_PropagateMessage(hwnd, wMsg, wParam, lParam);
break;
case WM_ERASEBKGND:
{
RECT rcClient; // client rectangle
GetClientRect(hwnd, &rcClient);
FillRect((HDC)wParam, &rcClient, ghbrPanel);
return TRUE;
}
case MM_WOM_DONE:
WaveOutDone((HWAVEOUT)wParam, (LPWAVEHDR) lParam);
return TRUE;
case MM_WIM_DATA:
WaveInData((HWAVEIN)wParam, (LPWAVEHDR) lParam);
return TRUE;
case WM_TIMER:
//
// timer message is only used for SYNCRONOUS drivers
//
UpdateDisplay(FALSE);
return TRUE;
case WM_MENUSELECT:
//Keep track of which menu bar item is currently popped up.
//This will be used for displaying the appropriate help from the mplayer.hlp file
//when the user presses the F1 key.
currMenuItem = (UINT)LOWORD(wParam);
return TRUE;
case MM_WIM_CLOSE:
return TRUE;
case WM_CTLCOLORBTN:
case WM_CTLCOLORSTATIC:
{
POINT pt;
pt.x = pt.y = 0;
ClientToScreen((HWND)lParam, &pt);
ScreenToClient(hwnd, &pt);
SetBrushOrgEx((HDC) wParam, -pt.x, -pt.y, NULL);
return (INT_PTR)ghbrPanel;
}
case WM_CLOSE:
if (gfInUserDestroy)
{
DestroyWindow(hwnd);
return TRUE;
}
DPF(TEXT("WM_CLOSE received\n"));
gfUserClose = TRUE;
if (gfHideAfterPlaying)
{
DPF(TEXT("Resetting HideAfterPlaying\n"));
gfHideAfterPlaying = FALSE;
}
if (gfErrorBox) {
// DPF("we have a error box up, ignoring WM_CLOSE.\n");
return TRUE;
}
if (PromptToSave(TRUE, FALSE) == enumCancel)
return TRUE;
//
// Don't free our data before terminating. When the clipboard
// is flushed, we need to commit the data.
//
TerminateServer();
FileNew(FMT_DEFAULT, FALSE, FALSE);
FreeACM();
FreeWaveHeaders();
//
// NOTE: TerminateServer() will destroy the window!
//
SoundRec_GetSetRegistryRect(hwnd, SGSRR_SET);
return TRUE; //!!!
case WM_USER_DESTROY:
DPF(TEXT("WM_USER_DESTROY\n"));
if (ghWaveOut || ghWaveIn) {
DPF(TEXT("Ignoring, we have a device open.\n"));
//
// Close later, when the play finishes.
//
return TRUE;
}
gfInUserDestroy = TRUE;
PostMessage(hwnd, WM_CLOSE, 0, 0);
return TRUE;
case WM_DESTROY:
DPF(TEXT("WM_DESTROY\n"));
WinHelp(hwnd, gachHelpFile, HELP_QUIT, 0L);
ghwndApp = NULL;
//
// Tell my app to die
//
PostQuitMessage(0);
return TRUE;
case WM_DROPFILES:
HANDLE_WM_DROPFILES(hwnd, wParam, lParam, SoundRec_OnDropFiles);
break;
default:
#ifdef CHICAGO
//
// if we have an ACM help message registered see if this
// message is it.
//
if (guiACMHlpMsg && wMsg == guiACMHlpMsg)
{
//
// message was sent from ACM because the user
// clicked on the HELP button on the chooser dialog.
// report help for that dialog.
//
WinHelp(hwnd, gachHelpFile, HELP_CONTEXT, IDM_NEW);
return TRUE;
}
//
// Handle context-sensitive help messages from acm dialog
//
if( wMsg == guChooserContextMenu )
{
WinHelp( (HWND)wParam, NULL, HELP_CONTEXTMENU,
(UINT_PTR)(LPSTR)aChooserHelpIds );
}
else if( wMsg == guChooserContextHelp )
{
WinHelp( ((LPHELPINFO)lParam)->hItemHandle, NULL,
HELP_WM_HELP, (UINT_PTR)(LPSTR)aChooserHelpIds );
}
#endif
break;
}
return FALSE;
} /* SoundRecDlgProc */
/*
* Bitmap Buttons
* */
BOOL SoundRec_OnDrawItem (
HWND hwnd,
const DRAWITEMSTRUCT *lpdis )
{
int i;
i = lpdis->CtlID - ID_BTN_BASE;
if (lpdis->CtlType == ODT_BUTTON ) {
/*
** Now draw the button according to the buttons state information.
*/
tbPlaybar[i].fsState = LOBYTE(lpdis->itemState);
if (lpdis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) {
BtnDrawButton( hwnd, lpdis->hDC, (int)lpdis->rcItem.right,
(int)lpdis->rcItem.bottom,
&tbPlaybar[i] );
return(TRUE);
}
else if (lpdis->itemAction & ODA_FOCUS) {
BtnDrawFocusRect(lpdis->hDC, &lpdis->rcItem, lpdis->itemState);
return(TRUE);
}
}
return(FALSE);
}
/*
* void SoundRec_ControlPanel
*
* Launch "Audio" control panel/property sheet upon request.
*
* */
void SoundRec_ControlPanel(
HINSTANCE hInst,
HWND hParent)
{
const TCHAR gszOpen[] = TEXT("open");
const TCHAR gszRunDLL[] = TEXT("RUNDLL32.EXE");
const TCHAR gszMMSYSCPL[] = TEXT("MMSYS.CPL,ShowAudioPropertySheet");
ShellExecute (NULL, gszOpen, gszRunDLL, gszMMSYSCPL, NULL, SW_SHOWNORMAL);
}
/* ResolveLink
*
* This routine is called when the user drags and drops a shortcut
* onto Media Player. If it succeeds, it returns the full path
* of the actual file in szResolved.
*/
BOOL ResolveLink(LPTSTR szPath, LPTSTR szResolved, LONG cbSize)
{
IShellLink *psl = NULL;
HRESULT hres;
if (!gfOleInitialized)
{
if (!InitializeOle(ghInst))
return FALSE;
}
hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC,
&IID_IShellLink, &psl);
if (SUCCEEDED(hres) && (psl != NULL))
{
IPersistFile *ppf;
psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf);
if (ppf)
{
WCHAR wszPath[MAX_PATH];
#ifdef UNICODE
lstrcpy (wszPath, szPath);
#else
AnsiToUnicodeString(szPath, wszPath, UNKNOWN_LENGTH);
#endif
hres = ppf->lpVtbl->Load(ppf, wszPath, 0);
ppf->lpVtbl->Release(ppf);
if (FAILED(hres))
{
psl->lpVtbl->Release(psl);
psl = NULL;
}
}
else
{
psl->lpVtbl->Release(psl);
psl = NULL;
}
}
if (psl)
{
psl->lpVtbl->Resolve(psl, NULL, SLR_NO_UI);
psl->lpVtbl->GetPath(psl, szResolved, cbSize, NULL, 0);
psl->lpVtbl->Release(psl);
}
return SUCCEEDED(hres);
}
/* ResolveIfLink
*
* Called to check whether a given file name is a shortcut
* on Windows 95.
*
* Copies the resolved file name into the buffer provided,
* overwriting the original name.
*
* Returns TRUE if the function succeeded, whether or not the
* file name was changed. FALSE indicates that an error occurred.
*
* Andrew Bell, 16 February 1995
*/
BOOL ResolveIfLink(PTCHAR szFileName)
{
SHFILEINFO sfi;
BOOL rc = TRUE;
if ((SHGetFileInfo(szFileName, 0, &sfi, sizeof sfi, SHGFI_ATTRIBUTES) == 1)
&& ((sfi.dwAttributes & SFGAO_LINK) == SFGAO_LINK))
{
TCHAR szResolvedLink[MAX_PATH];
if (ResolveLink(szFileName, szResolvedLink, SIZEOF(szResolvedLink)))
lstrcpy(szFileName, szResolvedLink);
else
rc = FALSE;
}
return rc;
}
#if DBG
void FAR cdecl dprintfA(LPSTR szFormat, ...)
{
char ach[128];
int s,d;
va_list va;
va_start(va, szFormat);
s = vsprintf (ach,szFormat, va);
va_end(va);
for (d=sizeof(ach)-1; s>=0; s--)
{
if ((ach[d--] = ach[s]) == '\n')
ach[d--] = '\r';
}
OutputDebugStringA("SNDREC32: ");
OutputDebugStringA(ach+d+1);
}
#ifdef UNICODE
void FAR cdecl dprintfW(LPWSTR szFormat, ...)
{
WCHAR ach[128];
int s,d;
va_list va;
va_start(va, szFormat);
s = vswprintf (ach,szFormat, va);
va_end(va);
for (d=(sizeof(ach)/sizeof(WCHAR))-1; s>=0; s--)
{
if ((ach[d--] = ach[s]) == TEXT('\n'))
ach[d--] = TEXT('\r');
}
OutputDebugStringW(TEXT("SNDREC32: "));
OutputDebugStringW(ach+d+1);
}
#endif
#endif