Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17


Creating controls on main form from a DLL

Posted on 1997-09-04
Medium Priority
Last Modified: 2010-04-04
I have a situation where I need to create objects on the main applications form (or a panel) from inside a DLL. When I create a button in the manner described below, I experience these 3 problems:

1) the button is not displayed until I make the panel invisible then visible again
2) If I TAB to teh button, I generate the 'EInvalid Operation' exception with the message 'Control 'BB' has no parent window'
3) The object will not get destroyed when the application exits

The prime area of my concern is the second one. The strange thing is that if I use EXACTLY the same code inside the main application, none of these problems are evident!

I have drilled down through the Parent panels properties to compare all properties of the button and compared them to when it is created from inside teh main application, and can find no significant variation. In particular, the button's FParent property is set to the Panel!

Here is the code which I used inside the DLL to create the button:

procedure MakePB( UserOutput:TWinControl ); stdcall;
   BB := TButton.Create( UserOutput );
   with UserOutput.ClientRect do begin
     BB.Left := Left + 5;
     BB.Top := Top + 35;
   BB.Font.Style := [];
   BB.Font.Size := 10;
   BB.Parent := UserOutput;
   BB.Caption := 'A PB';
   BB.Name := 'A_PB';

This function is called like this:

procedure TForm1.Button3Click(Sender: TObject);

Any ideas???

(Note: The nature of my application is such that I can't create a Form inside the DLL for the button ...)
Question by:sonique
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions

Expert Comment

ID: 1343800
At first glance, my reaction was to have you set the BB.Parent property before you set the other stuff (still a good idea).   I believe a TWinControl's Owner should be the Form, not the panel.  The 'Parent' is the panel, the form is the 'Owner'.  If you know the panel (UserOutput) has the form as the owner, then BB.Create( UserOutput.Owner ) will set that correctly.  Then set the parent as UserOutput like you are already doing.
Now, as for the object's destruction you might consider using the Form's InsertComponent method instead.  This will have the component inserted in the Form's component array and consequently destroyed when the form cleans up.

Hope this helps,
Ian C.

Author Comment

ID: 1343801
Thanks for the reply, but ....

Setting the Parent before setting the font results in: "ConvertError with message 'Cannot assign a TFont to a TFont'". This is why I placed it near the end (note that this does not happen if compiled into the main program).

Setting the owner to the form I had tried previously to no affect. Using the UserOutput.Owner.InsertComponent method does not seem to make any difference either!

This is all obviously something to do with the DLL accessing the main App's variables in a different manner - but I have no idea what it is. I even tried passing the main Apps Application.Handle and setting it to that value in the DLL to no avail.


Expert Comment

ID: 1343802
The problem is that objects in your dll is not the same as in your app (because they are diff. .exes), so you have to make controls with your app.
To do this, write an exported procedure in your app. This proc. will make the controll.
When you call your dll pass the addres of this proc., so your dll can make controls, as it's code was in the app.

Good luck

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Author Comment

ID: 1343803
Thanks for the suggestion, but unfortunately creating the control in the app itself is not an option because it defeats the whole purpose of the DLL. I used a pushbutton as a simple example, but in actual fact the DLL could create any sort of control, and the main APP (by design) does not know ahead of time what sort of control the DLL will create!
I have designed an architecture whereby the main app acts as a sort of interpreter, and a collection of DLL's act as "function Blocks". Some of these DLL's do non-visual work. For example one DLL is a multi-threaded comms manager for an RS422 network. Another provides printer control and status monitoring functions (displayed on a seperate form created by the DLL so that's no problem). Some of the DLL's will create controls on a common form, and the button is just an example.
There has to be a way to make the main App's VCL thread completely aware of the control - all other functionality works OK (such as mouse clicks, button text display, etc.), so why not keyboard control??

Any other takers?


Accepted Solution

JimBob091197 earned 400 total points
ID: 1343804
I had a similar problem before, and found no suitable solution.  There is a way around the problem as follows:

In your DLL you currently declare:
procedure MakePB( UserOutput:TWinControl );

I changed this to:
function MakePB(UserOutputWnd: THandle): TButton;
   NewButton: TButton;
   NewButton := TButton.Create(nil);
   NewButton.Caption := '&Hello';
   NewButton.ParentWindow := UserOutputWnd;
   Result := NewButton;

1)  MakePB expects UserOutputWnd instead of UserOutput.
2)  No owner was given to NewButton, and I assigned NewButton.ParentWindow (NOT .Parent).
3)  I made it a function which returns a button.  The form (in my e.g.) later freed the button.

In your form you now call:
AButton := MakePB(Panel1.Handle);

In your form's Destroy event:

(You can ignore the font stuff without worrying about the "Cannot assign a TFont to a TFont" error.)

All this works fine, but there are several caveats.  I mentioned above that I never found a SUITABLE solution.  Here's why:
1) In your form, after the call to MakePB, try assigning AButton.OnClick := .....;
The OnClick event will be ignored...  (However, AButton.Caption := '&Hit Me' will change the caption!!)

2) Instead of a TButton, try a control with an Align property (e.g. TListBox).  The listbox will not be resized when Panel1 is resized.

There are a few other disadvantages too, but I'll let you experiment...  You may find many solutions that I missed.

Author Comment

ID: 1343805
Sounds like it will do the trick ... but there doesn't seem to be a ParentWindow property ... I even searched the VCL source!

Which version of Delphi are you talking about? I'm using v2.02


Expert Comment

ID: 1343806
Mmm... I'm using Delphi 3.  

The VCL reveals that setting the ParentWindow property uses the Windows SetParent API call.  You could try this.  

e.g.  SetParent(MyButton.Handle, MyPanel.Handle);

Hope this works for you!!

Author Comment

ID: 1343807
I'll try that when I'm back at work on Monday .... if It doesn't work I'll have to use a different approach to the problem.

Thanks for the help!


Expert Comment

ID: 1343808
Welcome.  Keep me posted.

Author Comment

ID: 1343809
Well, no luck I'm afraid. If you look at the Win32 API Help, SetParent() is used to change Parents. When I try this approach I get an exception raised:

EInvalid Operation. Message 'Control '' has no parent window'

Back to the drawing board .....

Expert Comment

ID: 1343810

The following code will give that exception:
AButton := TButton.Create(nil);
Windows.SetParent(AButton.Handle, APanel.Handle);

The reason for the exception is because at the time that you call "SetParent", AButton does not have a handle. (Put a break on the SetParent line, and look at the value of AButton.Handle.)  Delphi calls CreateHandle, which in turn calls CreateWnd.  CreateWnd raises that exception if the parent does not exist.

In Delphi 3, the call to AButton.ParentWindow (i.e. TButton.SetParentWindow in the VCL) only calls the SetParent API if there is an existing parent window.  If not, then the FParentWindow property is set, which will be used when the handle is created (actually in CreateParams).

That is why the following code does work in Delphi 3, but the code above does not work in Delphi 2 or 3:
AButton := TButton.Create(nil);
AButton.ParentWindow := APanel.Handle;

It OFTEN frustrates me that so much functionality in Delphi has been hidden in the Private sections of the classes!!  (Although many would say that this is required by the Object Oriented approach...)  The trick is to set the FParentWindow value (or the equivalent in Delphi 2), or to get Delphi to create the handle for you (via a call to HandleNeeded or something.)

I'll ask a colleague of mine who uses Delphi 2 when he gets in later.  He may have some suggestions.


Author Comment

ID: 1343811
Thanks ....
I'm working on another problem today (DOS C Code), so I'll wait to see if you come up with anything new before I have another look at this.

I appreciate the assistance by the way!


Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : All lightning effects with instructions : http://www.mediaf…
Suggested Courses

715 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question