I am working in Delphi XE3, on a 64-bit Windows 8 machine, building 32-bit and 64-bit applications.
I am using EnumWindows to find out the Windows Handle of the main window of a process given its Process ID. The code uses the LPARAM parameter in the call back routine to pass a pointer to a record.
The code I am using has worked fine for a 32-bit build.
It is failing when I compile and run the 64-bit build. The problem occurs because the LPARAM value appears to be passed in the Wnd parameter. The Param value is always set to $FFFF ... in other words I don't get passed the HWND value at all ... so it's not as through the parameters are just swapped around.
type
PEnumInfo = ^TEnumInfo;
TEnumInfo = record
ProcessID : DWORD;
HWND : THandle;
end;
function EnumWindowsProc(Wnd: HWND; Param : LPARAM): Bool; stdcall;
var
PID : DWORD;
PEI : PEnumInfo;
begin
// in 32-bit Param matches the address of the param that is passed
// in 64-bit Param is set to $FFFF - however Wnd = the expected address
ShowMessage('PEI = '+IntToStr(Param));
PEI := PEnumInfo(Param);
GetWindowThreadProcessID(Wnd, @PID);
// the code fails at this next line in 64-bit build because PEI = $FFFF rather than the actual pointer passed
Result := (PID <> PEI^.ProcessID) or
(not IsWindowVisible(WND)) or
(not IsWindowEnabled(WND));
if not Result then PEI^.HWND := WND; //break on return FALSE
end;
function FindMainWindow(PID: DWORD): DWORD;
var
EI : TEnumInfo;
begin
EI.ProcessID := PID;
EI.HWND := 0;
ShowMessage('PEI = '+IntToStr(LPARAM(@EI)));
EnumWindows(@EnumWindowsProc, LPARAM(@EI));
Result := EI.HWND;
end;
Is the Win64 calling convention different? Or am I making some other fundamental mistake?
Any help or ideas gratefully accepted.
The code in your question works fine. Your declaration of EnumWindowsProc
is correct. The parameters and return value have the correct type. The calling convention is correct, although this does not actually matter for x64 Windows which only has one calling convention.
If you build a simple application using the code from your question, you will find that it behaves correctly and enumerates windows correctly.
The problem is surely that your actual code differs from the code that you have shown. My guess is that in your actual code, EnumWindowsProc
is a nested function: Why cannot take address to a nested local function in 64 bit Delphi? But that is just a guess. I don't know what your real code looks like. I do know that the code in the question works correctly.
One other comment is that you erroneously declare the HWND
member to be of type THandle
. This won't affect your program's correctness, but it is semantically wrong. I would declare that type like this:
type
TEnumInfo = record
PID: DWORD;
Wnd: HWND;
end;