Hello!

My service (not windowed application) for winXP (32) creates a list of processes (like task manager) and setts every process to run in just one CPU in multiproccessor system.
1) when I try to get the handle of the process I get error: "The handle is invalid". If I remove "CloseHandle" for "OpenProcess" and run the service again, I get error "The parameter is incorrect". I tried with "PROCESS_ALL_ACCESS" and "true" combinations in "OpenProcess", but the problem still the same.
2) THe procedure "ProcessList" runs once a minute and reports a different (!?) handle for the same process every time, e. g. for "explorer" reports handle 455 first time and next time reports handle 856 for "explorer", and soon on.
Any idea?

Type
  PrcRec = packed record  // the object
    Prcs: String;
    CPUnr: Cardinal;
  end;


var
  ProcList: packed array of PrcRec;  // The global variable


procedure TMyService.ProcessList;
var CPUcnt, i: Cardinal;
    Info: SYSTEM_INFO;
    Flag: BOOL;
    SSHandle, ProcHandle: THandle;
    Snapshop: TProcessEntry32;
    vMaskProcess, vMaskSystem: Cardinal;
begin
  SetLength(ProcList, 0);
  GetSystemInfo(Info);
  CPUcnt:=Info.dwNumberOfProcessors;
  SSHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if SSHandle<>THandle(0) then begin
     Snapshop.dwSize:=SizeOf(Snapshop);
     Flag:=Process32First(SSHandle, Snapshop);
     i:=-1;
     While Integer(Flag)<>0 do begin
       Inc(i);
       // The problematic function
       ProcHandle:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, Snapshop.th32ProcessID);
       if CPUcnt>1 then SetProcessAffinityMask(ProcHandle, CPUcnt -1);
       SetLength(ProcList, i +1);
       ProcList[i].Prcs:=Snapshop.szExeFile;
       ProcList[i].CPUnr:=CPUcnt -1;  // :=GetProcessAffinityMask(ProcHandle, vMaskProcess, vMaskSystem);
       CloseHandle(ProcHandle);
       Flag:=Process32Next(SSHandle, Snapshop);
     end;
     CloseHandle(SSHandle);
  end;
end;

Thanks in advance, Adaltino.
.

Attachments
Type
  PrcRec = packed record  // the object
    Prcs: String;
    CPUnr: Cardinal;
  end;


var
  ProcList: packed array of PrcRec;  // The global variable


procedure TMyService.ProcessList;
var CPUcnt, i: Cardinal;
    Info: SYSTEM_INFO;
    Flag: BOOL;
    SSHandle, ProcHandle: THandle;
    Snapshop: TProcessEntry32;
begin
  SetLength(ProcList, 0);
  GetSystemInfo(Info);
  CPUcnt:=Info.dwNumberOfProcessors;
  SSHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if SSHandle<>THandle(0) then begin
     Snapshop.dwSize:=SizeOf(Snapshop);
     Flag:=Process32First(SSHandle, Snapshop);
     i:=-1;
     While Integer(Flag)<>0 do begin
       Inc(i);
       // The problematic function
       ProcHandle:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, Snapshop.th32ProcessID);
       if CPUcnt>1 then SetProcessAffinityMask(ProcHandle, CPUcnt -1);
       SetLength(ProcList, i +1);
       ProcList[i].Prcs:=Snapshop.szExeFile;
       ProcList[i].CPUnr:=CPUcnt -1;
       CloseHandle(ProcHandle);  // :=GetProcessAffinityMask(ProcHandle, vMaskProcess, vMaskSystem);
       Flag:=Process32Next(SSHandle, Snapshop);
     end;
     CloseHandle(SSHandle);
  end;
end;

Try it:

function TProcessControl.GetProcessList(AList: TStrings): Boolean;
var
  hSnapshoot: THandle;
  pe32: TProcessEntry32;
begin
  Result := true;
  AList.Clear;
  hSnapshoot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if (hSnapshoot <> -1) then begin
    pe32.dwSize := SizeOf(TProcessEntry32);
    if (Process32First(hSnapshoot, pe32)) then
      repeat
        AList.AddObject(pe32.szExeFile,TObject(pe32.th32ProcessID));
      until not Process32Next(hSnapshoot, pe32);
      CloseHandle (hSnapshoot);
  end else
      Result := False;
end;

Example:

procedure ShowProcessInfo;
var
  i: integer;
  ProcessList: TStringList;
behin
  ProcessList: TStringList;
  ProcessList := TStringList.Create;
  ProcessList.Sorted := true;
  ProcessList.Duplicates := dupIgnore;
  try
    if GetProcessList(ProcessList) then
    begin
       for i:=0 to ProcessList.Count-1 do
        WriteLn(ProcessList.Strings[i], integer(ProcessList.Objects[i]));
    end;
  finally
    ProcessList.Free;
  end;

Thank Wolfgan!
Very nice solution. But you missed the point: To get a HANDLE of each process in the list. In my solution I use the function "OpenProcess" to get the HANDLE (which I don't really get) of the object, but other solutions are also welcome. Please, understand me right: I need to get a HANDLE of every process in the list. Some other ideas?

Greetings Adaltino.

What's the problem?
Look for the line 13: TObject(pe32.th32ProcessID) - This process id.
Do it like this:

procedure TMainForm.StopProcess(AHandle: THandle);
var
  Res: THandle;
begin
  res := OpenProcess(PROCESS_TERMINATE, False, AHandle);
  if Res <> 0 then
     TerminateProcess(res, NO_ERROR);
end;

and next:

StopProcess(integer(ProcessList.Objects[index]));

This is the code from a real program. GetProcessList called from additional Thread and passes the process ID in the main thread. Function StopProcess belongs to the main form window and called on pressing the button.

Maybe you need something like this:

res := OpenProcess(PROCESS_TERMINATE, False, pe32.th32ProcessID);
  if Res <> 0 then
    AList.AddObject(pe32.szExeFile,TObject(res));

Edited 6 Years Ago by Wolfgan: n/a

This article has been dead for over six months. Start a new discussion instead.