Link to home
Start Free TrialLog in
Avatar of hush021299
hush021299

asked on

GetModuleFileNameEx, Platform XP, 2000, retrieve Path of calling application

I still dont find a way to retrieve a path of the calling application (Full file path from a windows handle) with getmodulefilename (or something else).

This function should retrieve the filepath of a window when I pass a handle of this window in the edit1.text

...
{First I did a enumwindows and listed all handles.
then I write a handle in the edit box:}
...
var FN: array[0..256] of Char;
begin
GetWindowModuleFileName( strtoint(edit1.text),
    FN,
    256);
    Showmessage(FN);
...

Result: Allways the path of MY application (same like application.exename)
MS says:
Following exerpt from [http://support.microsoft.com/default.aspx?scid=KB;en-us;q228469]

GetWindowModuleFileName and GetModuleFileName correctly retrieve information about windows and modules in the calling process. In Windows 95 and 98, they return information about windows and modules in other processes. However, in Windows NT 4.0 and Windows 2000, since module handles are no longer shared by all processes as they were on Windows 95 and 98, these APIs do not return information about windows and modules in other processes.

To get more information on Windows 2000, use the Process Status Helper set of APIs (known as PSAPI, see Psapi.h include file), available since Windows NT 4.0. APIs such as GetModuleFileNameEx and GetModuleBaseName offer equivalent functionality.

Hence: I need to work with getmodulefileex, but I can not translate the c example:
#include <windows.h>
#include <stdio.h>
#include "psapi.h"

void PrintModules( DWORD processID )
{
    HMODULE hMods[1024];
    HANDLE hProcess;
    DWORD cbNeeded;
    unsigned int i;

    // Print the process identifier.

    printf( "\nProcess ID: %u\n", processID );

    // Get a list of all the modules in this process.

    hProcess = OpenProcess(  PROCESS_QUERY_INFORMATION |
                                    PROCESS_VM_READ,
                                    FALSE, processID );
    if (NULL == hProcess)
        return;

    if( EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
    {
        for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
        {
            char szModName[MAX_PATH];

            // Get the full path to the module's file.

            if ( GetModuleFileNameEx( hProcess, hMods[i], szModName,
                                      sizeof(szModName)))
            {
                // Print the module name and handle value.

                printf("\t%s (0x%08X)\n", szModName, hMods[i] );
            }
        }
    }

    CloseHandle( hProcess );
}

void main( )
{
    // Get the list of process identifiers.

    DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i;

    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
        return;

    // Calculate how many process identifiers were returned.

    cProcesses = cbNeeded / sizeof(DWORD);

    // Print the name of the modules for each process.

    for ( i = 0; i < cProcesses; i++ )
        PrintModules( aProcesses[i] );
}
The main function obtains a list of processes by using the EnumProcesses function. For each process, the main function calls the PrintModules function, passing it the process identifier. PrintModules in turn calls the OpenProcess function to obtain the process handle. If OpenProcess fails, the output shows only the process identifier. For example, OpenProcess fails for the Idle and CSRSS processes because their access restrictions prevent user-level code from opening them. Next, PrintModules calls the EnumProcessModules function to obtain the module handles function. Finally, PrintModules calls the GetModuleFileNameEx function, once for each module, to obtain the module names

????

Cheers
Avatar of Madshi
Madshi

You need to call GetWindowThreadProcessID to get the process ID to which the window belongs. Then you can use my free unit "enumStuff", which can enumerate all running processes. You can do something like this:

uses enumStuff;

function GetProcessName(processID: dword) : string;
var pl : TProcessList;
begin
  pl := GetProcessList;
  for i1 := 0 to high(pl) do
    if pl[i1].pid = processID then begin
      result := pl[i1].Name;
      exit;
    end;
  result := '';
end;

The unit enumStuff is available here:

http://madshi.net/enumStuff.zip

Regards, Madshi.
Avatar of hush021299

ASKER

I got something working as well..

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    ProcessesListBox: TListBox;
    RefreshBtn: TButton;
    procedure RefreshBtnClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  TLHelp32, PsApi;

function RunningProcessesList(List: TStrings): Boolean;

  function BuildListTH: Boolean;
  var
    SnapProcHandle: THandle;
    ProcEntry: TProcessEntry32;
    NextProc: Boolean;
  begin
    SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if SnapProcHandle <> THandle(-1) then
    begin
      Result := True;
      ProcEntry.dwSize := Sizeof(ProcEntry);
      NextProc := Process32First(SnapProcHandle, ProcEntry);
      while NextProc do
      begin
        List.AddObject(ProcEntry.szExeFile, Pointer(ProcEntry.th32ProcessID));
        NextProc := Process32Next(SnapProcHandle, ProcEntry);
      end;
      CloseHandle(SnapProcHandle);
    end else
      Result := False;
  end;

  function BuildListPS: Boolean;
  var
    PIDs: array[0..1024] of DWORD;
    Handle: THandle;
    Needed: DWORD;
    I: Integer;
    ModuleFileName: array[0..MAX_PATH] of Char;
  begin
    Result := EnumProcesses(@PIDs, Sizeof(PIDs), Needed);
    if not Result then Exit;
    for I := 0 to (Needed div Sizeof(DWORD)) - 1 do
      if PIDs[I] <> 0 then
      begin
        Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PIDs[I]);
        if Handle <> 0 then
        begin
          if GetModuleFileNameEx(Handle, 0, ModuleFileName, Sizeof(ModuleFileName)) = 0 then
            List.AddObject('[System]', Pointer(INVALID_HANDLE_VALUE))
          else
            begin
            List.AddObject(ModuleFileName, Pointer(PIDs[I]));
            List.add(string(modulefilename));
            end;
          CloseHandle(Handle);
        end;
      end;
  end;

begin
  Assert(Assigned(List));
  List.BeginUpdate;
  try
    List.Clear;
    //if
  //  (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion = 4) //then
      Result := BuildListPS;
  //  else
    //  Result := BuildListTH;
  finally
    List.EndUpdate;
  end;
end;

{ TForm1 }

procedure TForm1.RefreshBtnClick(Sender: TObject);
begin
  RunningProcessesList(ProcessesListBox.Items);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  RefreshBtnClick(nil);
end;

end.

..I'll check out yours now
Madshi, what do I need to enter into the processID?
I have a problem to demarcate between process handle and window handle??
A process handle is something totally different than a window handle. And a process ID is something different than a process handle.

Each process has one unique ID. But there can be multiple handles to a process. Each window has only one handle, but no ID. You could say the window handle is for the window what the process ID is for the process.

Anyway, use this to convert a windows handle to a process ID:

function WindowHandleToProcessID(windowHandle: dword) : dword;
begin
  GetWindowThreadProcessID(windowHandle, @result);
end;

Give the result of this function in as the "processID".

Regards, Madshi.

P.S: The code you listed should also work fine.
Sorry, one more..
I have listed all processes:
procedure TForm1.Button5Click(Sender: TObject);
var pl : TProcessList;  I:integer;
begin
 pl := GetProcessList;
 for i := 0 to high(pl) do
     listbox1.items.add(pl[i].Name);

end;
This is similar to the task-list. Now I need to apply getmodulefilenameex to receive a path??
You mean you need the full file path? enumStuff only gives you the file name in NT/2k/XP. If you need the full path there, too, you have to use psApi. The code you posted above yourself does use psApi, so you might want to use just that...
..and one more

with this function I list the path of all processes:
1:

But I want to get a process based on a window handle
2:

can I use GetWindowThreadProcessId to get the module for getmodulefilename from a handle of a window?

======================================================
uses
  TLHelp32, PsApi ;


function BuildListPS: Boolean;
  var
    PIDs: array[0..1024] of DWORD;
    Handle: THandle;
    Needed: DWORD;
    I: Integer;
    ModuleFileName: array[0..MAX_PATH] of Char;
  begin
    Result := EnumProcesses(@PIDs, Sizeof(PIDs), Needed);
    if not Result then Exit;
    for I := 0 to (Needed div Sizeof(DWORD)) - 1 do
      if PIDs[I] <> 0 then
      begin
        Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PIDs[I]);
        if Handle <> 0 then
        begin
          if GetModuleFileNameEx(Handle, 0, ModuleFileName, Sizeof(ModuleFileName)) = 0 then
            Form1.Listbox1.items.AddObject('[System]', Pointer(INVALID_HANDLE_VALUE))
          // Form1.Listbox1.items.add(string(modulefileName));
          else
            begin
            Form1.Listbox1.items.AddObject(ModuleFileName, Pointer(PIDs[I]));
          //  List.add(string(modulefilename));
            end;
          CloseHandle(Handle);
        end;
      end;
  end;
procedure TForm1.Button1Click(Sender: TObject);
begin
   BuildListPS;
end;
//this get the path of all listed processes
==========================================================
2:
var pointer:=WinProcessID
begin
Handle :=  GetWindowThreadProcessId(wparam, WinProcessID);
//wparam comes from a keyhook dll
...
but also this seems to be false
ASKER CERTIFIED SOLUTION
Avatar of Madshi
Madshi

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks a lot
it works now! Great

Rgds
Hush