How to get applications from Windows Task manager (Applications Tab) + their locations on HDD from Delphi
Asked Answered
B

2

6

I would like to get list of programs running and visible in windows task manager's Applications Tab (not processes tab) and get their locations on HDD?
I need it to be done in Delphi. Anybody can help?

Bybee answered 1/8, 2010 at 14:34 Comment(0)
C
4

As far as I know, Application tab in Task Manager is a list of top-level windows which are not owned by other windows, have no parent, and are not tool windows. In my Process Info, I have a unit called AppInfo.pas which returns a list of windows with such characteristics, and the list matches what you see in Task Manager. Here is the main part of the code which is written as a call-back function for EnumWindows API function:

{$IFDEF DELPHI2007UP}
class function TAppWindowCollection.EnumWinProc(wHandle: HWND; lparam: integer): Bool;
{$ELSE}
function EnumWinProc(wHandle: HWND; lparam: integer): Bool; stdcall;
{$ENDIF}
Const
  MAX_TEXT = MAX_PATH;
var
  WindowItem : TWindowItem;
  strText,strClass : array [0..MAX_TEXT] of char;
  IsAppMainWin : Boolean;
begin
  //Check if the window is a visible application main window.
  IsAppMainWin := IsWindowVisible(wHandle)          AND                        //Visible
                  (GetWindow(wHandle,GW_OWNER) = 0) AND                        //Not owned by other windows
                  (GetParent(wHandle) = 0)          AND                        //Does not have any parent
                  (GetWindowLong(wHandle,GWL_EXSTYLE) AND WS_EX_TOOLWINDOW = 0); //Not a tool window

  if IsAppMainWin then
  begin
    WindowItem := TAppWindowCollection(lparam).Add;

    GetWindowText(wHandle,strText,MAX_TEXT);
    GetClassName(wHandle,strClass,MAX_TEXT);

    WindowItem.FCaption := strText;
    WindowItem.FHandle := wHandle;
    WindowItem.FWindowClass := strClass;
    GetWindowThreadProcessId(wHandle,WindowItem.FProcessID);
  end;

  Result := True;
end;

For the full source code, you can refer to AppInfo.pas.

and get their locations on HDD

These are just windows. If you want to get path of EXE file corresponding to each item, you should first find the process which is owning this window, using GetWindowThreadProcessID API function. That is what I did in the above code. Once you have the process ID, you can get a process handle from it, and enumerate its modules. The first module is the main EXE file. I implemented that in my TProcessInfo component which is included in the same package with AppInfo.pas.

Constitutionally answered 1/8, 2010 at 15:13 Comment(2)
Where is TWindowItem declared?Mistress
@Mistress Welcome to Stack Overflow. Just read all answers, not just one. And don't forget to upvote what you like instead of deleting everything.Scraper
S
3

Here is a complete standalone solution (no more broken links)

program ApplicationList;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  Winapi.Windows,
  Winapi.PsAPI;

function GetPathFromPID( const PID : cardinal ) : string;
var
  hProcess : THandle;
  path :     array [0 .. MAX_PATH - 1] of char;
begin
  hProcess := OpenProcess( PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, PID );
  if hProcess <> 0
  then
    try
      if GetModuleFileNameEx( hProcess, 0, path, MAX_PATH ) = 0
      then
        RaiseLastOSError;
      Result := path;
    finally
      CloseHandle( hProcess )
    end
  else
    RaiseLastOSError;
end;

function EnumWinProc( wHandle : hWnd; lparam : integer ) : Bool; stdcall;
Const
  MAX_TEXT = MAX_PATH;
var
  strText, strClass : array [0 .. MAX_TEXT] of char;
  strPath :           string;
  IsAppMainWin :      Boolean;
  ProcId :            cardinal;
begin
  // Check if the window is a visible application main window.
  IsAppMainWin := IsWindowVisible( wHandle ) AND // Visible
    ( GetWindow( wHandle, GW_OWNER ) = 0 ) AND   // Not owned by other windows
    ( GetParent( wHandle ) = 0 ) AND             // Does not have any parent
    ( GetWindowLong( wHandle, GWL_EXSTYLE ) AND WS_EX_TOOLWINDOW = 0 ); // Not a tool window

  if IsAppMainWin
  then
    begin

      GetWindowText( wHandle, strText, MAX_TEXT );
      GetClassName( wHandle, strClass, MAX_TEXT );

      GetWindowThreadProcessID( wHandle, ProcId );

      try
        strPath := GetPathFromPID( ProcId );
      except
        strPath := '???';
      end;

      WriteLn( ProcId, ' - ', strClass, ' - ', strText, ' - ', strPath );
    end;

  Result := True;
end;

procedure DoEnumWindows;
var
  FirstWnd : cardinal;
begin
  EnumWindows( @EnumWinProc, cardinal( @FirstWnd ) );
end;

begin
  try
    DoEnumWindows;
  except
    on E : Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;

  ReadLn;

end.
Stringed answered 7/1, 2013 at 8:22 Comment(3)
@Kermia what is not usable to this code? It compiles and retrieves all wanted informations (Delphi XE3)Stringed
@Kermia - How should one figure out what's wrong with the code with that comment of yours, I wonder..Duggan
I am so sorry. I'm just not too familiar with console applications. Thank you @SirRufo :)Gon

© 2022 - 2024 — McMap. All rights reserved.