Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to get the command-line of all running processes? 2

Status
Not open for further replies.

Griffyn

Programmer
Jul 11, 2002
1,077
AU
I want to see the full path of every running process on my system. Task Manager shows, eg.

delph32.exe
firefox.exe
svchost.exe
svchost.exe

but I want to see where those processes were executed from, eg.

c:\program files\borland\delphi6\bin\delphi32.exe
c:\program files\mozilla firefox\firefox.exe
C:\WINDOWS\System32\svchost.exe -k netsvcs
C:\WINDOWS\system32\svchost.exe -k LocalService

I've gotten started with this code snippet that shows the first bare list:
Code:
[navy][i]uses TLHelp32;[/i][/navy]
[b]var[/b]
  MyHandle: THandle;
  Struct: TProcessEntry32;
[b]begin[/b]
  Memo1.Clear;
  [b]try[/b]
    MyHandle:=CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, [purple]0[/purple]);
    Struct.dwSize:=Sizeof(TProcessEntry32);
    [b]if[/b] Process32First(MyHandle, Struct) [b]then[/b]
      Memo1.Lines.Add(Struct.szExeFile);
    [b]while[/b] Process32Next(MyHandle, Struct) [b]do[/b]
      Memo1.Lines.Add(Struct.szExeFile);
  [b]except[/b]
    ShowMessage([teal]'Error showing process list'[/teal]);
  [b]end[/b];

But Google isn't helping me out getting any further. Help please?
 
Yep. That seems to be the way to go, along with some selective filtering.
Code:
{$APPTYPE CONSOLE}
program procbrowse; uses Windows, TLHelp32;

// be careful with this.  In Windows 7, it shows up in kernel32.dll, so you might want to code to check for this and load dynamically
  function GetModuleFileNameEx(inProcess: THandle; inModule: THandle;
        Filename: PChar; size: DWord): DWord; stdcall;
        external 'psapi.dll' name 'GetModuleFileNameExA';

  function GetMFEx(inmod: THandle): string;
    var
      hProcess: THandle;
      ModuleName: array [0..300] of Char;
    begin
      hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
                  False, inmod);
      if (hProcess <> 0) then
        begin
          GetModuleFilenameEx(hProcess, 0, ModuleName, SizeOf(ModuleName));
          CloseHandle(hProcess);
          Result := ModuleName;
        end;
    end;

  var
    MyHandle: THandle;
    Struct: TProcessEntry32;
    pathstr: string;
  begin
    try
      MyHandle:=CreateToolHelp32SnapShot(TH32CS_SNAPProcess, 0);
      Struct.dwSize:=Sizeof(TProcessEntry32);
      if Process32First(MyHandle, Struct) then
        begin
          pathstr := GetMFEx(Struct.Th32ProcessID);
          writeln(pathstr);
        end;
      while Process32Next(MyHandle, Struct) do
        begin
          pathstr := GetMFEx(Struct.Th32ProcessID);
          writeln(pathstr);
        end;
    except
      writeln('Error showing process list');
    end;
    readln;
  end.


Measurement is not management.
 
Module32First / Module32Next functions will also do the trick. Remember that GetModuleFileNameEx is only available from windows 2000 and up. Module32x functions are available from win95 (psapi)

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
I got to thinking and realized you might want the command-line parms too, so I got to looking around a bit and ported a C program I found online (can't refind it to give proper credit). See the note at the top of the source, as it's VERY IMPORTANT to remember. Again, what is returned will be incomplete so you'll have to pair this up with the other function if you use both.

Anyhow, it uses NTDLL.DLL, so somehow I believe you won't find too much support if you run with using it:

Code:
{$APPTYPE CONSOLE}
program getcommline; uses windows;

// ported C program to Delphi.  Returns exact command-line used in calling program, including command-line parms.
  type
    TUnicodeString = record
      Length: ShortInt;
      MaxLength: ShortInt;
      Buffer: PWideChar;
    end;
    TProcessBasicInformation = record
      ExitStatus: DWord;
      PEBBaseAddress: Pointer;
      AffinityMask: DWord;
      BasePriority: DWord;
      UniqueProcessID: Word;
      ParentProcessID: DWord;
    end;

  function GetPEBAddress(inhandle: THandle): pointer;
    type
      NTQIP = procedure(ProcessHandle: THandle;
                        ProcessInformationClass: DWord;
                        ProcessInformation: Pointer;
                        ProcessInformationLength: DWord;
                        ReturnLength: Pointer); stdcall;
    var
      pbi: TProcessBasicInformation;
      MyHandle: THandle;
      myFunc: NTQIP;
    begin
      MyHandle := LoadLibrary('NTDLL.DLL');
      if MyHandle <> 0 then
        begin
          myfunc := GetProcAddress(myHandle, 'NtQueryInformationProcess');
          if @myfunc <> nil then
            MyFunc(inhandle, 0, @pbi, sizeof(pbi), nil);
        end;
      FreeLibrary(Myhandle);
      Result := pbi.PEBBaseAddress;
    end;

 function getcommandline(inproc: THandle): string;
    var
      myproc: THandle;
      rtlUserProcAddress: Pointer;
      PMBAddress: Pointer;
      command_line: TUnicodeString;
      command_line_contents: WideString;
      outr: DWord;
    begin
      myproc := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
                        false, inproc);
      PMBAddress := GetPEBAddress(myproc);
      ReadProcessMemory(myproc, Pointer(Longint(PMBAddress) + $10),
            @rtlUserProcAddress, sizeof(Pointer), outr);
      ReadProcessMemory(myproc, Pointer(Longint(rtlUserProcAddress) + $40),
            @command_line, sizeof(command_line), outr);

      SetLength(Command_Line_Contents, command_line.length);
      ReadProcessMemory(myproc, command_Line.Buffer, @command_Line_contents[1],
               command_line.length, outr);
      CloseHandle(myproc);

      Result := WideCharLenToString(PWideChar(command_Line_Contents),
                           command_line.length div 2);
    end;

 begin
   writeln('This process invoked with: ');
   writeln(GetCommandLine(GetCurrentProcessID));
   readln;
 end.

whosrdaddy said:
Module32First / Module32Next functions will also do the trick. Remember that GetModuleFileNameEx is only available from windows 2000 and up. Module32x functions are available from win95 (psapi)

1) Actually all that is needed is Module32First. Any subsequent calls enumerates all the DLLs associated with the main process. It seemed a bit...troublesome, so I went the other path.
2) All the documentation I found (like seems to indicate that GetModuleFileName returns a full path on 95/98/ME systems. So not so much an issue, assuming that is indeed the case. But might be worth testing there if you do plan to implement there.

Anyway, Griffyn hope all this helps you out.

Measurement is not management.
 
[thumbsup]

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Thanks guys. The combination Process32x, plus the GetCommandLine function works great. And in WinNT too.

 
Glenn9999,

Thanks so much for translating that code to Delphi. It's just what I was looking for. One problem, though. It wasn't returning the command lines for all the processes, just some of them. I found the problem.

type
TUnicodeString = record
Length: ShortInt;
MaxLength: ShortInt;
Buffer: PWideChar;
end;

should be:

type
TUnicodeString = record
Length: UShort;
MaxLength: UShort;
Buffer: PWideChar;
end;

ShortInt is signed whlie UShort is not and can hold numbers twice the size of ShortInt. The processes it was not working for were the ones with longer command lines.

Cheers.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top