Jump to content

Problem assigning parent property

- - - - -

  • Please log in to reply
6 replies to this topic

#1
Zorfox

Zorfox

    Learning Programmer

  • Members
  • PipPipPip
  • 36 posts
I'm trying to add a panel to an external application window. I intend on using it like a hint box, a panel with labels etc., but still need onclick functionalities. I also need to be able to drag it around. I thought I could simply set the parent of the control to the external window. It seems to work on some applications but not others. The panel is assigned but is not visible. Below is a down and dirty example of what I'm doing. The code below does work. There is one problem. I can't see the panel in notepad yet it appears if I change the parent application to MS Word for example. Any ideas would be greatly appreciated. Even a new approach to complete the task entirely.

procedure TForm1.Button1Click(Sender: TObject);

var

  hNotepad, hPanel: Hwnd;

begin

  hNotepad := Windows.FindWindow(nil,'Untitled - Notepad'); 

  hPanel := Panel1.Handle;

  Windows.SetParent(hPanel, hNotepad);

end;

Edited to add code wrap, and fix a typo, thanks for the tip LuthfiHakim.

Edited by Zorfox, 28 January 2011 - 09:51 AM.


#2
LuthfiHakim

LuthfiHakim

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 765 posts
Hi Zorfox, welcome to the forum!

Quote

Windows.SetParent(hPanel, MyHand);

What is MyHand? Where did you get that handle?

Just a thought, perhaps the problem with notepad related that it only has a "memo" control that does not support rendering child controls. To make things a bit clearer, maybe you can show us a screenshot of what you expected (i.e. when using MS Word).

Next time please wrap your source code with CODE tag, it will be easier to read.

Cheers!

Edited by LuthfiHakim, 28 January 2011 - 03:36 AM.


#3
Zorfox

Zorfox

    Learning Programmer

  • Members
  • PipPipPip
  • 36 posts
Thanks for the reply LuthfiHakim!

Quote

What is MyHand? Where did you get that handle?
An erroneous typo. I had been using that variable in an enumerate function in the actual procedure.

I suppose a little history would be in order. I enjoy playing online poker. I have to use three applications for each table to get the information I want. Every one of those applications gets their information out of a simple text file (basically). Sounds pretty straightforward, “I'll just write my own rather than use three apps at once”. Why is it the simple sounding applications ALWAYS end up being the most complex :cursing:. I want the information displayed over the table windows like the images below rather than deciphering it out of an external window.

I won't try to describe what I have tried in detail right now. Basically I have made two basic approaches to the problem. Initially I tried to create one window with controls then overlay that window to the host application. Make everything except the controls transparent. Since that was fraught with problems I tried setting the parent of controls to the host. As you can see that doesn't work so well either. I would rather have one window I can call from a DLL or the like. It would be much easier with multiple instances that way (only keep track of one window rather than 30 controls).

Below is an image of the table with the overlays. The big black popup is what you see when you click one of the smaller ones. Otherwise you only see the small "hints". Those "hints" are draggable by the way.

Posted Image

This image shows how the previous hand is showed over the host application. It appears to be several images over the host application at coordinates X,Y etc.

Posted Image

Sorry for the long winded post. But to explain what I’m trying to do seems to be where the confusion is. Any ideas of how I can accomplish this? I feel like I am making a basic mistake in my approach. Invariably, when I write a few hundred lines of code to do something simple another person says, "You could do that in two lines". I think I’m missing the obvious here as well.


Quote

Next time please wrap your source code with CODE tag, it will be easier to read.
I didn't even notice that option. That's a very nice feature! Thanks for pointing it out.

#4
Zorfox

Zorfox

    Learning Programmer

  • Members
  • PipPipPip
  • 36 posts
I did post a reply explaining what I am trying to do hours ago. Still waiting on an approval. I suppose images require site approval.

#5
LuthfiHakim

LuthfiHakim

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 765 posts
Seems that the external application use its own custom code when handling the painting. It's like in Delphi you override a method without calling inherited. This way it bypasses default windows behaviour, thus you can not attach your window to it. Or you simply chose the wrong window handle from the external program. have you investigated its structure thoroughly? Like using Winsight? Try to use different parent.

If all detected window handle do not work, there actually another option. If now you want to attach your window to external application, why don't you try the other way around? I.e. by attaching that external window to your own form. I believe now you will have more freedom on painting the surface.

If the above also does not work, or you don't like the result. You have the option of directly draw to the external window. For best result, you can hook into its message queue to be notified when it receives WM_PAINT, WM_ERASEBKGND message and do your custom drawing there.

#6
Zorfox

Zorfox

    Learning Programmer

  • Members
  • PipPipPip
  • 36 posts
Thanks for the reply. I completely forgot about Winsight, good advice. There does appear to be modified message handling routines. There are actually 4 windows in the main window displayed. I am using the main window handle however. Changing it to any one of the others does not help.

Encapsulating the application into my form is a good thought. But would'nt that hide my controls? To be quite honest I think I am missing the obvious. Sending my application to notepad causes the same issues, non-visible window, clipping, trailing artifact when dragging etc.

Here is a VERY basic example,

procedure TForm1.Button1Click(Sender: TObject);

begin

  Windows.SetParent(Self.Handle, FindWindow(nil,'Untitled - Notepad'));

end;

Just one button on an unmodified form. Shouldn't the form be visible? I don't understand why only portions are clipped at times. I would expect either it was fully visible or not. Apparently I simply don't understand the basic concept here. That is all I need to do is make sure my form is ALWAYS visible and never clipped. I can interact with the external application because I have made the form transparent. Form style fsStayonTop makes no difference (I think the inheritance from the parent overides that, of course I am most likely wrong lol).

#7
LuthfiHakim

LuthfiHakim

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 765 posts

Zorfox said:

Encapsulating the application into my form is a good thought. But would'nt that hide my controls?

Now that's the tricky part. In this case, you have to handle WM_PAINT message and WM_ERASEBKGND (if, i'm not mistaken with the erase background msg) carefully. You must take into account that you are hosting external windows - which has its own handler of WM_PAINT and WM_ERASEBKGND running on different process - and order the painting process carefully. Since you want the external window to be your background, then in those messages handler you want to relay them first to the external window. This way it's painted first before your children controls.

Zorfox said:

To be quite honest I think I am missing the obvious. Sending my application to notepad causes the same issues, non-visible window, clipping, trailing artifact when dragging etc.
...
Apparently I simply don't understand the basic concept here. That is all I need to do is make sure my form is ALWAYS visible and never clipped. I can interact with the external application because I have made the form transparent. Form style fsStayonTop makes no difference (I think the inheritance from the parent overides that, of course I am most likely wrong lol).

Remember that the codes that handle WM_PAINT and WM_ERASEBKGND of notepad and yours are in different process space (also remember that Windows is multitasking and messages should go through queue before handled). You should implement some sort of synchronizer between these two processes. That's why i recommend to host that external window in your application. I think it's easier.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users