【问题标题】:Enumerate running processes in Delphi枚举 Delphi 中正在运行的进程
【发布时间】:2009-07-09 07:48:26
【问题描述】:

如何使用 Delphi 在我的机器上获取正在运行的进程列表(包括 PID、所有者等的详细信息)?

编辑:所提出的解决方案都没有给我拥有进程的用户,只有 PID、ExeName 等信息......

【问题讨论】:

  • 您应该使用下面建议的 JCL。直接使用toolhelp或者EnumProcesses函数比较麻烦。

标签: delphi winapi


【解决方案1】:

一种方法是使用Tool Help library(参见TlHelp32 单元),或在Windows NT 上使用EnumProcesses(参见PsAPI 单元)。以JCL 中的JclSysInfo.RunningProcessesList 为例。

下面是一个如何获取进程用户名的简单示例:

type
  PTokenUser = ^TTokenUser;
  TTokenUser = packed record
    User: SID_AND_ATTRIBUTES;
  end;

function GetProcessUserName(ProcessID: Cardinal; out DomainName, UserName: string): Boolean;
var
  ProcessHandle, ProcessToken: THandle;
  InfoSize, UserNameSize, DomainNameSize: Cardinal;
  User: PTokenUser;
  Use: SID_NAME_USE;
  _DomainName, _UserName: array[0..255] of Char;
begin
  Result := False;
  DomainName := '';
  UserName := '';

  ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessID);
  if ProcessHandle = 0 then
    Exit;

  try
    if not OpenProcessToken(ProcessHandle, TOKEN_QUERY, ProcessToken) then
      Exit;

    try
      GetTokenInformation(ProcessToken, TokenUser, nil, 0, InfoSize);
      User := AllocMem(InfoSize * 2);
      try
        if GetTokenInformation(ProcessToken, TokenUser, User, InfoSize * 2, InfoSize) then
        begin
          DomainNameSize := SizeOf(_DomainName);
          UserNameSize := SizeOf(_UserName);

          Result := LookupAccountSid(nil, User^.User.Sid, _UserName, UserNameSize, _DomainName, DomainNameSize, Use);

          if Result then
          begin
            SetString(DomainName, _DomainName, StrLen(_DomainName));
            SetString(UserName, _UserName, StrLen(_UserName));
          end;
        end;
      finally
        FreeMem(User);
      end;
    finally
      CloseHandle(ProcessToken);
    end;
  finally
    CloseHandle(ProcessHandle);
  end;
end;

【讨论】:

  • 很遗憾,这并不能满足我寻找进程所有者的需求
  • 使用工具帮助库,在返回的条目中有 th32ParentProcessID 字段。 JclSysInfo 本身不使用它,但您可以使用它作为起点。
  • TOndrej - 我实际上是在考虑拥有/运行该进程的用户
  • 我明白了。我假设“所有者”是指父进程。我添加了代码来获取运行进程的帐户的用户名。
【解决方案2】:

这是我们用来检查进程是否存在的函数,FProcessEntry32 保存了进程的所有信息,所以你应该能够将它扩展到你需要的每一个。

取自here

  uses TlHelp32

function processExists(exeFileName: string): Boolean;
{description checks if the process is running
URL: http://www.swissdelphicenter.ch/torry/showcode.php?id=2554}
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  FSnapshotHandle        := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  ContinueLoop           := Process32First(FSnapshotHandle, FProcessEntry32);
  Result := False;


  while Integer(ContinueLoop) <> 0 do
  begin

    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
      UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
      UpperCase(ExeFileName))) then
    begin
      Result := True;
    end;

    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;

TProcessEntry32 记录如下所示:

tagPROCESSENTRY32 = packed record
    dwSize: DWORD;
    cntUsage: DWORD;
    th32ProcessID: DWORD;       // this process
    th32DefaultHeapID: DWORD;
    th32ModuleID: DWORD;        // associated exe
    cntThreads: DWORD;
    th32ParentProcessID: DWORD; // this process's parent process
    pcPriClassBase: Longint;    // Base priority of process's threads
    dwFlags: DWORD;
    szExeFile: array[0..MAX_PATH - 1] of Char;// Path
  end;

【讨论】:

  • 感谢您的代码,它工作得很好。顺便说一句,您可以将 if 子句替换为 if StrUtils.EndsText(exeFileName, FProcessEntry32.szExeFile) then
  • 提示:我们可以在result := TRUE之后Exit。当我们已经有了结果时,迭代完整的东西是没有意义的。并且使用SameText 而不是UpperCase 也有帮助。
【解决方案3】:

你必须使用:

PROCESSENTRY32 Structure 将包含您可能需要的所有信息。

文档来自 MDSN,用于 C++,但在 Delphi 中是 相同的

【讨论】:

    【解决方案4】:

    This class will give you a list of all open windows(在下面列出)带有 PID、标题、尺寸等。它不完全是正在运行的进程信息,但我已经使用它通过它来查找应用程序。

    //   Window List Component 1.5 by Jerry Ryle
    //
    //   Aaugh! I accidentally uploaded the wrong source
    //   which had a nasty bug in the refresh procedure!
    //   Thanks to Serge, who found my mistake and suggested
    //   a few other improvements!
    //
    //   This component will enumerate windows and return
    //   information about them in the Windows property.
    //   The component currently returns a handle, caption text,
    //   associated ProcessID, visibility, and dimensions.
    //   For documentation, please read the accompanying
    //   WindowList.txt
    //
    //   This component is completely free of course. If you find
    //   it useful, and are compelled to send me cash, beer, or
    //   dead things in envelopes, please feel free to do so.
    //
    //   email me if you make it better:  gryle@calpoly.edu
    
    unit WindowList;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
    
    type
    
      TWindowObject = record
                        WinHandle  : HWnd;    // Window Handle
                        WinCaption : String;  // Window Caption Text (If any)
                        ProcessID  : Integer; // Process the window belongs to
                        IsVisible  : Boolean; // Is the window visible?
                        IsEnabled  : Boolean; // Is the window enabled for mouse/keyboard input?
                        IsIconic   : Boolean; // Is the window minimized?
                        WindowRect : TRect;   // Window Dimensions
                        // Add more properties here if you like,
                        // then fill them in at the WindowCallback
                        // function.
                      end;
      PTWindowObject = ^TWindowObject;
    
      TWindowList = class(TComponent)
      private
        WindowLst : TList;
        FCount : Integer;
      protected
        Function GetAWindow(Index : Integer) : TWindowObject;
      public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
    
        Procedure Refresh;
        Property Windows[Index : Integer]: TWindowObject read GetAWindow;
        Property Count : Integer read FCount;
      published
        // Published declarations
      end;
    
    procedure Register;
    
    implementation
    
    // Note that this function is not a member of WindowList.
    // Therefore, the list to be filled needs to be passed
    // as a pointer. Note that this is passed as a VAR. if you
    // don't do this, bad things happen in memory.
    
    Function WindowCallback(WHandle : HWnd; Var Parm : Pointer) : Boolean; stdcall;
    // This function is called once for each window
    Var MyString : PChar;
         MyInt : Integer;
         MyWindowPtr : ^TWindowObject;
    begin
        New(MyWindowPtr);
    
        // Window Handle (Passed by the enumeration)
        MyWindowPtr.WinHandle := WHandle;
    
        // Window text
        MyString := Allocmem(255);
        GetWindowText(WHandle,MyString,255);
        MyWindowPtr.WinCaption := String(MyString);
        FreeMem(MyString,255);
    
        // Process ID
        MyInt := 0;
        MyWindowPtr.ProcessID := GetWindowThreadProcessId(WHandle,@MyInt);
    
        // Visiblity
        MyWindowPtr.IsVisible := IsWindowVisible(WHandle);
    
        // Enabled
        MyWindowPtr.IsEnabled := IsWindowEnabled(WHandle);
    
        // Iconic
        MyWindowPtr.IsIconic := IsIconic(WHandle);
    
        // Window Dimensions
        MyWindowPtr.WindowRect := Rect(0,0,0,0);
        GetWindowRect(WHandle,MyWindowPtr.WindowRect);
    
        // Add the structure to the list. Do not dereference Parm...
        // once again, bad things happen.
        TList(Parm).Add(MyWindowPtr);
        Result := True; // Everything's okay. Continue to enumerate windows
    end;
    
    constructor TWindowList.Create(AOwner: TComponent);
    var MyWindowPtr : PTWindowObject;
    begin
      inherited;
      WindowLst := TList.Create;
    
      // Thanks Serge, I should've done this from the start :)
      // Sloppy me. 
      If Not ( csDesigning in ComponentState ) Then
        Begin
          EnumWindows(@WindowCallback,Longint(@WindowLst));
          FCount := WindowLst.Count;
        End
      Else
        FCount := 0;
    end;
    
    destructor TWindowList.Destroy;
    var I : Integer;
    begin
      If WindowLst.Count > 0 Then
        Begin
          For I := 0 To (WindowLst.Count - 1) Do
            Dispose(PTWindowObject(WindowLst[I]));
        End;
      WindowLst.Free;
      inherited;
    end;
    
    procedure TWindowList.Refresh;
    begin
      WindowLst.Clear; {Clear the list!}
      EnumWindows(@WindowCallback,Longint(@WindowLst));
      FCount := WindowLst.Count;
    end;
    
    function TWindowList.GetAWindow(Index : Integer) : TWindowObject;
    begin
      Result := PTWindowObject(WindowLst[Index])^;
    end;
    
    procedure Register;
    begin
      RegisterComponents('System', [TWindowList]);
    end;
    
    end.
    

    【讨论】:

      【解决方案5】:

      您可以考虑使用WMISet components(单一许可证 69 美元,站点许可证 199 美元,提供试用版)。 TWmiProcessControl component 似乎封装了对 Win32_Process 的调用。他们还有一个getting a process owner 的例子。

      【讨论】:

        【解决方案6】:

        我认为Madshi madKernel 可能会很有趣。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-03-08
          • 1970-01-01
          • 1970-01-01
          • 2011-10-22
          • 1970-01-01
          • 1970-01-01
          • 2012-04-04
          相关资源
          最近更新 更多