Creating Custom MDI Form Backgrounds

by Dan Appleman - Desaware, Inc.

Many programmers take advantage of the Multiple Document Interface (MDI) standard as the basis for their application. As nice as MDI forms are, if you use them you are stuck with the bland, plain solid background color offered by Visual Basic. The other day I received a message from a programmer who said that if only we offered a control that would let him put a custom logo or picture on the MDI form background, he would be the first to buy it.

I had to disappoint him, because as you will soon see - SpyWorks has supported this capability for ages, and now supports it under 32 bit VB4 as well. After several false starts (which are described in chapter 17 in the Visual Basic Programmer's Guide to the Win32 API), I came up with the following code that works very nicely.

Add a picture control to an MDI form at the top or bottom if you do not have one already - you will need it to hold the dwsbc32.ocx control. Don't worry if you don't want the picture control to appear in your application - you can simply turn the Visible property for the control to False to hide it. Load a bitmap into the picture control (or a second child picture control). Drop a dwsbc32.ocx control on the first picture control and use the Messages property to intercept the WM_ERASEBKGND message. We are going to completely take over the background drawing for the MDI form. Set the Type property to Pre-Default. The declarations you will need are shown in Listing 1. In this example they are declared as private declarations for use in the MDI form code. You can also declare them as public and place them in a module.

In the form load event for the MDI form you will need the following code:

  SubClass1.HwndParam = GetWindow(hwnd, GW_CHILD)
What's going on here? Every MDI form actually consists of two windows. The background area of the form is a separate window from the MDIform - it is a window with the class MDIClient. The hWnd property for the form returns the form window handle, but we need to subclass the MDIClient window - thus we use the GetWindow function to retrieve the handle to the child window.

The real work is done by the SubClass1_WndMessage event. The device context for drawing is provided as the wp parameter for the function. Normally, this device context has a clipping region set so that only those areas that need to be drawn are accessable by the device context. In this case, we must clear the clipping region because we need to override the normal scrolling operation provided by the form. (Try commenting out the SelectClipRgn function and see what happens when you scroll the MDI form.)

We create a temporary compatible device context and select into it the handle of the bitmap that we want to display. The FillRect function draws the main background area (outside of the bitmap area). The BitBlt function copies the bitmap into the desired location on the form.

Note how the bitmap and compatible device context are cleaned up after they are used. The retval event parameter is set to True to notify Windows that the background has been erased. The nodef event parameter is set to True to prevent the default WM_ERASEBKGND message processing from taking place.

Code Listing 1 and Listing 2

Written by: Dan Appleman
Feb 1996