Jerry Dodge
Jerry Dodge

Reputation: 27276

How to get instance of TForm from a Handle?

I'm converting some functions into a DLL which relate to Windows 7 functionality. I can't pass a TForm through DLL, so I need to pass its handle instead. except, once I have that handle on the other side, how do I reconstruct it back into a TForm instance? Also, what's the appropriate way to pass the handle (HWND) through a Delphi DLL to be compatible to call from C# for example?

If not possible, then I at least need to know how to change the color of a window using windows API only, no reference to the TForm. The goal is that from within this DLL, it needs to somehow change the color of a Form. Passing the handle to the DLL is no problem, but how to use that handle to work with the form that the handle represents?

What I'm doing specifically is putting together a single DLL that contains everything needed to make a Delphi7 application compatible with Windows7, for example, drawing glass, properly showing multiple forms in the taskbar (and minimizing forms), showing the green progress in the taskbar's icon, and whatever else might be involved. This type of work though requires modifying the form. I need to be able to do those modifications from within the DLL.

Upvotes: 8

Views: 14319

Answers (3)

Ken White
Ken White

Reputation: 125669

You can't get a TForm from a handle. There's no such thing outside of your Delphi app, unless you're using packages (as David's answer said).

You can use the Handle (HWND) directly in API calls, but only for API calls.

You can pass that HWND directly to API calls like GetDC to get a device context (DC), and then use that DC directly with the DrawTheme related functions like DrawThemeText or anything else that requires a windows DC. You can also pass it to other API calls that require an HWND.

Upvotes: 5

David Heffernan
David Heffernan

Reputation: 612954

You can't pass Delphi objects across DLL boundaries. It simply does not work. There is no mechanism to export a Delphi class from a DLL.

You are aware of this but passing a handle across the boundary does not help. You wish to operate on a TForm on the other side of the boundary. But the only TForm instance that can make sense is the only which created the handle, and that instance is trapped by the module boundary.

There are some objects which can be recreated from just a handle. For example, bitmaps and icons have this property. This is because they have no state beyond what is stored in the GDI handle. More complex VCL objects do have such state and therein lies the problem.

Your options are:

  1. Use packages. This works a treat but you must use the same compiler version for all modules.
  2. Use interfaces or COM. This gives you freedom of mixing compiler versions and even different languages.

Upvotes: 4

Remy Lebeau
Remy Lebeau

Reputation: 595981

In general, you can convert an HWND to a VCL TWinControl-derived object pointer using the VCL's FindControl() function in the Controls unit. You can then check if the TWinControl is actually a TForm using the is operator.

However, as others have stated, passing VCL objects over the DLL boundary in general is dangerous and can cause problems if both EXE and DLL are not compiled with the exact same VCL version, RTL version, memory manager, etc. To pass VCL objects over the DLL boundary safely, change your DLL project into a BPL Package project, and make sure Dynamic RTL is enabled in both EXE and BPL.

Upvotes: 10

Related Questions