//====== Тип стуктур для описания ошибок struct ErrorType { string Code; // Код ошибки string Identifier; // Ее идентификатор string Message; // Текстовое описание //====== Конструктор с параметрами ErrorType(string с, string i, string m) { Code = c; Identifier = i; Message = m; } }; typedef vector 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) { //=== Ищет подстроку или первую непустую строку //=== Цикл прохода по всем строкам файла 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 // Потоковый ввод-вывод STL //=== Буферизованные потоки, связанные с файлами (STL) #include #include // Текстовые строки STL #include // Контейнеры STL типа vector //====== Работаем в пространстве имен std using namespace std;