/*++
*******************************************************************************
* Copyright (c) 1990-98 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 copyrighted work of Digi International	*
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly	*
* prohibited.																						*
* 																										*
* Restricted Rights Legend																		*
*																										*
* Use, duplication, or disclosure by the Government is subject to					*
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in			*
* Technical Data and Computer Software clause at DFARS 252.227-7031 or			*
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -				*
* Restricted Rights at 48 CFR 52.227-19, as applicable.								*
*																										*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343				*
*																										*
*******************************************************************************

Module Name:

   sxbmem.cpp

Abstract:

   ???

Author:

   Rodger Bernstein

--*/

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

#include "stdafx.h"
#include "sxbmem.h"

#include "sxbmedoc.h"
#include "memview.h"
#include "sxbmevw.h"
#include "mainfrm.h"
#include "childfrm.h"
#include "dlg.h"

#include "clyde.h"
#include "syncport.h"
#include "prime.h"
#include "houston.h"
#include "RegNames.h"

#include <fstream.h>

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#define DEFAULT_DEFS_FILE 	"sync.kme"
#define DEFAULT_SYM_FILE	"sync.sym"


/////////////////////////////////////////////////////////////////////////////
// CSxbmemApp

BEGIN_MESSAGE_MAP(CSxbmemApp, CWinApp)
	//{{AFX_MSG_MAP(CSxbmemApp)
	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
	ON_COMMAND(ID_CAPTURE_TRACEPORT, OnCaptureTraceport)
	ON_UPDATE_COMMAND_UI(ID_CAPTURE_TRACEPORT, OnUpdateCaptureTraceport)
	ON_COMMAND(ID_FILE_LOADSYMBOLTABLE, OnFileLoadsymboltable)
	ON_COMMAND(ID_FILE_LOADDEFINITIONS, OnFileLoaddefinitions)
	//}}AFX_MSG_MAP
	// Standard file based document commands
	ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
	ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
	// Standard print setup command
	ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSxbmemApp construction

CSxbmemApp::CSxbmemApp()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CSxbmemApp object

CSxbmemApp theApp;

/////////////////////////////////////////////////////////////////////////////
// CSxbmemApp initialization

BOOL CSxbmemApp::InitInstance()
{
	// 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.

	// Add all supported adapter classes to the list!
	CAdapter::AddAdapter("SyncPort", RUNTIME_CLASS(CSyncPort));
	CAdapter::AddAdapter("Prime", RUNTIME_CLASS(CDatafirePrime));
	CAdapter::AddAdapter("London", RUNTIME_CLASS(CHouston));
	CAdapter::AddAdapter("Chaska", RUNTIME_CLASS(CHouston));
	CAdapter::AddAdapter("Houston", RUNTIME_CLASS(CHouston));
	CAdapter::AddAdapter("Clydesdale", RUNTIME_CLASS(CClydesdale));

	BOOL hasadapters = LoadConfig(); // look for SyncPort adapters
	if (!hasadapters) { // Did we find any?
		AfxMessageBox("There are no Digi adapters installed or functioning on this machine.\n");
		return FALSE;
		}

	SetRegistryKey("Digi"); // default program settings are at HKEY_CURRENT_USER\SoftWare\DigiBoard
	LoadStdProfileSettings();  // Load standard INI file options (including MRU)

	// Register the application's document templates.  Document templates
	//  serve as the connection between documents, frame windows and views.

	CMultiDocTemplate* pDocTemplate;
	pDocTemplate = new CMultiDocTemplate(
		IDR_SXBMEMTYPE,
		RUNTIME_CLASS(CSxbmemDoc),
		RUNTIME_CLASS(CChildFrame),       // main SDI frame window
		RUNTIME_CLASS(CSxbmemView));
	AddDocTemplate(pDocTemplate);

	CString fname = GetProfileString("Settings", "SymTable", DEFAULT_SYM_FILE);
	CFileStatus fs;

	if (!CFile::GetStatus(fname, fs)) {
		CString msg = "The symbol file '" + fname + "' could not be found. "
									"Would you like browse for it?";

		if (AfxMessageBox(msg, MB_YESNO) == IDYES)
			OnFileLoadsymboltable();
		}
	else
		LoadSymbolTable(fname);
	
	fname = GetProfileString("Settings", "DefTable", DEFAULT_DEFS_FILE);

	if (!CFile::GetStatus(fname, fs)) {
		CString msg = "The KME definitions file '" + fname + "' could not be found. "
									"Would you like browse for it?";
		if (AfxMessageBox(msg, MB_YESNO) == IDYES)
			OnFileLoaddefinitions();
		}
	else
		LoadDefs(fname);

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

	return TRUE;
}

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

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

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

// Implementation
protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//{{AFX_MSG(CAboutDlg)
		// No message handlers
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

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

/////////////////////////////////////////////////////////////////////////////
// CSxbmemApp commands

BOOL CSxbmemApp::GetMemory(DWORD MemAddress, LPBYTE Buffer, DWORD *Size)
{
	return m_CurDataSource->GetMemory(MemAddress, Buffer, Size);
}

BOOL CSxbmemApp::SetMemory(DWORD MemAddress, LPBYTE Buffer, DWORD *Size)
{
	return m_CurDataSource->SetMemory(MemAddress, Buffer, Size);
}

CString CSxbmemApp::GetCurDataSourceName()
{
	return m_CurDataSource->GetName();
}

/*******************************************************************************
/*
/* function : BOOL LoadConfig(void)
/* return:		NT4 or NT5 LoadConfig Status
/* params:		None
/* desc:			Determine if this is NT5 or NT4 and call the appropriate
/*                  Load COnfig Routine.
*******************************************************************************/

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

	}
	return bSuccess;
}

/*******************************************************************************
/*
/* function : BOOL LoadConfigNT5(void)
/* return:		TRUE if there is atleast one functioning SyncPort adapter
/* params:		None
/* desc:			Look in the registry for installed SyncPort adapters.
/*						They can be running X.25 or Frame Relay. For each one found
/*						create an 'CAdapter' derived class. After creation the adapters
/*						parameters are loaded, these parameters are the ones 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 variable 'm_CurDataSource'
/*						is set to the first adapter added to 'm_Adapters'.
/*						'm_CurDataSource' must be set to an 'CAdapter' derived class when
/*						every there is a stat or trace window in existence.
*******************************************************************************/
BOOL CSxbmemApp::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 += _T("Parameters");

			TRACE("SXBMEM %s\n",strKey);
			
			// open key\Parameter registry key
			if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, strKey, &hkParams) == ERROR_SUCCESS)
			{
				// Get the Digi-specific Option value, defining the adapter type
				BYTE Option[256];
				DWORD cbOption = 256;
				DWORD OptionType = REG_SZ;
				LONG Success;
				Success = RegQueryValueEx(hkParams, "Option", 0, &OptionType, Option, &cbOption);
				if (Success == ERROR_SUCCESS)
				{
					// Finally!  Is this a supported adapter?
					CRuntimeClass *rts = CAdapter::RegistryLookUp(Option);
					if (rts != NULL)
					{
						LPTSTR	lpstrDevice;
						CAdapter *adapter = (CAdapter *)rts->CreateObject();
						CString strDevice = CString(c_pszKeyServiceName) + KeyName;
						lpstrDevice = strDevice.GetBuffer(256);
						// 'CAdapter::LoadConfig' load the adapters params and tests the driver
						if (adapter->LoadConfig((PCHAR)lpstrDevice)) 
						{
							m_Adapters.Add(adapter);
							if (m_CurDataSource == NULL)
								m_CurDataSource = adapter;
						}
						else
							delete adapter;
					}
				}

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

	return m_Adapters.GetSize() > 0;

}

/*******************************************************************************
/*
/* function : BOOL LoadConfigNT4(void)
/* return:		TRUE if there is atleast one functioning SyncPort adapter
/* params:		None
/* desc:			Look in the registry for installed SyncPort adapters.
/*						They can be running X.25 or Frame Relay. For each one found
/*						create an 'CAdapter' derived class. After creation the adapters
/*						parameters are loaded, these parameters are the ones 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 variable 'm_CurDataSource'
/*						is set to the first adapter added to 'm_Adapters'.
/*						'm_CurDataSource' must be set to an 'CAdapter' derived class when
/*						every there is a stat or trace window in existence.
*******************************************************************************/
BOOL CSxbmemApp::LoadConfigNT4()
{
	HKEY digisoft;
 	
	// try to open key where all NT adapters are listed
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
	                 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", 
	                 &digisoft) == ERROR_SUCCESS) 
	{
		char KeyName[256];
		DWORD cbName;
		DWORD i = 0;
		FILETIME time;

		// loop through all adapters in registry
		while (cbName = 256, RegEnumKeyEx(digisoft, i++, KeyName, &cbName, NULL, NULL, NULL, &time) == ERROR_SUCCESS) 
		{
			HKEY digidriver;

			if ( RegOpenKeyEx(digisoft, KeyName, &digidriver) == ERROR_SUCCESS )
			{
				BYTE Service[256];
				DWORD ServiceType = REG_SZ, cbService = 256;
				LONG Success = RegQueryValueEx(digidriver, "ServiceName", 0, &ServiceType, Service, &cbService);
				RegCloseKey(digidriver);
				
				if ( Success == ERROR_SUCCESS )
				{
					BYTE ServicePath[256];
					HKEY hService;
					strcpy( (PCHAR)ServicePath, "SYSTEM\\CurrentControlSet\\Services\\" );
					strcat( (PCHAR)&ServicePath[strlen( (PCHAR)ServicePath )], (PCHAR)Service );
					strcat( (PCHAR)&ServicePath[strlen( (PCHAR)ServicePath )], "\\Parameters" );
					if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, (PCHAR)ServicePath, &hService ) == ERROR_SUCCESS )
					{
						BYTE Option[256];
						DWORD cbOption = 256;
						DWORD OptionType = REG_SZ;
						LONG Success;
						Success = RegQueryValueEx(hService, "Option", 0, &OptionType, Option, &cbOption);
						RegCloseKey( hService );

						if ( Success == ERROR_SUCCESS )
						{
							CRuntimeClass *rts = CAdapter::RegistryLookUp(Option);
							if (rts != NULL)
							{
								CAdapter *adapter = (CAdapter *)rts->CreateObject();
								// 'CAdapter::LoadConfig' load the adapters params and tests the driver
								if (adapter->LoadConfig((PCHAR)Service)) 
								{
									m_Adapters.Add(adapter);
									if (m_CurDataSource == NULL)
										m_CurDataSource = adapter;
								}
								else
									delete adapter;
							}
						}
					}
				}
			}
		}
		RegCloseKey(digisoft);
	}
	return m_Adapters.GetSize() > 0;
}

/*******************************************************************************
/*
/* function : void OnCaptureTraceport (void)
/* return:		None
/* params:		None
/* desc:			this brings up the dialog box where the user changes the
/*						current data source. The user can also see the some of the 
/*						data sources information, like driver names, desc., etc...
/*						If the user does change data sources the stats and capture
/*						windows need to be reinited
/* note:			Future versions may need to support X.25 and Frame Relay or
/*						what ever at the same time. If the frame contains X.25 panes
/*						and the user switches to a Frame Relay data source reiniting
/*						will not be good enough. The stat and trace windows will have
/*						to be destroyed and recreated with Frame Relay panes. You could
/*						also code the frame windows to change panes instead but that 
/*						would be a greater coding undertaking
/*						
*******************************************************************************/
void CSxbmemApp::OnCaptureTraceport() 
{
	// TODO: Add your command handler code here
	if (m_Adapters.GetSize() > 0) {
		CDataSourceDlg dsDlg;

		if (dsDlg.DoModal() == IDOK) {
			}
		}
}

void CSxbmemApp::OnUpdateCaptureTraceport(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_Adapters.GetSize() > 0);
}

int CSxbmemApp::ExitInstance() 
{
	// TODO: Add your specialized code here and/or call the base class
	for (short i = 0; i < m_Adapters.GetSize(); i++)
		delete m_Adapters[i];

	return CWinApp::ExitInstance();
}

BOOL CSxbmemApp::LoadSymbolTable(const CString& fname)
{
	ifstream symbfile(fname);

	if (!symbfile.is_open())
		return FALSE;

	m_SymbolTable.RemoveAll();

	BOOL startdata = FALSE;
	DWORD addr;
	char flag;
	char name[64];
	char line[256];
	CSymbol *last = NULL;

	while (!symbfile.eof()) {
		symbfile.getline(line, 256);

		if (sscanf(line, "%x %c %s\n", &addr, &flag, name) != 3)
			continue;

		CSymbol *symb = new CSymbol;
		symb->m_Address = addr & 0x00FFFFFF;
		symb->m_Flags = flag;
		symb->m_Size = 0;
		
		if (last)
			last->m_Size = symb->m_Address - last->m_Address;

		if (FindSymbol(name))
			m_SymbolTable.RemoveKey(name);

		m_SymbolTable.SetAt(name, symb);
		last = symb;
		}

	return TRUE;
}

inline void AFXAPI DestructElements(CSymbol ** pElements, int nCount)
{
	for (int i = 0; i < nCount; i++)
		delete pElements[i];
}

void CSxbmemApp::AddSymbols(CComboBox& box)
{
	POSITION pos = m_SymbolTable.GetStartPosition();

	CSymbol *symb;
	CString key;

	box.ResetContent();
	while (pos) {
		m_SymbolTable.GetNextAssoc(pos, key, symb);
		box.SetItemDataPtr(box.AddString(key), symb);
		}
}

const CSymbol *CSxbmemApp::FindSymbol(const CString& key) const
{
	CSymbol *symb;

	return m_SymbolTable.Lookup(key, symb) ? symb : NULL;
}

class CFormat
{
	DWORD m_Size;
	eDisplayFlags m_Flags;

public :
	CFormat() { m_Size = 0; };
	CFormat(DWORD s, int f) { m_Size = s; m_Flags = (eDisplayFlags)f; };

	DWORD Size() const { return m_Size; };
	eDisplayFlags Flags() const { return m_Flags; };
};

CMap<char, char, CFormat, CFormat> m_FormatTable;


BOOL MakeDef(ifstream& deffile, CDef *& def)
{
	char token; // last read token char
	int curmember = 0; // next member var need format/size info
	int repeat = 1; // last digit read
	CFormat format; // format assoc with last read token

	def = new CDef;
	def->m_Size = 0;

	while (!deffile.eof()) {
		deffile >> token >> ws;

		switch (token) {
			default :
				if (m_FormatTable.Lookup(token, format)) {
					do {
						if (curmember == def->m_Members.GetSize())
							curmember--;

						CElement *element = def->m_Members[curmember++];

						if (curmember == def->m_Members.GetSize() && repeat > 1) {
							element->m_Size += format.Size() * repeat;
							def->m_Size += format.Size() * (repeat - 1);
							repeat = 1;
							}
						else
							element->m_Size = format.Size();

						element->m_Flags = format.Flags();
						element->m_Offset = def->m_Size;
						def->m_Size += format.Size();
						} while (--repeat > 0);
					repeat = 1;
					break;
					}
				else if (!isupper(token)) {
					CString msg;

					msg.Format("Error: Format token %c is not supported.", token);
					AfxMessageBox(msg);
					delete def;
					return FALSE;
					}
				// else fall through
			case '#' : case '!' : { // end of definition
				deffile.putback(token);
				int actual = (int)(def->m_Members.GetSize());

				if (curmember != actual) {
					CString msg;

					msg.Format("Error: Number of Strings %d does not match number of Formats %d.", 
											actual,
											curmember);
					AfxMessageBox(msg);
					delete def;
					return FALSE;
					}

				return TRUE;
				}
			case '\n' : case '\t' : case ' ' : 
				ASSERT(FALSE);
			case 'n' :
				// fall through 
			case '.' :
				break; // ignore these
			case '\"' : case '\'' : { // start of member name
				char name[128];

				deffile.getline(name, 128, '\"');
				
				CElement *element = new CElement;
				element->m_Name = name;
				element->m_Size = 0;

				def->m_Members.Add(element);
				} break;
			case '0' : case '1' : case '2' : case '3' : case '4' : 
			case '5' : case '6' : case '7' : case '8' : case '9' :
				deffile.putback(token);
				deffile >> repeat >> ws;
				break;
			case '+' :
				def->m_Size += repeat;
				repeat = 1;
				break;
			}
		}

	return TRUE;
}

BOOL CSxbmemApp::LoadDefs(const CString& fname)
{
	ifstream deffile(fname);

	if (!deffile.is_open())
		return FALSE;

	m_FormatTable.SetAt('a', CFormat(1, dfMaskChar));
	m_FormatTable.SetAt('b', CFormat(1, dfByteHex));
	m_FormatTable.SetAt('c', CFormat(1, dfChar));
	m_FormatTable.SetAt('d', CFormat(1, dfShort | dfSigned));
	m_FormatTable.SetAt('e', CFormat(4, dfLong));
	m_FormatTable.SetAt('g', CFormat(1, dfPadding));
	m_FormatTable.SetAt('i', CFormat(2, dfShortHex));
	m_FormatTable.SetAt('l', CFormat(4, dfLongHex));
	m_FormatTable.SetAt('s', CFormat(8, dfString));
	m_FormatTable.SetAt('x', CFormat(2, dfShortHex));
	m_FormatTable.SetAt('z', CFormat(4, dfLong));

	char token;
	CDef *def = NULL;
	char name[128];

	while (!deffile.eof()) {
		deffile >> token >> ws;

		switch (token) {
			case '#' : { // comment til end of line
				char line[256];
				deffile.getline(line, 256);
				deffile.eatwhite();
				} break;
			case '!' : // named definition
				deffile >> name >> ws;
				if (MakeDef(deffile, def))
					m_DefTable.SetAt(name, def);
				else {
					CString msg;

					msg.Format("Error: Parsing error in Struct %s.", name);
					AfxMessageBox(msg);
					return FALSE;
					}
				break;
			case '\n' : case '\t' : case ' ' :
				break;
			default : { // uppercase definition name
				CString msg;

				if (isupper(token)) {
					if (MakeDef(deffile, def))
					{
						CString TokenName(token);
						m_DefTable.SetAt(TokenName, def);
					}
					else // parse error
						msg.Format("Error: Parsing error in Struct %c.", token);
					}
				else
					msg.Format("Error: Undefined token %c.", token);

				if (msg != "") {
					AfxMessageBox(msg);
					return FALSE;
					}
				}
			}
		}
	return TRUE;
}

inline void AFXAPI DestructElements(CDef **pElements, int nCount)
{
	for (int i = 0; i < nCount; i++)
		delete pElements[i];
}

inline void AFXAPI DestructElements(CElement **pElements, int nCount)
{
	for (int i = 0; i < nCount; i++)
		delete pElements[i];
}

void CSxbmemApp::AddDefs(CComboBox& box)
{
	POSITION pos = m_DefTable.GetStartPosition();

	CDef *def;
	CString key;

	box.ResetContent();
	box.AddString("Raw bytes");
	while (pos) {
		m_DefTable.GetNextAssoc(pos, key, def);
		box.SetItemDataPtr(box.AddString(key), def);
		}
}

const CDef *CSxbmemApp::FindDef(const CString& key) const
{
	CDef *def;

	return m_DefTable.Lookup(key, def) ? def : NULL;
}


void CSxbmemApp::OnFileLoadsymboltable() 
{
	// TODO: Add your command handler code here
	CString fname = GetProfileString("Settings", "SymTable", DEFAULT_SYM_FILE);

	CFileDialog file(TRUE, "sym", fname, OFN_HIDEREADONLY,
										"Symbol Files (*.sym)|*.sym|All Files (*.*)|*.*||");

	if (file.DoModal() == IDCANCEL)
		return;

	fname = file.GetPathName();
	WriteProfileString("Settings", "SymTable", fname);
	LoadSymbolTable(fname);

	POSITION pos = GetFirstDocTemplatePosition();
	CDocTemplate *pDocTemplate = GetNextDocTemplate(pos);

	pos = pDocTemplate->GetFirstDocPosition();
	while (pos) {
		CDocument *pDoc = pDocTemplate->GetNextDoc(pos);
		POSITION viewPos = pDoc->GetFirstViewPosition();
		CView *pView = pDoc->GetNextView(viewPos);

		pDocTemplate->InitialUpdateFrame(pView->GetParentFrame(), pDoc, TRUE);
		}
}

void CSxbmemApp::OnFileLoaddefinitions() 
{
	// TODO: Add your command handler code here
	CString fname = GetProfileString("Settings", "DefTable", DEFAULT_DEFS_FILE);

	CFileDialog file(TRUE, "kme", fname, OFN_HIDEREADONLY,
										"Definitions Files (*.kme)|*.kme|All Files (*.*)|*.*||");

	if (file.DoModal() == IDCANCEL)
		return;

	fname = file.GetPathName();
	WriteProfileString("Settings", "DefTable", fname);
	LoadDefs(fname);

	POSITION pos = GetFirstDocTemplatePosition();
	CDocTemplate *pDocTemplate = GetNextDocTemplate(pos);

	pos = pDocTemplate->GetFirstDocPosition();
	while (pos) {
		CDocument *pDoc = pDocTemplate->GetNextDoc(pos);
		POSITION viewPos = pDoc->GetFirstViewPosition();
		CView *pView = pDoc->GetNextView(viewPos);

		pDocTemplate->InitialUpdateFrame(pView->GetParentFrame(), pDoc, TRUE);
		}
}
