Using EnumWindows in 64-bit Delphi application

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 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 pointer is not passed correctly, and so the de-reference causes an access violation.

  PEnumInfo = ^TEnumInfo;
  TEnumInfo = record
    ProcessID : DWORD;
    HWND      : THandle;

function EnumWindowsProc(Wnd: HWND;  Param : LPARAM): Bool; stdcall;
      PID : DWORD;
      PEI : PEnumInfo;
// in 32-bit Param matches the address of the param that is passed
// in 64-bit Param is set to 65535
      ShowMessage('PEI = '+IntToStr(Param));

      PEI := PEnumInfo(Param);
      GetWindowThreadProcessID(Wnd, @PID);

// the code fails at this next line in 64-bit build because PEI = 65535 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

    function FindMainWindow(PID: DWORD): DWORD;
      EI : TEnumInfo;
      EI.ProcessID := PID;
      EI.HWND := 0;
      ShowMessage('PEI = '+IntToStr(LPARAM(@EI)));
      EnumWindows(@EnumWindowsProc, LPARAM(@EI));
      Result := EI.HWND;

Open in new window

Any clues as to why the the call back routine has a different value passed to the Param parameter under 64-bit?


Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Sinisa VukSoftware architectCommented:
try to change lparam with Pointer:
function EnumWindowsProc(Wnd: HWND;  Param : Pointer): Bool; stdcall;

Open in new window

EnumWindows(@EnumWindowsProc, Pointer(@EI));

Open in new window

Sinisa VukSoftware architectCommented:
... alternatively ... go to this EE question and scroll down (find function FindExeProcess2) where I wrote function using wmi to find process ... similar ... using wmi you can find what you want.
jon_rsAuthor Commented:
Thanks for the response.

Changing Param to be a pointer makes no difference - the value the function receives when compiled for Win64 is still $FFFF

Your alternative WMI code snippet FindExeProcess2 returns the Process ID, not the Handle to the Main Window - which (in this instance) is what I actually want.  I want to be able to post Windows messages to the main window of Process N .. so need to know the Windows Handle of that process's Main Window.

And (while I am interested in a work-around if necessary) this doesn't answer my original question as to why the EnumWindowsProc is being passed $FFFF (65535) instead of correct address of the structure I am passing.
It works under Win32 compilation ... but not Win64.  I can't believe I am the only person in the world who uses this function, so I must be doing something wrong, and I'd like to understand what that is ...


Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

jon_rsAuthor Commented:
Some further information:

It transpires that the value I am expecting to be passed in the Param parameter, is in fact being passed in the Wnd parameter.

The Wnd value is NOT however swapped and sent in the Param parameter .. this is always set to $FFFF

It's almost as though the parameters being passed to the callback routine have slipped along one position ...
Sinisa VukSoftware architectCommented:
I run your code on windows 7/64 bit + XE3 ... and code works ok for both 32 bit and 64 bit app. Strange.
Maybe you can upload here small project .... Maybe I can see more ... (in project settings....)
jon_rsAuthor Commented:
Thanks for the offer :-)

I've built a standalone Test project with the core functionality embedded.

You should be able to recreate both a 32-bit and 64-bit version of the Test App from this.
However, I have also included MY compiled versions of the 32 and 64 bit EXEs which produce the following results on my machine...

32-bit Application
64-bit Application
One more bit of info which I didn't mention before ... I am running Windows 8.1 on a MAC within Parallels 9 ... wonder if this might explain what is going on ... be interesting to see if my compiled EXEs work OK on your machine ...

Sinisa VukSoftware architectCommented:
Yes, this is my intention. Post project here - so I can rebuild it.
jon_rsAuthor Commented:
Sorry ... attached link first time .. but looks like it didn't attach properly ...
Here it is again
Sinisa VukSoftware architectCommented:
Found your problem. You cannot use local callback function (inside other procedure) on win 64.
I move all local functions out - and all works - for 32 bit and 64 bit. Look at modified main pas file.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jon_rsAuthor Commented:
Thanks for your help.  It's great to nail the actual cause rather just find a work around :-)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.