Часть 1
Часть 2
Часть 3
Пора копнуть поглубже…
Для начала хорошая новость: хочется надеяться, что Borland всё-таки не окончательно "кинула"
разработчиков на C++ Builder 1. Кажется, теперь Delphi и C++ Builder сольются, наконец, в экстазе.
Эта и несколько последующих статей ценны, в основном, большим количеством кода, который может пригодиться.
Приступаю к описанию системных компонентов с закладки "ASK Tools". В первой статье я агитировал за то, что обработка любых ошибок и нештатных ситуаций времени исполнения должна быть единообразной и должна использовать только механизм исключений (Exceptions). Все выгоды такой унификации описаны там же.
Исходим из предположения, что мы проделали большую работу по обёртке всех C и API-вызовов в свои классы с "исключительной" обработкой ошибок. Теперь программа не "валится" без объяснений в нештатной ситуации. Пришло время, наконец, снять сливки с наших трудов.
Как всегда, хочется большего: чтобы все проблемы, возникающие во время выполнения программы, протоколировались. Протокол должен быть содержательным в той мере, которая поможет разработчику устранить проблему. Ещё надо бы иметь средство визуализации протокола сбоев. Ну и, конечно, хотелось бы, чтобы для включения этой замечательной функциональности в каждом новом проекте, не пришлось напрягаться.
Общий план реализации таков. Компонент TAskExceptionHandler "бросается" на главную форму приложения. На этом, собственно, "ручное кодирование" заканчивается. Компонент перехватывает все исключения и "вываливает" их в лог-файл, после чего исключение обрабатывается стандартным образом. Если вам понадобится раскрыть более полно информацию об исключении особо хитрого типа, вы всегда сможете включить обработку этого типа в метод LogExceptionState.
В момент возникновения исключений делается "снимок состояния" системы, который также регистрируется в лог-файле вместе с событием. Лог-файл имеет структуру ini-файла и имя, сформированное по имени приложения. Образец прилагается.
[12.11.2004 16:06:47]
ExceptionType=EToFile
ExceptionMess=Ошибка записи в файл
ToFileFileName=A:\big_file.txt
ToFileErrNo=28
ToFileDosErrNo=112
ToFileErrNoStr=Недостаточно места на устройстве
ToFileDosErrNoStr=not enough space on the disk
ClassName=FormOptions (TFormOptions)
FormName=FormOptions (TFormOptions)
ProgramVersion=1.0.0.0
TotalVirtMem=2047
AvailVirtMem=2000
TotalPageMem=1228
AvailPageMem=895
DiskC_Total=76316
DiskC_Free=41916
Компонент, естественно, использует классы из упоминавшейся библиотеки классов (IniFile, ToFile), а также некоторые компоненты, речь о которых пойдёт ниже. Также используются файлы текстовых ресурсов – для формирования сообщений на языке пользователя.
Пример использования. Функция CreateVeryBigFile создаёт ситуацию нехватки дискового пространства. Файловая ошибка (спасибо нашему классу-обёртке) преобразуется в исключение, которое перехватывается компонентом, выводится в лог-файл, и далее обрабатывается стандартным образом.
void CreateVeryBigFile()
{
ToFile w("w", "A:\\big_file.txt");
while(1) w.fprintf("Очень-очень большой файл…\n");
}
Результат работы "перехватчика исключений" можно рассмотреть с помощью стандартной просмотровой формы. Библиотека форм общего назначения также является ресурсом и представляет собою отдельную DLL, которая будет описана в последующих статьях.
Как уже говорилось, благодаря такой организации обработки ошибок, программы не "валятся" без объяснений причин. Протокол работы помогает выявить и устранить многие проблемы времени выполнения. Более того, можно организовать отсылку протоколов разработчику – через e-mail или FTP – для удалённой диагностики проблем и выпусков патчей.
Кстати, перехват ошибок файловой системы весьма помогает при работе с устаревшими Windows 9x, в которых часто возникают сбои в FAT.
TAskExceptionHandler использует несколько компонентов с закладки "ASK SysInfo", на которую мы плавно переместимся. Знакомьтесь: TAskOS. Не секрет, что в процессе разработки программ часто бывает необходимо определить версию Windows, под управлением которой выполняется программа. На разных форумах довольно много подобных вопросов от новичков. Свойства компонента:
- enumOSType Type – Тип ОС. Может принимать значения: otUnknown, WIN_95, WIN_98, WIN_ME, WIN_NT, WIN_2000, WIN_XP, WIN_2003, WIN_LATEST
- AnsiString OSName – строковое наименование ОС
- enumOSPlatform Platform – тип платформы Windows; может принимать значения: opUnknown, _9x, NT
- AnsiString Version – версия Windows
- AnsiString WinDir – папка, в которую установлена Windows
- AnsiString WinSetupDir – папка, из которой установлена Windows
- AnsiString WinSysDir – системная папка (%WinDir%\SYSTEM для Windows 9x/ME и %WinDir%\SYSTEM32 для Windows NT/2000/XP/2003 etc.)
- AnsiString TempPath – папка для временных файлов
- AnsiString WinLang – строковое обозначение языка локализации Windows
- bool Plus – индикатор, установлен ли пакет Plus! Для Windows 9x
- enumWinRole Role – Роль Windows. Может принимать значения: wrUnknown, wrServer, wrWorkstation. Критики, минуточку внимания! Я знаю, что можно расширить и углубить значения этого свойства, но указанных значений для моих целей достаточно. Кому не хватает – напрягутся сами.
- AnsiString AppData – полный путь к папке "\Documents and Settings\<текущий пользователь>\Application Data"
- AnsiString LocalSettings – полный путь к папке "\Documents and Settings\<текущий пользователь>\Local Settings"
- AnsiString LocalAppData – полный путь к папке "\Documents and Settings\<текущий пользователь>\Local Settings\Application Data"
Компонент TAskOS, как и все остальные с этой закладки, имеет метод Refresh(), который вызывается автоматически, если компонент лежит на форме. То есть, после создания формы все свойства компонента уже содержат правильные значения и готовы к использованию. А вот если компонент создаётся динамически в куче, следует вызвать этот метод вручную для инициализации свойств.
Также многие компоненты имеют свойство bRefresh. Если этому свойству во время проектирования присвоить значение "true", то будет вызван метод Refresh и значения свойств можно будет увидеть в инспекторе объектов.
Компонент TAskComputer инкапсулирует следующие свойства:
- AnsiString ComputerName – имя компьютера
- AnsiString UserName – имя пользователя
- long RAM – объём оперативной памяти
- long RAMUsage – объём используемой памяти. Вычисляется динамически, в момент чтения значения свойства
Компонент TAskProcessor имеет следующие полезные свойства:
- AnsiString CPUName – наименование процессора
- AnsiString CPUIdentifier – идентификатор процессора
- long Frequency – Частота процессора
- double Usage – Процент использования процессора. Вычисляется динамически, в момент чтения значения свойства
Компонент TAskDisplay.
- short Width – текущая ширина экрана в пикселях
- short Height - текущая высота экрана в пикселях
- __int64 ColorsCount – глубина цвета
- short ColorsBits - глубина цвета в битах
- TStringList * ListModes – список поддерживаемых режимов
- AnsiString CardName – наименование видеокарты
- short RefreshRate – частота обновления
- AnsiString DisplayName – наименование монитора
Компонент TAskKeyboard.
- bool NumLock – индикатор и манипулятор клавиши "NumLock". Метод Read возвращает состояние кнопки; метод Write устанавливает кнопку в соответствующее состояние (включает/выключает NumLock)
- bool CapsLock – индикатор и манипулятор клавиши "CapsLock"
- int LangsCount – количество установленных в системе языков локализации
- AnsiString LangName – текущий язык локализации Windows (например, "Русский")
- AnsiString LangCode3 – трёхбуквенное обозначение текущей раскладки (например, "RUS")
- AnsiString LangCode2 - двухбуквенное обозначение текущей раскладки (например, "RU")
Именно с помощью этого компонента выставляются клавиатурные свойства у компонентов TAskEdit, TAskMaskEdit, TAskRxCalcEdit, TAskCurrencyEdit, TAskComboBox, TAskMemo из предыдущей статьи.
Компонент TAskPrinter. Я не настаиваю на общественной полезности этого компонента; просто в последующих статьях он будет упоминаться, поэтому он и описан здесь.
- AnsiString DefPrinter – принтер по умолчанию
- AnsiString CurPrinter – текущий принтер
- AskPrinterSystem PrintSystem – система печати; может принимать значения: apsMatrix, apsLaser, apsStream, apsOther, apsUnknown=666
- TStringList * Printers – список установленных в системе принтеров
- int ItemIndex – индекс текущего принтера
- AnsiString PaperFeed – управляющий символ "прогон листа" - различается для принтеров разных систем печати (матричный, лазерный)
Основные функции.
- Во-первых, компонент пытается (не всегда удачно) определить тип принтера: матричный, лазерный, струйный, и т.п. Вообще, лучше бы ему указать это явно.
- Во-вторых, компонент печатает любой текст методом PrintStringList(), причём делает это крайне разумно: текст печатается в текстовом (не графическом) режиме, что обеспечивает высокую скорость печати на матричных принтерах. Это есть хорошо для бюджетных контор, которые осознают, что стоимость владения и эксплуатации матричного принтера намного меньше, чем лазерного.
- В-третьих, компонент сам подбирает шрифт таким образом, чтобы печатаемый текст полностью уместился на бумаге. Вот для этого ему и нужно указывать тип принтера, так как управляющие последовательности для матричных и лазерных принтеров различны.
Компонент TAskDisk предоставляет наиболее употребимую информацию о логических дисках.
- AnsiString Letter – буква диска. При присвоении значения этому свойству выполняется метод Refresh() для соответствующего диска
- AnsiString SerialNum – серийный номер
- enumDiskType Type - тип диска; может принимать значения: dtUnknown, dtNOTROOTDIR, dtREMOVABLE, dtFIXED, dtREMOTE, dtCDROM, dtRAMDISK
- AnsiString Label – метка диска
- AnsiString FileSystem – файловая система
- __int64 Size – размер диска в байтах
- __int64 Free – размер свободного места
- bool DiskInDrive – признак, вставлен ли съёмный диск в устройство; обращение к этому свойству не вызывает неубираемого системного окошка типа "Нет диска в дисководе"
- AnsiString sType – тип диска на языке локализации Windows (например, "Сменный", "Локальный", "CD-ROM", и т.д.). Здесь используется файл строковых ресурсов, о котором говорилось в первой статье.
Компонент TAskListDisks содержит список всех логических дисков.
- int Count – количество дисков
- AnsiString List – список дисков
- TAskDisk * Disk – указатель на компонент, могущий полноценно описать выбранный диск
Компонент TAskCard – описание карты (платы).
- enumCardType Type – тип карты; может принимать значения: ctNetwork, ctSound, ctVideo, ctSCSI
- AnsiString CardName – наименование карты
- AnsiString MACAddr – MAC адрес сетевой карты
- AnsiString IPAddress – IP адрес сетевой карты
Компонент TAskShutdown несколько выбивается из ряда компонентов, предоставляющих информацию о системе. Он предназначен для удобного "гашения" Windows и обладает следующими свойствами:
- ShutdownType Type – тип "гашения"; может принимать значения: ewxLOGOFF, ewxPOWEROFF, ewxREBOOT, ewxSHUTDOWN
- bool Force – признак "ускоренного гашения" - без ожидания ответа на вопросы, закрывать ли то или иное приложение
- Метод DoIt() выполнит поставленную задачу (заданную описанными свойствами).
Ну, и на сладкое – компонент TAskSysInfo, являющийся контейнером компонентов: TAskOS * OS, TAskCPU * CPU, TAskListDisks * ListDisks, TAskComputer * Computer, TAskKeyboard * Keyboard, TAskDisplay * Display, TAskCard * NetworkCard, TAskCard * SoundCard, TAskCard * SCSICard.
Помимо этого, компонент обладает следующими свойствами:
- bool ActiveOnLoaded – указывает, начинать ли тестирование системы сразу же, как появляется форма, на которой лежит компонент. Может случиться, что это надо сделать не сразу, а немного погодя. В таком случае вызовите метод Refresh() вручную.
- TStringList * Printers – список установленных принтеров
- TStringList * Resources – список ресурсов, отданных "в общее пользование"
- TStringList * SoftList – список установленного в системе софта. Кроме того, в массиве TMapSoft содержится следующая информация о каждом установленном продукте:
- Версия
- Производитель
- URL продукта или производителя
- ID продукта
- На кого зарегистрирован
- Компания, в которой работает товарищ, на которого зарегистрирован продукт
Кроме того, у компонента TAskSysInfo есть 2 события:
- OnEndRefresh – возникает по окончании "нарывания" общесистемной информации; в общем случае это событие возникает раньше, чем OnEndRefreshDisks
- OnEndRefreshDisks - возникает по окончании "нарывания" информации о логических дисках
Результат работы компонента во время проектирования представлен на рисунках SysInfo1, SysInfo2, SysInfo3, SysInfo4, SysInfo5, SysInfo6.
Результат работы компонента во время выполнения представлен на рисунке FormSysInfo, которая также лежит в DLL форм общего назначения. Подключение этой и любых других DLL к любому проекту осуществляется двумя кликами мышки с помощью методов, описанных в грядущем продолжении цикла статей.
Скачать архив AskTools3.rar (35K)
1
Часть 1
Часть 2