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

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

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
bit defender blocks good applications 2 94
SLMGR Switches Are Not Working On KMS Host 3 92
Visual Studio search word table and return Cell index 8 61
Hide vba in gp 7 94
Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

770 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