Solved

SetParent API

Posted on 1998-04-01
5
1,234 Views
Last Modified: 2008-02-01
Here's a fun one.  

We have a very large application that we need to partition out.  The application's interface is MDI.  The idea is to break each functional area out into smaller DLL's, where each DLL would (for the most part) correspond to a single screen (we have almost 200 screens).  The benefits of partitioning the application into DLLs provides us with better manageability, smaller EXE size and lower resource utilization.

Using VB5, each screen will be displayed modeless with the goal of the window being treated as an MDI child.  To accomplish this we are using the SetParent API call.  When the child screen is displayed, SetParent is invoked with the handle of the MDI parent form.

This works great - until we try to drag a window or click on its caption.  What happens next is the confusing part.  When we click on the title bar, the child form "jumps" to a lower-right offset.  We can drag the form around but the mouse pointer does not actually touch the child form’s title bar.  Once the mouse button is release, the child form "jumps" back to where it would be had everything worked correctly.

I have determined that the coordinate system of the MDI parent is not being assigned to the new child window.  Instead, the child window seems to retain the coordinate system of the desktop (the previous parent).

Does anyone know how to correct this behavior?

Incidentally, the Parent form does not need to be an MDI form.  You can duplicate this behavior with two normal forms, too.  Also, for testing, you do not need to create a DLL.  Simply create two forms in your project and use the following (pseudo)code.


Form1:
=====
Private Sub Form_Load()
     Form2.Load
End Sub

Form2:
=====
Private Sub Form_Load()
     Call SetParent(Form2.Hwnd, Form1.hWnd)
End Sub

Thanks!
0
Comment
Question by:zsi
5 Comments
 
LVL 1

Expert Comment

by:jbabcock
ID: 1460182
The SetParent function makes the target window parentless if the second parameter is Null. I'll bet you that Null is being passed in that call.

To test this, put a stop marker at the beginning of Form2.Load(), and check the value of Form1.hWnd. It may be zero, which means that you're attempting to use an invalid handle.

Try moving the setparent call up into Form1.Load(), like this:

Form1:
=====
Private Sub Form_Load()
  Form2.Load
  Call SetParent(Form2.hWnd, Form1.hWnd)
End Sub


0
 
LVL 4

Author Comment

by:zsi
ID: 1460183
Actually, I am calling SetParent from within the parent form.  Also, my code (and yours) contains an error: Form2.Load will not work.  It should be Form2.Show.  Sorry about that.

The actual code should read:
Form1:
=====
Private Sub Form_Load
   Me.Show
   Form2.Show
   Call SetParent(Form2.hwnd, Form1.hwnd)
End Sub

No code is required in Form2.

Regarding the Null handle, there is no such thing.  When Windows creates a new window (or any other element for that matter) the very first thing that it does is allocates a memory handle.  Therefore, even if the SetParent call was being made in the child form, the .hWnd property would still not be null.
0
 

Expert Comment

by:mattyboy
ID: 1460184
Just a thought...

You could hook all events coming into the Child Forms in the App.  Then, instead of letting VB process these Forms normally when the caption is clicked or they are dragged, handle the behavior yourself.  That way, instead of working to fix odd behavior, you just prevent it altogether.

Just a thought...

mattyboy
0
 
LVL 39

Accepted Solution

by:
abel earned 50 total points
ID: 1460185
I've had the same problem with an old VB-app which as compiled with VB3 and uses the function SetParent as well. I'm not going to provide you a "real" solution, but I will try to ease your search for it and I will provide a workaround.

My project contained several separate executables which needed to communicate with each other and act like a MDI form with childs for the end-user. To achieve that I did the same as you by using the SetParent API call. It worked well in Win16 and the first releases of Win32. At first the problem occurred on NT4 and only when "dragging of full windows" was on. When I turned that off (and you'll only see a wireframe when dragging a window), the problem disappeared.
On Win95 OSR2 it is also possible to drag full windows and the problem occurred again. After some research I began to think that it was a bug of Windows, and I still think that, although I never found a real prove.

To get rid of the problem I made a workaround. I used the following function:
SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, False, 0, SPIF_UPDATEINIFILE Or SPIF_SENDCHANGE)

I first retrieved the setting with SPI_GETDRAGFULLWINDOWS and if False, there was nothing to do, when True, I changed the setting. When my application was loosing focus I restored the setting. Again, when it was False before, there was nothing to do either.

It did the trick. Off course you won't be seeing fully dragged windows when in your application the user moves a child, but at the other hand, it looks better to the enduser (who probably won't even give it any thought). I know, it IS a workaround, but it's better then nothing. I'm sorry that I can't provide you a "real" solution for your problem, but maybe this'll do.

When you need some more info, just post a comment,

Regards, Abel

BTW: mattyboy, what did you do with your question "Refresh all maximized windows on desktop" (Q.10045126)? When I tried to read your comment, the question seemed to be deleted....
0
 
LVL 4

Author Comment

by:zsi
ID: 1460186
Hmm... Well, this has certainly gotten me closer than anything else I have found.  

I put the SET to FALSE command in the Form.Activate and the SET to TRUE in the ChildForm.Deactivate.  This way, I can toggle the settings back and forth so that only the child is dragged by the frame only.

Keeping in mind that it IS a workaround, one undesired effect is that you have to give the parent an opportunity to receive the system message that the setting has changed.  This means that instead of clicking and dragging directly on the parent's titlebar, you have to click in the parent's area (or titlebar), release the mouse, then click on the title bar to move it.

Also, setting SETDRAGFULLWINDOWS to True does not work - it has to be 1.

But, it gets the job done and solves the problem at an acceptable level.  

I guess this behavior is just one more to add to Microsoft's bug list.

Thanks for the help!
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

706 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

22 Experts available now in Live!

Get 1:1 Help Now