Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 12568
Последний выпуск: 9.07.2014

Системная информация о компьютере

Автор: Садовой А.Г.
3 сентября 2006 года

1. Введение.

В статье рассматриваются способы получения системной информации о компьютере (операционная система, статус памяти, процессор и др.) Большинство примеров опирается на Windows API. Робота их подразумевается только под WIN32 (лишь отдельные функции работают под WIN32s). Статья направлена на аудиторию программистов Delphi, но может быть полезна программистам и других сред разработки приложений, интересующимся API и системной информацией. В статье использованы документы сайта http://apiwallst.ru/ , а также коды:

  • SysInfo Component, Angel's;
  • TSysInfo Component, RicoSoft;
  • TSYSINFO 2.1, Brent Boswell.

Главы о памяти и процессах ранее мной публиковались в интернете. Здесь они представлены с незначительными изменениями. Остальные главы публикуются впервые.

2. Состояние памяти.

Для получения детальной информации о состоянии памяти компьютера предназначена функция API GlobalMemoryStatus. В функцию передается переменная типа TMemoryStatus, которая представляет собой запись, тип которой определен следующим образом:
type
   TMemoryStatus = record
       dwLength: DWORD;
       dwMemoryLoad: DWORD;
       dwTotalPhys: DWORD;
       dwAvailPhys: DWORD;
       dwTotalPageFile: DWORD;
       dwAvailPageFile: DWORD;
       dwTotalVirtual: DWORD;
       dwAvailVirtual: DWORD;
   end;

Поля записи имеют следующий смысл:

dwLengthДлина записи. Поле необходимо инициализировать функцией SizeOf до обращения к функции GlobalMemoryStatus.
dwMemoryLoadКоличество использованной памяти в процентах.
dwTotalPhysЧисло байт установленной на компьютере ОЗУ (физической памяти).
dwAvailPhysСвободная физическая память в байтах.
dwTotalPageFileОбщий объем в байтах, который могут сохранить файлы/файл подкачки (вообще говоря, не совпадает с размером последних).
dwAvailPageFileДоступный объем из последней величины в байтах.
dwTotalVirtualОбщее число байтов виртуальной памяти, используемой в вызывающем процессе.
dwAvailVirtualОбъем виртуальной памяти, доступной для вызывающего процесса.

Можно использовать следующий код получения информации о наличной памяти ОЗУ:

function GetRAM: Cardinal;
var MS: TMemoryStatus;
begin
    MS.dwLength:=SizeOf(MS);
    GlobalMemoryStatus(MS);
    Result:=MS.dwTotalPhys;
end;

Пользовательская функция GetRAM возвращает общее число байт физической памяти, установленной на компьютере. Эту информацию она читает из поля dwTotalPhys записи MS, имеющей тип TMemoryStatus. Перед этим вызывается API-функция GlobalMemoryStatus с параметром MS. Обратите внимание, что перед вызовом GlobalMemoryStatus инициализируется поле dwLength функцией SizeOf.

По аналогии с примером можно получить информацию об остальных параметрах памяти, для этого надо заменить строку Result:=MS.dwTotalPhys на одну из перечисленных ниже:

Result:=MS.dwMemoryLoad;
Result:=MS.dwAvailPhys;
Result:=MS.dwTotalPageFile;
Result:=MS.dwAvailPageFile;
Result:=MS.dwTotalVirtual;
Result:=MS.dwAvailVirtual;

3. Информация о процессоре.

Функция GetSystemInfo с единственным параметром типа записи TSystemInfo дает доступ к различной системной информации. В частности, уровень процессора можно узнать из поля записи TSystemInfo – wProcessorLevel. Соответствие значений поля и основных уровней процессора приведено в таблице:

Значение поля wProcessorLevelУровень процессора
380386
480486
5Pentium
6Pentium Pro

Следующая пользовательская функция определяет уровень процессора:

function GetProcessorLevel: String;
var SI: TSystemInfo;
begin
   GetSystemInfo(SI);
   Case SI.wProcessorLevel of
     3: Result:='80386';
     4: Result:='80486';
     5: Result:='Pentium';
     6: Result:='Pentium Pro'
   else Result:=IntToStr(SI.wProcessorLevel);end;
end;

Тактовую частоту процессора можно вычислить на основе следующего кода, использующего Ассемблер. Я его заимствовал, он хорошо работает, деталей реализации не знаю - привожу его без комментариев:

function GetCPUSpeed: Double;
const DelayTime = 500; 
var TimerHi : DWORD; 
     TimerLo : DWORD; 
     PriorityClass : Integer; 
     Priority : Integer; 
begin 
  PriorityClass := GetPriorityClass(GetCurrentProcess); 
  Priority := GetThreadPriority(GetCurrentThread);  
  SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS); 
  SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL); 
  Sleep(10); 
  asm 
    DW 310Fh // rdtsc 
    MOV TimerLo, EAX 
    MOV TimerHi, EDX 
  end; 
  Sleep(DelayTime); 
  asm 
    DW 310Fh // rdtsc 
    SUB EAX, TimerLo 
    SBB EDX, TimerHi 
    MOV TimerLo, EAX 
    MOV TimerHi, EDX 
  end; 
  SetThreadPriority(GetCurrentThread, Priority); 
  SetPriorityClass(GetCurrentProcess, PriorityClass); 
  Result := TimerLo / (1000.0 * DelayTime); 
end;

Данная пользовательская функция возвращает тактовую частоту процессора.

4. Информация о дисках.

Функция GetDriveType возвращает значение, по которому можно определить тип диска. Аргумент функции – буква, связанная с диском. Возвращаемые функцией значения и их смысл приведены в таблице:

Возвращаемое значениеСмысл
0Неизвестный
1Не существует
Drive_RemovableСъемный
Drive_FixedПостоянный
Drive_RemoteВнешний
Drive_CDROMПривод CD
Drive_RamDiskДиск RAM

Следующая пользовательская функция иллюстрирует использование функции GetDriveType. По букве диска она определяет тип диска и возвращает последний в строку:

function GetDrive(Drive: String): String;
var
DriveType : uInt;
begin
  DriveType := GetDriveType(PChar(Drive));
  case DriveType of
    0: Result := '?';
    1: Result := 'Path does not exists';
      Drive_Removable: Result := 'Removable';
      Drive_Fixed: Result := 'Fixed';
      Drive_Remote: Result := 'Remote';
      Drive_CDROM: Result := 'CD-ROM';
      Drive_RamDisk: Result := 'RAMDisk'
    else Result := 'Unknown';
  end;
end;

Для определения размера диска служит функция DiskSize. Параметр, который в нее передается – номер диска (0 – текущий, далее по порядку: 1 – A, 2 – B и т.д.). Для получения размера в Мегабайтах можно использовать следующую пользовательскую функцию:

function GetDriveSize(Num: Byte): String;
begin
if DiskSize(Num)  -1 then
      Result := format('%d MB', [Trunc(DiskSize(Num)/1024/1024)])
   else
      Result := '';
end;

При ошибке ответ – пустая строка.

5. Операционная система.

Информация об операционной системе хранится в записи типа TOSVersionInfo, выглядещей следующим образом:

type
  TOSVersionInfo = record
  dwOSVersionInfoSize: DWORD;
  dwMajorVersion: DWORD;
  dwMinorVersion: DWORD;
  dwBuildNumber: DWORD;
  dwPlatformId:  DWORD;
  szCSDVersion: array [0..126] of AnsiChar;
end;

Поля записи имеют следующий смысл:

dwOSVersionInfoSizeРазмер записи.
dwMajorVersionСтарший номер версии ОС.
dwMinorVersionМладший номер версии ОС.
dwBuildNumberНомер сборки ОС (в нижнем слове поля).
dwPlatformIdПлатформа.
szCSDVersionСтрока поддержки для использования PSS. Содержит дополнительную информацию об ОС. Чаще всего – это пустая строка.

Поле dwPlatformId может иметь следующие значения:

Ver_Platform_Win32sWin32s в Windows 3.1
Ver_Platform_WindowsWin32 в Windows 95
Ver_Platform_Win32_NTWindows NT

Получить информацию об ОС позволяет API-функция GetVersionEx с единственным параметром типа TOSVersionInfo. Приведу пример ее использования:

function GetOS(var MajVer:Byte; var MinVer:Byte; var BuildNo:Word):String;
var VI: TOSVersionInfo;
begin
VI.dwOSVersionInfoSize:=SizeOf(VI);
GetVersionEx(VI);
MajVer:= VI.dwMajorVersion;
MinVer:= VI.dwMinorVersion;
BuildNo:= LoWord(VI.dwBuildNumber);
Result:= 'OS Version '+
        IntToStr(MajVer)+'.'+
        IntToStr(MinVer)+' build No '+
        IntToStr(BuildNo);
end;

Пользовательская функция GetOS выводит строку с номером версии ОС. Обратите внимание, что перед вызовом GetVersionEx инициализируется поле dwOSVersionInfoSize функцией SizeOf.

Другой вариант реализации пользовательской функции получения информации о версии ОС может быть, например, таким (здесь используется дополнительная информация о системе из поля szCSDVersion):

function GetOS_2: string;
var
  OSVersion: TOSVersionInfo;
begin
   OSVersion.dwOSVersionInfoSize := SizeOf(OSVersion);
   if GetVersionEx(OSVersion) then
   Result:= Format('%d.%d (%d.%s)',
   [OSVersion.dwMajorVersion, OSVersion.dwMinorVersion,
   (OSVersion.dwBuildNumber and $FFFF), OSVersion.szCSDVersion]);
end;

Следующая пользовательская функция выводит версию платформы:

function GetPlatform: String;
var VI: TOSVersionInfo;
begin
  VI.dwOSVersionInfoSize:=SizeOf(VI);
  GetVersionEx(VI);
  Case VI.dwPlatformId of
    Ver_Platform_Win32s: Result:= 'Win32s';
    Ver_Platform_Win32_Windows: Result:='Win95';
    Ver_Platform_Win32_NT: Result:='WinNT'
    else Result:='Unknown Platform'; end;
end;

6. Информация об основных каталогах.

Три функции дают пути к трем основным каталогам: GetWindowsDirectory – к каталогу ОС, GetSystemDirectory – к системной папке ОС и GetCurrentDirectory – к текущей папке. Эти функции имеют два параметра – путь к папке и размер его представления в памяти.

Следующая пользовательская функция иллюстрируют применение функции GetWindowsDirectory для получения пути к каталогу Windows:

function GetWindowsDir: string;
var S: array[0..MAX_PATH] of Char;
begin
  GetWindowsDirectory(S,SizeOf(S));
  Result:=S;
end;

Для получения пути к системной папке в вышеприведенном примере вместо строки GetWindowsDirectory(S,SizeOf(S)) надо использовать GetSystemDirectory(S,SizeOf(S)), а для получения пути к текущему каталогу - GetCurrentDirectory(SizeOf(S),S). Комментарии тут, думаю, излишни. Замечу только, что в обращении к функции GetCurrentDirectory первым параметром стоит размер пути, в отличие от двух других функций, где он на втором месте.

7. Информация о пользователе и компьютере.

Имя компьютера позволяет получить функция GetComputerName. В нее передается два параметра – параметр типа PChar, в который записывается имя компьютера и второй параметр, определяющий длину записи под имя. Следующая пользовательская функция выводит имя компьютера в строку:

function GetCompName: String;
var
i: DWORD;
p: PChar;
begin
i:=255;
GetMem(p, i);
GetComputerName(p, i);
Result:=String(p);
FreeMem(p);
end;

Очень похожим способом получается имя пользователя из функции GetUserName:

function GetUser: String;
var
   UserName : PChar;
   NameSize : DWORD;
begin
   UserName := #0;
   NameSize := 50;
   try
      GetMem(UserName, NameSize);
      GetUserName(UserName, NameSize);
      Result:= StrPas(UserName);
   finally
      FreeMem(UserName);
   end;
end;

Используя регистр, можно получить информацию о зарегистрированном владельце и зарегистрированном компьютере ОС (пользовательская функция GetPlatform описана ранее):

function GetRegInfo(var RegOwner: String; var RegOrg: String): Integer;
const
  WIN95_KEY = '\SOFTWARE\Microsoft\Windows\CurrentVersion';
  WINNT_KEY = '\SOFTWARE\Microsoft\Windows NT\CurrentVersion';
var
  VersionKey : PChar;
begin
    Result:=0;
    If GetPlatform = 'Win95' then VersionKey := WIN95_KEY else
    If GetPlatform = 'WinNT' then VersionKey := WINNT_KEY else
    begin Result:=-1; exit; end;
   with TRegistry.Create do
   try
       RootKey := HKEY_LOCAL_MACHINE;
       if OpenKey(VersionKey, False) then
          begin
          RegOwner:= ReadString('RegisteredOwner');
          RegOrg:= ReadString('RegisteredOrganization');
          end;
   finally
     Free;
   end;
end;

8. Процессы, выполняемые на компьютере.

Получить информацию о выполняющихся в данный момент на компьютере процессах можно на основе функций API. Для разных платформ эти функции отличаются, как и подключаемые для этих целей модули. Рассмотрим платформу Win95 и WinNT.

В Win95 (Windows 95/98) код может выглядеть следующим образом:

function GetProcessesWin95(var Proc: TProcArray):Integer;
var
FSnap: THandle;
PE: TProcessEntry32;
PPE: PProcessEntry32;
I: Integer;
begin
If FSnap > 0 then CloseHandle(FSnap);
FSnap:=CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PE.dwSize:=SizeOf(PE);
I:=0;
SetLength(Proc, $3FFF-1); // заведомо большой массив
If Process32First(FSnap,PE) then
  	repeat
    		New(PPE);
    		PPE^:=PE;
    		Proc[I]:=PPE.szExeFile;
    		I:=I+1;
  	until not Process32Next(FSnap, PE);
Result:=I;
If FSnap > 0 then CloseHandle(FSnap); // очищаем память
end;

Для работы этого кода нужно подключить в разделе USES модуль TlHelp32 (Help Tool API 32).

Функция возвращает число процессов и записывает их пути в массив-переменную Proc. Тип переменной Proc – обычный массив строк, который нужно описать в разделе описания типов:

type TProcArray = Array of String;

Строка FSnap:=CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0) означает получение «моментального снимка всех процессов». Точнее, в результате ее выполнения мы получаем дескриптор снимка. Функции Process32First и Process32Next позволяют «пробежаться» по всем процессам.

Для NT-платформы (Windows NT/2000) аналогичный код может выглядеть следующим образом (здесь уже используется модуль PSAPI, который необходимо включить в раздел USES):

function GetProcessesWinNT(var Proc: TProcArray):Integer;
var
Num: Integer;
LP: Array[0..$3FFF-1] of Dword; // заведомо большой массив
CB: DWord;
CBNeeded:DWord;
ProcHndl: THandle;
ModHand: HModule;
ModName: array [0..MAX_PATH] of Char;
I: Integer;
begin
  EnumProcesses(@LP,CB,CBNeeded);
  Num:= CBNeeded div SizeOf(DWORD);
  SetLength(Proc,Num);
 For I:=0 to Num-1 do
  begin
    ProcHndl:=
    OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,False,LP[I]);
    If GetModuleFileNameEx(ProcHndl,ModHand,ModName,SizeOf(ModName))> 0 then
    Proc[I]:=ModName else Proc[I]:='Unknown';
  end;
IF ProcHndl > 0 then CloseHandle(ProcHndl);
Result:=Num;
end;

9. Дисплей и клавиатура.

Краткую информацию о дисплеи можно поучить с помощью следующего кода, базирующегося на функции EnumDisplayDevices и структуре типа TDisplayDevice:

function GetVideoCard: String;
var
  lpDisplayDevice: TDisplayDevice;
  dwFlags: DWORD;
  cc: DWORD;  
begin  
lpDisplayDevice.cb := sizeof(lpDisplayDevice);
dwFlags := 0;  
cc:= 0;  
while EnumDisplayDevices(nil, cc, lpDisplayDevice , dwFlags) do  
  begin  
    Inc(cc);
    Result:=lpDisplayDevice.DeviceName;
  end;
end;

Раскладку клавиатуры можно получить, используя следующую пользовательскую функцию:

function GetKeyBoardLanguage: String;
var
ID:LangID;
Language: array [0..100] of Char;
begin
ID:=GetSystemDefaultLangID;
VerLanguageName(ID,Language,100);
Result:=String(Language);
end;

Здесь всю работу делает функция VerLanguageName, работающая в связке с функцией GetSystemDefaultLangID.

10. Заключение.

В статье были рассмотрены способы получения основной информации о компьютере. Реализацию примеров на Delphi6 можно найти в моем модуле SysInfo v.3 на моем сайте http://sadovoya.narod.ru . Там можно найти и динамическую библиотеку, правда, с несколько урезанным набором функций. Она может быть полезна программистам других сред разработки.

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
87K
10 декабря 2012 года
Андрей Гром
0 / / 10.12.2012
Мне нравитсяМне не нравится
10 декабря 2012, 12:07:46
Спасибо! Очень полезная информация
2.
202
19 ноября 2005 года
sadovoya
567 / / 19.11.2005
+1 / -0
Мне нравитсяМне не нравится
13 марта 2011, 15:55:14
Важное дополнение о функции GetProcessesWinNT().

Чтобы OpenProcess() работал более успешно, надо вызывающей программе повысить привилегии до уровня SeDebugPrivilege (константа SE_DEBUG_NAME). Это дает доступ к процессам вплоть до PROCESS_ALL_ACCESS. Без этого OpenProcess() может не получить \"хэндла\" с запрошенными флагами доступа.

Делается это примерно так. Вставляем до цикла \"For I:=0 to Num-1 do...\" следующий код:

Код:
ImpersonateSelf(SecurityImpersonation);

    OpenThreadToken(

            GetCurrentThread(), //наша программы

            TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,

            FALSE,

            @hToken

            );



    tp.PrivilegeCount:=0;

    tp.Privileges[0].Attributes:=0;

    tp.Privileges[0].Luid:=0;



    cbT:= sizeof(TOKEN_PRIVILEGES);

    LookupPrivilegeValue( 0, SE_DEBUG_NAME, @luidMod );

    tp.PrivilegeCount:= 1;

    tp.Privileges[0].Luid:= luidMod;

    tp.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges( hToken, false, @tp, cbT, 0, 0 );

    if (hToken <> 0) then CloseHandle(hToken); //больше не нужен

А в раздел var добавляем переменные:
Код:
cbT : Cardinal;

    hToken : Cardinal;

    tp: TOKEN_PRIVILEGES;

    luidMod: LUID;

Проверил этот метод в Lazarus. В uses подключил модуль Windows. В Delphi должно быть тоже самое. В списке процессов по-прежнему неопределенные процессы присутствуют, но их всего несколько - это системныее процессы самого высшего уровня. Увеличение до PROCESS_ALL_ACCESS флага в OpenProcess() ситуацию не улучшает.

Автор
3.
202
19 ноября 2005 года
sadovoya
567 / / 19.11.2005
+0 / -1
Мне нравитсяМне не нравится
4 августа 2010, 19:24:42
Проблема с процессами на NT платформах (сам пользуюсь XP и Vista) вероятно в API-функции OpenProcess(). Анализировал ошибки после ее выполнения - чаще всего ошибка доступа. Пробовал разные комбинации ключа, включаю полный доступ - ничего не удалось. Видимо от библиотеки PSAPI придется отказаться. Гораздо лучше ситуация с библиотекой TlHelp32. Там процессы выдаются отлично (в XP и Vista по крайней мере). На днях выложу обновленные исходники. Там добавил еще инфу о принтерах и нек. др. Пока тестовая версия, но достаточно работоспособная.
4.
3.4K
13 февраля 2006 года
CrazyTimon
125 / / 13.02.2006
+0 / -1
Мне нравитсяМне не нравится
2 января 2010, 22:03:09
список процессов все равно не выдает...на NT весь массив заполнен uknown
5.
202
19 ноября 2005 года
sadovoya
567 / / 19.11.2005
+2 / -0
Мне нравитсяМне не нравится
29 сентября 2006, 15:46:08
Верная ссылка в начале статьи - http://api.wallst.ru/
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог