Jump to content
Ian Branch

TProcessList issue.

Recommended Posts

Hi Team,

D11.3.1.

I have the following function I am trying to get to work..

function GetApplicationInstances(const FileName: string): TArray<string>;
var
  ProcessList: TProcessList;
  Process: TProcess;
  i: Integer;
begin
  Result := TArray<string>.Create;
  ProcessList := TProcessList.Create;
  try
    for i := 0 to ProcessList.Count - 1 do begin
      Process := ProcessList[i];
      if Process.FileName = FileName then begin
        Result.Add(Process.UserName);
      end;
    end;
  finally
    ProcessList.Free;
  end;
end;

I have bothe System.SysUtils and System.Diagnostics in my Uses clause but I am still gettin an 'undeclared identifier' for TProcessList and TProcess.

What have I missed please?

 

Regards & TIA,

Ian

Edited by Ian Branch

Share this post


Link to post

@Ian Branch  in my RAD11.3 UP1 and I dont have this Class/record named TProcessList in all sources!!! verify your project sources or anyother used in your project!

Edited by programmerdelphi2k

Share this post


Link to post
48 minutes ago, Ian Branch said:

I have bothe System.SysUtils and System.Diagnostics in my Uses clause but I am still gettin an 'undeclared identifier' for TProcessList and TProcess.

What have I missed please?

Delphi does not have any native classes named TProcess or TProcessList.  Your example is clearly based on 3rd party code that you don't have installed, which is why the classes are undefined.

Edited by Remy Lebeau

Share this post


Link to post
1 minute ago, Remy Lebeau said:

Delphi does not have any native classes named TProcess or TProcessList.  This is clearly based on 3rd party code.

Bummer.

Any suggestions?

 

Share this post


Link to post

Hi Team,

I found that bit of code and thought it would do the trick.  Oh well.

What I am try to achieve is a delphi function that when given a full application path/name, return how many instances are in use and who is using them.

 

Share this post


Link to post

OK.  Moving on.  Using Enums rather than TProcess.

function GetApplicationInstances(const FileName: string): TArray<string>;
var
  ProcessEntry      : TProcessEntry32;
  Snapshot          : THandle;
  ProcessList       : TList<string>;
begin
  ProcessList := TList<string>.Create();
  try
    Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if Snapshot <> INVALID_HANDLE_VALUE then
    begin
      ProcessEntry.dwSize := SizeOf(ProcessEntry);
      if Process32First(Snapshot, ProcessEntry) then
      begin
        repeat
          if (ProcessEntry.szExeFile = FileName) then // Replace with appropriate condition
          begin
            ProcessList.Add(ProcessEntry.szExeFile);
          end;
        until not Process32Next(Snapshot, ProcessEntry);
      end;
      CloseHandle(Snapshot);
    end;

    Result := ProcessList.ToArray;
  finally
    ProcessList.Free;
  end;
end;

I have the following lines.

var Instances: TArray<string>;
Instances := GetApplicationInstances(sFileName);

I can't see a way to get the number of elements in the TArray.

I thought "for var i := 0 to TArray(Instances).Count do Memo1.Lines.Add(Instances);" would be a monty, but no.

How please?

 

Edited by Ian Branch

Share this post


Link to post

Solved.  I added the count to the function.

function GetApplicationInstances(const FileName: string; out Count: Integer): TArray<string>;
var
  ProcessEntry: TProcessEntry32;
  Snapshot: THandle;
  ProcessList: TList<string>;
begin
  ProcessList := TList<string>.Create;
  try
    Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if Snapshot <> INVALID_HANDLE_VALUE then
    begin
      ProcessEntry.dwSize := SizeOf(ProcessEntry);
      if Process32First(Snapshot, ProcessEntry) then
      begin
        repeat
          if (ProcessEntry.szExeFile = FileName) then // Replace with appropriate condition
          begin
            ProcessList.Add(ProcessEntry.szExeFile);
          end;
        until not Process32Next(Snapshot, ProcessEntry);
      end;
      CloseHandle(Snapshot);
    end;

    Result := ProcessList.ToArray;
    Count := ProcessList.Count;
  finally
    ProcessList.Free;
  end;
end;

Tks Guys.

 

Regards,

Ian

Share this post


Link to post
1 hour ago, Ian Branch said:

I can't see a way to get the number of elements in the TArray.

Use the Length() function.

Quote

I thought "for var i := 0 to TArray(Instances).Count do Memo1.Lines.Add(Instances);" would be a monty, but no.

How please?

Use this instead:

for var i := 0 to Length(Instances)-1 do
  Memo1.Lines.Add(Instances[i]);

Alternatively,  you can use the Low()/High() functions to get the first and last indexes of the array:

for var i := Low(Instances) to High(Instances) do
  Memo1.Lines.Add(Instances[i]);

Alternatively, you can use a for..in loop instead, no indexes needed:

for var elem in Instances do
  Memo1.Lines.Add(elem);

However, in your particular example, the TMemo.Lines property has an overloaded method that accepts a TArray<string> as input, so you don't even need a loop at all:

Memo1.Lines.AddStrings(Instances);
Quote

Solved.  I added the count to the function.

You don't need that.  Dynamic arrays know their own length.

 

Edited by Remy Lebeau
  • Like 2

Share this post


Link to post
2 hours ago, Remy Lebeau said:

I thought "for var i := 0 to TArray(Instances).Count do Memo1.Lines.Add(Instances);" would be a monty, but no.

How please?

// function GetApplicationInstances(const FileName: string; out Count: Integer): TArray<string>;
//
for var Item in GetApplicationInstances do
	Memo1.Lines.Add( Item ); // Item  = string
    
// or
Memo1.Lines.AddStrings( GetApplicationInstances )

// anyway, if result = [] then nothing will be add on Memo!

 

Edited by programmerdelphi2k

Share this post


Link to post

UNnecessary usage:

3 hours ago, Ian Branch said:

ProcessList: TList<string>;    UNnecessary this!

...

ProcessList.Add(ProcessEntry.szExeFile);  // boommmm

 

just use this:   

function GetApplicationInstances(const FileName: string): TArray<string>;
var
  ProcessEntry: TProcessEntry32;
  Snapshot: THandle;
begin
    Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if Snapshot <> INVALID_HANDLE_VALUE then
    begin
      ProcessEntry.dwSize := SizeOf(ProcessEntry);
      if Process32First(Snapshot, ProcessEntry) then
      begin
        repeat
          if (ProcessEntry.szExeFile = FileName) then // Replace with appropriate condition
          begin
            result := result + [ProcessEntry.szExeFile];
          end;
        until not Process32Next(Snapshot, ProcessEntry);
      end;
      CloseHandle(Snapshot);
    end;
end;

// on client-code = your form/app/etc...
MyArrayFromMyFunc := GetApplicationInstances;

ShowMessage( Length(MyArrayFormMyFunc ).ToString );

for var A in MyArrayFromMyFunc do
  Memo1.Lines.Add( A )

 

Edited by programmerdelphi2k

Share this post


Link to post

Something like this?     It's like Borland's old 'side kick' only expanded to switch between different desktops. The thing can focus GE stuff so very handy. Here's a good start on it.  

Applister
const
  hour2dot3 ='hr %2.3f ';   //hour meter style
  hour2dot3wS ='hr %2.3f %s';

  GoodApps: Tarray<string> = ['Notepad', 'TAppBuilder', 'Window', 
   'Chrome_WidgetWin_1', 'Notepad++', 'TfrmMultiMain'];

type
  ptrApp = ^TApp;
  TApp = record
    Handle: HWnd;
    ...
  end;
    
  TptrApps = class(Tlist<ptrApp>)
    AppBuilderCount: Integer; // mark BDS's as loaded    
    slLog: TStrings;  //ref to CB.Items
    sBanner: PString;  
    sgGrid: TStringGrid; //ref to Sg
    ChBx: TCheckListBox; //ref to chLB
    ...
  end;  

 

MTD.thumb.png.9b0534361b64f85f330ae9e7d4c4f56a.png

Edited by Pat Foley
Modified Pix

Share this post


Link to post
12 hours ago, programmerdelphi2k said:

UNnecessary usage:

Not really.  Your way reallocates the array on every item added.  Whereas TList has a Capacity so it doesn't reallocate on every individual add, and then the final array is allocated only 1 time based on the TList's final Count.

Share this post


Link to post
7 minutes ago, Remy Lebeau said:

so it doesn't reallocate on every individual add

for sure, but in sometime it do it! capacity > n =  reallocate it please! at end, a List will do it, expand the items like a array! or a array-of-pointers!

Share this post


Link to post
1 minute ago, programmerdelphi2k said:

for sure, but in sometime it do it! capacity > n =  reallocate it please! at end, a List will do it, expand the items like a array! or a array-of-pointers!

Yes, it reallocates when its Capacity is exceeded.  And, it uses an array internally.  But, that reallocation won't happen on every add, since the Capacity grows algorithmically (see SysUtils.GrowCollection()).  It is very inefficient to reallocate on every add.

Share this post


Link to post
1 hour ago, Remy Lebeau said:

It is very inefficient to reallocate on every add.

ok, for sure! but how many "process" can be in a system in a moment? ... 100, 1000, 10000...

how many fragmentations we can have on 32GB memory, when using Chrome  ?  😂

 

dont forget "GetApplicationInstances" always return an "array"... same using a TList (with internal array usage) into it!  :classic_ohmy:

 

Edited by programmerdelphi2k

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×