Reputation: 13
I'm creating a function to get all window handles with processid.
My code:
unit untCommonUitls;
interface
uses
System.SysUtils, Winapi.Windows, Winapi.Messages, System.Classes;
function GetWindowHandlesByPID(const cPID: Cardinal): TStringList;
var
slHandles: TStringList;
implementation
function GetWindowHandlesByPID(const cPID: Cardinal): TStringList;
var
hFound: THandle;
function EnumWindowsProcMy(_hwnd: HWND; ProcessId: Cardinal): BOOL; stdcall;
var
dwPid: Cardinal;
begin
GetWindowThreadProcessId(_hwnd, @dwPid);
if ProcessId = dwPid then
begin
hFound := _hwnd;
slHandles.Add(IntToStr(hFound));
end;
end;
begin
if not Assigned(slHandles) then
begin
slHandles := TStringList.Create;
end;
slHandles.Clear;
EnumWindows(@EnumWindowsProcMy, LPARAM(cPID));
Result := slHandles;
end;
When I try this code, everything works, EnumWindowsProcMy
call many times, slHandles
get a list of handle;
But in others, it does not work. EnumWindowsProcMy
only call once, so slHandles
is empty.
Upvotes: 1
Views: 1224
Reputation: 598134
You are not setting the Result of EnumWindowsProcMy()
to anything, so it contains a random value when EnumWindowsProcMy()
exits. You MUST return either TRUE
to continue enumeration or FALSE
to stop it.
But, more importantly, you CANNOT use a nested function for the EnumWindows()
callback (or any other Win32 callback, for that matter)! A nested function shares the parent function's stack frame, so they can share parameters and local variables with each other. As such, that involves compiler trickery that makes a nested function incompatible for use with the Win32 API. The callback MUST be a standalone function!
Use something more like this instead:
unit untCommonUitls;
interface
uses
System.Classes;
function GetWindowHandlesByPID(const cPID: Cardinal): TStringList;
implementation
uses
Winapi.Windows;
var
slHandles: TStringList = nil;
function MyEnumWindowsProc(wnd: HWND; ProcessId: LPARAM): BOOL; stdcall;
var
dwPid: Cardinal;
begin
GetWindowThreadProcessId(wnd, @dwPid);
if dwPid = ProcessId then
slHandles.Add(IntToStr(wnd));
Result := TRUE;
end;
function GetWindowHandlesByPID(const cPID: Cardinal): TStringList;
begin
if not Assigned(slHandles) then
slHandles := TStringList.Create
else
slHandles.Clear;
EnumWindows(@MyEnumWindowsProc, cPID);
Result := slHandles;
end;
finalization
slHandles.Free;
end.
Alternatively:
unit untCommonUitls;
interface
uses
System.Classes;
procedure GetWindowHandlesByPID(const cPID: Cardinal; List: TStrings);
implementation
uses
Winapi.Windows;
type
PMyEnumInfo = ^MyEnumInfo;
MyEnumInfo = record
ProcessId: DWORD;
List: TStrings;
end;
function MyEnumWindowsProc(wnd: HWND; param: LPARAM): BOOL; stdcall;
var
dwPid: Cardinal;
begin
GetWindowThreadProcessId(wnd, @dwPid);
if dwPid = PMyEnumInfo(param).ProcessId then
PMyEnumInfo(param).List.Add(IntToStr(wnd));
Result := TRUE;
end;
procedure GetWindowHandlesByPID(const cPID: Cardinal; List: TStrings);
var
Info: MyEnumInfo;
begin
Info.ProcessId := cPID;
Info.List := List;
List.BeginUpdate;
try
EnumWindows(@MyEnumWindowsProc, LPARAM(@Info));
finally
List.EndUpdate;
end;
end;
end.
Upvotes: 8