Рис. 6.4. Результат работы приложения «Alpha-смешивание точечного рисунка»
На этом закончим рассмотрение работы с графикой в Delphi.
Глава 7 Системная информация и реестр Windows
• Системная информация
• Системное время
• Реестр
Возникала ли у вас необходимость программно определить текущее состояние компьютера или узнать какие-нибудь сведения об операционной системе? Можно только удивляться, как близко – практически «под носом» у программиста – находятся средства для получения системной информации и как сложно о них узнать. Речь идет о средствах, которые всегда доступны при программировании для Windows – функции Windows API.
В данной главе мы рассмотрим некоторые способы, при помощи которых можно «добыть» информацию, касающуюся операционной системы. Это может пригодиться, например, если вы используете в своих приложениях возможности, отличающиеся в различных платформах Windows. Но и не только в этих случаях.
Рассмотренные в данной главе функции Windows API являются самыми обычными во всех смыслах этого слова. Просто они часто упоминаются вскользь либо вообще не упоминаются в книгах для программирования в таких средах, как Borland Delphi.
В примерах представленной вашему вниманию главы, кроме получения информации о самой Windows, некотором оборудовании компьютера, также рассмотрена работа с системным реестром Windows – этакой базой данных, в которой хранится много всего полезного и не очень: от параметров ОС и настроек приложений до сведений о работе компьютера в реальном времени. Правда, по определенным причинам последние сведения хранятся не в реальных, а в виртуальных ключах реестра. Но обо всем по порядку.7.1. Системная информация
Начнем с несложных примеров, позволяющих получить информацию об операционной системе, установленном на компьютере оборудовании и такие сведения реального времени, как загрузка памяти компьютера, состояние питания и т. д.
Версия операционной системы
Получение сведений об операционной системе хотя и не является повседневной необходимостью, но все же в некоторых специфичных случаях может пригодиться. Например, когда ваша программа ведет себя по-разному при разных установленных обновлениях Windows. Либо когда вы самостоятельно пишете инсталлятор, который способен устанавливать версии программы, скомпилированные для Windows Me (95, 98) или Windows NT (2000, ХР).
Одним из способов узнать версию Windows является использование API-функции GetVersionEx. Она принимает в качестве параметра структуру OSVERSIONINFO (или OSVERSIONINFOEX, но об этом позже), заполняет поля этой структуры и в случае удачи возвращает ненулевое значение.
Объявление ANSI-версии структуры OSVERSIONINFO в библиотеке Delphi 7 выглядит следующим образом:
OSVERSIONINFOA = record
dwOSVersionInfoSize: DWORD; //Размер структуры
dwMajorVersion: DWORD; //Старшая часть версии ОС Windows
dwMinorVersion: DWORD; //Младшая часть версии
dwBuildNumber: DWORD; //Номер сборки операционной системы
dwPlatformId: DWORD; //Идентификатор платформы Windows
szCSDVersion: array[0..127] of AnsiChar; //Дополнительные
//сведения, например, установленный пакет обновлений
end;
Не будем вдаваться в подробное описание возможных значений полей этой структуры: практически все будет ясно из приведенного далее примера. Напомним лишь, чтобы вы не забывали заполнять поле dwOSVersionInf oSize перед вызовом функции GetVersionEx.
Итак, пример обработки данных, помещаемых в структуру OSVERSIONINFO, приведен в листинге 7.1. При загрузке формы элемент управления ListView с именем lvwVerlnf о заполняется сведениями о версии системы, представленными в читабельной форме.
Листинг 7.1.
Получение и отображение сведений о Windows
procedure TForm1.FormCreate(Sender: TObject);
var
info: OSVERSIONINFO;
item: TListItem;
begin
//Получаем информацию о версии ОС
info.dwOSVersionInfoSize := SizeOf(info);
GetVersionEx(info);
//Заполняем список информацией о ОС
//..версия ОС
item := lvwVerInfo.Items.Add();
item.Caption := \'Версия системы\
item.SubItems.Insert(0, IntToStr(Integer(info.dwMajorVersion)) +
\'.\' + IntToStr(Integer(info.dwMinorVersion)));
//..номер сборки
item := lvwVerInfo.Items.Add();
item.Caption := \'Сборка\
item.SubItems.Insert(0, IntToStr(Integer(info.dwBuildNumber)));
//..платформа
item := lvwVerInfo.Items.Add();
item.Caption := \'Платформа\
case info.dwPlatformId of
VER_PLATFORM_WIN32s:
//Эмуляция Win32 или Win16
item.SubItems.Insert(0, \'Win16\');
VER_PLATFORM_WIN32_WINDOWS:
//"Классическая" Win32: 95, 98 или Me
item.SubItems.Insert(0, \'Win32\');
VER_PLATFORM_WIN32_NT:
//Ядро NT
item.SubItems.Insert(0, \'WinNT\');
end;
//..дополнительная информация (например, пакет обновлений)
item := lvwVerInfo.Items.Add();
item.Caption := \'Дополнительные сведения\
item.SubItems.Insert(0, info.szCSDVersion);
end;
Возможный результат работы программы (для Windows ХР SP1) приводится на рис. 7.1.
Рис. 7.1. Информация о версии Windows
Теперь снова обратимся к функции GetVersionEx, точнее говоря, к структуре OSVERSIONINFOEX, которая может также передаваться в качестве параметра в функцию. К сожалению, в библиотеке Delphi 7 эта структура не объявлена. Но это можно сделать самостоятельно:
OSVERSIONINFOEX = record
dwOSVersionInfoSize: DWORD;
dwMajorVersion: DWORD;
dwMinorVersion: DWORD;
dwBuildNumber: DWORD;
dwPlatformId: DWORD;
szCSDVersion: array[0..127] of AnsiChar;
//Поля, которых нет в OSVERSIONINFO
wServicePackMajor: WORD; //Старшая цифра версии пакета
//обновлений
wServicePackMinor: WORD; //Младшая цифра версии пакета
//обновлений
wSuiteMask: WORD; //Комплектация системы
wProductType: BYTE; //Дополнительная информации об ОС
wReserved: BYTE;
end;
Дополнительные (по сравнению с OS VERS ION INFO) поля структуры может заполнить ОС Windows NT 4.0 SP6 и более поздние версии Windows NT (в том числе 2000 и ХР). Значения дополнительных полей структуры OSVERSIONINFOEX пояснены комментариями в объявлении структуры.
Значение поля wSuiteMask (является битовой маской) может быть составлено из значений следующих констант (увы, но их объявления также пришлось добавить самостоятельно).
VER_SUITE_BACKOFFICE = 4; //Установлена Microsoft Back Office
VER_SUITE_DATACENTER = 128;//Установлена Microsoft Data Center
VER_SUITE_ENTERPRISE = 2; //Установлена ОС Windows 2000
//Advanced Server
VER_SUITE_SMALLBUSINESS = 1; //Установлена Microsoft Small
//Business Server
VER_SUITE_SMALLBUSINESS_RESTRICTED = 32; //Установлена
//ограниченная версия Microsoft
//Small Business Server
VER_SUITE_TERMINAL = 16; //Установлены терминальные службы
VER_SUITE_PERSONAL = 512; //Персональная версия ОС (типичный
//набор функций меньше, чем в Professional)
Значение поля wProductType может быть одним из приведенных ниже (тип сетевой ОС и соответственно роль, которую компьютер с данной ОС может исполнять при подключении в сети):
VER_NT_WORKSTATION = 1; //Рабочая станция
VER_NT_DOMAIN_CONTROLLER = 2; //Контроллер домена
VER_NT_SERVER = 3; //Сервер
Чтобы можно было просто передавать в функцию GetVersionEx ссылку на структуру OSVERSIONINFOEX, а не OSVERSIONINFO, перегрузим эту функцию следующим образом:
function GetVersionEx(var lpVersionInformation: OSVERSIONINFOEX): BOOL;
stdcall; external kernel32 name \'GetVersionExA\
Теперь определение полной информации о версии ОС для случая Windows на платформе NT (выше NT 4.0 SP6) может выглядеть следующим образом (листинг 7.2) (часть, одинаковая с листингом 7.1, опущена).
Листинг 7.2.
Определение версии ОС (NT, 2000, ХР)
procedure TForm1.FormCreate(Sender: TObject);
var
info: OSVERSIONINFOEX;
item: TListItem;
suite, additional: String;
begin
//Получаем информацию о версии ОС
info.dwOSVersionInfoSize := SizeOf(info);
GetVersionEx(info);
//Заполняем список информацией об ОС
//…
//..версия о пакете обновлений
item := lvwVerInfo.Items.Add();
item.Caption := \'Версия ServicePack\
item.SubItems.Insert
(0, IntToStr(Integer(info.wServicePackMajor)) + \'.\' +
IntToStr(Integer(info.wServicePackMinor)));
//..комплекация ОС
suite := \'\
if info.wSuiteMask and VER_SUITE_BACKOFFICE <> 0 then
suite := suite + \'[Установлен Back Office] \
if info.wSuiteMask and VER_SUITE_DATACENTER <> 0 then
suite := suite + \'[Microsoft Data Center] \
if info.wSuiteMask and VER_SUITE_ENTERPRISE <> 0 then
suite := suite + \'[Windows 2000 Advanced Server] \
if info.wSuiteMask and VER_SUITE_SMALLBUSINESS <> 0 then
suite := suite + \'[Small Business Server] \
if info.wSuiteMask and VER_SUITE_SMALLBUSINESS_RESTRICTED <> 0
then
suite := suite + \'[Small Business Server, ограниченная версия] \
if info.wSuiteMask and VER_SUITE_TERMINAL <> 0 then
suite := suite + \'[Terminal Service] \
if info.wSuiteMask and VER_SUITE_PERSONAL <> 0 then
suite := suite + \'[Workstation Personal (не Professional)] \