[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1105
  • Last Modified:

Hard problem: Focus of embeded DLL Form

   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
article
Asked:
article
  • 13
  • 5
  • 4
  • +3
1 Solution
 
geobulCommented:
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
 
DragonSlayerCommented:
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
 
articleAuthor Commented:
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
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!

 
BaksaCommented:
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
 
articleAuthor Commented:
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
 
articleAuthor Commented:
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
 
articleAuthor Commented:
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
 
BaksaCommented:
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
 
BaksaCommented:
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
 
DragonSlayerCommented:
Baksa,

Nope, the child window doesn't handle any messages.
0
 
nnbbb09Commented:

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
 
SChertkovCommented:
If exe and dll is Delphi projects,
try build it with "build with runtime packages"
options.
0
 
BaksaCommented:
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
 
articleAuthor Commented:
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
 
articleAuthor Commented:
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
 
DragonSlayerCommented:
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
 
articleAuthor Commented:
Hi all,
I solve this problem myself.  It's a delphi bug, and nobody point it out.  Now, who wants the points?
0
 
DragonSlayerCommented:
How did you solve it?
0
 
articleAuthor Commented:
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
 
DragonSlayerCommented:
Oh... it uses the Mainform's handle instead of the Client's handle, is it?
0
 
SChertkovCommented:
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
 
articleAuthor Commented:
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
 
articleAuthor Commented:
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
 
SChertkovCommented:
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
 
articleAuthor Commented:
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
 
articleAuthor Commented:
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
 
geobulCommented:
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
 
articleAuthor Commented:
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 13
  • 5
  • 4
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now