//====== Тип стуктур для описания ошибок
struct ErrorType
{
	string Code;			// Код ошибки
	string Identifier;	// Ее идентификатор
	string Message;		// Текстовое описание

	//====== Конструктор с параметрами
	ErrorType(string с, string i, string m)
	{
		Code = c;
		Identifier = i;
		Message = m;
	}
};


typedef vector<ErrorType> ERROR_VECTOR;


	HICON hMyIcon = ::LoadIcon(0,IDI_WINLOGO);
	SetIcon(hMyIcon, TRUE);			// Set big icon
	SetIcon(hMyIcon, FALSE);		// Set small



Тип элемента
Заголовок (комментарий)
Идентификатор
Dialog
WinError View
IDD_LOOK_DIALOG
Group-box
Error Number:
IDC_STATIC
Spin

IDC_SPIN
Edit
// справа от IDC_SPIN
IDC_CURRENT
Slider

IDC_SLIDER
Text
Total:
IDC_STATIC
Text
// под Total:
IDC_TOTAL
Button
Close
IDCANCEL
Group-box
Parameters:
IDC_STATIC
Text
Error Code:
IDC_STATIC
Text
// справа от Error Code:
IDC_CODE
Text
Find:
IDC_STATIC
Edit
// справа от Find:
IDC_FIND
Picture

IDC_RIGHT
Picture

IDC_LEFT
Text
Severity:
IDC_STATIC
Text
// справа от Severity:
IDC_SEVERITY
Text
Facility:
IDC_STATIC
Text
// справа от Facility:
IDC_FACILITY
Text
Identifier:
IDC_STATIC
Text
// справа от Identifier:
IDC_ID
Text
Message:
IDC_STATIC
Text
// справа от Message:
IDC_MSG

void CLookDlg::OnDeltaposSpin(NMHDR *pNMHDR,
												LRESULT *pResult)
{
	NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;

	// TODO: Add your control notification handler code here
	*pResult = 0;
}


//====== Вычисляем желаемую позицию
int nPos = m_Spin.GetPos() + pNMUpDown->iDelta;
//====== Если она вне недопустимых пределов, то уходим
if (nPos < 0 || m_nItems <= nPos)
	return;

//====== Корректируем позицию ползунка
m_Slider.SetPos(nPos);

//====== Расшифровываем код ошибки
GetInfo(nPos);

//====== Вызываем обмен данными с элементами окна диалога
UpdateData(FALSE);



CString s;
//====== Выбираем код ошибки, введенный пользователем
GetDlgItemText(IDC_FIND, s);

//====== Преобразуем к типу string, с которым мы работаем
string find = s; 

//====== Ищем код в контейнере m_Vector
for(int n=0; n < m_nItems && find != m_Vector[n].Code; n++)
		;

if (n < m_nItems)			// Если нашли,
{
	GetInfo(n);				// то расшифровываем этот код
	m_Slider.SetPos(n);		// и синхронизируем ползунок
	UpdateData(FALSE);		// Высвечиваем данные в окнах
}


void CLookDlg::OnHScroll(UINT nSBCode, UINT nPos,
											CScrollBar* pScrollBar) 
{
	//====== Расшифровываем новый код
	GetInfo(m_Slider.GetPos());
	//====== Помещаем данные в поля диалога
	UpdateData(FALSE);
}


void CLookDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	CRect left, right;

	//====== Узнаем координаты левой картинки
	GetDlgItem(IDC_LEFT)->GetWindowRect(&left);

	//====== Переход к относительным координатам
	ScreenToClient(&left);

	//====== Узнаем координаты правой картинки
	GetDlgItem(IDC_RIGHT)->GetWindowRect(&right);
	ScreenToClient(&right);

	//====== Объединяем площади двух картинок
	left.UnionRect(left,right);

	//====== Если координаты курсора внутри этой площади
	if (left.PtInRect(point))
		//====== Вызываем диалог About
		OnSysCommand(IDM_ABOUTBOX,0);

	//====== Вызов родительской версии	CDialog::OnLButtonDown(nFlags, point);
}


void CLookDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
		CDialog(IDD_ABOUTBOX).DoModal();
	else
		CDialog::OnSysCommand(nID, lParam);
}


BOOL CLookDlg::OnInitDialog()
{
	//======= Добываем адрес меню управления окном
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu)
	{
		//====== Добавляем команду About
		pSysMenu->AppendMenu(MF_SEPARATOR);
		pSysMenu->AppendMenu(MF_STRING,
								IDM_ABOUTBOX, "About...");
	}
	//====== Загружаем свой (нестандартный) значок  
	HICON hMyIcon =
		::LoadIcon(GetModuleHandle(0),(char*)(IDI_EYELEFT));
	SetIcon(hMyIcon, TRUE);			// Set big icon
	SetIcon(hMyIcon, FALSE);		// Set small icon
	
	//====== Если не удалось найти файл,
	if (!ReadErrors())
	{
		PostMessage(WM_QUIT);	// уходим
		return FALSE;
	}

	//====== Количество элементов в контейнере
	//====== преобразуем в строку
	m_Total.Format("%d",m_nItems);

	//====== Ищем и расшифровываем первый код ошибки
	GetInfo(0);
	
	//====== Вызов родительской версии диалога
	CDialog::OnInitDialog();
	
	//====== Устанавливаем окно-двойник для счетчика
	m_Spin.SetBuddy(GetDlgItem(IDC_CURRENT));
	//====== Диапазон изменения показаний счетчика
	m_Spin.SetRange(0, m_nItems-1);
	
	//====== Диапазон изменения позиции ползунка
	m_Slider.SetRange(0, m_nItems-1);
	//====== Устанавливаем цену делений для шкалы ползунка
	m_Slider.SetTicFreq(m_nItems/10);

	return TRUE;
}


if ((nID & 0xFFF0) == IDM_ABOUTBOX)
		CDialog(IDD_ABOUTBOX).DoModal();


//====== Контейнер структур типа ErrorType
ERROR_VECTOR m_Vector;
//====== Размерность контейнера
int m_nItems;


bool CLookDlg::ReadErrors()		
{
	//====== Поиск и чтение информации об ошибках

	//====== Пытаемся найти путь в реестре
	string sPath = GetPathFromRegistry();

	//====== В случае неудачи пытаемся узнать у пользователя
	if (sPath.empty())
		sPath = GetPathFromUser();
	if (sPath.empty())
		return false;			// При отказе уходим
	
	//====== Пытаемся открыть файл
	ifstream is (sPath.c_str());
	if (!is)
	{
		MessageBox ("Не могу найти WinError.h","Выход");
		return false;
	}
	else
	{
		//====== Последовательно ищем все ошибки
		while (GetNextErrorCode(is))
		{
			//==== Создаем новый объект типа ErrorType и 
			//==== помещаем его в контейнер
			m_Vector.push_back(ErrorType(gCode, gsID, gsMsg));
		}
		is.close();					// Закрываем файл
	}

	//====== Запоминаем размер контейнера
	m_nItems = m_Vector.size();
	return bool(m_nItems != 0);
}



//=== Текущие значения кода, индекса и текста сообщения
string gCode, gsID, gsMsg;

//====== Количество категорий (групп) ошибок
const int N_FACILITIES = 23; 

//====== Имена категорий ошибок
TCHAR *gsFacilities[N_FACILITIES + 1] =
{
	"NULL",		"RPC",				"Dispatch",
 "Storage",	"Interface",		"Unknown",
 "Unknown",	"Win32",			"Windows",
 "SSPI",		"Control",		"Cert",
	"Internet",	"MediaServer",	"MSMQ",
 "SetupAPI",	"Smart Card",		"COM+",
 "AAF",			"URT",				"ACS",
 "DPlay",		"UMI",				"SXS"
};


void CLookDlg::GetInfo(int nPos)
{
	//====== Текущая позиция
	m_CurPos.Format("%d",nPos);
		
	if (nPos >= m_nItems)
		return;

	//======= Выбираем поля структуры
	m_Code	= m_Vector[nPos].Code.c_str();
	m_Msg	= m_Vector[nPos].Message.c_str();
	m_ID= m_Vector[nPos].Identifier.c_str();

	//====== Преобразование кода в целое число
	DWORD dw = strtoul(LPCTSTR(m_Code),0,0);

	//====== Выделяем старший бит (Severity)
	m_Severity = dw & 0x80000000 ? "Fail" : "Success";
	
	//=== COM-коды это HEX-коды, длина которых > 8 символов
	//=== В этой ветви мы обрабатываем Win32-ошибки
	if (m_Code.GetLength() < 8)
	{
		if (dw)
		{	
			//====== Вставляем поля facility и severity
			dw = 0x80000000 | (0x7 << 16) | (dw & 0xFFFF);
			m_Severity = "Error";
		}
	}
		
	//====== Выделяем поле facility
	UINT f = (dw>>16) & 0x1FFF;

	//====== Выбираем нужную аббревиатуру
	m_Facility = f <= N_FACILITIES ? gsFacilities[f]
										: "Unknown";
}



string CLookDlg::GetPathFromRegistry(void)
{
	HKEY hkey;				// Описатель ключа реестра
	TCHAR path[MAX_PATH];	// Временный буфер

	TCHAR vs[] =				// Строка для поиска ключа
		"SOFTWARE\\Microsoft\\VisualStudio\\7.0\\Setup\\VC";

	DWORD dw, d;

	//====== Пытаемся найти ключ и открыть его,
	//====== затем пробуем открыть второй ключ (subkey)
	//====== и прочесть его запись (value)
	bool ok = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, vs, 0,
						KEY_READ, &hkey)== ERROR_SUCCESS
			&& ::RegQueryValueEx (hkey,"ProductDir", 0, &dw,
						(LPBYTE)path, &d) == ERROR_SUCCESS;

	string sPath = "";
	if (ok)
	{
		sPath = path;
		//====== Дополняем путь именем папки и файла
		sPath += "\\Include\\Winerror.h";
	}
	return sPath;
}



string CLookDlg::GetPathFromUser(void)
{
	//====== Путь к файлу WinError.h пока пуст
	string path = "";
	//====== Указатель на интерфейс IMalloc
	LPMALLOC pMalloc;

	if (MessageBox("Не могу найти папку,"
					" где расположена студия"
					"Visual C++.\r\rВы покажете путь к ней?",
					"Поиск в реестре Windows",
					MB_YESNO | MB_ICONQUESTION)==IDNO
				|| FAILED( SHGetMalloc(&pMalloc) ))
		return path;
	
	BROWSEINFO bi;
	ZeroMemory (&bi,sizeof(bi));
	bi.ulFlags = BIF_RETURNONLYFSDIRS;
	
	//====== Запуск диалога поиска папки
	LPITEMIDLIST pidl = SHBrowseForFolder(&bi);

	if (pidl)
	{
		TCHAR szDir[MAX_PATH];
		if (SHGetPathFromIDList(pidl,szDir))
		{
			path = szDir;
			path += "\\Include\\Winerror.h";
		}
			
		pMalloc->Free(pidl);
 	pMalloc->Release();
	}
	return path;
}



bool GetNextErrorCode(ifstream& is)
{
	//===== Поиск и выбор очередной ошибки из потока is
	string s;
	//==== Ищем строку текста "MessageId: "
	int pos = FindText(is, s, "MessageId: ");
	//==== Если дошли до конца файла, уходим
	if (is.eof())
		return false;

	//=== Индекс ошибки следует за строкой "MessageId:
	gsID = s.substr(pos);
	//=== Ищем строку текста "MessageText: "
	FindText(is, s, "MessageText:");

	// Текстовое описание ошибки следует за пустым текстом
	FindText(is, gsMsg="");	

	// Код ошибки (или HRESULT) следует за #define
	FindText(is, s, "#define");

	//== Ищем 'L' и стираем его и все, что за ним следует
	s.erase(pos=s.rfind("L"));	

	//======= Ищем пробел слева от кода
	gCode = s.substr(s.rfind(" ",pos)+1);
	//=== Ищем скобку, которая предшествует COM-ошибкам
	if ( (pos=gCode.rfind("(")) != -1)
		gCode.erase(0,pos+1);	// Усекаем строку слева
	
	return true;
}



int FindText (ifstream& is, string& s, TCHAR *text=NULL)
{
	//=== Ищет подстроку <text> или первую непустую строку
	//=== Цикл прохода по всем строкам файла
	for (int pos=-1;  pos==-1 && !is.eof(); )
	{
		//====== Считываем всю строку (до символа'\n')
		getline(is, s, '\n');

		//====== В первом режиме text не равен нулю
		//====== и мы ищем этот текст, иначе ищем
		//====== первый непустой символ

		pos = text ? s.find(text) : s.find_first_not_of("/ ");

		if (pos!=-1) 			// Если нашли
			s.erase(0,pos);	// Усекаем строку слева
	}
	//=== Если искали и нашли текст, то возвращаем его длину,
	//=== которая имеет смысл позиции, следующей за текстом
	if (text && !is.eof())
		return strlen(text);

	//== Если ищем непустую строку, то пропускаем все пустые
	string st;

	for (pos=0;  pos!=-1 && !is.eof(); )
	{
		getline(is,st,'\n');
		pos = st.find_first_not_of("/ ");

		//====== Если нашли непустой текст,
		//====== то сливаем его с уже найденным
		if (pos != -1)
			s += ' ' + st.substr(pos);
	}
	//=== Возвращаем 0-ю позицию, так как нужен весь текст
	return 0;
}



~CLookDlg() { m_Vector.clear(); }



#include <iostream>	// Потоковый ввод-вывод STL
//=== Буферизованные потоки, связанные с файлами (STL)
#include <fstream>
#include <string>		// Текстовые строки STL
#include <vector>		// Контейнеры STL типа vector

//====== Работаем в пространстве имен std
using namespace std;







