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(hProces s, 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
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(hProces
{
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
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(T H32CS_SNAP PROCESS, 0);
if SnapProcHandle <> THandle(-1) then
begin
Result := True;
ProcEntry.dwSize := Sizeof(ProcEntry);
NextProc := Process32First(SnapProcHan dle, ProcEntry);
while NextProc do
begin
List.AddObject(ProcEntry.s zExeFile, Pointer(ProcEntry.th32Proc essID));
NextProc := Process32Next(SnapProcHand le, 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_ INFORMATIO N 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_VAL UE))
else
begin
List.AddObject(ModuleFileN ame, Pointer(PIDs[I]));
List.add(string(modulefile name));
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(Sen der: TObject);
begin
RunningProcessesList(Proce ssesListBo x.Items);
end;
procedure TForm1.FormShow(Sender: TObject);
begin
RefreshBtnClick(nil);
end;
end.
..I'll check out yours now
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:
function BuildListTH: Boolean;
var
SnapProcHandle: THandle;
ProcEntry: TProcessEntry32;
NextProc: Boolean;
begin
SnapProcHandle := CreateToolhelp32Snapshot(T
if SnapProcHandle <> THandle(-1) then
begin
Result := True;
ProcEntry.dwSize := Sizeof(ProcEntry);
NextProc := Process32First(SnapProcHan
while NextProc do
begin
List.AddObject(ProcEntry.s
NextProc := Process32Next(SnapProcHand
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_
if Handle <> 0 then
begin
if GetModuleFileNameEx(Handle
List.AddObject('[System]',
else
begin
List.AddObject(ModuleFileN
List.add(string(modulefile
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(Sen
begin
RunningProcessesList(Proce
end;
procedure TForm1.FormShow(Sender: TObject);
begin
RefreshBtnClick(nil);
end;
end.
..I'll check out yours now
ASKER
Madshi, what do I need to enter into the processID?
I have a problem to demarcate between process handle and window handle??
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(wi ndowHandle : dword) : dword;
begin
GetWindowThreadProcessID(w indowHandl e, @result);
end;
Give the result of this function in as the "processID".
Regards, Madshi.
P.S: The code you listed should also work fine.
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(wi
begin
GetWindowThreadProcessID(w
end;
Give the result of this function in as the "processID".
Regards, Madshi.
P.S: The code you listed should also work fine.
ASKER
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].N ame);
end;
This is similar to the task-list. Now I need to apply getmodulefilenameex to receive a path??
I have listed all processes:
procedure TForm1.Button5Click(Sender
var pl : TProcessList; I:integer;
begin
pl := GetProcessList;
for i := 0 to high(pl) do
listbox1.items.add(pl[i].N
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...
ASKER
..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_ INFORMATIO N or PROCESS_VM_READ, False, PIDs[I]);
if Handle <> 0 then
begin
if GetModuleFileNameEx(Handle , 0, ModuleFileName, Sizeof(ModuleFileName)) = 0 then
Form1.Listbox1.items.AddOb ject('[Sys tem]', Pointer(INVALID_HANDLE_VAL UE))
// Form1.Listbox1.items.add(s tring(modu lefileName ));
else
begin
Form1.Listbox1.items.AddOb ject(Modul eFileName, Pointer(PIDs[I]));
// List.add(string(modulefile name));
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(w param, WinProcessID);
//wparam comes from a keyhook dll
...
but also this seems to be false
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_
if Handle <> 0 then
begin
if GetModuleFileNameEx(Handle
Form1.Listbox1.items.AddOb
// Form1.Listbox1.items.add(s
else
begin
Form1.Listbox1.items.AddOb
// List.add(string(modulefile
end;
CloseHandle(Handle);
end;
end;
end;
procedure TForm1.Button1Click(Sender
begin
BuildListPS;
end;
//this get the path of all listed processes
==========================
2:
var pointer:=WinProcessID
begin
Handle := GetWindowThreadProcessId(w
//wparam comes from a keyhook dll
...
but also this seems to be false
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks a lot
it works now! Great
Rgds
Hush
it works now! Great
Rgds
Hush
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.