【问题标题】:How can I get other processes' information with Delphi?如何使用 Delphi 获取其他进程的信息?
【发布时间】:2010-04-11 07:05:29
【问题描述】:

我想制作一个显示此信息的任务管理器程序:

  1. 图片名称
  2. 内存使用情况
  3. PID

我该怎么做?

【问题讨论】:

  • 您恢复改善问题的编辑并添加无用的信息标签的原因是什么?

标签: delphi process


【解决方案1】:

因此,您不需要 J(WS)CL,有一个简单的 WinAPI 调用几乎可以满足您的所有需求,这就是 CreateToolhelp32Snapshot。要获取所有正在运行的进程的快照,您必须按如下方式调用它:

var
  snapshot: THandle;
begin
  snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 

现在您有了所有正在运行的进程的列表。您可以使用Process32FirstProcess32Next 函数浏览此列表,列表条目为PROCESSENTRY32-结构(其中包含进程ID 和图像名称等)。

uses 
  Windows, TLHelp32, SysUtils; 

var 
  snapshot: THandle; 
  ProcEntry: TProcessEntry32; 
  s: String; 
begin
  snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
  if (snapshot <> INVALID_HANDLE_VALUE) then begin 
    ProcEntry.dwSize := SizeOf(ProcessEntry32); 
    if (Process32First(snapshot, ProcEntry)) then begin 
      s := ProcEntry.szExeFile; 
      // s contains image name of the first process 
      while Process32Next(snapshot, ProcEntry) do begin 
        s := ProcEntry.szExeFile; 
        // s contains image name of the current process 
      end; 
    end; 
  end; 
  CloseHandle(snapshot);

但是,内存消耗信息似乎不包括在内,但您可以通过另一个简单的 API 调用获得此信息,GetProcessMemoryInfo

uses
  psAPI;

var
  pmc: TProcessMemoryCounters;
begin
  pmc.cb := SizeOf(pmc) ;
  if GetProcessMemoryInfo(processID, @pmc, SizeOf(pmc)) then
    // Usage in Bytes: pmc.WorkingSetSize
  else
    // fail

您只需使用从快照中检索到的进程 ID 调用此函数。

【讨论】:

  • 你应该删除最后一个sn-p中的动态内存分配,并简单地在堆栈上使用TProcessMemoryCounters变量。
  • +1;凉爽的!我不知道这个;仅关于 PSAPI。请注意,在线文档在这里:msdn.microsoft.com/en-us/library/ms682489(VS.85).aspx
  • 这里发生的可能性非常非常小,但 PID 可以重复使用,因此无法 100% 保证返回的内存信息实际上属于快照中获得的 PID。跨度>
  • @Remko:您可以将此评论放在此处的任何回复下,我严重怀疑内核之外是否有任何方法可以 100% 保证告诉您给定进程的确切内存使用情况在请求的确切时间点 - 你不能认真对待。 (请记住,即使 GetProcessMemoryInfo 函数调用期间,PID 重用也可能理论上发生,因此这很可能与它一样好)。
  • @Mef:好吧,我说这不太可能;-) 那就是说您可以使用带有 SystemProcessInformation 信息类的 NtQuerySystemInformation 检索一个查询中的所有信息,这将返回一个数组_SYSTEM_PROCESSES 记录,其中包含进程名称、pid 和内存使用情况。这是 taskmanager 所做的,也是 WMI、PsApi 和 Tool Help 功能在水下所做的。
【解决方案2】:

使用PSAPI(进程状态API)。 开源JCL 有一个用于 PSAPI 的 Delphi 包装器。

还有一些更好的stackoverflowDelphi PSAPI questions你可以查看答案。

--杰罗恩

【讨论】:

    【解决方案3】:

    您可以使用 WMI Win32_Process 类来获取所有正在运行的进程信息。此外,您可以检查Win32_PerfFormattedData_PerfProc_Process 类以获取与 CPU 和内存使用相关的性能计数器。

    检查此示例

    program WMIProcessInfo;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils
      ,ActiveX
      ,ComObj
      ,Variants;
    
    
    procedure GetWin32_Process;
    var
      objWMIService : OLEVariant;
      colItems      : OLEVariant;
      colItem       : OLEVariant;
      oEnum         : IEnumvariant;
      iValue        : LongWord;
    
      User          : OLEVariant;
      Domain        : OLEVariant;
    
      function GetWMIObject(const objectName: String): IDispatch;
      var
        chEaten: Integer;
        BindCtx: IBindCtx;
          Moniker: IMoniker;
      begin
        OleCheck(CreateBindCtx(0, bindCtx));
        OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));
        OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
      end;
    
    begin
      objWMIService := GetWMIObject('winmgmts:\\localhost\root\cimv2');
      colItems      := objWMIService.ExecQuery('SELECT * FROM Win32_Process','WQL',0);
      oEnum         := IUnknown(colItems._NewEnum) as IEnumVariant;
    
          WriteLn(Format('%-20s %6s %10s %10s %10s',['Caption','PID','User','Domain','Working Set ( Kb Memory)']));
      while oEnum.Next(1, colItem, iValue) = 0 do
      begin
          colItem.GetOwner(User,Domain);
          if colItem.GetOwner( User, Domain ) =0 then //get the user and domain
          WriteLn(Format('%-20s %6s %10s %10s %10s',[colItem.Caption,colItem.ProcessId,User,Domain,colItem.WorkingSetSize / 1024]))
          else
          WriteLn(Format('%-20s %6s %10s %10s %10s',[colItem.Caption,colItem.ProcessId,'','',colItem.WorkingSetSize / 1024]));
    
      end;
    end;
    
    
    begin
     try
        CoInitialize(nil);
        try
          GetWin32_Process;
          Readln;
        finally
        CoUninitialize;
        end;
     except
        on E:Exception do
        Begin
            Writeln(E.Classname, ': ', E.Message);
            Readln;
        End;
      end;
    end.
    

    【讨论】:

    • WMI 非常慢,如果 NiliDelphi 想要创建类似 TaskManager 的东西来经常刷新进程列表,我不会推荐 WMI。
    【解决方案4】:

    在 Jwscl 中有一个类可以为你做这件事(JwsclTerminalServer):

     var
       ATerminalServer: TJwTerminalServer;
       i: Integer;
     begin
       // Create Terminal Server instance and allocate memory for it
       ATerminalServer := TjwTerminalServer.Create;
    
       // Set servername (only in case of remote server)
       ATerminalServer.Server := 'TS001';
    
       // Remember that EnumerateProcesses will automatically connect to the
       // Terminal Server for you. The connect function raises an Exception
       // if the connection attempt was unsuccessfull, so better use try..except
       try
         if ATerminalServer.EnumerateProcesses then
         begin
    
           // Now loop through the list
           for i := 0 to ATerminalServer.Processes.Count - 1 do
           begin
             Memo1.Lines.Add(ATerminalServer.Processes[i].ProcessName);
           end;
    
         end;
       except
         on E: EJwsclWinCallFailedException do
         begin
           // Handle Exception here
         end;
       end;
    
       // Free Memory
       ATerminalServer.Free;
     end;
    

    虽然该单元是针对终端服务器的,但这部分可以在有和没有的情况下工作,并且作为奖励,您也可以在远程系统上使用它。

    对于每个返回的过程详细信息,请查看文档了解详细信息。

    对于内存使用,您可以使用 ProcessMemUsage 和 ProcessVirtualSize 属性,对于 Pid,有 ProcessId 属性

    【讨论】:

      【解决方案5】:

      ProcessInfo 提供有关在 Windows 中运行的进程的基本信息。它是开源的,并包含一个任务管理器的演示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-09
        • 1970-01-01
        • 2015-06-21
        • 2016-10-20
        相关资源
        最近更新 更多