/*
*******************************************************************************
* Copyright (c) 1996-97 Digi International Inc., All Rights Reserved          *
*                                                                             *
* This  software  contains  proprietary  and  confidential   information   of *
* Digi International  Inc.   By  accepting  transfer  of this copy, Recipient *
* agrees to retain this software in  confidence,  to  prevent  disclosure  to *
* others,  and  to make no  use of this software other than that for which it *
* was delivered.  This is an unpublished copyright work  Digi   International *
* Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is *
* strictly prohibited.                                                        *
*                                                                             *
* Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc. *
* Confidential  when   combined   with   the   aggregated  modules  for  this *
* product) OBJECT CODE ONLY SOURCE MATERIALS                                  *
*                                                                             *
* (C) COPYRIGHT Digi International Inc. 1996-97                               *
*                                                                             *
* All Rights Reserved                                                         *
*                                                                             *
* US   Government   Users   Restricted   Rights   -   Use,   duplication   or *
* disclosure  restricted by GSA ADP Schedule Contract with Digi International *
* Inc.                                                                        *
*                                                                             *
*******************************************************************************

// Diagnostic.cpp : Defines the class behaviors for the application.
//

The big picture.

	You must understand how WAN Links software before this description can
	make sense to you. You should also more than a little familiar with MFC.
	Implemented in this release are support for the SyncPort adapter and
	X.25 and Frame Relay protocols. The architecture allows additional
	adapter or protocol support to be relatively easy.

	Classes with <> around them are abstract base classes. Classes with <<>>
	around them are abstract base classes used for protocol specific
	functionality. If you were to add a new protocol like PPP you would
	derive a class from a <<>> enclosed class. This app tries to be as MFC
	standard as possible.

	The CDiagApp class implements most of the menu item's. There are three
	CMultiDocTemplete classes, only one is registered with CDiagApp. It is
	the only one that can save and open files. There is no file new in this
	app, documents either have no data or start with data, i.e. they don't
	have an empty document state, so file new makes no sense. The three
	CMultiDocTempletes display the statistics, Summary, and trace capture
	windows. The Summary windows displays information about all lines of
	all adapter installed on this machine in column format. A Statistics
	windows displays the current statistics of a line. A trace capture
	window displays the frames captured when the user runs a trace on a line.

	First the documents
		CTraceDoc - document for Summary window, holds no data, exists only for
								MFC standard implementation, there will alos be one of these
								object in existence. If the user has no WAN Links adapter
								installed then a Summary window will not be created.

		<<CStatDoc>> -	abstract base class document for statistics. It does not
										hold the statitics data. It holds a copy of the stats
										data so that when the user does a "clear statistics" the
										statistics displayed will appear to go to zero when they 
										are only being subtracted from the copy held by the
										document. Like a good MFC document it does provide it's
										view's with access to the stat data on demand.

		CDiagDoc -	document for trace data which includes trace stats and the
								captured frames. This document is implemented in the way
								MFC had in mind. It saves and load data from disk. It holds
								the data that it's view display. The only non MFC standard
								thing is it never starts out empty that is with no data. It
								is created new but given it's data to start out with.

	Next the MDI child frame windows
		CTraceChildFrame - frame window used to hold the Summary window view

		CChildFrame - frame windows used to hold a <<CStatViewBase>>

		CPacketChildFrame - holds three views in a splitter window. They are the
												CPacketListView, CPacketTreeView,and CPacketByteView.

	And the views
		CDataSourceView - the Summary view. Does not get it's data from it's
											document. CDataSourceView is a derived CListView class.

		<<CStatViewBase>> - abstract base class any view that displays protocol stats 
												on a line.

		CPacketListView - a CListView derived class. Displays a list of captured fram
		CPacketTreeView - a CTreeView derived class. Diaplays a frame detailed in
											a tree format
		CPacketByteView - a CScrollView derived class. Displays the actual bytes of
											a frame in hex and char format

	Finally the CMultiDocTemplates themselves.
		All doc template used different menu bars but they are have a "Diagnostics" menu
		after the "File" menu which for the most part is identical. They all share the
		same toolbar. Most of the menu item's are implemented by MFC or CDiagApp


	CMultiDocTemplate - Summary window template
		IDR_TRACETYPE - menu bar resource
		CTraceDoc
		CTraceChildFrame
		CDataSourceView

	CMultiDocTemplate - this is the statistics window template. Instances of
											this template are not created with OpenDocumentFile.
											The actual <<CStatDoc>> derived class used is aquired
											first. When the CChildFrame is created it asks the
											documents for the actual <<CStatViewBase>> derived view
											class used. See CDiagApp::MakeStatFrame()
		IDR_STATTYPE - menu bar resource
		<<CStatDoc>>
		CChildFrame
		<<CStatViewBase>>

	CTraceMultiDocTemplate -	Only this doctemplate is registered with CDiagApp.
														This doc template overrides CMultiDocTemplate so
														that a new documents could be created and given
														their data.
		IDR_DIAGTYPE - menu bar resource
		CDiagDoc
		CPacketChildFrame - on create this MDI frame class will actuall make
												a splitter and add the three views to it not just
												CPacketListView.
		CPacketListView

	Of cource, CDiagApp creates a main window CMainFrame. CMainFrame creates the toolbar
	and statusbar. The toolbar contains two combobox's. The rather important one is
	IDW_DataSource or CMainFrame::m_DataSourceBox. When CMainFrame is created it puts
	up a splash screen first then it calls CDiagApp::LoadConfig() to scan for adapters
	and create the key data classes. Each line on an adapter is represented by a
	CDataSource class. For each CDataSource class an item is added to IDW_DataSource.
	The user will then use this combo box to select what line they want to display
	stats on or start a trace on or maybe what line to clear stats. Most menu items
	use the current selection in IDW_DataSource to enable or disable themselves as
	appropriate. The Summary window will get it's items from IDW_DataSource. Suffice
	it to say IDW_DataSource is central to most of the functionality of this app. In
	order to help manage functionality based on the currently selected item
	in IDW_DataSource is the CDataSourceControl class. It is held as item data in
	every item in IDW_DataSource. 

	When the user starts a trace on a line trace statistics are displayed to the user
	in a property sheet which float above other windows. What is created is specifically
	a CTraceMiniFrame which is derived from CMiniFrame. When the CTraceMiniFrame is created
	a protocol specific <<CTraceSheet>> class is created which knows what protocol
	specific <<CTracePage>> classes to add to the sheet

	The remaining UI classes not described are CDialog classes. Some CDialog classes are
	protocol specific which are used by other protocol specific classes.

*/

#include "stdafx.h"
#include "Diagnostic.h"

#include "MainFrm.h"

#include "StatDoc.h"
#include "ChildFrm.h"
#include "StatView.h"

#include "PacketChildFrame.h"
#include "DiagDoc.h"
#include "PacketListView.h"

#include "TraceChildFrame.h"
#include "DataSource.h"

#include "Splash.h"

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

// when the config is changed a system message will be sent
// with this ID
//const UINT ConfigChangeMsg = RegisterWindowMessage(WM_ConfigChange);

// named mutex to prevent multiple app instances
const LPCTSTR c_szMutexName = _T("SxbDiagPreventSecondInstance");

/////////////////////////////////////////////////////////////////////////////
// CDiagApp

BEGIN_MESSAGE_MAP(CDiagApp, CWinApp)
	//{{AFX_MSG_MAP(CDiagApp)
	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
	ON_COMMAND(ID_WINDOW_CLOSEALLSTATISTICSWINDOWS, OnWindowCloseallstatisticswindows)
	ON_UPDATE_COMMAND_UI(ID_WINDOW_CLOSEALLSTATISTICSWINDOWS, OnUpdateWindowCloseallstatisticswindows)
	ON_COMMAND(ID_SPYGLASS_REFRESH_UPDATENOW, OnSpyglassRefreshUpdatenow)
	ON_UPDATE_COMMAND_UI(ID_SPYGLASS_REFRESH_UPDATENOW, OnUpdateSpyglassRefreshUpdatenow)
	ON_COMMAND_RANGE(ID_SPYGLASS_REFRESH_CONSTANTLY, ID_SPYGLASS_REFRESH_MANUAL, OnSpyglassRefresh)
	ON_UPDATE_COMMAND_UI_RANGE(ID_SPYGLASS_REFRESH_CONSTANTLY, ID_SPYGLASS_REFRESH_MANUAL, OnUpdateSpyglassRefresh)
//	ON_REGISTERED_THREAD_MESSAGE(ConfigChangeMsg, OnConfigChange)
	ON_CBN_SELCHANGE(IDW_COMBO, OnSelchangeRefresh)
	ON_COMMAND(ID_CAPTURE_STARTTRACE, OnCaptureStarttrace)
	ON_UPDATE_COMMAND_UI(ID_CAPTURE_STARTTRACE, OnUpdateCaptureStarttrace)
	ON_COMMAND(ID_CAPTURE_STOPTRACE, OnCaptureStoptrace)
	ON_UPDATE_COMMAND_UI(ID_CAPTURE_STOPTRACE, OnUpdateCaptureStoptrace)
	ON_COMMAND(ID_CAPTURE_PAUSETRACE, OnCapturePausetrace)
	ON_UPDATE_COMMAND_UI(ID_CAPTURE_PAUSETRACE, OnUpdateCapturePausetrace)
	ON_COMMAND(ID_CAPTURE_STOPANDVIEW, OnCaptureStopandview)
	ON_UPDATE_COMMAND_UI(ID_CAPTURE_STOPANDVIEW, OnUpdateCaptureStopandview)
	ON_COMMAND(ID_CAPTURE_DISPLAYCATUREDDATA, OnCaptureDisplaycatureddata)
	ON_UPDATE_COMMAND_UI(ID_CAPTURE_DISPLAYCATUREDDATA, OnUpdateCaptureDisplaycatureddata)
	ON_COMMAND(ID_EDIT_CLEARTRACESTATISTICS, OnEditClearTracestatistics)
	ON_UPDATE_COMMAND_UI(ID_EDIT_CLEARTRACESTATISTICS, OnUpdateEditClearTracestatistics)
	ON_COMMAND(ID_CAPTURE_BUFFERSETTINGS, OnCaptureBuffersettings)
	ON_COMMAND(ID_CAPTURE_SUMMARYINFO, OnCaptureSummaryinfo)
	ON_UPDATE_COMMAND_UI(ID_CAPTURE_SUMMARYINFO, OnUpdateCaptureSummaryinfo)
	ON_COMMAND(ID_CAPTURE_DISPLAYSTATISTICS, OnCaptureDisplaystatistics)
	ON_UPDATE_COMMAND_UI(ID_CAPTURE_DISPLAYSTATISTICS, OnUpdateCaptureDisplaystatistics)
	ON_COMMAND(ID_EDIT_CLEARSTATISTICS, OnEditClearstatistics)
	ON_UPDATE_COMMAND_UI(ID_EDIT_CLEARSTATISTICS, OnUpdateEditClearstatistics)
	//}}AFX_MSG_MAP
	// Standard file based document commands
	ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
	// Standard print setup command
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDiagApp construction

CDiagApp::CDiagApp() : m_RefreshEvent()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
	m_pStatDocTemplate = NULL;
	m_pDataSourceDocTemplate = NULL;
	m_RefreshThread = NULL;
}

CDiagApp::~CDiagApp()
{
	for (short i = 0; i < m_Adapters.GetSize(); i++)
		delete m_Adapters[i];
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CDiagApp object

// this variable is used in various files
// it is used to gain access to the current CDataSource
// a CDataSource class is where all stat and trace data come from
// This app could support having more than one CDataSource in use at one
// time. You would really only want to trace one line at a time.
// a CDataSource refers to a line on the SyncPort adapter.
CDiagApp theApp;

/////////////////////////////////////////////////////////////////////////////
// CDiagApp initialization
BOOL CDiagApp::InitInstance()
{
	// Only one instance of SpyGlass can run at a time
	m_hMutexOneInstance = CreateMutex(NULL, TRUE, c_szMutexName);
	if ( m_hMutexOneInstance )
	{
		BOOL Fail = ( GetLastError() == ERROR_ALREADY_EXISTS );
		ReleaseMutex( m_hMutexOneInstance );
		if ( Fail )
		{
			AfxMessageBox( IDP_ONEINSTANCE );
			return FALSE;
		}
	}
	
	// Add all supported adapter classes here!
	CAdapter::AddAdapter(DXB_REGVAL_OPTION_ENUM_SYNCPORT, RUNTIME_CLASS(CSXBAdapter));
	CAdapter::AddAdapter(DXB_REGVAL_OPTION_ENUM_PRIME,    RUNTIME_CLASS(CSXBAdapter));
	CAdapter::AddAdapter(DXB_REGVAL_OPTION_ENUM_HOUSTON,  RUNTIME_CLASS(CSXBAdapter));
	CAdapter::AddAdapter(DXB_REGVAL_OPTION_ENUM_LONDON,   RUNTIME_CLASS(CSXBAdapter));
	CAdapter::AddAdapter(DXB_REGVAL_OPTION_ENUM_CHASKA,   RUNTIME_CLASS(CSXBAdapter));
	CAdapter::AddAdapter(DXB_REGVAL_OPTION_ENUM_CLYDE,    RUNTIME_CLASS(CSXBAdapter));
	CAdapter::AddAdapter(DXB_REGVAL_OPTION_ENUM_SYNC570,  RUNTIME_CLASS(CSXBAdapter));
//	CAdapter::AddAdapter("Digi570LLD", RUNTIME_CLASS(C570LLDAdapter));

	// CG: The following block was added by the Splash Screen component.
	{
		CCommandLineInfo cmdInfo;
		ParseCommandLine(cmdInfo);

		CSplashWnd::EnableSplashScreen(cmdInfo.m_bShowSplash);
	}
	// Standard initialization
	// If you are not using these features and wish to reduce the size
	//  of your final executable, you should remove from the following
	//  the specific initialization routines you do not need.
	// default program settings are at HKEY_CURRENT_USER\SoftWare\<c_pszValueManufacturer>

#ifdef _AFXDLL
	Enable3dControls();			// Call this when using MFC in a shared DLL
#else
	Enable3dControlsStatic();	// Call this when linking to MFC statically
#endif

	SetRegistryKey(c_pszValueManufacturer); // store ini params in registry

	LoadStdProfileSettings();  // Load standard INI file options (including MRU)

	m_RefreshInterval = GetProfileInt(
		c_pszKeySettings,
		c_pszValueRefreshInterval,
		cDefaultRefreshInterval);
 
	// Register the application's document templates.  Document templates
	//  serve as the connection between documents, frame windows and views.

	// this is the trace capture window
	CMultiDocTemplate *TraceDocTemplate = new CTraceMultiDocTemplate( 
		IDR_DIAGTYPE,
		RUNTIME_CLASS(CDiagDoc),
		RUNTIME_CLASS(CPacketChildFrame), // custom MDI child frame
		RUNTIME_CLASS(CPacketListView));
	AddDocTemplate(TraceDocTemplate); // Only this doctemplate is registered

	// this is the statistics window
	m_pStatDocTemplate = new CMultiDocTemplate( 
		IDR_STATTYPE,
		RUNTIME_CLASS(CStatDoc),
		RUNTIME_CLASS(CChildFrame), // custom MDI child frame
		RUNTIME_CLASS(CStatViewBase));

	// this is the Summary window
	m_pDataSourceDocTemplate = new CMultiDocTemplate( 
		IDR_TRACETYPE,
		RUNTIME_CLASS(CTraceDoc),
		RUNTIME_CLASS(CTraceChildFrame), // custom MDI child frame
		RUNTIME_CLASS(CDataSourceView));

	// create main MDI Frame window
	CMainFrame* pMainFrame = new CMainFrame;
	if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
		return FALSE;
	m_pMainWnd = pMainFrame;

	// Enable drag/drop open
	m_pMainWnd->DragAcceptFiles();

	// Enable DDE Execute open
	EnableShellOpen();

	{
	// why this? becuse of some strange bug when debugging
		OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };

		::GetVersionEx(&info);

		BOOL bWin95 = info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS;

		RegisterShellFileTypes(bWin95);
	}

	// Parse command line for standard shell commands, DDE, file open
	CCommandLineInfo cmdInfo;

	// Do NOT create a new document at startup
	cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;

	ParseCommandLine(cmdInfo);

	// Dispatch commands specified on the command line
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// The main window has been initialized, so show and update it.
	pMainFrame->ShowWindow(m_nCmdShow);
	pMainFrame->UpdateWindow();

	// set current selection in IDW_COMBO
	for (short i = 0; i < pMainFrame->m_ComboBox.GetCount(); i++)
	{
		if (pMainFrame->m_ComboBox.GetItemData(i) == m_RefreshInterval)
			pMainFrame->m_ComboBox.SetCurSel(i);
	}

	// create a Summary window only if there are functioning adapters
	if (GetNumAdapters()) // Did we find any?
	{
		// create first Summary Window
		CDocument *pDoc = m_pDataSourceDocTemplate->OpenDocumentFile(NULL, TRUE);
		pDoc->OnIdle();

		m_RefreshThread = AfxBeginThread(RefreshThread, this);
	}

	// Check for trace file specified on commandline.  If so, open it.
	if (cmdInfo.m_strFileName != "")
		AfxGetApp()->OpenDocumentFile(cmdInfo.m_strFileName);
	
	// Display error message if no adapters were found - but only 
	// if a tracefile was not specified on the commandline.
	else if (!GetNumAdapters())	
		AfxMessageBox(IDP_NOADAPTERS);


	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	CString	m_VersionString;
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	virtual BOOL OnInitDialog();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	m_VersionString = _T("");
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	DDX_Text(pDX, IDC_VersionString, m_VersionString);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CAboutDlg::OnInitDialog() 
{
//
// Display the current version number 
//
	TCHAR szFullPath[246];
	DWORD dwVerHnd;

	// Get full path to this module
	GetModuleFileName(AfxGetInstanceHandle(),
										szFullPath,
										sizeof(szFullPath));

	DWORD dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);

	if (dwVerInfoSize > 0)
	{
		// If able to get the information, process it:
		BYTE *buf = new BYTE[dwVerInfoSize];

		if (GetFileVersionInfo(szFullPath, NULL, dwVerInfoSize, buf))
		{
			 LPVOID   lpBuffer;
			 UINT     dwBytes;

			 // Get the version number string
			 if (VerQueryValue(	buf,
													TEXT("\\StringFileInfo\\040904B0\\ProductVersion"),
													&lpBuffer,
													&dwBytes)) 
			 {
					// Update the dialog variable to display the string
					m_VersionString.Format(IDS_VersionFormat, (LPTSTR)lpBuffer);
			 }
		}

		delete[] buf;
	}

	CDialog::OnInitDialog();	
// TODO: Add extra initialization here

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

// App command to run the dialog
void CDiagApp::OnAppAbout()
{
	CAboutDlg aboutDlg;
	aboutDlg.DoModal();
}



BOOL CDiagApp::LoadConfig()
{
	BOOL bSuccess = FALSE;
	OSVERSIONINFO version;
	version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	if (GetVersionEx(&version))
	{
		if (version.dwMajorVersion <= 4)
			bSuccess = LoadConfigNT4();
		else
			bSuccess = LoadConfigNT5();

	}
	return bSuccess;
}
//*******************************************************************************
//*
//
//* return:		TRUE if there is atleast one functioning adapter
//* params:		None
//* desc:			Look in the registry for installed WAN Links adapters.
//*						They can be running X.25 or Frame Relay, etc. For each one found
//*						create a 'CAdapter' class. After creation, the adapters
//*						parameters are loaded.  These parameters are necessary
//*						to do stats and trace with. Then we try to get stats from the
//*						board to see if the drivers are working. If there is a failure
//*						at any point the CAdapter class is deleted. Successful adapters
//*						are added to the array 'm_Adapters'. 
//*******************************************************************************
// The NT4 version
BOOL CDiagApp::LoadConfigNT4()
{
	HKEY hkNetCards;
	if (RegOpenKeyEx(	HKEY_LOCAL_MACHINE, c_pszNTNetcardBase, &hkNetCards) == ERROR_SUCCESS)
	{
		char KeyName[256];
		DWORD cbName;
		DWORD i = 0;
		FILETIME time;

		// loop through all adapters in \Software\...\NetworkCards registry key
		while (cbName = sizeof KeyName, RegEnumKeyEx(hkNetCards, i++, KeyName, &cbName, NULL, NULL, NULL, &time) == ERROR_SUCCESS) 
		{
			// Open the netcard key
			HKEY hkNetCard;
			if ( RegOpenKeyEx(hkNetCards, KeyName, &hkNetCard) == ERROR_SUCCESS )
			{
				// Get the Services driver and adapter key names for this netcard
				CString AdapterName;
				CString DriverName;

				// Get driver name, i.e. DigiDxb
				LONG Success = RegGetString( hkNetCard, "ProductName", DriverName );

				// Get adapter name, i.e. DigiDxb2
				if ( Success == ERROR_SUCCESS )
					Success = RegGetString( hkNetCard, "ServiceName", AdapterName );

				if ( Success == ERROR_SUCCESS )
				{
					// Open the netcard Services key
					CString Parameters = c_pszNTServiceBase + ('\\' + AdapterName) + "\\Parameters";

					HKEY hkParams;
					if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, Parameters, &hkParams ) == ERROR_SUCCESS )
					{
						// Get the Digi-specific Option value, defining the adapter type
						CString Option;
						Success = RegGetString( hkParams, DXB_REGVAL_OPTION, Option );
						if ( Success == ERROR_SUCCESS )
						{
							// Finally!  Is this a supported adapter?
							CRuntimeClass *rts = CAdapter::RegistryLookUp(Option);
							if (rts != NULL)
							{
								CAdapter *adapter = (CAdapter *)rts->CreateObject();

								adapter->SetDriverName( DriverName );

								// Get the Device Name that is used to Communicate with
								// the adapter.  The device name and the adapter name
								// are not always the same (i.e. DigiSOH adpaters)
								CString AdapterDeviceName;
								Success = RegGetString( hkParams, DXB_REGVAL_DEVICE, AdapterDeviceName );
								if ( Success == ERROR_SUCCESS )
								{

									// Load the adapter params and test the driver
									if ( adapter->LoadConfig( AdapterDeviceName, Option, hkParams, Parameters ) ) 
										m_Adapters.Add( adapter );
									else
										delete adapter;

								}
							}
						}
						RegCloseKey( hkParams );
					}
				}
				RegCloseKey(hkNetCard);
			}
		}
		RegCloseKey(hkNetCards);
	}

	return GetNumAdapters() > 0;
}

// the NT5 version
BOOL CDiagApp::LoadConfigNT5()
{

#define NT5NetCardBase		_T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}")
	HKEY hkNetCards;
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT5NetCardBase, &hkNetCards) == ERROR_SUCCESS)
	{
		DWORD dwIndex = 0;
		DWORD dwSize;
		TCHAR KeyName[MAX_PATH];
		FILETIME time;
		// enumerate all keys and look for the Digi specific signature
		while(dwSize = sizeof KeyName, RegEnumKeyEx(hkNetCards, dwIndex++, KeyName, &dwSize, NULL, NULL, NULL, &time) == ERROR_SUCCESS)
		{
			HKEY hkParams;
			CString strKey(NT5NetCardBase);
			strKey += _T('\\');
			strKey += KeyName;
			strKey += _T('\\');
			strKey += DXB_REGKEY_PARAMETERS;
			
			// open key\Parameter registry key
			if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, strKey, &hkParams) == ERROR_SUCCESS)
			{
				// Get the Digi-specific Option value, defining the adapter type
				CString strOption;
				if (RegGetString( hkParams, DXB_REGVAL_OPTION, strOption ) == ERROR_SUCCESS)
				{
					// Finally!  Is this a supported adapter?
					CRuntimeClass *rts = CAdapter::RegistryLookUp(strOption);
					if (rts != NULL)
					{	
						// really the ServiceName of the form DigiDxbXXXX
						CString AdapterName;	
						long lSuccess = RegGetString( hkParams, DXB_REGVAL_SERVICENAME, AdapterName);
						if (lSuccess == ERROR_SUCCESS )
						{
							int nLen = AdapterName.GetLength();
							// build the product name without the XXXX instance #
							CString DriverName(AdapterName.Left(nLen-4));
							
							CAdapter *adapter = (CAdapter *)rts->CreateObject();
							adapter->SetDriverName( DriverName );

							// Load the adapter params and test the driver
							if ( adapter->LoadConfig( AdapterName, strOption, hkParams, strKey ) ) 
								m_Adapters.Add( adapter );
							else
								delete adapter;
						}
					}
				}

				RegCloseKey(hkParams);
			}
		}
		RegCloseKey(hkNetCards);
	}

	return GetNumAdapters() > 0;

}



/////////////////////////////////////////////////////////////////////////////
// CDiagApp commands

void CDiagApp::KillRefreshThread()
{
	if (m_RefreshThread != NULL)
	{
		HANDLE hThread = m_RefreshThread->m_hThread;

		m_RefreshThread->ResumeThread();
		m_RefreshEvent.SetEvent();

		MSG Msg;
		PeekMessage(&Msg,
								m_pMainWnd->GetSafeHwnd(),
								c_RefreshMessage,
								c_RefreshMessage,
								PM_REMOVE);

		WaitForSingleObject(hThread, INFINITE);
		m_RefreshThread = NULL;
	}
}

int CDiagApp::ExitInstance() 
{
	// TODO: Add your specialized code here and/or call the base class
	KillRefreshThread();

	// Destory all stats windows
	if (m_pStatDocTemplate != NULL)
		m_pStatDocTemplate->CloseAllDocuments(TRUE);
	delete m_pStatDocTemplate;

	// Destory all Summary windows
	if (m_pDataSourceDocTemplate != NULL)
		m_pDataSourceDocTemplate->CloseAllDocuments(TRUE);
	delete m_pDataSourceDocTemplate;

	WriteProfileInt(
		c_pszKeySettings,
		c_pszValueRefreshInterval,
		m_RefreshInterval);

	CloseHandle(m_hMutexOneInstance);

	return CWinApp::ExitInstance();
}

/*******************************************************************************
/*
/* function : void MakeStatFrame()
/* return:		None
/* params:		None
/* desc:			Creates a Statistics window for the selected item in IDW_DataSource Combobox
/*						The CDataSource returns what CStatDoc derived class to create. The CStatDoc
/*						derived class knows what views to give to the CMDIChildFrm to create. It also
/*						knows how to get the protocol specific data out of a protocol specific CDataSource
/*						derived class
/*						
*******************************************************************************/
void CDiagApp::MakeStatFrame()
{
	CDataSource *pDS = GetDataSource(); // Get CDataSource derived class from current selection
																		 // in IDW_DataSource Combobox
	CRuntimeClass *pRTC = NULL;

	if (pDS != NULL)
		pRTC = pDS->GetStatDocClass(); // Get CStatDoc derived class from CDataSource dervied class

	if (pRTC == NULL)
		return;

	CStatDoc *pDoc = (CStatDoc *)pRTC->CreateObject();
	
	// SetDataSource gives the CStatDoc class a pointer to the CDataSource to use until the
	// window is destoyed and calls the CStatDoc OnNewDocument member
	if (pDoc == NULL || !pDoc->SetDataSource(pDS))
	{
		// user has be alerted to what failed in OnNewDocument
		TRACE0("CDocument::OnNewDocument returned FALSE.\n");
		return;
	}

	// normaly these members are called from CDocTemplate::OpenDocumentFile
	// that mechanism has been duplicated here the unneccessary parts have been removed
	m_pStatDocTemplate->AddDocument(pDoc);
	CFrameWnd *pFrame = m_pStatDocTemplate->CreateNewFrame(pDoc, NULL);
	pFrame->InitialUpdateFrame(pDoc, TRUE);
	
	pDoc->OnIdle(); // the calling a documents OnIdle member updates it's views
}

UINT __cdecl CDiagApp::RefreshThread(LPVOID)
{
	CSingleLock Idle(&theApp.m_RefreshEvent);
	HWND hWnd = AfxGetMainWnd()->GetSafeHwnd();

	do
	{
		if (Idle.Lock(theApp.m_RefreshInterval * 1000))
			break;
		else
			::SendMessage(hWnd, c_RefreshMessage, 0, 0);

	} while(TRUE);

	return 0;
}

void CDiagApp::OnRefreshMessage()
{
	// CAdapter::UpdateDataSource has all CDataSource classes held by
	// the adapter update their statistics data
	for (short i = 0; i < GetNumAdapters(); i++)
		GetAdapter(i)->UpdateDataSource();

	m_pDataSourceDocTemplate->OnIdle(); // update Summary windows
	m_pStatDocTemplate->OnIdle();				// update stats windows

	// get refernce to MainFrame's IDW_DataSource Combo box
	CComboBox& ComboBox = static_cast<CMainFrame *>(m_pMainWnd)->m_DataSourceBox;

	// update the active page in running traces
	for (i = 0; i < ComboBox.GetCount(); i++)
	{
		CDataSourceControl *pControl = (CDataSourceControl *)ComboBox.GetItemDataPtr(i);

		if (pControl->GetDataSource()->IsTracing())
			UpdateActivePage(pControl);
	}

	m_pMainWnd->RedrawWindow(NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN);
}

/*******************************************************************************
/*
/* function : void OnIdle(LONG lCount)
/* return:		BOOL
/* params:		lCount - number of times called since last WM_message
/* desc:			MFC routine for handling background actions in on MFC app.
/*						
*******************************************************************************/
BOOL CDiagApp::OnIdle(LONG lCount) 
{
	// TODO: Add your specialized code here and/or call the base class
	if (lCount == 0)
	{
		// get refernce to MainFrame's IDW_DataSource Combo box
		CComboBox& ComboBox = static_cast<CMainFrame *>(m_pMainWnd)->m_DataSourceBox;

		for (short i = 0; i < ComboBox.GetCount(); i++)
		{
			CDataSourceControl *pControl = (CDataSourceControl *)ComboBox.GetItemDataPtr(i);

			UpdateAllDocuments(	(i << 16) + uavStateChange,
													(CObject *)pControl->GetState());
		}
	}

	return CWinApp::OnIdle(lCount);
}

//////////////////////////////////////////////////////////////////
// CTraceMultiDocTemplate
CTraceMultiDocTemplate::CTraceMultiDocTemplate(	UINT nIDResource,
																								CRuntimeClass* pDocClass,
																								CRuntimeClass* pFrameClass,
																								CRuntimeClass* pViewClass) :
	CMultiDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass)
{ 
	m_pNewDocDataSource = NULL;
	m_Properties = NULL;
};

// the only reason we have overrided CreateNewDocument is to give a new document
// data to start with. MFC only creates new docs with no data. This document is
// created and displayed after a trace. 
CDocument *CTraceMultiDocTemplate::CreateNewDocument()
{ 
	CDiagDoc *doc = (CDiagDoc *)CMultiDocTemplate::CreateNewDocument();

	if (m_pNewDocDataSource != NULL)
	{
		m_pNewDocDataSource->TraceDataToDoc(doc); // transfer CTraceData object to document
		m_pNewDocDataSource = NULL;
		doc->SetProperties(m_Properties); // the CTraceMiniFrame object is transfered to the document
		m_Properties = NULL;
	}

	return doc;
}

// the next document created will use this CDataSource and CTraceMiniFrame objects
void CTraceMultiDocTemplate::SetNewDocDataSource(CDataSourceControl *pControl)
{ 
	m_pNewDocDataSource = pControl->GetDataSource();
	m_Properties = *pControl;
}
/////////////////////////////////////////////////////////////////////

// Get Selcted item from CMainFrame IDW_DataSource combo box
// CB_ERR is return for no selected item
int CDiagApp::GetSelectedItem() const
{
	CMainFrame *pMainFrame = static_cast<CMainFrame *>(m_pMainWnd);

	return pMainFrame != NULL && IsWindow(pMainFrame->m_hWnd)
		? pMainFrame->m_DataSourceBox.GetCurSel()
		: CB_ERR;
}

// CDataSourceControl objects are stored in IDW_DataSource combo box's item data ptr
// the CDataSourceControl from the selected item is returned
// NULL is returned for no selected item
CDataSourceControl *CDiagApp::GetControl()
{ 
	CDataSourceControl *pControl = NULL;
	int sel = GetSelectedItem();

	if (sel > CB_ERR)
	{
		CMainFrame *pMainFrame = static_cast<CMainFrame *>(m_pMainWnd);
		
		pControl = (CDataSourceControl *)pMainFrame->m_DataSourceBox.GetItemDataPtr(sel);
	}
	
	return pControl;
}

const CDataSourceControl *CDiagApp::GetControl() const
{ 
	const CDataSourceControl *pControl = NULL;

	int sel = GetSelectedItem();
	if (sel > CB_ERR)
	{
		CMainFrame *pMainFrame = static_cast<CMainFrame *>(m_pMainWnd);
		
		pControl = (CDataSourceControl *)pMainFrame->m_DataSourceBox.GetItemDataPtr(sel);
	}
	
	return pControl;
}

// a CDataSource pointer is held in every CDataSourceControl object
// the CDataSource from the selected items CDataSourceControl is returned
// NULL is returned for no selected item
CDataSource *CDiagApp::GetDataSource()
{ 
	CDataSourceControl *pControl = GetControl();
	CDataSource *pDS = NULL;

	if (pControl != NULL)
		pDS = pControl->GetDataSource();
	
	return pDS;
}

const CDataSource *CDiagApp::GetDataSource() const
{ 
	const CDataSourceControl *pControl = GetControl();
	const CDataSource *pDS = NULL;

	if (pControl != NULL)
		pDS = pControl->GetDataSource();
	
	return pDS;
}

// Is the selected item currently tracing?
BOOL CDiagApp::IsTracing() const
{
	return GetSelectedItem() > CB_ERR && GetDataSource()->IsTracing();
}

// Is the selected item currently paused?
BOOL CDiagApp::IsPaused() const
{ 
	return GetSelectedItem() > CB_ERR && GetDataSource()->IsPaused();
}

// switch the selected item from play -> pause or pause -> play
void CDiagApp::ToggleTrace()
{ 
	int sel = GetSelectedItem();

	if (sel > CB_ERR)
	{
		CDataSource *ds = GetDataSource();

		ds->ToggleTrace();
		UpdateAllDocuments(	(sel << 16) + uavStateChange,
			(CObject *)(ds->IsPaused() ? dsiPause : dsiPlay));
	}
}

// switch off the trac running on the currently selected item
void CDiagApp::StopTrace()
{ 
	if (GetSelectedItem() > CB_ERR)
		GetDataSource()->StopTrace();
}

// update the active page in a running trace
void CDiagApp::UpdateActivePage(CDataSourceControl *pControl)
{ 
	if (pControl != NULL)
	{
		pControl->GetDataSource()->NextSecond();

		CTracePage *pPage = pControl->GetTraceSheet()->GetActiveTracePage();

		ASSERT_VALID(pPage);
		pPage->OnUpdate(uavTraceFasterPeriod);
		pPage->UpdateWindow();
	}
}

void CDiagApp::OnWindowCloseallstatisticswindows() 
{
	// TODO: Add your command handler code here
	m_pStatDocTemplate->CloseAllDocuments(FALSE);

	// StopStats closes streams devices and the drive file
	for (short i = 0; i < GetNumAdapters(); i++)
		for (short j = 0; j < GetAdapter(i)->GetNumDataSource(); j++)
			GetAdapter(i)->GetDataSource(j)->StopStats(NORMAL);
}

void CDiagApp::OnUpdateWindowCloseallstatisticswindows(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(GetNumAdapters() > 0);
}

void CDiagApp::OnSpyglassRefresh(UINT nID) 
{
	// TODO: Add your command handler code here
	CComboBox& ComboBox = static_cast<CMainFrame *>(m_pMainWnd)->m_ComboBox;
	
	ComboBox.SetCurSel((int)(nID - ID_SPYGLASS_REFRESH_CONSTANTLY));
	
	DWORD Temp = (DWORD)(ComboBox.GetItemData(nID - ID_SPYGLASS_REFRESH_CONSTANTLY));

	if (Temp != m_RefreshInterval)
	{
		if (Temp == c_ManualRefresh)
		{
			// switching to manual refresh
			// suspend thread, don't wanna wait INFINITE
			m_RefreshThread->SuspendThread();
			m_RefreshInterval = Temp;
			OnSpyglassRefreshUpdatenow();
		}
		else if (m_RefreshInterval == c_ManualRefresh)
		{
			// switching from manual refresh
			// resume thread, set new interval first
			m_RefreshInterval = Temp;
			m_RefreshThread->ResumeThread();
		}
		else
		{
			// terminate thread to start waiting with new interval immediately
			KillRefreshThread();
			m_RefreshInterval = Temp;
			m_RefreshThread = AfxBeginThread(RefreshThread, this);
		}
	}
}

void CDiagApp::OnSelchangeRefresh()
{
	UINT nIndex = static_cast<CMainFrame *>(m_pMainWnd)->m_ComboBox.GetCurSel();
	OnSpyglassRefresh(ID_SPYGLASS_REFRESH_CONSTANTLY + nIndex);
}

void CDiagApp::OnUpdateSpyglassRefresh(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	static_cast<CMainFrame *>(m_pMainWnd)->m_ComboBox.EnableWindow(GetNumAdapters() > 0);

	UINT nIndex = static_cast<CMainFrame *>(m_pMainWnd)->m_ComboBox.GetCurSel();
	pCmdUI->SetRadio((UINT)(ID_SPYGLASS_REFRESH_CONSTANTLY+nIndex) == pCmdUI->m_nID);
}

void CDiagApp::OnSpyglassRefreshUpdatenow() 
{
	// TODO: Add your command handler code here
	OnRefreshMessage();

	// close stream resources
	if (m_RefreshInterval == c_ManualRefresh)
		for (short i = 0; i < GetNumAdapters(); i++)
			for (short j = 0; j < GetAdapter(i)->GetNumDataSource(); j++)
				GetAdapter(i)->GetDataSource(j)->StopStats(NORMAL);
}

void CDiagApp::OnUpdateSpyglassRefreshUpdatenow(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(GetNumAdapters() > 0);
}

void CDiagApp::OnUpdateCaptureDisplaystatistics(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	CDataSourceControl *pControl = GetControl();

	pCmdUI->Enable(pControl != NULL && pControl->GetState() != dsiNone);
}

void CDiagApp::OnCaptureDisplaystatistics() 
{
	// TODO: Add your command handler code here
	CDataSourceControl *pControl = GetControl();

	if (pControl != NULL && pControl->GetState() != dsiNone)
		MakeStatFrame();		
}

void CDiagApp::OnUpdateCaptureStarttrace(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	CDataSourceControl *pControl = GetControl();

	pCmdUI->Enable(	pControl != NULL && 
		(pControl->GetState() == dsiStop || pControl->GetState() == dsiDisplay));
}

void CDiagApp::OnCaptureStarttrace() 
{
	// TODO: Add your command handler code here
	CDataSource *ds = GetDataSource();

	if (ds == NULL)
		;
	else if (ds->IsTracing())
	{
		CString msg;
		
		msg.Format(IDP_ALREADYTRACING, ds->GetName());
		AfxMessageBox(msg);
	}
	else if (!ds->StartTrace())
	{
		AfxMessageBox(IDP_TRACEFAIL);
	}
	else
	{
		CDataSourceControl *pControl = GetControl();
		
		pControl->KillTraceUI();
		if (!pControl->CreateMiniFrame())
		{
			OnCaptureStoptrace();
			AfxMessageBox(IDP_TRACEFAIL);
		}
		else
		{
			OnRefreshMessage();
			UpdateAllDocuments(	(GetSelectedItem() << 16) + uavStateChange,
				(CObject *)dsiPlay);
		}
	}
}

void CDiagApp::OnUpdateCaptureStoptrace(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(IsTracing());
}

void CDiagApp::OnCaptureStoptrace() 
{
	// TODO: Add your command handler code here
	StopTrace();

	CDataSourceControl *pControl = GetControl();
	eDataSourceImage Image;

	if (pControl != NULL)
	{
		if (!pControl->GetDataSource()->TraceDataExists())
		{
			pControl->KillTraceUI();
			Image = dsiStop;
		}
		else
		{
			UpdateActivePage(pControl);
			pControl->OnStopTrace();
			Image = dsiDisplay;
		}

		UpdateAllDocuments((GetSelectedItem() << 16) + uavStateChange, (CObject *)Image);
	}
}

void CDiagApp::OnUpdateCapturePausetrace(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(IsTracing());
	pCmdUI->SetCheck(IsPaused());
}

void CDiagApp::OnCapturePausetrace() 
{
	// TODO: Add your command handler code here
	if (IsTracing())
		ToggleTrace();
}

void CDiagApp::OnUpdateCaptureStopandview(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	const CDataSource *ds = GetDataSource();

	pCmdUI->Enable(ds != NULL && ds->IsTracing() && ds->GetTraceData()->GetNumFrames() > 0);
}

void CDiagApp::OnCaptureStopandview() 
{
	// TODO: Add your command handler code here
	OnCaptureStoptrace();
	OnCaptureDisplaycatureddata();
}

void CDiagApp::OnUpdateCaptureDisplaycatureddata(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	const CDataSource *ds = GetDataSource();

	pCmdUI->Enable(ds != NULL && !ds->IsTracing() && ds->TraceDataExists());
}

void CDiagApp::NewDocDataSource(CDataSourceControl *pControl)
{
	POSITION pos = GetFirstDocTemplatePosition();
	CTraceMultiDocTemplate *TraceDocTemplate = static_cast<CTraceMultiDocTemplate *>(GetNextDocTemplate(pos));

	TraceDocTemplate->SetNewDocDataSource(pControl);
	
	CDocument *doc = TraceDocTemplate->OpenDocumentFile(NULL, TRUE);
	doc->SetModifiedFlag();
}

void CDiagApp::OnCaptureDisplaycatureddata() 
{
	// TODO: Add your command handler code here
	CDataSourceControl *pControl = GetControl();

	if (pControl == NULL)
		return;

	const CDataSource *ds = GetDataSource();
	if (!ds->TraceDataExists())
		return;

	NewDocDataSource(pControl);
	pControl->OnNewDocument();
	UpdateAllDocuments((GetSelectedItem() << 16) + uavStateChange, (CObject *)dsiStop);
}

void CDiagApp::OnUpdateEditClearTracestatistics(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(IsTracing());
}

void CDiagApp::OnEditClearTracestatistics() 
{
	// TODO: Add your command handler code here
	if (IsTracing())
	{
		CDataSourceControl *pControl = GetControl();
		
		pControl->GetDataSource()->ClearTraceStats();
		for (short i = 0; i < pControl->GetTraceSheet()->GetPageCount(); i++)
			pControl->GetTraceSheet()->GetTracePage(i)->OnUpdate(uavClearStatistics);
		
	}
}

void CDiagApp::OnCaptureBuffersettings() 
{
	// TODO: Add your command handler code here
	CBufferSettings dlg;

	DWORD bs = GetProfileInt(
		c_pszKeySettings,
		c_pszValueBufferSize,
		cDefaultBufferSize);
	dlg.m_BufferSize.Format("%-3.1f", bs / (1024 * 1024.0f));

	DWORD fs = GetProfileInt(
		c_pszKeySettings,
		c_pszValueFrameSize,
		cDefaultFrameSize);
	if (fs == cDefaultFrameSize)
		dlg.m_FrameSize = "Full";
	else
		dlg.m_FrameSize.Format("%d", fs);

	if (dlg.DoModal() == IDOK)
	{
		WriteProfileInt(
			c_pszKeySettings,
			c_pszValueBufferSize,
			int(1024 * 1024 * atof(dlg.m_BufferSize)));
		WriteProfileInt(
			c_pszKeySettings,
			c_pszValueFrameSize,
			dlg.m_FrameSize == "Full" ? cDefaultFrameSize : atoi(dlg.m_FrameSize));
	}
}

void CDiagApp::OnUpdateCaptureSummaryinfo(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(GetSelectedItem() > CB_ERR);	
}

void CDiagApp::OnCaptureSummaryinfo() 
{
	// TODO: Add your command handler code here
	int sel = GetSelectedItem();

	if (sel > CB_ERR)
	{
		GetDataSource()->DoSummaryDlg();
		UpdateAllDocuments((sel << 16) + uavNewComment);
	}
}

// calls UpdateAllViews for all Summary window
void CDiagApp::UpdateAllDocuments(LPARAM lHint, CObject *pObject)
{
	POSITION pos = m_pDataSourceDocTemplate->GetFirstDocPosition();

	while (pos)
	{
		CTraceDoc *pDoc = (CTraceDoc *)m_pDataSourceDocTemplate->GetNextDoc(pos);

		pDoc->UpdateAllViews(NULL, lHint, pObject);
	}
}

void CDiagApp::OnEditClearstatistics() 
{
	// TODO: Add your command handler code here
	CDataSource *pDS = GetDataSource();

	if (pDS)
	{
		pDS->ClearStatistics();	
		OnSpyglassRefreshUpdatenow();
	}
}

void CDiagApp::OnUpdateEditClearstatistics(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(GetSelectedItem() > CB_ERR);	
}

BOOL CDiagApp::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class
	if (CSplashWnd::PreTranslateAppMessage(pMsg))
		return TRUE;
	
	return CWinApp::PreTranslateMessage(pMsg);
}

////////////////////////////////////////////////////////////////
// CWindowPlacement 1996 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
CWindowPlacement::CWindowPlacement()
{
   // Note: "length" is inherited from WINDOWPLACEMENT
	memset(&length, 0, sizeof(WINDOWPLACEMENT));
	length = sizeof(WINDOWPLACEMENT);
}

CWindowPlacement::~CWindowPlacement()
{
}

//////////////////
// Restore window placement from profile key
BOOL CWindowPlacement::Restore(LPCSTR lpKeyName, CWnd* pWnd)
{
	GetProfileWP(lpKeyName);

	// Only restore if window intersets the screen.
	//
	CRect rcTemp, rcScreen(	0, 0, 
		GetSystemMetrics(SM_CXSCREEN),
		GetSystemMetrics(SM_CYSCREEN));

	if (!::IntersectRect(&rcTemp, &rcNormalPosition, &rcScreen))
		return FALSE;

	pWnd->SetWindowPlacement(this);  // set placement

	return TRUE;
}

//////////////////
// Get window placement from profile.
void CWindowPlacement::GetProfileWP(LPCSTR lpKeyName)
{
	CWinApp *pApp = AfxGetApp();
	ASSERT_VALID(pApp);

	showCmd = pApp->GetProfileInt(lpKeyName, c_pszValueCmdShow, showCmd);
	flags   = pApp->GetProfileInt(lpKeyName, c_pszValuePosFlags, flags);

	ptMinPosition.x = pApp->GetProfileInt(lpKeyName,
		c_pszValueMinPosX,
		ptMinPosition.x);

	ptMinPosition.y = pApp->GetProfileInt(lpKeyName,
		c_pszValueMinPosY,
		ptMinPosition.y);

	ptMaxPosition.x = pApp->GetProfileInt(lpKeyName,
		c_pszValueMaxPosX,
		ptMaxPosition.x);

	ptMaxPosition.y = pApp->GetProfileInt(lpKeyName,
		c_pszValueMaxPosY,
		ptMaxPosition.y);

   RECT& rc = rcNormalPosition;  // because I hate typing

   rc.left  = pApp->GetProfileInt(lpKeyName, c_pszValuePosLeft,   rc.left);
   rc.right = pApp->GetProfileInt(lpKeyName, c_pszValuePosRight,  rc.right);
   rc.top   = pApp->GetProfileInt(lpKeyName, c_pszValuePosTop,    rc.top);
   rc.bottom= pApp->GetProfileInt(lpKeyName, c_pszValuePosBottom, rc.bottom);
}

////////////////
// Save window placement in app profile
void CWindowPlacement::Save(LPCSTR lpKeyName, CWnd* pWnd)
{
   pWnd->GetWindowPlacement(this);
   WriteProfileWP(lpKeyName);
}

//////////////////
// Write window placement to app profile
void CWindowPlacement::WriteProfileWP(LPCSTR lpKeyName)
{
   CWinApp *pApp = AfxGetApp();
   ASSERT_VALID(pApp);
 
   pApp->WriteProfileInt(lpKeyName, c_pszValueCmdShow, showCmd);
   pApp->WriteProfileInt(lpKeyName, c_pszValuePosFlags,   flags);
   pApp->WriteProfileInt(lpKeyName, c_pszValueMinPosX, ptMinPosition.x);
   pApp->WriteProfileInt(lpKeyName, c_pszValueMinPosY, ptMinPosition.y);
   pApp->WriteProfileInt(lpKeyName, c_pszValueMaxPosX, ptMaxPosition.x);
   pApp->WriteProfileInt(lpKeyName, c_pszValueMaxPosY, ptMaxPosition.y);

   RECT& rc = rcNormalPosition;  // because I hate typing

   pApp->WriteProfileInt(lpKeyName, c_pszValuePosLeft,   rc.left);
   pApp->WriteProfileInt(lpKeyName, c_pszValuePosRight,  rc.right);
   pApp->WriteProfileInt(lpKeyName, c_pszValuePosTop,    rc.top);
   pApp->WriteProfileInt(lpKeyName, c_pszValuePosBottom, rc.bottom);
}

//////////////////
// Write window placement to archive
// WARNING: archiving functions are untested.
CArchive& operator<<(CArchive& ar, const CWindowPlacement& wp)
{
   ar << wp.length;
   ar << wp.flags;
   ar << wp.showCmd;
   ar << wp.ptMinPosition;
   ar << wp.ptMaxPosition;
   ar << wp.rcNormalPosition;

   return ar;
}

//////////////////
// Read window placement from archive
// WARNING: archiving functions are untested.
CArchive& operator>>(CArchive& ar, CWindowPlacement& wp)
{
   ar >> wp.length;
   ar >> wp.flags;
   ar >> wp.showCmd;
   ar >> wp.ptMinPosition;
   ar >> wp.ptMaxPosition;
   ar >> wp.rcNormalPosition;
 
   return ar;
}
 

