Solved

How to make "GetModuleFileName" work in Win95 ?

Posted on 1998-11-05
24
322 Views
Last Modified: 2010-04-04
Has anyone "successfully" used GetModuleFileName in W95 ? it always returns "the calling exe name", or in rare instances "ole32.dll" & a few other dlls, but never works as it should.

Any comments....

as per Microsoft this shd be the function to used except in NT ? (http://support.microsoft.com/support/kb/articles/q119/1/63.asp)
0
Comment
Question by:DelphiOnly
  • 9
  • 7
  • 5
  • +1
24 Comments
 
LVL 12

Expert Comment

by:rwilson032697
Comment Utility
Can you post the code you use to call it?

You need to make sure you are passing the correct module handle for the module you are getting the filename for. How are you getting the module handle?

Cheers.

Raymond.
0
 

Author Comment

by:DelphiOnly
Comment Utility
Here goes a quick example of what i would normally do:

GetModuleFileName(
       GetWindowLong(
       GetWindow(GetDesktopWindow, GW_child),
       GWL_HInstance),
       @c, 255);

as you can see, ModuleHandle comes from GetWindowLong (GWL) and the HWND for GWL comes from GetWindow.
0
 

Author Comment

by:DelphiOnly
Comment Utility
ok.. here goes an actual code snipet from my program:

  dh := GetDesktopWindow;
  h    := GetWindow(dh, GW_child);
  ih   := GetWindowLong(h, GWL_HInstance);
  GetModuleFileName(ih, @c, 255);

This returns "J:\Borland\Delphi\Bin\Project.exe" for all child windows of Desktop !
0
 
LVL 12

Expert Comment

by:rwilson032697
Comment Utility
Your GetWindow(dh, GW_Child) will return the child window of the desktop topmost in the Z order, which will be your app!

Try GW_OWNER (or failing that either GW_HWNDFIRST or GW_HWNDLAST).

Cheers,

Raymond.
0
 
LVL 4

Expert Comment

by:dwwang
Comment Utility
My I know what do you want do do by calling this function?
0
 

Author Comment

by:DelphiOnly
Comment Utility
rwilson:

if you read my secod comment, you'll see that i said "it returns blah..blah.. for ALL CHILD WINDOWS of desktop !".  -(those you get by using GetWindow(h, HWNDNEXT).

btw, as i have originally asked in my question, Have you EVER successfully used that function ?
because if one tries to answer from MS Knowledgebase then the function would have to work, but does it happen in reality :-)



dwwang:

you "supposedly" use that function to find the executable name that spawned a given process.
0
 
LVL 4

Expert Comment

by:dwwang
Comment Utility
The functions in toolhelp32 unit have the ability do find all modules as well as processes currently loaded into win95 system. If what you want is this, I can give you an example, it even has the ability to "kill" a program.
0
 
LVL 12

Expert Comment

by:rwilson032697
Comment Utility
Are the handles valid, or NULL (in which case they would all map to your app...)

Raymond.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
With windows 3.1 every DLL was loaded only once. There worked this GetModuleFileName function like you expected it. But in 32bit windows each and every process has it's own copy of the DLL in it's memory context. It's like the DLL was just a part of the process. So the function returns always the name of the process file, not the name of the dll.
You could use something like toolhelp functions (only win95/98/NT5 or NT4 with service pack 4) to get the list of all dlls (like dwwang suggested). Then you could check which DLL has "your" module handle.

Regards, Madshi.
0
 

Author Comment

by:DelphiOnly
Comment Utility
rwilson:

The window handles are valid. i can get the ClassName & Window Title and they are ok.

Madshi, dwwang:

i find all the processes running using enumwindows.

In this case, I am trying to find the executable that started a process. e.g.:
say we have the notepad running. (one find the corresponding hWND & THandle). i want to find the executable that started this program (in this case i expect GetModuleFileName to return 'c:\Windows\notepad.exe')

i like to find the EXEs as well as DLLs.
0
 
LVL 4

Expert Comment

by:dwwang
Comment Utility
Well, for processes, I can send you an example showing this function; for modules, please see this site to get an example.

http://www.innotts.co.uk/~zephyr/modules.html

They all use ToolHelp32 Modules, that mean you must have Win95/98.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
dwwang, you're right and you're not right. Toolhelp functions work with NT5 and with NT4 (with service pack 4 installed), too.
However, I'm not sure if this is what DelphiOnly wants.

DelphiOnly, how do you get the processes by using enumWindows? I guess, you're using GetWindowProcessThreadID to get the process ID. Is that right?
Ok, now you have the process ID. Perhaps you can call OpenProcess to get a handle to it. But you can't use all these values with GetModuleFileName.
It's difficult. Let me explain: Every process has it's own address context. Your process can use the addresses 0-FFFFFFFF and notepad can use the same addresses, too. There's no conflict because every process has it's own addresses.
GetModuleFileName wants a module handle. A module handle is just the pointer to the beginning of the executable/dll in YOUR address context. Now if you have a value of another process, like an ID or a handle, it's another type of value. It's no module handle. Or if it is, it's at least not valid in your address context. So you give a invalid value to GetModuleFileName. Perhaps a pointer, that is valid only in the context of another process.
How can you make this all work? You could use the toolhelp functions to enumerate all processes (with all IDs and all exe names). But you can't get the dlls that other processes have loaded in their address context. That just doesn't work.
There is a way to get the dlls of other processes, too. But it's very very hard. You would have to "inject" the other processes with a self written dll. Then this dll could call the toolhelp functions in the context of the other process to enumerate the dlls. But it's very hard.

I hope, you now understand the problems a little bit better...

Regards, Madshi.
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 

Author Comment

by:DelphiOnly
Comment Utility
Madshi,

Looks like i got mixed up in terminology. Processes & Modules. I want to find the path of the executables for all running programs.

Look at the following code & suggest what shd i be doing to find the exe names:

dh := GetDesktopWindow;
h := GetWindow(dh, GW_child);

repeat
  ih := GetWindowLong(h, GWL_HInstance);
  if ih <> 0 then
     GetModuleFileName(ih, @c, 255);  //how do you find the exe for ModuleHandle ih ?
  h := GetWindow(h, GW_HWNDNext);
until  h = 0;


0
 

Author Comment

by:DelphiOnly
Comment Utility
dwwang:

unless i see your example how can i accept your answer ?
I'll take a look at ToolHelp functions, but it doesn't solve my problem.
0
 
LVL 4

Accepted Solution

by:
dwwang earned 100 total points
Comment Utility
Yes, but surely when I said "I can e-mail you an example", I was asking for your e-mail address. If you don't want to give it here, I can just paste the procedure here. It's tather simple, and do exactly what you want: All running programms' processID and EXE filename/path.
0
 

Author Comment

by:DelphiOnly
Comment Utility
yup. i want the answer to be posted here and not through email.
 thx.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
DelphiOnly,

I didn't know the GetWindowLong with GWL_HInstance. I don't know what type the result has. However, even if it is the pointer to the beginning of the other application, it's valid only in the address context of that application. So you can't get the application's name/path from that value. Sorry.
You'll have to use the toolhelp functions. I guess, dwwang's example is just a short implementation of these functions. And I think it will solve your problem. It's quite overdressed, but AFAIK there's no other way in 32bit windows.

Regards, Madshi.

BTW: For winNT 4 there exists this function:
function GetModuleFileHandleEx(hProcess,hModule: cardinal; fileName: PChar; nSize: cardinal) : cardinal; stdcall;
But it's hidden in an extra dll (psapi.dll) which you would have to download from Microsoft. And this would work only for winNT 4.
0
 
LVL 4

Expert Comment

by:dwwang
Comment Utility
Below is the whole contents of the source file, there are one string grid and two buttons(for the purpose of visually viewing the results), then main idea is in the TForm1.btShowProcClick.


unit frmProcF;

interface

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

type
  TForm1 = class(TForm)
    btShowProc: TButton;
    StringGrid1: TStringGrid;
    Label1: TLabel;
    Label2: TLabel;
    btKill: TButton;
    procedure btShowProcClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btKillClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.btShowProcClick(Sender: TObject);
var
   ProcessSnap: THandle;
   ProcessEntry32: TProcessEntry32;
   More: Boolean;
   i:Integer;

begin
     StringGrid1.RowCount:=1;
     i:=0;
     try
        ProcessSnap := CreateToolhelp32Snapshot(TH32CS_SNAPProcess,
        GetCurrentProcessID);
        if ProcessSnap = -1 then Exit;
        ProcessEntry32.dwSize := SizeOf(ProcessEntry32);
        More := Process32First(ProcessSnap, ProcessEntry32);
        while More do
              begin
                 StringGrid1.Cells[0,i]:=IntToStr(ProcessEntry32.th32ProcessID);
                 StringGrid1.Cells[1,i]:=StrPas(ProcessEntry32.szExeFile);
                 StringGrid1.RowCount:=StringGrid1.RowCount+1;
                 i:=i+1;
                 More := Process32Next(ProcessSnap, ProcessEntry32);
              end;
     finally
            CloseHandle(ProcessSnap);
     end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
     stringgrid1.ColWidths[0]:=100;
     stringgrid1.ColWidths[1]:=400;
end;

procedure TForm1.btKillClick(Sender: TObject);
var
   ProcHandle:THandle;
begin
     ProcHandle:=OpenProcess(PROCESS_ALL_ACCESS,False,StrToInt64(StringGrid1.Cells[0,StringGrid1.row]));
     TerminateProcess(ProcHandle,0);
end;

end.
0
 
LVL 4

Expert Comment

by:dwwang
Comment Utility
By the way, I use D4 so there is a StrToInt64
0
 

Author Comment

by:DelphiOnly
Comment Utility
yup, your code lists all executables running in the system, but now how do i find which program created which "Window" (with known window handles).

I can iterate through all window handles and all EXEs (that'll be two loops within each other: one for ToolHelp functions and the other for enumwindows), but obviously that is not the elegant/fast way.

Can you give any pointers regarding this ?

and btw, where (in which unit in D2) is PROCESS_ALL_ACCESS defined ?
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
You should call GetWindowThreadProcessID to get exe's process ID. Then use the toolhelp loop to find the matching entry to that process ID.
You're right. It's not very elegant at all. But this is due to the lack of appropriate windows APIs. AFAIK, there's no better *documented* way. Perhaps there are some undocumented ones...

Regards, Madshi.
0
 
LVL 4

Expert Comment

by:dwwang
Comment Utility
As Madshi said, there may be no easy way for the first question.

If process_all_access is defined in D2, it should be in Windows.pas, below is the definition in D4:

  PROCESS_TERMINATE         = $0001;
  {$EXTERNALSYM PROCESS_TERMINATE}
  PROCESS_CREATE_THREAD     = $0002;
  {$EXTERNALSYM PROCESS_CREATE_THREAD}
  PROCESS_VM_OPERATION      = $0008;
  {$EXTERNALSYM PROCESS_VM_OPERATION}
  PROCESS_VM_READ           = $0010;
  {$EXTERNALSYM PROCESS_VM_READ}
  PROCESS_VM_WRITE          = $0020;
  {$EXTERNALSYM PROCESS_VM_WRITE}
  PROCESS_DUP_HANDLE        = $0040;
  {$EXTERNALSYM PROCESS_DUP_HANDLE}
  PROCESS_CREATE_PROCESS    = $0080;
  {$EXTERNALSYM PROCESS_CREATE_PROCESS}
  PROCESS_SET_QUOTA         = $0100;
  {$EXTERNALSYM PROCESS_SET_QUOTA}
  PROCESS_SET_INFORMATION   = $0200;
  {$EXTERNALSYM PROCESS_SET_INFORMATION}
  PROCESS_QUERY_INFORMATION = $0400;
  {$EXTERNALSYM PROCESS_QUERY_INFORMATION}
  PROCESS_ALL_ACCESS        = (STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $FFF);
  {$EXTERNALSYM PROCESS_ALL_ACCESS}
0
 

Author Comment

by:DelphiOnly
Comment Utility
Madshi,

are there any "documents" on the net about the "undocumented" APIs :-)

dwwang,
Thx for introducing me to ToolHelp functions !
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Maybe there are some, but I don't know where. Sorry...
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now