首页  编辑  

WinNT/2000进程信息

Tags: /超级猛料/OS.操作系统/Process.进程/   Date Created:

Windows NT/2000: PSAPI

正如前面提到的那样,To o l H e l p 3 2 在Windows NT/2000 下是不存在的。不过,Wi n d o w s 平台S D K 提

供了一个叫P S A P I . D L L 的动态链接库,通过这个动态链接库可以获取类似于To o l H e l p 3 2 能够获取的信

息,包括:

?正在运行的进程。

?每个进程已加载的模块。

?已加载的设备驱动程序。

?进程内存信息。

?映射每个进程的文件内存。

Windows NT 的较高版本和Windows 2000 的所有版本都包含P S A P I . D L L 。但你要让你的应用程序的用户可以使它,还是应该随程序分发这个文件。D e l p h i 为这个D L L 提供了一个叫P S A P I . p a s 的接口单元,可以动态地加载所有的函数。因此,无论机器上有没有安装P S A P I . D L L ,引用这个单元的应用程序都能够运行(当然,不安装P S A P I . D L L ,函数无法工作,但应用程序能够运行)。

使用P S A P I 获取进程信息,首先要调用E n u m P r o c e s s e s ( )函数,其声明如下:

BOOL EnumProcesses(

 DWORD * lpidProcess,  // array to receive the process identifiers

 DWORD cb,             // size of the array

 DWORD * cbNeeded      // receives the number of bytes returned

);

?lpidProcess 是一个指向D W O R D 数组的指针,由函数用进程I D 填充。

?cb 包含由l p i d P r o c e s s 指定的数组的元素数。

?c b N e e d e d 返回拷贝到l p i d P r o c e s s 数组的实际字节数。用此值除以S i z e O f ( D W O R D )将得到拷贝到数组的元素数,即正在运行的进程数。

调用这个函数后,l p i d P r o c e s s 指定的数组将包含一些进程的I D 。进程I D 在自身进程中无用,但可以传递给OpenProcess() API 函数以获取进程的句柄。一旦拥有一个进程句柄,就可以调用针对进程句柄的其他P S A P I 函数,甚至其他Win32 API 函数。

P S A P I 提供了一个相似的函数-E n u m D e v i c e D r i v e r s ( )函数,用于获取已加载的设备驱动程序的

信息。声明如下:

BOOL EnumDeviceDrivers(

 LPVOID *lpImageBase,  // array to receive the load addresses

 DWORD cb,             // size of the array

 LPDWORD lpcbNeeded    // receives the number of bytes returned

);

先把一个叫B i g A r r a y 的数组传递给函数E n u m P r o c e s s e s ( )和E n u m D e v i c e D r i v e r s ( ),然后把

B i g A r r a y 内的数据分别移到叫F P r o c L i s t 和F D r v L i s t 的动态数组中。之所以这么复杂地实现,原因是

E n u m P r o c e s s e s ( )和E n u m D e v i c e D r i v e r s ( )都不能预先分配数组内存,因为它们不知道将要返回多少个数

组元素。因此先声明一个大数组(希望足够大),再把结果拷贝到适当大小的动态数组中。

**********************************************

get process informations? (Windows NT/2000)

{

 This function write all nt process informations into memo1. In Edit1 you can

 specify the processID.

}

type

 PDebugModule = ^TDebugModule;

 TDebugModule = packed record

   Reserved: array [0..1] of Cardinal;

   Base: Cardinal;

   Size: Cardinal;

   Flags: Cardinal;

   Index: Word;

   Unknown: Word;

   LoadCount: Word;

   ModuleNameOffset: Word;

   ImageName: array [0..$FF] of Char;

 end;

type

 PDebugModuleInformation = ^TDebugModuleInformation;

 TDebugModuleInformation = record

   Count: Cardinal;

   Modules: array [0..0] of TDebugModule;

 end;

 PDebugBuffer = ^TDebugBuffer;

 TDebugBuffer = record

   SectionHandle: THandle;

   SectionBase: Pointer;

   RemoteSectionBase: Pointer;

   SectionBaseDelta: Cardinal;

   EventPairHandle: THandle;

   Unknown: array [0..1] of Cardinal;

   RemoteThreadHandle: THandle;

   InfoClassMask: Cardinal;

   SizeOfInfo: Cardinal;

   AllocatedSize: Cardinal;

   SectionSize: Cardinal;

   ModuleInformation: PDebugModuleInformation;

   BackTraceInformation: Pointer;

   HeapInformation: Pointer;

   LockInformation: Pointer;

   Reserved: array [0..7] of Pointer;

 end;

const

 PDI_MODULES = $01;

 ntdll = 'ntdll.dll';

var

 HNtDll: HMODULE;

type

 TFNRtlCreateQueryDebugBuffer = function(Size: Cardinal;

   EventPair: Boolean): PDebugBuffer;  

 stdcall;

 TFNRtlQueryProcessDebugInformation = function(ProcessId,

   DebugInfoClassMask: Cardinal; var DebugBuffer: TDebugBuffer): Integer;  

 stdcall;

 TFNRtlDestroyQueryDebugBuffer = function(DebugBuffer: PDebugBuffer): Integer;  

 stdcall;

var

 RtlCreateQueryDebugBuffer: TFNRtlCreateQueryDebugBuffer;

 RtlQueryProcessDebugInformation: TFNRtlQueryProcessDebugInformation;

 RtlDestroyQueryDebugBuffer: TFNRtlDestroyQueryDebugBuffer;

function LoadRtlQueryDebug: LongBool;

begin

 if HNtDll = 0 then

 begin

   HNtDll := LoadLibrary(ntdll);

   if HNtDll <> 0 then

   begin

     RtlCreateQueryDebugBuffer       := GetProcAddress(HNtDll, 'RtlCreateQueryDebugBuffer');

     RtlQueryProcessDebugInformation := GetProcAddress(HNtDll,

       'RtlQueryProcessDebugInformation');

     RtlDestroyQueryDebugBuffer      := GetProcAddress(HNtDll,

       'RtlDestroyQueryDebugBuffer');

   end;

 end;

 Result := Assigned(RtlCreateQueryDebugBuffer) and

   Assigned(RtlQueryProcessDebugInformation) and

   Assigned(RtlQueryProcessDebugInformation);

end;

procedure TForm1.Button1Click(Sender: TObject);

var

 DbgBuffer: PDebugBuffer;

 Loop: Integer;

begin

 if not LoadRtlQueryDebug then Exit;

 Memo1.Clear;

 Memo1.Lines.BeginUpdate;

 DbgBuffer := RtlCreateQueryDebugBuffer(0, False);

 if Assigned(DbgBuffer) then

   try

     if RtlQueryProcessDebugInformation(StrToIntDef(Edit1.Text, GetCurrentProcessId),

       PDI_MODULES, DbgBuffer^) >= 0 then

     begin

       for Loop := 0 to DbgBuffer.ModuleInformation.Count - 1 do

         with DbgBuffer.ModuleInformation.Modules[Loop], Memo1.Lines do

         begin

           Add('ImageName: ' + ImageName);

           Add('  Reserved0: ' + IntToHex(Reserved[0], 8));

           Add('  Reserved1: ' + IntToHex(Reserved[1], 8));

           Add('  Base: ' + IntToHex(Base, 8));

           Add('  Size: ' + IntToHex(Size, 8));

           Add('  Flags: ' + IntToHex(Flags, 8));

           Add('  Index: ' + IntToHex(Index, 4));

           Add('  Unknown: ' + IntToHex(Unknown, 4));

           Add('  LoadCount: ' + IntToHex(LoadCount, 4));

           Add('  ModuleNameOffset: ' + IntToHex(ModuleNameOffset, 4));

         end;

     end;

   finally

     RtlDestroyQueryDebugBuffer(DbgBuffer);

   end;

 Memo1.Lines.EndUpdate;

end;