Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Transferring Application.Handle to DLL in my components

387 views
Skip to first unread message

Troels Jakobsen

unread,
Mar 19, 2003, 6:00:46 PM3/19/03
to
Greetings, group.

I've made a few components which hook into the message
handling of the application, in order to intercept specific messages
like WM_WINDOWPOSCHANGED etc.

The problem is that when you use my components in a DLL the
DLL doesn't know Application.Handle of the calling application,
and so the message hook fails. However, this can be easily solved
with a method or a property in the component which receives the
application handle.

So my question is: Is that the way to do it? Create a property,
called DllOwner for instance, and let the user set
DllOwner = Application.Handle if he wants to use the component
in a DLL?

Personally, I think it's the (only) way to do it - I'm just wondering
why I've never seen any components with this extra property.

Troels


Alexander Bauer

unread,
Mar 19, 2003, 7:17:51 PM3/19/03
to
Hi,

I think there is an easyer way. TApplication creates a hidden Window (the
Main window of the application - it's alway hidden and all the forms are
'only' dialogs. I hope you know windows programming, message pump and stuff
not only from Delphi, than you surely understand). So I made a little test:

I created a new project with just one TButton on it with the OnClick
handling below, pressed F9 and then the button.

procedure TForm1.Button1Click(Sender: TObject);
begin
if Owner <> nil then
if Application.Handle = TApplication(Owner).Handle then ShowMessage
('!!');
end;

If the Handle of the Application = the Handle of the Forms owner the message
should pop up. It did pop up so you can get the Application.Handle like

AppHandle := TApplication(GetParentForm(Self).Owner).Handle;

in your components - I hope ;o)

Regards,
Alexander Bauer


"Troels Jakobsen" <do...@like.spam> schrieb im Newsbeitrag
news:3e78f691$1...@newsgroups.borland.com...

Troels Jakobsen

unread,
Mar 20, 2003, 3:36:43 PM3/20/03
to
Thanks, Alexander, but since my components are derived from
TComponent rather than TControl, I can't use methods like
GetParentForm, and the Owner property can't be cast to
TApplication.

However, I solved the problem.

In my component's constructor I check whether Application.Handle is 0.
If not (which means the component is used in an application or service),
I use Application.HookMainWindow. If it is 0 (the component is used
in a DLL), I get a virtual handle by calling AllocateHWnd.

Both of these approaches require a callback method. I have both
callback methods call the same method which filters the received
application messages.

Troels


Alexander Bauer wrote in message ...

Alexander Bauer

unread,
Mar 20, 2003, 7:17:05 PM3/20/03
to
Hi Troels,

?? Why not ??

GetParentForm take a TControl as input. TControl publishes (Public) the
property Parent.
GetParentForm uses the controls Parent to find the form. If no Parent is
availabel (TComponent don't have a property Parent) you can't get the parent
Form directly but a TComponent (non visual Component) has a Owner. You can
use this too like this: GetParentForm (Self.Owner).

Anyway... I think it's not the best solution to override a WnindowProc via
Delphi because so the End-User of your components must not uses this
property no matter if you use WindowProc or HookMainWindow or what ever. I
would redirect the WndProc using the WinAPI "SetWindowLong". So the user
still can override the Delphi WndProcs (no matter wich one) and you can be
sure that no matter what the user is doing your WndProc gets called.

Regards,
Alexander Bauer


"Troels Jakobsen" <do...@like.spam> schrieb im Newsbeitrag

news:3e7a2647$1...@newsgroups.borland.com...

Troels Jakobsen

unread,
Mar 21, 2003, 3:16:15 PM3/21/03
to
Hi Alexander,
Well, you're right, normally I can cast a component's Owner (or
the Owner's Owner) to a TApplication object. But not always.
I'll try to explain:

I have the class TMyComponent which contains this constructor:
constructor Create(AOwner: TComponent); override;

From Unit2 I call the constructor, using the current application:
mc := TMyComponent.Create(Application);

Inside the constructor I can perform a simple check, which
returns true:
if AOwner is TApplication then .... // true

Now, let's put Unit2 into a DLL together with the unit for
TMyComponent. Since Unit2 no longer knows the current
application that is calling the DLL, we add an initialization
method to Unit2 and export the method:
procedure InitDll(App: TApplication);

The application calls InitDll using its own Application object,
and inside InitDll we call the constructor:
mc := TMyComponent.Create(App);

And I don't really know why, but inside TMyComponent
AOwner is no longer of type TApplication, so the previous
check fails:
if AOwner is TApplication then .... // FALSE!!!
Also, attempting to typecast AOwner gives an exception.

So, between the calling application and the DLL something
is lost. Perhaps it's because the app. and the DLL run in
different processes. It puzzles me. Can anyone explain this?

As for overriding the Windows message handling procedure:
I can insert any number of hooks and the original message
handling will remain intact, as long as I pass the messages on.
The component user can add his own hooks if he likes.

Alexander Bauer

unread,
Mar 21, 2003, 4:44:00 PM3/21/03
to
Hi Troels,

I wonder why you bind you components to the Application instad of a form but
anyway, if you havn't redefined the property Owner it's alway a TComponent.
So even if you reintroduce the constructor with TApplication, if you request
the components owner a TComponent will be returned.
If I understood you correctly, the controls are created like usual by eg.
dropping them on the form or the programm creates them dynamically. Anyway
it's the programm, not the DLL that calls the constructor - right, even the
constructor and the component are in a DLL? If so the control, even if it's
in a DLL must be able to access the Form and so the Application too. An
other thing, if you call the constructor with TApplication, why don't you
reintroduce it like that:

prublic
constructor Create(aOwner: TApplication); reintroduce;
[...]

So you can access the Application.Handle directly.
Well, I havn't tried but a TApplication(aOwner) causes an exception? I
wonder since TApplication is a descendant of TComponent.
Even the DLL and the application are running in different proccesses the
object references must be OK.

Regards,
Alexander Bauer


"Troels Jakobsen" <do...@like.spam> schrieb im Newsbeitrag

news:3e7b...@newsgroups.borland.com...

0 new messages