SetParent API

Posted on 1998-04-01
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.

Private Sub Form_Load()
End Sub

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

Question by:zsi
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions

Expert Comment

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:

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


Author Comment

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:
Private Sub Form_Load
   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.

Expert Comment

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...

LVL 39

Accepted Solution

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:

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....

Author Comment

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!

Featured Post

Industry Leaders: 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!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction While answering a recent question ( in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
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…

740 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