
/*	Copyright (C) G. Jespersen
	See Licence.txt.*/

// MainFrm.cpp : implementation of the CMainFrame class
//

#include "stdafx.h"
#include "DsLavSplit.h"

#include "MainFrm.h"

#define TIMER_VID_ID		1

// New Static Split
#include "DsLavDoc.h"
#include "DsLavTreeView.h"
#include "DsLavListView.h"

// For GetView()
#include "DsLavSplitterView.h"

// For StartVideoPlayback
#include "DsLavVideoView.h"

// For WM_DEVICECHANGE
#include "Dbt.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMainFrame

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	//{{AFX_MSG_MAP(CMainFrame)
	ON_WM_CREATE()
	ON_WM_TIMER()
	ON_WM_ACTIVATE()
	//}}AFX_MSG_MAP

	// CD inserted.
//	ON_MESSAGE(WM_DEVICECHANGE, OnMyDeviceChange)
	ON_WM_DEVICECHANGE()

	// Control Bar msgs
	//
	// Video callback.
	ON_MESSAGE(WM_USER_VIDEOEVENT, OnVideoEvent)

	// Hide CDsLavSplitterView's left pane - slides it over
	ON_MESSAGE(WM_USER_HIDE_LEFT_PANE, OnHideLeftPane)

	// Activation
//	ON_MESSAGE(WM_USER_SET_ACTIVATE, OnSetActivate)

	// From ControlsBar and ListView.
	ON_MESSAGE(WM_USER_VID_START, OnPlaybackStart)
	ON_MESSAGE(WM_USER_DVD_START, OnPlaybackDvdStart)
	ON_MESSAGE(WM_USER_CD_START,  OnPlaybackCdStart)

	// From ControlsBar.
	ON_MESSAGE(WM_USER_VID_STOP,  OnPlaybackStop)
	ON_MESSAGE(WM_USER_VID_PAUSE, OnPlaybackPause)
	ON_MESSAGE(WM_USER_VID_MUTE,  OnPlaybackMute)
	ON_MESSAGE(WM_USER_VID_VOL,	  OnPlaybackVol)
	ON_MESSAGE(WM_USER_VID_TIME,  OnPlaybackTime)
	ON_MESSAGE(WM_USER_VID_TIME_KEYBOARD,  OnPlaybackTimeKeyboard) // 7/22

	// From RB Update worker thread in CDsLavDoc
	ON_MESSAGE(WM_USER_THREAD_FINISHED, OnUpdateFinished)
	ON_MESSAGE(WM_USER_THREAD_ABORTED, OnUpdateAborted)

END_MESSAGE_MAP()

static UINT indicators[] =
{
	ID_SEPARATOR,           // status line indicator
	ID_INDICATOR_CAPS,
	ID_INDICATOR_NUM,
	ID_INDICATOR_SCRL,
};

/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{
	// Zero Automatic CD playback.
	m_bCdPlaying = FALSE;
	m_curCdTrack = -1;
}

CMainFrame::~CMainFrame()
{
}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	/* No toolbar	
	if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
		!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
	{
		TRACE0("Failed to create toolbar\n");
		return -1;      // fail to create
	}*/

	// Create status bar (hidden at start-up below). 11/22-3
	if (!m_wndStatusBar.Create(this) ||
		!m_wndStatusBar.SetIndicators(indicators,
		  sizeof(indicators)/sizeof(UINT)))
	{
		TRACE0("Failed to create status bar\n");
		return -1;      // fail to create
	}
	/* No toolbar	
	// TODO: Delete these three lines if you don't want the toolbar to
	//  be dockable
	m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
	EnableDocking(CBRS_ALIGN_ANY);
	DockControlBar(&m_wndToolBar);*/

	//////////////////////////////
	// Video Controls Dialog Bar.
	//
	// Create
	if (!m_controlsBar.Create(this,  IDD_CONTROLS_BAR, 
									 WS_TABSTOP			| 
									 CBRS_ALIGN_TOP		|
									 CBRS_GRIPPER		| 
									 CBRS_TOOLTIPS		| 
									 CBRS_FLYBY			|
									 CBRS_SIZE_DYNAMIC,
									 IDD_CONTROLS_BAR)	)
	{
		TRACE(_T("Failed to create m_controlsBar\n"));
		return -1;      // fail to create
	}
	EnableDocking(CBRS_ALIGN_ANY);// need once
	m_controlsBar.EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM);
	DockControlBar(&m_controlsBar);

	// Show ControlsBar.
 	ShowControlBar(&m_controlsBar, TRUE, FALSE);

	// Hide status bar on start. 11/22-3 
 	ShowControlBar(&m_wndStatusBar, FALSE, FALSE);

	return 0;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !CFrameWnd::PreCreateWindow(cs) )
		return FALSE;
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers

// Send Command Messages to inactive views. Enables menu items.
// See CDsLavDoc::RouteCmdToAllViews().
// From Wanderer - Prosise - ch. 11.
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
    // Route to standard command targets first, which includes the active view
    if (CFrameWnd::OnCmdMsg (nID, nCode, pExtra, pHandlerInfo))
        return TRUE;
	
	// Get CDoc.
	CDsLavDoc * pLavDoc = (CDsLavDoc *) GetActiveDocument();

	// If message was not handled, try the inactive views.
	if (pLavDoc != NULL) 
		return pLavDoc->RouteCmdToAllViews(GetActiveView(), nID, nCode, pExtra, pHandlerInfo);

    return FALSE;
}

// Set focus to the VideoView or ListView when activating.
// Can also implement video pause here when deactivating - todo.
void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{
	CFrameWnd::OnActivate(nState, pWndOther, bMinimized);

	// The window is being deactivated
	if(nState == WA_INACTIVE)
	{
	//	HWND hwndView = ((CApp*)AfxGetApp())->m_hwndView;
	//	if(hwndView)
	//		::PostMessage(hwndView, WM_USER_SET_ACTIVATE, 0, 1);
	}
	// The window is being activated.
	else if(nState == WA_ACTIVE || nState == WA_CLICKACTIVE)
	{
		TRACE(_T("CMainFrame::OnActivate - setting focus to view\n"));

		SetFocusToView();
//		HWND hwndView = ((CApp*)AfxGetApp())->m_hwndView;
//		if(hwndView)
//			::PostMessage(hwndView, WM_USER_SET_ACTIVATE, 1, 0);
	}
	
}

// delete rework - used for pausing video when minimizing - todo
// todo -Called via message from CMainFrame::OnActivate().
//  8/22 revised for enter key - not used 
LRESULT CMainFrame::OnSetActivate(WPARAM wParam, LPARAM lParam)	// WM_USER_SET_ACTIVATE
{
	return 0;

	/* todo
	// test 10/04/2020
//	if(!m_pauseActivate) // future user set flag

	// If deactivating, pause the video.
	if(lParam && m_player.IsRunning())
	{
		TRACE(_T("CMainFrame::OnSetActivate - de-activating"));
		ToggleVideoPlaybackPause();
	}
	// If activating, we leave the video paused.
	// OnDraw will repaint.
	else if(wParam && m_player.IsPaused())
	{
		TRACE(_T("CMainFrame::OnSetActivate - activating"));
	}
	return 0;*/
}

// works
// Detect if a CD has been inserted/removed.
BOOL CMainFrame::OnDeviceChange(UINT nEventType, DWORD dwData )
{
	BOOL bReturn = CWnd::OnDeviceChange(nEventType, dwData);

	DEV_BROADCAST_VOLUME * volume = (DEV_BROADCAST_VOLUME *)dwData;
	CString str, drive;
	int inserted = -1;	// 1 inserted, 0 removed

	// Get CDoc.
	CDsLavDoc * pLavDoc = (CDsLavDoc *) GetActiveDocument();
	if(!pLavDoc)
		return bReturn;

	switch(nEventType)
	{
		// CD-USB inserted - 32768
		case DBT_DEVICEARRIVAL: 
		{
			if(volume && volume->dbcv_devicetype == DBT_DEVTYP_VOLUME)
			{
				for(int n = 0; n < 32; n++)
				{
					// Drive E: Inserted - cd  n = 4 dbcv_unitmask = 16
					// Drive H: Inserted - usb n = 7 dbcv_unitmask = 128
					if( (volume->dbcv_unitmask & (1 << n)) )	// 16 cd
					{
						str.Format(_T("Drive %c: Inserted\n"), n + 'A'); //Drive E: Inserted 
						drive.Format(_T("%c:"), n + 'A');
						inserted = 1;
						break;
					}
				}
			}
			break;
		}
		// CD-USB removed - 32772
		case DBT_DEVICEREMOVECOMPLETE:
		{
			if(volume && volume->dbcv_devicetype == DBT_DEVTYP_VOLUME)
			{
				for(int n = 0; n < 32; n++)
				{
					// Drive E: Removed - cd  n = 4 dbcv_unitmask = 16
					// Drive H: Removed - usb n = 7 dbcv_unitmask = 128
					if( (volume->dbcv_unitmask & (1 << n)) )
					{
						str.Format(_T("Drive %c: Removed\n"), n + 'A'); 
						drive.Format(_T("%c:"), n + 'A');
						inserted = 0;
						break;
					}
				}
			}
			break;
		}
		case DBT_DEVNODES_CHANGED: 	// 7 usb - caught above
		case DBT_DEVICETYPESPECIFIC:
		case DBT_CONFIGCHANGED:
		default:
			break;
	}
	if(inserted != -1 && !drive.IsEmpty())
	{
		pLavDoc->DriveDeviceChanged(drive, inserted);
	}
	return bReturn;
}

// Radio Browser Update worker thread message from CDoc.
LRESULT CMainFrame::OnUpdateFinished(WPARAM wParam, LPARAM lParam)	// WM_USER_THREAD_FINISHED
{
	CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;
	if(!pDoc)
		return 0;
	pDoc->UpdateFinished();
	return 0;
}
LRESULT CMainFrame::OnUpdateAborted(WPARAM wParam, LPARAM lParam)	// WM_USER_THREAD_ABORTED
{
	CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;
	if(!pDoc)
		return 0;
	pDoc->UpdateAborted();
	return 0;
}


/////////////////////////////////////////////////////////////////////////////
// CPlayer functions

// Video Playback event callback from CPlayer.
// See: EvCode.h, DVDevCod.h
LRESULT CMainFrame::OnVideoEvent(WPARAM wParam, LPARAM lParam)		// WM_USER_VIDEOEVENT
{
	// CPlayer handles.
	m_player.HandleVideoEvent(this); // 8/22
	return NOERROR;
}

// Controls Bar Vid playback time position handling.
// See ControlsBarEnable()/Disable() below.
// 8/22 rework for menu domain
void CMainFrame::OnTimer(UINT nIDEvent) 
{
	// If playback not stopped and not paused.
	if(m_player.IsRunning())
	{
		//TRACE(_T("CMainFrame::OnTimer\n")); // 8/22

		UINT pos = 0, seconds = 0;

		// If in a DVD menu.
		DVD_DOMAIN domain = m_player.DvdGetCurDomain();
		if(m_player.IsRunningDvd() && domain == DVD_DOMAIN_VideoTitleSetMenu)
		{
			// Zero ControlsBar time slider.
			TRACE(_T("CMainFrame::OnTimer DVD Domain menu\n"));
			PostMessageToControlBar(WM_USER_BAR_TIME, (WPARAM)0, (LPARAM)0);
		}
		// Else normal playback.
		else if(m_player.PlaybackGetCurTime(pos, seconds))
		{
			// Update ControlsBar time slider.
			PostMessageToControlBar(WM_USER_BAR_TIME, (WPARAM)seconds, (LPARAM)pos);
			// Note WPARAM is UINT: 4,294,967,295 / 60 / 60 = 1190 hrs 
		}
	}
	// Base
	CFrameWnd::OnTimer(nIDEvent);
}

// Video playback is starting - set up the Controls Bar.
void CMainFrame::ControlsBarEnable(int volumePercent)		//  11/23-1 int
{
	if(!m_player.IsRunning())
		return;

	// Set a timer for ControlBar vid playback position. 
	// See OnTimer().
	// Update 30 times a second seconds.
	SetTimer(TIMER_VID_ID, 34, NULL);
	SetTimer(TIMER_VID_ID, 1000, NULL); // 8/22

	// Set a timer for ControlBar vid playback position. 
	// See OnTimer().
	// Update once a second.
	SetTimer(TIMER_VID_ID, 1000, NULL); // 8/22

	// Enable controls.
	//PostMessageToControlBar(WM_USER_BAR_START, 0, 0);

	// Enable controls with volume ctrl set to param.	11/23-1
	PostMessageToControlBar(WM_USER_BAR_START, (WPARAM)volumePercent, 0);
}

// Video playback is stopping - disable Controls Bar.
void CMainFrame::ControlsBarDisable()
{
	// Timer off.
	KillTimer(TIMER_VID_ID);

	// Disable controls.
	PostMessageToControlBar(WM_USER_BAR_STOP, 0, 0);
}

//////////////////////////////////////////////////////////////
// CPlayer handlers
//
// Start playback.   11/23-1 update
// Note CPlayer will call CMainFrame::SetVideoWindow() from PlayVideoLav().
// 
// Called from:
//  OnPlaybackStart()
//	CDsLavDoc::OnOpenFile() 
//	CDsLavDoc::OnOpenMediaUrl()
BOOL CMainFrame::StartVideoPlayback(const CString & filePath)
{
	TRACE(_T("In CMainFrame StartVideoPlayback calling CPlayer PlayVideoLav\n"));

	// Get CDoc ptr.
	CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;

	// Clean any current playback. 11/23-1
	if(m_player.IsRunningOrPaused())
	{
		TRACE(_T("In CMainFrame StartVideoPlayback - stopping player.\n"));

		// Update CDoc volume member. - replaces code in CleanPlayback()
		int curVol = m_player.GetVolPercent();
		pDoc->SetPlayerStartVolumePercent(curVol);

		// Clean current playback.
		if(!m_player.StopPlayback())
			return FALSE;
	}
	// Set Player's volume from CDoc volume member. 11/23-1
	int vol = pDoc->GetPlayerStartVolumePercent();
	TRACE(_T("In CMainFrame StartVideoPlayback calling CPlayer SetVolPercent vol= %d\n"), vol);
	m_player.SetVolPercent(vol);

	// Zero any auto CD playback.
	m_bCdPlaying = FALSE;
	m_curCdTrack = -1;
	m_cdFilesAr.RemoveAll();

	// Player calls CMainFrame::SetVideoWindow with stream
	// types and then plays.
	if(m_player.PlayVideoLav(filePath, this))
	{
		// Set controls bar.
		//ControlsBarEnable();
		ControlsBarEnable(vol); //  11/23-1

		// Update Frame Caption.
		//
		// Use file path name.
		if(m_strMediaName == _T(""))
		{
			CString shortName = filePath;
			int len = shortName.ReverseFind('\\');
			if(len)
			{
				shortName.Delete(0, len + 1);
				CString title;
				title.Format(_T("DSLAV:  %s"), shortName);
				SetWindowText(title);
			}
			else
				SetWindowText(_T("DSLAV"));
		}
		// Or use stored name set by caller.
		else
			SetWindowText(m_strMediaName);

		// Set focus to view.
		SetFocusToView();

		return TRUE;
	}
	// If failed, set right pane to Listview.
	else
	{
		TRACE(_T("ERROR In CMainFrame StartVideoPlayback - PlayVideoLav failed - calling replace view\n"));

		// Switch. Ok if already switched.
		CDsLavSplitterView * pSplitterView = GetSplitterView();
		if(pSplitterView->ReplaceView(RUNTIME_CLASS(CDsLavListView)))
		{
			// Set focus to view.
			SetFocusToView();
			return FALSE;
		}
	}
	// Set focus to view.
	SetFocusToView();
	return FALSE;
}

/*
Blu-Ray - todo
add .bdmv and .mpls files to CDsLavDoc::ExtensionValid() and see what happens.

https://en.wikipedia.org/wiki/Blu-ray#Filesystem
https://forum.doom9.org/showthread.php?p=1892829
https://forum.doom9.org/showthread.php?p=1748215

  index.bdmv and MovieObject.bdmv both work)
  \BDMV\MovieObject.bdmv
BluRay (.bdmv and .mpls)
playlist directory?
00802.MPLS english only (german hidden)
00001.M2TS (german and english)
00002.M2TS (english only) 
 index.bdmv or the largest m2ts file
 BluRay playlists (.mpls), as well as the index.bdmv file
 menu m2ts (00000.m2ts)
*/


// Called from:				11/23-1 update
//  OnPlaybackDvdStart()
//	CDsLavDoc::OnOpenMediaFile()
//  CDsLavDoc::OnDvdPlayDvd()
// Example dvdTsPath param: "E:\VIDEO_TS\" - the ROOT directory. 8/22-3
BOOL CMainFrame::StartDvdPlayback(const CString & dvdTsPath)
{
	TRACE(_T("In CMainFrame StartDvdPlayback calling CPlayer PlayDvdLav\n"));

	// Get CDoc ptr.
	CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;

	// Clean any current playback. 11/23-1
	if(m_player.IsRunningOrPaused())
	{
		TRACE(_T("In CMainFrame StartDvdPlayback - stopping player.\n"));

		// Update CDoc volume member.
		int curVol = m_player.GetVolPercent();
		pDoc->SetPlayerStartVolumePercent(curVol);

		// Clean current playback.
		if(!m_player.StopPlayback())
			return FALSE;
	}
	// Set Player's volume from CDoc volume member. 11/23-1
	int vol = pDoc->GetPlayerStartVolumePercent();
	m_player.SetVolPercent(vol);

	// Player calls CMainFrame::SetVideoWindow with stream
	// types and then plays.
	if(m_player.PlayDvdLav(dvdTsPath, this))
	{
		// Set controls bar.
		//ControlsBarEnable();
		ControlsBarEnable(vol);		// 11/23-1

		// Update Frame Caption - todo.
		if(m_strMediaName)
			SetWindowText(m_strMediaName);
		else
			SetWindowText(_T("DSLAV DVD"));

		// Set focus to view.
		SetFocusToView();

		return TRUE;
	}
	// If failed, set right pane to Listview.
	else
	{
		TRACE(_T("ERROR In CMainFrame StartDvdPlayback - PlayDvdLav failed - calling replace view\n"));

		// Switch. Ok if already switched.
		CDsLavSplitterView * pSplitterView = GetSplitterView();
		if(pSplitterView->ReplaceView(RUNTIME_CLASS(CDsLavListView)))
		{
			// Set focus to view.
			SetFocusToView();
			return FALSE;
		}
	}
	// Set focus to view.
	SetFocusToView();
	return FALSE;
}

// Called from:					11/23-1 update 
//  StartCdPlaybackMenu()
//  OnPlaybackCdStart()
//	CDsLavDoc::OnOpenMediaFile() 
//  CDsLavDoc::OnDvdPlayCd()
BOOL CMainFrame::StartCdPlayback(const CString & cdaPath)
{
	TRACE(_T("In CMainFrame StartCdPlayback calling CPlayer PlayCdLav\n"));

	// Get CDoc ptr.
	CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;

	// Clean any current playback. 11/23-1
	if(m_player.IsRunningOrPaused())
	{
		TRACE(_T("In CMainFrame StartCdPlayback - stopping player.\n"));

		// Update CDoc volume member.
		int curVol = m_player.GetVolPercent();
		pDoc->SetPlayerStartVolumePercent(curVol);

		// Clean current playback.
		if(!m_player.StopPlayback())
			return FALSE;
	}
	// Set Player's volume from CDoc volume member. 11/23-1
	int vol = pDoc->GetPlayerStartVolumePercent();
	m_player.SetVolPercent(vol);

	// Player calls CMainFrame::SetVideoWindow with stream
	// types and then plays.
	if(m_player.PlayCdLav(cdaPath, this))
	{
		// Set controls bar.
		//ControlsBarEnable();
		ControlsBarEnable(vol);		// 11/23-1

		// Update Frame Caption. 8/22-3
		//
		// Use file path name.
		if(m_strMediaName == _T(""))
		{
			CString shortName = cdaPath;
			int len = shortName.ReverseFind('\\');
			if(len)
			{
				shortName.Delete(0, len + 1);
				CString title;
				title.Format(_T("DsLav CD:  %s"), shortName);
				SetWindowText(title);
			}
			else
				SetWindowText(_T("DsLav CD"));
		}
		// Else use stored name set by caller.
		else
			SetWindowText(m_strMediaName);

		// Set focus to view.
		SetFocusToView();

		return TRUE;
	}
	// If failed, set right pane to Listview.
	else
	{
		TRACE(_T("ERROR In CMainFrame StartCdPlayback - PlayCdLav failed - calling replace view\n"));

		// Switch. Ok if already switched.
		CDsLavSplitterView * pSplitterView = GetSplitterView();
		if(pSplitterView->ReplaceView(RUNTIME_CLASS(CDsLavListView)))
		{
			// Set focus to view.
			SetFocusToView();
			return FALSE;
		}
	}
	// Set focus to view.
	SetFocusToView();
	return FALSE;
}

// Called only from StopVideoPlayback(). 11/23-1 
// See notes in OnPlaybackCdStart(). 
BOOL CMainFrame::ContinueCdPlayback()
{
	TRACE(_T("Entering CMainFrame ContinueCdPlayback.\n"));
	int sz = m_cdFilesAr.GetSize();

	// Should be playing (track has completed).
	BOOL playing = m_player.IsRunningOrPaused();

	// If the next track should be played.
	if(playing && m_bCdPlaying && sz && 
	   m_curCdTrack != -1 && m_curCdTrack + 1 < sz)
	{
		// Increment.
		m_curCdTrack ++;

		// Get path.
		CString cdaPath = m_cdFilesAr[m_curCdTrack];

		// Get CDoc ptr.  11/23-1
		CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;

		// Get current volume for use below.
		int	curVolPercent = m_player.GetVolPercent();	// 0 - 100
		if(curVolPercent < 0 || curVolPercent > 100)
			curVolPercent = 50;

		// Clean any current playback.
		if(m_player.IsRunningOrPaused())
		{
			TRACE(_T("In CMainFrame ContinueCdPlayback - stopping player.\n"));

			// Clean current playback.
			//  Note - this sets the player volume to default 50%.
			if(!m_player.StopPlayback())
				return FALSE;
		}
		// Set Player's volume to same as last track.
		m_player.SetVolPercent(curVolPercent);

		// Update the CDoc volume member - volume saved only 
		// when the CDoc::m_bUseLastVol member is set.
		pDoc->SetPlayerStartVolumePercent(curVolPercent);

		// Note ControlsBarEnable() was called for the 
		// first track played, and We leave it enabled.

		// Run the new track.
		if(m_player.PlayCdLav(cdaPath, this, curVolPercent))
		{
			// Update Frame Caption. 8/22-3
			CString title;
			CString shortName = cdaPath;
			int len = shortName.ReverseFind('\\');
			if(len)
			{
				shortName.Delete(0, len + 1);
				title.Format(_T("DsLav CD:  %s"), shortName);				
			}
			else
				title.Format(_T("DsLav CD:  %s"), cdaPath);				
			SetWindowText(title);

			// Set focus to view.
			SetFocusToView();
			return TRUE;
		}
		else
		{
			TRACE(_T("CMainFrame ContinueCdPlayback PlayCdLav failed, calling replace view\n"));

			// Switch. Ok if already switched.
			CDsLavSplitterView * pSplitterView = GetSplitterView();
			if(pSplitterView->ReplaceView(RUNTIME_CLASS(CDsLavListView)))
			{
				// Set focus to view.
				SetFocusToView();
				return FALSE;
			}
		}
	}
	// Else shut down auto CD Playback and stop the Player.
	else
	{
		// Zero.
		m_bCdPlaying = FALSE;
		m_curCdTrack = -1;
		m_cdFilesAr.RemoveAll();

		// Stop.
		//  Note StopVideoPlayback() updates the CDoc volume.
		StopVideoPlayback();
		return true;
	}
	return FALSE;
}

// Called only from override of:
//	CPlayer::PlayVideoLav()
// to set up the Video Window per available streams.
//
// The ListView is used for audio only streams, and 
// the VideoView otherwise.
BOOL CMainFrame::SetVideoWindow(BOOL hasVideoStream, BOOL hasAudioStream,
								HWND & hwndVideo, HWND & hwndEvents, CRect & videoRect)
{
	TRACE(_T("In CMainFrame::SetVideoWindow hasVideoStream = %d, hasAudioStream = %d\n"),
			hasVideoStream, hasAudioStream);
	//
	// Note hwndVideo sends messages to CPlayer, and hwndEvents recieves
	//		messages from CPlayer.
	//
	// Ensure a stream.
	if(!hasVideoStream && !hasAudioStream)
	{
		TRACE(_T("ERROR CMainFrame SetVideoWindow - no audio or video stream.\n"));
		return FALSE;
	}
	// Set right pane to VideoView if hasVideoStream is true.
	if(hasVideoStream)
	{
		CDsLavSplitterView * pSplitterView = GetSplitterView();
		if(!pSplitterView)
		{
			TRACE(_T("ERROR CMainFrame SetVideoWindow - pSplitterView NULL\n"));
			AfxMessageBox(_T("ERROR Video Window not accessable."));
			return FALSE;
		}
		if(!pSplitterView->ReplaceView(RUNTIME_CLASS(CDsLavVideoView)))
		{
			TRACE(_T("ERROR CMainFrame SetVideoWindow - could not create VideoView Window.\n"));
			AfxMessageBox(_T("ERROR could not create VideoView Window"));
			return FALSE;
		}
		// Set hwndVideo param to right pane VideoView.
		hwndVideo = ((CDsLavApp*)AfxGetApp())->m_hwndVideoView;
		if(!hwndVideo)
		{
			TRACE(_T("ERROR In CMainFrame SetVideoWindow - no right pane VideoView HWND\n"));
			AfxMessageBox(_T("VideoView Window not created."));
			return FALSE;
		}
		// Set VideoView client rect param.
		if( !::GetClientRect(hwndVideo, &videoRect))
		{
			TRACE(_T("ERROR In CMainFrame SetVideoWindow - no VideoView rect\n"));
			AfxMessageBox(_T("VideoView Window area not available."));
			return FALSE;
		}
	}
	// Else use existing ListView window for audio only.
	else
	{
		// Set hwndVideo param to right pane ListView.
		hwndVideo = ((CDsLavApp*)AfxGetApp())->m_hwndListView;
		if(!hwndVideo)
		{
			TRACE(_T("ERROR In CMainFrame SetVideoWindow - no right pane ListView HWND\n"));
			AfxMessageBox(_T("ListView Video Window not available."));
			return FALSE;
		}
		// Set ListView client rect param.
		if( !::GetClientRect(hwndVideo, &videoRect))
		{
			TRACE(_T("ERROR In CMainFrame SetVideoWindow - no ListView rect\n"));
			AfxMessageBox(_T("ListView Window area not available."));
			return FALSE;
		}
	}
	// Set video events param to CMainFrame - for video events and msg boxes.
	hwndEvents = GetSafeHwnd();

	//dbg
	//CString msg;
	//msg.Format(_T("hasVideoStream = %d, hasAudioStream = %d"), hasVideoStream, hasAudioStream);
	//AfxMessageBox(msg);

	// Good.
	return TRUE;
}

// Get ptr to CDsLavSplitterView
CDsLavSplitterView * CMainFrame::GetSplitterView()
{
	if(	((CDsLavApp*)AfxGetApp())->m_pSplitterView == NULL)
	{
		TRACE(_T("ERROR In CMainFrame::GetSplitterView - App's m_pSplitterView is NULL.\n"));
		return NULL;
	}
	// OK.
	return ((CDsLavApp*)AfxGetApp())->m_pSplitterView;
}

// Stop playback - called from:
//  ControlsBar via OnPlaybackStop()
//	CMainFrame::OnVideoEvent().
//	CDsLavDoc::OnCloseDocument()
//	CDsLavDoc::DriveDeviceChanged()
void CMainFrame::StopVideoPlayback(BOOL isVideoEvent /*= FALSE*/)
{
	// If playing.
	if(m_player.IsRunningOrPaused())
	{
		// If a CD Audio track has completed - CD Auto Play.
		if(isVideoEvent && m_bCdPlaying)
		{
			ContinueCdPlayback();
			return;
		}
		TRACE(_T("In CMainFrame StopVideoPlayback calling m_player StopPlayback\n"));

		// Update CDoc volume member.  11/23-1
		CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;
		int curVol = m_player.GetVolPercent();
		pDoc->SetPlayerStartVolumePercent(curVol);

		// Zero CD Auto Play.
		m_bCdPlaying = FALSE;
		m_curCdTrack = -1;
		m_cdFilesAr.RemoveAll();

		// Stop the playback.
		if(m_player.StopPlayback())
		{
			// Disable bar.
			ControlsBarDisable();

			// Caption
			SetWindowText(_T("DSLAV"));

			// Url and Name used by CListView,
			m_strMediaPath = _T("");
			m_strMediaName = _T("");

			// Switch from VideoView to ListView.
			// Set right pane to VideoView.
			TRACE(_T("In CMainFrame StopVideoPlayback - playback stopped - calling ReplaceView.\n"));
			CDsLavSplitterView * pSplitterView = GetSplitterView();
			if(pSplitterView)
			{
				if(pSplitterView->ReplaceView(RUNTIME_CLASS(CDsLavListView)))
				{
					TRACE(_T("In CMainFrame StopVideoPlayback ReplaceView ok\n"));
				}
				else
				{
					TRACE(_T("In CMainFrame StopVideoPlayback ReplaceView failed\n"));
				}
			}
			else
			{
				TRACE(_T("In CMainFrame StopVideoPlayback GetSplitterView failed\n"));
			}
			// Set focus to view. 
			// NO causes list to not reapear for unknown reasons.
			//SetFocusToView();
		}
	}
	else
	{
		TRACE(_T("In CMainFrame StopVideoPlayback Player not running\n"));
	}
}

// Toggle video playback Pause / Play and
// update the Controls Bar.
// Called from:
//  CMainFrame::OnPlaybackPause
//  8/22 revised for enter key
void CMainFrame::ToggleVideoPlaybackPause(BOOL bEnterPressed)
{
	// Toggle playback.
	m_player.TogglePlaybackPause();

	// Update Controls Bar.
	//
	// Paused.
	if(m_player.IsPaused())
	{
		// Set bar text to "Play" (depause).
		PostMessageToControlBar(WM_USER_BAR_PAUSE, 0, 1);
	}
	else
	{
		// Set bar text to "Pause".
		PostMessageToControlBar(WM_USER_BAR_PAUSE, 0, 0);
	}
	// If enter key pressed, leave focus as is.
	if(bEnterPressed)
		return;

	// Else set focus to view.
	SetFocusToView();
}


//////////////////////////////////////////////////////
// Helpers

// Post a msg to the Controls Bar.
BOOL CMainFrame::PostMessageToControlBar(UINT Msg, WPARAM wParam, LPARAM lParam)
{
	// Get bar hwnd.
	HWND hwndBar = m_controlsBar.GetSafeHwnd();
	if(!hwndBar)
		return FALSE;
	// Post.
	::PostMessage(hwndBar, Msg, wParam, lParam);
	return TRUE;
}

// Set focus to View window - same window Video is displayed in.
void CMainFrame::SetFocusToView()
{
	// Set focus to view - List or Video View.
	HWND hwnd = ((CDsLavApp*)AfxGetApp())->m_hwndCurRightPane;
	if(hwnd)
		::SetFocus(hwnd);
}

// Called from CListView.
// Note m_strMediaPath and m_strMediaName used  
// by OnPlaybackStart() msg handler.
void CMainFrame::SetMediaPath(CString strPath)
{
	m_strMediaPath = strPath;
}
void CMainFrame::SetMediaName(CString strName)
{
	m_strMediaName = strName;
}


///////////////////////////////////////////
// Controls Bar messages arriving
//
// Controls Bar start button pressed - not used as starting happens
// when user opens a file.
//
// Called from CDsLavListView::OnLButtonDblClk().
LRESULT CMainFrame::OnPlaybackStart(WPARAM wParam, LPARAM lParam) // WM_USER_VID_START
{
	TRACE(_T("In CMainFrame OnPlaybackStart\n"));

	// Play using stored path.
	if(m_strMediaPath == _T(""))
		return 0;
	StartVideoPlayback(m_strMediaPath);
	return 0;
}

// 8/22-3 update notes
// Called from:
//  CDsLavListView::OnLButtonDblClk()
//  CDsLavListView::OnKeyDown()
LRESULT CMainFrame::OnPlaybackDvdStart(WPARAM wParam, LPARAM lParam) // WM_USER_DVD_START
{
	TRACE(_T("In CMainFrame OnPlaybackDvdStart\n"));

	// Play using stored path.
	if(m_strMediaPath == _T(""))
		return 0;
	StartDvdPlayback(m_strMediaPath);
	return 0;
}

// Called only from CDsLavListView::OnLButtonDblClk().
LRESULT CMainFrame::OnPlaybackCdStart(WPARAM wParam, LPARAM lParam) // WM_USER_CD_START
{
	TRACE(_T("In CMainFrame OnPlaybackCdStart\n"));

	/*-------------------------------------------------------------
	When a cda file is selected, we initialize an array with all 
	the CD's file names, save the index of the selected file, and
	set a flag indicating automatic CD playback is in effect.

	We then play the file with m_player.PlayCdLav(), which will call
	the Video Event handler when the track finishes. That handler
	calls StopVideoPlayback() which then calls ContinueCdPlayback()
	which plays the next track in the list until all tracks have 
	played.

	Note ContinueCdPlayback() is only called via the video event 
	handler - if the user selects another cda file, the whole 
	proccess begins again.
	--------------------------------------------------------------*/

	// Set up the automatic cda track play.
	//
	// Get CDoc.
	CDsLavDoc * pDoc = (CDsLavDoc *) GetActiveDocument();
	if(!pDoc)
		return 0;

	// Get ref to the Current Topic in CDsLavDoc, which is
	// loaded with cd tracks when the user selects the CD
	// drive in the TreeView.
	// See CDsLavDoc::TreeViewSelectedDrive().
	CTopic & curTopic = pDoc->m_curTopic;

	// Get ref to topic's media list.
	CMediaArray & mediaAr = curTopic.m_topicMediaAr;

	// Zero any existing.
	m_bCdPlaying = FALSE;
	m_curCdTrack = -1;
	m_cdFilesAr.RemoveAll();

	// Save list of CD track file names, and current cd track.
	int sz = mediaAr.GetSize();
	int curTrack = -1;
	CString path;
	for(int i = 0; i < sz; i ++)
	{
		path = mediaAr[i].m_mediaUrl;
		m_cdFilesAr.Add(path);

		// If this file is the one selected by user.
		if(path == m_strMediaPath)
			m_curCdTrack = i;
	}
	// Validate and set flag.
	if(m_cdFilesAr.GetSize() && m_curCdTrack != -1)
		m_bCdPlaying = TRUE;

	// Else forget it - play a single track.
	else
	{
		m_bCdPlaying = FALSE;
		m_curCdTrack = -1;
		m_cdFilesAr.RemoveAll();
	}

	// Play using stored path set in CDsLavListView::OnLButtonDblClk().
	if(m_strMediaPath == _T(""))
		return 0;
	StartCdPlayback(m_strMediaPath);
	return 0;
}

// 8/22-3
// Called only from CDsLavDoc::OnDvdPlayCd() for CD-DVD menu selection.
BOOL CMainFrame::StartCdPlaybackMenu(CString strCdDrive)
{
	TRACE(_T("In CMainFrame OnPlaybackCdStartMenu\n"));

	/*-------------------------------------------------------------
	From OnPlaybackCdStart() above:

	Param strCdDrive is the drive holding the CDROM.

	When a cda file is selected, we initialize an array with all 
	the CD's file names, save the index of the selected file, and
	set a flag indicating automatic CD playback is in effect.

	We then play the file with m_player.PlayCdLav(), which will call
	the Video Event handler when the track finishes. That handler
	calls StopVideoPlayback() and then ContinueCdPlayback() which 
	plays the next track in the list until all tracks have played.

	Note ContinueCdPlayback() is only called via the video event 
	handler.
	--------------------------------------------------------------*/

	// Prep for multi track playback.
	m_bCdPlaying = FALSE;
	m_curCdTrack = -1;
	m_cdFilesAr.RemoveAll();
	m_strMediaPath = _T("");
	m_strMediaName = _T("");

	// Build list of .cda files.
	//
	// File Storage API.
	HANDLE hFind;
	WIN32_FIND_DATA fd;
	CString mediaPath;
	CString strComp, strDir;
	CString strCdaFile;

	// Prep path.
	CString strPath = strCdDrive;
	if(strPath.Right(1) != _T ("\\"))
		strPath += _T ("\\");
	strPath += _T ("*.*");

	// If a Drive file or Directory.
	if((hFind = ::FindFirstFile(strPath, &fd)) != INVALID_HANDLE_VALUE) 
	{
		// A directory - problem.
		if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
		{
			TRACE(_T("WARNING CDsLavDoc::OnDvdPlayCd child directory in cdrom drive\n"));
		}
		// Else get the first .cda file.
		else
		{
			// Add to array
			strCdaFile = strCdDrive + (LPCTSTR)&fd.cFileName;	// E:\Track06.cda
			m_cdFilesAr.Add(strCdaFile);

			// Set member path for the first .cda file.
			m_strMediaPath = strCdaFile;

			// Set member name - used for screen caption.
			CString shortName = strCdaFile;
			int len = shortName.ReverseFind('\\');
			if(len)
			{
				shortName.Delete(0, len + 1);
				m_strMediaName.Format(_T("DsLav:  %s"), shortName);
			}
			else
				m_strMediaName.Format(_T("DsLav:  %s"), strCdaFile);
		}
		// Get the following .cda files.
		while(::FindNextFile(hFind, &fd)) 
		{
			// A directory - problem.
			if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
			{
				TRACE(_T("WARNING CDsLavDoc::OnDvdPlayCd child directory in cdrom drive 2\n"));
			}
			// Else get file.
			else
			{
				// Add to array
				strCdaFile = strCdDrive + (LPCTSTR)&fd.cFileName;	// E:\Track06.cda
				m_cdFilesAr.Add(strCdaFile);
			}
		}
		::FindClose (hFind);
	}
	// Check results.
	//
	// Need tracks.
	int nTracks = m_cdFilesAr.GetSize();
	if(!nTracks)
	{
		TRACE(_T("ERROR CDsLavDoc::OnDvdPlayCd no tracks\n"));
		return FALSE;
	}
	// Ensure path.
	if(m_strMediaPath == _T(""))
	{
		TRACE(_T("ERROR CDsLavDoc::OnDvdPlayCd no media path\n"));
		return FALSE;
	}

	// Set to play first track in array.
	m_curCdTrack = 0;

	// Set flag.
	m_bCdPlaying = TRUE;

	// Play.
	StartCdPlayback(m_strMediaPath);
	return TRUE;
}

// Controls Bar stop button pressed.
LRESULT CMainFrame::OnPlaybackStop(WPARAM wParam, LPARAM lParam)	// WM_USER_VID_STOP
{
	TRACE(_T("In CMainFrame OnPlaybackStop\n"));

	StopVideoPlayback();

	// Focus off controls bar.
	//
	// Set focus to view.
	SetFocusToView();
	return 0;
}

// Controls Bar pause button pressed - toggle.
//  8/22 revised for enter key
LRESULT CMainFrame::OnPlaybackPause(WPARAM wParam, LPARAM lParam)	// WM_USER_VID_PAUSE
{
	TRACE(_T("In CMainFrame OnPlaybackPause\n"));

	// Enter key pressed in ControlsBar.
	BOOL enterPressed = wParam;

	ToggleVideoPlaybackPause(enterPressed);
	return 0;
}

// Controls Bar mute button pressed - toggle.
//  8/22 revised for enter key.
LRESULT CMainFrame::OnPlaybackMute(WPARAM wParam, LPARAM lParam)	// WM_USER_VID_MUTE
{
	TRACE(_T("In CMainFrame OnPlaybackMute\n"));

	// Call player.
	m_player.ToggleVolumeMute();
	
	// Update Controls Bar.
	//
	// Enter key pressed in ControlsBar.
	BOOL enterPressed = wParam;

	// Paused.
	if(m_player.IsMuted())
	{
		// Set bar text to "Unmute" (depause).
		PostMessageToControlBar(WM_USER_BAR_MUTE, 0, 1);
	}
	else
	{
		// Set bar text to "Mute".
		PostMessageToControlBar(WM_USER_BAR_MUTE, 0, 0);
	}

	// If enter key pressed, leave focus as is.
	if(enterPressed)
		return 1;

	// Else set focus to view.
	SetFocusToView();
	return 1;
}

// Controls Bar video slider changed.
// Called from CControlsBar OnHScroll() and OnReleasedcaptureSliderVid().
LRESULT CMainFrame::OnPlaybackTime(WPARAM wParam, LPARAM lParam)	// WM_USER_VID_TIME
{
	TRACE(_T("In CMainFrame OnPlaybackTime\n"));

	// Ensure.
	if(m_player.IsStopped())
		return 0;

	BOOL moving = wParam ? TRUE : FALSE;
	UINT newPos = (UINT)lParam; // 0 - 1000, 
	UINT seconds;

	// Update video time, and get the new position in seconds.
	if(m_player.PlaybackTimeSliderMoved(moving, newPos, seconds))
	{
		// User moving the slider.
		if(moving)
		{
			// Update the controls bar position time string. Note the lParam
			// newPos value is not used as user is moving the slider.
			//
			// Calls CControlsBar::OnVidTimeChange().
			PostMessageToControlBar(WM_USER_BAR_TIME, (WPARAM)seconds, (LPARAM)newPos);
		}
		// Finished moving the slider - set focus to the View.
		else
		{
			// Set focus to view.
			SetFocusToView();
		}
	}

	/* dbg mesage
	CDsLavDoc* pDoc = GetDocument();
	CString str;
	str.Format(_T("Seek Pos %d"), (int)lParam);
	pDoc->m_statBarMsg = str;*/
	return 0;
}

// 7/22 OnPlaybackTimeKeyboard
// 8/22
// Controls Bar video slider changed.
// Called from CControlsBar OnHScroll() and OnReleasedcaptureSliderVid().
LRESULT CMainFrame::OnPlaybackTimeKeyboard(WPARAM wParam, LPARAM lParam)	// WM_USER_VID_TIME_KEYBOARD
{
	TRACE(_T("In CMainFrame OnPlaybackTimeKeyboard\n"));

	// Ensure.
	if(m_player.IsStopped())
		return 0;

	UINT newPos = (UINT)lParam; // 0 - 1000, 
	UINT seconds;

	// Update video time, and get the new position in seconds.
	if(m_player.PlaybackTimeSliderMovedKeyboard(newPos, seconds))
	{
		// Update the controls bar slider and time string to final. 
		//  Calls CControlsBar::OnVidTimeChange().
		PostMessageToControlBar(WM_USER_BAR_TIME, (WPARAM)seconds, (LPARAM)newPos);
	}
	// Failed. Note ControlsBar slider will be reset 
	// to current time via OnTimer().
	else
	{
		TRACE(_T("In CMainFrame OnPlaybackTimeKeyboard - PlaybackTimeSliderMovedKeyboard failed.\n"));
	}

	/* dbg mesage
	CDsLavDoc* pDoc = GetDocument();
	CString str;
	str.Format(_T("Seek Pos %d"), (int)lParam);
	pDoc->m_statBarMsg = str;*/
	return 0;
}

// 7/22 revise for keyboard input.		11/23-1 update
// Controls Bar vol slider changed.
//  Called from CControlsBar::OnHScroll().
//	 wParam nonzero to set focus to View.
//	 lParam is slider position (0-100).
// See also StepVolume() below.
LRESULT CMainFrame::OnPlaybackVol(WPARAM wParam, LPARAM lParam)	// WM_USER_VID_VOL
{
	TRACE(_T("In CMainFrame OnPlaybackVol\n"));

	int percent = 0;
	BOOL bFocusToView = wParam ? TRUE : FALSE;

	// If paused, force the Controls Bar slider back to its
	// current value, effectively disabling the slider.
	//  Should not get here as done in CControlsBar::OnHScroll().
	if(m_player.IsPaused())
	{
		percent = m_player.GetVolPercent();

		// Set bar vol.
		PostMessageToControlBar(WM_USER_BAR_VOL, 0, (LPARAM)percent);
		return 0;
	}

	// Else validate range.
	percent = (int)lParam;
	if(percent > 100)
		percent = 100;
	if(percent < 0)
		percent = 0;

	// Set new volume.
	if(m_player.PlaybackVolSliderMoved(percent))
	{
		// Update CDoc member used to set player volume.  11/23-1
		CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;
		pDoc->SetPlayerStartVolumePercent(percent);
		// dbg msg
 		//CDsLavDoc * pDoc = GetDocument();
		//pDoc->m_statBarMsg.Format(_T("Volume percent = %d"), percent);
	}
	// Set focus to view per param.
	//  Done when user drags slider with mouse.
	//  See CControlsBar::OnHScroll().
	if(bFocusToView)
		SetFocusToView();
	return 0;
}

// Step player's vol up-down per stepUp param.	11/23-1 new func
// Called from:
//  CDsLavListView::OnMouseWheel()
//	CDsLavVideoView::OnMouseWheel()
BOOL CMainFrame::StepVolume(BOOL stepUp)
{
	TRACE(_T("In CMainFrame::StepVolume - step vol up=%d.\n"), stepUp);

	// Step the running player's vol, update the ControlsBar 
	// slider and the CDoc vol member with vol param.
	LONG vol = 0;
	if(m_player.IsRunning() &&
	   m_player.StepVolume(stepUp, vol))
	{
		// Update CDoc member used to set player volume.
		CDsLavDoc * pDoc = ((CDsLavApp*)AfxGetApp())->m_pDocument;
		pDoc->SetPlayerStartVolumePercent(vol);

		// Set ControlsBar vol - calls CControlsBar::OnVidVolChange().
		HWND hwndBar = m_controlsBar.GetSafeHwnd();
		::PostMessage(hwndBar, WM_USER_BAR_VOL, 0, (LPARAM)vol);

		TRACE(_T("In CMainFrame::StepVolume - new vol=%d.\n"), vol);

		// Good.
		return TRUE;
	}
	return FALSE;
}

// Forward msg from Controls Bar to CDsLavSplitterView.
LRESULT CMainFrame::OnHideLeftPane(WPARAM wParam, LPARAM lParam)	// WM_USER_HIDE_LEFT_PANE
{
	TRACE(_T("In CMainFrame OnHideLeftPane\n"));

	// Get CDsLavApp handle
	HWND hwndSplitterView = ((CDsLavApp*)AfxGetApp())->m_hwndSplitterView;
	if(!hwndSplitterView)
		return 0;
	::PostMessage(hwndSplitterView, WM_USER_HIDE_LEFT_PANE, wParam, lParam);
	return 1;

	// Note focus set to view in CDsLavSplitterView::OnHideLeftPane
}

/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics

#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
	CFrameWnd::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
	CFrameWnd::Dump(dc);
}

#endif //_DEBUG






