Link to home
Start Free TrialLog in
Avatar of zsi
zsi

asked on

SetParent API

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!
Avatar of jbabcock
jbabcock

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


Avatar of zsi

ASKER

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.
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
ASKER CERTIFIED SOLUTION
Avatar of abel
abel
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of zsi

ASKER

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!