Solved

Hard problem: Focus of embeded DLL Form

Posted on 2001-07-19
28
969 Views
Last Modified: 2012-05-04
   I wrote a DLL which has a Form.  In another Exe, I load  the DLL, and embed it's Form to a panel of the Exe's mainform by set the ParentWindow property.
    The problem is when I press TAB in the DLL form's control, the focus shift to the main form, and never come back.
    I need to solve this ugently, please feel free to add any comments.
0
Comment
Question by:article
  • 13
  • 5
  • 4
  • +3
28 Comments
 
LVL 17

Expert Comment

by:geobul
ID: 6301118
Hi,
If you have access over the DLL-Form properties, try this way:

with Form2 do begin
  Parent := Panel1;
  Top := 0;
  Left := 0;
  Width := Panel1.ClientWidth;
  Height := Panel1.ClientHeight;
end;

Regards, Geo
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 6301249
article,

I have encountered this problem as well... Tab keys, and even Alt keys do not work well.

One of my colleagues added this to the child's OnCreate:
PostMessage(Self.Handle, WM_USER + $1000, 0, 0);

I do not know what it is, what it does, or how my colleague came up with this number... but it seems to have solved the Tab problem.

As for the Alt key problem, it was solved when I compiled the DLL with runtime packages and then distribuing the DLL together with the BPL. That's the only solution I came up with so far :(


DragonSlayer
0
 

Author Comment

by:article
ID: 6301337
To geobul:
    I tried your method, but the DLL form hide itself.

To DragonSlayer:
    I tried your magic postmessage, but nothing happens.
I use C++ Builder 5, I think it's just identical with Delphi 5.  I don't encounter any problem in C++ Builder 4, do you know why?
0
 
LVL 1

Expert Comment

by:Baksa
ID: 6301367
On exe form find the last component in tab order, and this line in OnExit procedure :

Windows.SetFocus(DllForm.Handle);


So when you are on EXE form and you get to the last control in tab order focus will be switched on DLL form.


Another aproach :
Question is how are you creating your form, if you are not doing it like this, try it, I put show code in DLL, in your case you must send and parent window handle or pointer to parent TForm object, but important thing is to set up Application variable in DLL, you will do this by putting forms in uses clause of your DLL, here is the code:

call this from exe form :

DllForm := ShowChildForm(Application.Handle, self.Handle);

kill it

KillDllForm(dllForm);


DLL CODE:

Funtion ShowChildForm(AHandle: THandle, ParentWnd: HWND):LongInt;
var
  dllForm: TDllForm;
begin
  Application.Handle := AHandle
  dllForm := TDllForm.Create(Application);
  dllForm.ParentWindow := ParentWnd;
  Result := LongInt(dllForm);
  dllForm.Show;
end;

procedure KillDllForm(dllForm: LongInt);
begin
  TDllForm(dllForm).Release;
end;

This is mostly copied from "Delphi 5 Developer's Guide".
 


0
 

Author Comment

by:article
ID: 6301413
To geobul:
    I tried your method, but the DLL form hide itself.

To DragonSlayer:
    I tried your magic postmessage, but nothing happens.
I use C++ Builder 5, I think it's just identical with Delphi 5.  I don't encounter any problem in C++ Builder 4, do you know why?
0
 

Author Comment

by:article
ID: 6301549
Baksa,
Thanks to your comment.  The first part of your comment is right, it can shift to the DLL Form.  But when I press TAB in the DLL Form, it will not execute the onExit code.
I create the dll just the same you've mentioned.
0
 

Author Comment

by:article
ID: 6301589
Baksa,
Thanks to your comment.  The first part of your comment is right, it can shift to the DLL Form.  But when I press TAB in the DLL Form, it will not execute the onExit code.
I create the dll just the same you've mentioned.
0
 
LVL 1

Expert Comment

by:Baksa
ID: 6301594
Article,

You must put similar code in OnExit procedure of last control in tab order on dllForm, like this :

Windows.SetFocus(ExeForm.Handle);


If you allready do this, maybe your exeform handle is not valid, I can't think of anything else.
0
 
LVL 1

Expert Comment

by:Baksa
ID: 6301606
DragonSlayer,

About your "magic" message, probably your collegue implemented handling of that message in same child's window window procedure. Posting WM_USER + $1000 will do nothing unless window procedure of window that message is send to doesn't handle that message.
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 6301723
Baksa,

Nope, the child window doesn't handle any messages.
0
 
LVL 3

Expert Comment

by:nnbbb09
ID: 6301921

You need to set the parent property of the DLL form to be the panel in your exe form. I think this is re-iterating Geobul suggestion. I've tried it with a simple exe and dll and the tabbing seems to work ok.

procedure TForm1.Button1Click(Sender: TObject);
var
  frm:TForm;
begin
  frm:=CreateForm;  // this is the DLL function to create form
  frm.Parent := panel2;
  frm.WindowState:=wsMaximized;
  frm.Show;
end;
0
 
LVL 2

Expert Comment

by:SChertkov
ID: 6301951
If exe and dll is Delphi projects,
try build it with "build with runtime packages"
options.
0
 
LVL 1

Expert Comment

by:Baksa
ID: 6301989
DragonSlayer,

Maybe this message handling is implemented in ancestor class of child window, which class is that window, TForm ?

I searched Delphi source code and only WM_USER + $1000 was defined in comctrls, but this is some message for ToolBars
0
 

Author Comment

by:article
ID: 6304335
Hi all,
Can anyone post whole tested source code?  If it works, I will give additional points.
I can be reached at article@163.com.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:article
ID: 6304342
Baksa,
I put the similar code in OnExit procedure in the DLL Form, the problem is it will never be executed.  Press Tab will shift to the main form, not the next control in the tab order.
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 6306923
Baksa,

All forms in that project are direct descendants of TForm...


Article,

Did you try rebuilding everything with 'Build with runtime packages' as I'd earlier suggested?
0
 

Author Comment

by:article
ID: 6307069
Hi all,
I solve this problem myself.  It's a delphi bug, and nobody point it out.  Now, who wants the points?
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 6307127
How did you solve it?
0
 

Author Comment

by:article
ID: 6307537
Hi DragonSlayer,
Just open the forms.pas, and look at the TApplication.IsKeyMsg function, you'll find out the bug.  If you use Delphi, you'll be lucky, just fix it, and everything will be OK.  I've tested it.  Now, my problem is I don't know how to patch the vcl50.bpl.  I have to do it because all the projects build with packages.  
And anybody knows how to patch the vcl bug in C++ builder?  I just include the fixed forms.pas, but the build speed will be very slow, and only solve part of the problem, the tab key still not functions properly.
Need Help!!!
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 6307590
Oh... it uses the Mainform's handle instead of the Client's handle, is it?
0
 
LVL 2

Accepted Solution

by:
SChertkov earned 300 total points
ID: 6309470
I am not find any problem:

// EXE

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Button2: TButton;
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

function GetForm: TFormClass; external 'lib.dll';

{$R *.DFM}

procedure TForm1.FormShow(Sender: TObject);
var
  Form: TForm;
begin
  Form := GetForm.Create(self);
  Form.Parent := Panel1;
  Form.Visible := True;
end;

// DLL

type
  TForm2 = class(TForm)
    Edit1: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Edit2: TEdit;
    Button1: TButton;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

function GetForm: TFormClass;

implementation

function GetForm: TFormClass;
begin
  Result := TForm2;
end;

{$R *.DFM}

All projects build with 'runtime package' option.
In my case is when I press TAB in the DLL form's control, the focus shift to the main form, and
normal come back.
Also i am not detect any problems in TApplication.IsKeyMsg

0
 

Author Comment

by:article
ID: 6310853
SChertkov,
Yes, your code works.  But it's impossible for me to use.  Cause we use dll form to seperate the program.  If the customer need new functions, we just write a new dll, and the main program won't need to modify and recompile.
So we must use loadlibrary to load the dll.  But if you use the loadlibrary,  when you call these code,
 Form := GetForm.Create(self);
 Form.Parent := Panel1;
 Form.Visible := True;
the Form will still invisible.  You must set the ParentWindow instead of Parent property.  That's the problem.  If you use the loadlibrary, and set Parent,  the Dll Form is still visible, just let me know, I'll very appreciate it.
0
 

Author Comment

by:article
ID: 6310898
SChertkov,
I'm wrong.  Use LoadLibrary still works.  Lucky Delphi users!  But I have to use C++ Builder.  The problem now is how to translate it into C++ Builder.
The skill is to get a form varible, and call its create method.  But it seems C++ Builder don't have the corresponding create method.
Anyone knows?  It seems that the success is very near.

0
 
LVL 2

Expert Comment

by:SChertkov
ID: 6311068
Unfortunately i am not work with C++ Builder.
Class variable is the beautiful but not necessarily.
You can successfully create form inside you dll and
pass pointer to it in main program.
It is important
1. Build projects with 'runtime package' option.
2. Use TWinControl.Parent property instead of
   ParentWindow property.
For form creation you can use
Application.CreateForm in DLL.
I think this approach have analogs in C++ Builder.

If you have any problems later sign me
i can install C++ Builder.
0
 

Author Comment

by:article
ID: 6311182
SChertkov,
Use TWinControl.Parent property cause the dll form invisible in c++ builder, that's why I use ParentWindow.  I always choose build project with packages.  I will try to use the Application.CreateForm.
Could you please do some test in C++ Builder?  Thanks a lot.
0
 

Author Comment

by:article
ID: 6311263
SChertkov,
I just write a function in delphi,  and include the pas file in the c++ builder project,  call the function from c++ file, and solve the problem.
If you can use c++ builder's own method, just let me know.
Thank you very much.
0
 
LVL 17

Expert Comment

by:geobul
ID: 6311432
Hi,
As I see the accepted answer is what I've written at the beginning of this thread. Please, correct me if I'm wrong.

Regards, Geo
0
 

Author Comment

by:article
ID: 6315624
Geo,
Sorry, but your answer is too simple.  The key is dll return the class, and exe use the class to create the form, not dll create the form itself.  Maybe you know exactly the answer,  but just I'm not smart enough to understand you.
And I don't know how to give points to several person.  
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
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…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

746 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now