Clive Henson
asked on
EnumProcessModules - error 299 - 'Only part of a Read/WriteProcessMemory
When using the API on W7 64 bit and looking at a 64 bit process the error above occurs.
I am trying to get the Application Name and Path from the Window Handle
The reason is explained in:
http://msdn.microsoft.com/en-us/library/ms682631(v=vs.85).aspx
I think the only solution is a 64 bit DLL or COM object which can be called from a 32 bit application. Are you aware of such a component.
I am trying to get the Application Name and Path from the Window Handle
The reason is explained in:
http://msdn.microsoft.com/en-us/library/ms682631(v=vs.85).aspx
I think the only solution is a 64 bit DLL or COM object which can be called from a 32 bit application. Are you aware of such a component.
Can't you do a 64 bit build of the app (and use EnumProcessModulesEx) ?
Are you using C++ (native)?
Anyway, consider using WMI. It will allow you to lista all you need.
Anyway, consider using WMI. It will allow you to lista all you need.
ASKER
No current version of Delphi outputs 64 bit code, so suggestion from AndyAinscow will not work.
I have considered building a 64 bit DLL to do this but this would involve working in some other development system which I would prefer to avoid if possible.
I will look at the other suggestions.
I have considered building a 64 bit DLL to do this but this would involve working in some other development system which I would prefer to avoid if possible.
I will look at the other suggestions.
GHG-RCH
Can you post the code you are using
Well the question is posted in the MFC question area.
It was not clear from the beginning what development tool OOP is using.
That is why i asked question:
Are you using C++ (native)?
I did not get an answer but from following posts it looks like the answer is NO it is Delphi.
That is why i asked question:
Are you using C++ (native)?
I did not get an answer but from following posts it looks like the answer is NO it is Delphi.
ASKER
ewangoya
Thanks for your help
BUT
this code appears to work, but it only shows 32 bit applications.
If you run on W7 64 bit then 64 bit applications appear in the list but the file Path/Name is gibberish.
See the link in the original questions for details
I have extended the code with a stripped down version of my ExeFromWindow routine and some additional buttons and a timer to assist in testing. The timer picks up the active window handle unless it it is this form. Then clicking the ActiveWin button calls ExeFromWindow for that handle. Try it after focssing a 32 bit application (e.g. Word 2003) then try NotePad or Windows Explorer, both 64 bit apps on W7-64. The same gibberish is returned.
unit ProcessListU;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ShellAPI, StdCtrls, PSapi, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
Timer1: TTimer;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
FProcessID: Integer;
fActiveWindow: HWnd;
fWinCount: Integer;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure GetProcessNames(AList: TStrings);
var
PIDArray: array [0..1023] of DWORD;
cbNeeded: DWORD;
I: Integer;
ProcessCount: Integer;
hMod: HMODULE;
hProcess: THandle;
ModuleName: array [0..512] of Char;
begin
if EnumProcesses(@PIDArray, SizeOf(PIDArray), cbNeeded) then
begin
ProcessCount := cbNeeded div SizeOf(DWORD);
for I := 0 to ProcessCount - 1 do
begin
hProcess := OpenProcess(PROCESS_QUERY_ INFORMATIO N or PROCESS_VM_READ, False, PIDArray[ I ]);
if (hProcess <> 0) then
try
EnumProcessModules(hProces s, @hMod, SizeOf(hMod), cbNeeded);
GetModuleFilenameEx(hProce ss, hMod, ModuleName, SizeOf(ModuleName));
AList.Add(string(ModuleNam e));
finally
CloseHandle(hProcess);
end;
end;
end;
end;
procedure TForm1.Button1Click(Sender : TObject);
begin
Memo1.Lines.Clear;
GetProcessNames(Memo1.Line s);
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
Memo1.SelectAll;
Memo1.CopyToClipboard;
Memo1.SelLength := 0;
end;
Function ExeFromWindow(ThisHandle: HWnd; NameOnly:Boolean=False):St ring;
{Use API calls to return the EXE name for the specified window}
{This one based on Brian Long reply}
{See old function below}
function Wnd2PID(Wnd: THandle): DWord;
var
ReturnVal: DWord;
begin
Result := 0;
try
GetWindowThreadProcessId(W nd, @ReturnVal);
Result := ReturnVal;
except
{ShowException('Wnd2PID'); }
end;{except}
end;
function PID2Name(PID: DWord): String;
var
PH, MH: THandle;
Needed: DWord;
ModName: array[0..MAX_PATH] of Char;
begin
try
Result := '';
PH := OpenProcess(PROCESS_QUERY_ INFORMATIO N or PROCESS_VM_READ, False, PID);
try
try
Win32Check(EnumProcessModu les(PH, @MH, SizeOf(MH), Needed));
except
{Technical Debt: Throw away exceptions 299 error in 64bit W7}
end;
try
Win32Check(Bool(GetModuleF ileNameEx( PH, MH, ModName, SizeOf(ModName))));
except
{Technical Debt: Throw away exceptions 299 error in 64bit W}
end;
Result := ModName
finally
CloseHandle(PH)
end{finally}
except
{ShowException('PID2Name') ;}
end;{except}
end; {PID2Name}
var
ExeText: String;
begin
try
try
if ThisHandle=0
then result := ''
else begin
ExeText := PID2Name(Wnd2PID(ThisHandl e));
if NameOnly
then Result := ExtractFileName(ExeText)
else Result := ExeText;
end;
except
Result := '';;
{ShowException('ExeFromWin dow')}
end;{except}
Finally
end;{Finally}
end;{ExeFromWindow}
procedure TForm1.Button3Click(Sender : TObject);
begin
Memo1.Lines.Add(IntToStr(f WinCount)+ ':'+ExeFro mWindow(fA ctiveWindo w,False));
Inc(fWinCount);
end;
procedure TForm1.Button4Click(Sender : TObject);
begin
Memo1.Lines.Clear;
fWinCount := 1;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
ActiveWindow: HWnd;
begin
ActiveWindow := GetForeGroundWindow; {Check the differences later}
if ActiveWindow<>self.Handle then
fActiveWindow:=ActiveWindo w;
end;
end.
Thanks for your help
BUT
this code appears to work, but it only shows 32 bit applications.
If you run on W7 64 bit then 64 bit applications appear in the list but the file Path/Name is gibberish.
See the link in the original questions for details
I have extended the code with a stripped down version of my ExeFromWindow routine and some additional buttons and a timer to assist in testing. The timer picks up the active window handle unless it it is this form. Then clicking the ActiveWin button calls ExeFromWindow for that handle. Try it after focssing a 32 bit application (e.g. Word 2003) then try NotePad or Windows Explorer, both 64 bit apps on W7-64. The same gibberish is returned.
unit ProcessListU;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ShellAPI, StdCtrls, PSapi, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
Timer1: TTimer;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
FProcessID: Integer;
fActiveWindow: HWnd;
fWinCount: Integer;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure GetProcessNames(AList: TStrings);
var
PIDArray: array [0..1023] of DWORD;
cbNeeded: DWORD;
I: Integer;
ProcessCount: Integer;
hMod: HMODULE;
hProcess: THandle;
ModuleName: array [0..512] of Char;
begin
if EnumProcesses(@PIDArray, SizeOf(PIDArray), cbNeeded) then
begin
ProcessCount := cbNeeded div SizeOf(DWORD);
for I := 0 to ProcessCount - 1 do
begin
hProcess := OpenProcess(PROCESS_QUERY_
if (hProcess <> 0) then
try
EnumProcessModules(hProces
GetModuleFilenameEx(hProce
AList.Add(string(ModuleNam
finally
CloseHandle(hProcess);
end;
end;
end;
end;
procedure TForm1.Button1Click(Sender
begin
Memo1.Lines.Clear;
GetProcessNames(Memo1.Line
end;
procedure TForm1.Button2Click(Sender
begin
Memo1.SelectAll;
Memo1.CopyToClipboard;
Memo1.SelLength := 0;
end;
Function ExeFromWindow(ThisHandle: HWnd; NameOnly:Boolean=False):St
{Use API calls to return the EXE name for the specified window}
{This one based on Brian Long reply}
{See old function below}
function Wnd2PID(Wnd: THandle): DWord;
var
ReturnVal: DWord;
begin
Result := 0;
try
GetWindowThreadProcessId(W
Result := ReturnVal;
except
{ShowException('Wnd2PID');
end;{except}
end;
function PID2Name(PID: DWord): String;
var
PH, MH: THandle;
Needed: DWord;
ModName: array[0..MAX_PATH] of Char;
begin
try
Result := '';
PH := OpenProcess(PROCESS_QUERY_
try
try
Win32Check(EnumProcessModu
except
{Technical Debt: Throw away exceptions 299 error in 64bit W7}
end;
try
Win32Check(Bool(GetModuleF
except
{Technical Debt: Throw away exceptions 299 error in 64bit W}
end;
Result := ModName
finally
CloseHandle(PH)
end{finally}
except
{ShowException('PID2Name')
end;{except}
end; {PID2Name}
var
ExeText: String;
begin
try
try
if ThisHandle=0
then result := ''
else begin
ExeText := PID2Name(Wnd2PID(ThisHandl
if NameOnly
then Result := ExtractFileName(ExeText)
else Result := ExeText;
end;
except
Result := '';;
{ShowException('ExeFromWin
end;{except}
Finally
end;{Finally}
end;{ExeFromWindow}
procedure TForm1.Button3Click(Sender
begin
Memo1.Lines.Add(IntToStr(f
Inc(fWinCount);
end;
procedure TForm1.Button4Click(Sender
begin
Memo1.Lines.Clear;
fWinCount := 1;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear;
end;
procedure TForm1.Timer1Timer(Sender:
var
ActiveWindow: HWnd;
begin
ActiveWindow := GetForeGroundWindow; {Check the differences later}
if ActiveWindow<>self.Handle then
fActiveWindow:=ActiveWindo
end;
end.
ASKER
AndyAinscow JohnCz:
My apologies, I should have mentioned in the original question that i was working in Delphi 7 (though I also have the current version of Delphi 2010).
The Zones I intended to add were:
Microsoft Operating Systems, Delphi Programming,
Somehow: Windows MFC Programming, Microsoft Visual C++.Net also got added, this was not intentional.
However because at present there is no Delphi 32 bit compiler I was asking if there are any components that can provide process information on 64 bit applications to 32 bit code.
My apologies, I should have mentioned in the original question that i was working in Delphi 7 (though I also have the current version of Delphi 2010).
The Zones I intended to add were:
Microsoft Operating Systems, Delphi Programming,
Somehow: Windows MFC Programming, Microsoft Visual C++.Net also got added, this was not intentional.
However because at present there is no Delphi 32 bit compiler I was asking if there are any components that can provide process information on 64 bit applications to 32 bit code.
ASKER
JohnCz:
I am not familiar with WMI.
The issue I am trying to sort out at present is determining the executable for a particular window from the Window handle. See the code in my previous submission.
The code I have works fine on W7-32 bit and for all 32 bit processes on W7-64 bit.
If WMI can provide this information I would be more than happy to use it.
What WMI functionality is available for this.
I am not familiar with WMI.
The issue I am trying to sort out at present is determining the executable for a particular window from the Window handle. See the code in my previous submission.
The code I have works fine on W7-32 bit and for all 32 bit processes on W7-64 bit.
If WMI can provide this information I would be more than happy to use it.
What WMI functionality is available for this.
GHG-RCH,
As previously mentioned, 32-bbit application will not retrieve/enumerate 64-process.
WMI (Windows Management Instrumentation) is not a set of API. It is a set classes created to provide certain information about the system in general.
From MSDN:
Windows Management Instrumentation (WMI) is the Microsoft implementation of Web-based Enterprise Management (WBEM), which is an industry initiative to develop a standard technology for accessing management information in an enterprise environment. WMI uses the Common Information Model (CIM) industry standard to represent systems, applications, networks, devices, and other managed components. CIM is developed and maintained by the Distributed Management Task Force (DMTF).
I am not efficient enough with Delphi. My primary language is C++ (and C#, VB after). I have not used Delphi for eons.
I could give you some help if you were using above mentioned languages.
The only think I can mention is general remark:
WMI is designed for C++ developers, however I think any language that is able to handle ActiveX can be used. I am not sure if Delphi is one of them. Check MSDN.
I have suggested WMI since you can use it in 32-bit application and retrieve tons of information just about anything in any version of Windows 32 and 64-bit.
I am assuming that you are familiar with DLL. If it is really important for you to have 32-bit app achieving what you want in 64-bit world, I may consider writing a sample C++ dll that will do it (retrieve module given windows handle).
As previously mentioned, 32-bbit application will not retrieve/enumerate 64-process.
WMI (Windows Management Instrumentation) is not a set of API. It is a set classes created to provide certain information about the system in general.
From MSDN:
Windows Management Instrumentation (WMI) is the Microsoft implementation of Web-based Enterprise Management (WBEM), which is an industry initiative to develop a standard technology for accessing management information in an enterprise environment. WMI uses the Common Information Model (CIM) industry standard to represent systems, applications, networks, devices, and other managed components. CIM is developed and maintained by the Distributed Management Task Force (DMTF).
I am not efficient enough with Delphi. My primary language is C++ (and C#, VB after). I have not used Delphi for eons.
I could give you some help if you were using above mentioned languages.
The only think I can mention is general remark:
WMI is designed for C++ developers, however I think any language that is able to handle ActiveX can be used. I am not sure if Delphi is one of them. Check MSDN.
I have suggested WMI since you can use it in 32-bit application and retrieve tons of information just about anything in any version of Windows 32 and 64-bit.
I am assuming that you are familiar with DLL. If it is really important for you to have 32-bit app achieving what you want in 64-bit world, I may consider writing a sample C++ dll that will do it (retrieve module given windows handle).
ASKER
JohnCz:
Thanks fof this.
I have found some other answers on WMI which include Delphi code, so I should be able to get access to WMI working.
The problem I usually find with such large sets is finding the appropriate objects and properties.
if you are familiar with the WMI Process Information Objects could you point me at the relevant object names.
I will follow up WMI as it could be very useful for various things.
I am familiar with implementing and calling DLLs. I implement DLLs in Delphi for calling from some of our apps which are written in VB. I also need to interface to 3rd party DLLs particularly for device management (we do speech recognition and need to interface to various audio devices).
A 64 bit DLL that takes a Windows handle and returns the Module path would be extremely helpful. The API calls are in the ExeFromWindow routine above.
Thanks fof this.
I have found some other answers on WMI which include Delphi code, so I should be able to get access to WMI working.
The problem I usually find with such large sets is finding the appropriate objects and properties.
if you are familiar with the WMI Process Information Objects could you point me at the relevant object names.
I will follow up WMI as it could be very useful for various things.
I am familiar with implementing and calling DLLs. I implement DLLs in Delphi for calling from some of our apps which are written in VB. I also need to interface to 3rd party DLLs particularly for device management (we do speech recognition and need to interface to various audio devices).
A 64 bit DLL that takes a Windows handle and returns the Module path would be extremely helpful. The API calls are in the ExeFromWindow routine above.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Sorry for a post spam but i have inadvertently pressed SUMBIT second time before closing page.
Please disregard this post.
Please disregard this post.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I have given most of the points to ewangoya as his solution was very easy to include in my existing code and he had obviously spent some time researching and sorting out working code.
I have given the remaining points to JohnCz as the WMI solution looks capable of solving the problem and has the potential for being helpful in all sorts of similar areas. To implement it however will require quie a lot of additional reaearch and development on my side in getting WMI working in Delphi, and then identifying the objects relevant to my specific current problem. I do not have time for this at present as the problem raised is causing us serious problems on 64 bit Windows. I will look at this approach as a medium term project however
I have given the remaining points to JohnCz as the WMI solution looks capable of solving the problem and has the potential for being helpful in all sorts of similar areas. To implement it however will require quie a lot of additional reaearch and development on my side in getting WMI working in Delphi, and then identifying the objects relevant to my specific current problem. I do not have time for this at present as the problem raised is causing us serious problems on 64 bit Windows. I will look at this approach as a medium term project however
ASKER
Ewangoya,
I had intended to say thank you very much for your work on this question. It was much appreciated, and resolved the problem for us.
I had intended to say thank you very much for your work on this question. It was much appreciated, and resolved the problem for us.
You are welcome
I just did this in Delphi 2010, Windows 7 64 Bit and it worked fine for me
Open in new window