2

In my app, I catch all event via SetWindowsHookEx and when a user clicks on a button I retrieve an hwnd that I guess is the handle of the Tbutton.

typedef struct tagMSG {
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;
  DWORD  lPrivate;
} MSG, *P

Now how can I from this hwnd retrieve the button name (or better the Delphi object representing the button?).

Maybe I can also retrieve the component via the POINT pt; ?

zeus
  • 12,173
  • 9
  • 63
  • 184
  • 1
    `GetWindowText()` will normally give you the button label, but it depends how Delphi have implemented their buttons. – Jonathan Potter Dec 16 '19 at 23:40
  • "TButton"s are button controls but GetWindowText would retrieve the button's caption, not its control name. – Sertac Akyuz Dec 17 '19 at 00:03
  • Component names are used among the Delphi/Pascal flavor of programming, and most others. Controls based on the Windows API, or otherwise across VCL, only have a `Name` property to make it easier to do your work. And sure, that information could potentially be recorded in the final executable. However, Windows itself has no idea what these names might be. There's no connection between the two. You can get the text (caption) of a window, as mentioned already, but not the name, because from the scope of Windows itself, there is no such thing as a "name". Just a handle and text. – Jerry Dodge Dec 17 '19 at 02:48
  • Does this answer your question? [How to get instance of TForm from a Handle?](https://stackoverflow.com/questions/8190224/how-to-get-instance-of-tform-from-a-handle) – Jerry Dodge Dec 17 '19 at 04:59
  • 2
    Do you want the name or the instance? Is the control in the same process as your code? Is your code linked against the same instance of the VCL? – David Heffernan Dec 17 '19 at 06:37

1 Answers1

6

You can use FindControl, which will retrieve the object instance if the window is created by a control that belongs to the same instance of the VCL that calls the function. Since Name is published in TComponent, you can access the property regardless of the actual class type.

Every windowed VCL control has its object instance address stored in the API window's property list, along with properties containing information of module address, process id, thread id. This makes it possible for the VCL to backtrack a control from the window it created.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • 4
    Note, this will only work for HWNDs that are owned by the same process that receives them. `FindControl()` doesn't work for HWNDs owned by other processes. – Remy Lebeau Dec 17 '19 at 03:15
  • To refine what @RemyLebeau means by "doesn't work" (which could be misleading), `FindControl()` will check the processID of the component, and will return nil if the handle is not from a VCL component of the current process calling the function. This is due to the fact that a process doesn't have access to other processes memory, so accessing the component would fail (without a lot of hacking). And also because `FindControl` uses Windows global atoms, which may be buggy in cross-process. – Arnaud Bouchez Dec 18 '19 at 09:37
  • Also the module address.. That's why *same instance of VCL* have been mentioned in comments, VCL in a dll would not attempt to refer to a control from the VCL in the executable. All of the information mentioned in the answer that's stored as properties should match. – Sertac Akyuz Dec 18 '19 at 10:15
  • Most of these should be sort of obvious I think, and probably shouldn't matter for the case of the question since it mentions retrieving the object instance is even better and an object instance would of course only work in the process that it belongs - I edited the answer to emphasize it somewhat. – Sertac Akyuz Dec 18 '19 at 10:27