README.TXT - Read-me file for SUBCLS.ZIP

------------------------------------------------------------------------
NOTE: Use -d when unzipping SUBCLS.ZIP to have subdirectories recreated.
------------------------------------------------------------------------

Subclassing Examples, Copyright (c) 1995 Jonathan Wood and Karl Peterson
Redistributed by Permission


INTRODUCTION:
The accompanying files provide several examples of using a subclassing
control with Visual Basic to intercept Windows messages. Emphasis is
placed on those messages that result in functionality that cannot be
obtained through Visual Basic alone.

These files include complete source code for an article in the September
1995 issue of Visual Basic Programmer's Journal (tentatively entitled
"Subclass your way around VB's limitations"). Refer to that article for
additional information on the techniques used. Also included here are
four additional examples not mentioned in the article.

In addition, the subclassing control MSGHOOK.VBX is also included.
Although other subclassing controls are available, the examples
presented here are written to work with this control. See MSGHOOK.TXT
for more information regarding the Message Hook custom control.

If you'd like to contact the authors of the demo programs and article,
they can be reaced on CompuServe. Jonathan Wood at 72134,263 and Karl
Peterson at 72000,1751.


EXAMPLES:
The article contains 8 tips. They are described briefly below and
reference is made to the project that corresponds to the tip. Following
these 8 tips are 4 additional ones. Since these were not covered in the
article, a discussion of them is provided.

1. SHOWING STATUSBAR INFORMATION FOR MENU COMMANDS
Refer to the article and the MENUSEL project.

2. ADDING A COMMAND TO A FORM'S SYSTEM MENU
Refer to the article and the SYSCMD project.

3. SUPPORTING DRAG-AND-DROP FROM FILE MANAGER
Refer to the article and the DROPFILE project.

4. LEFT JUSTIFYING CAPTION TEXT
Refer to the article and the LEFTCAP project.

5. RESTRICTING A WINDOW SIZE RANGE
Refer to the article and the GETMINMX project.

6. PAINTING THE BACKGROUND OF AN MDIFORM
Refer to the article and the MDIPAINT project.

7. DRAWING CUSTOM MENU COMMANDS
Refer to the article and the OWNRDRAW project.

8. HOOKING INTO THE CLIPBOARD VIEWER CHAIN
Refer to the article and the CLIPVIEW project.


9. CHANGING MENU TEXT (INITMENU)
Visual Basic allows you to modify the text of a menu command by setting
the Caption property of a menu object. However, it often makes more
sense to be able to set this caption just before the drop down menu is
displayed. For example, let's say you had a spreadsheet with names and,
when a menu was dropped down, you wanted the currently selected name to
appear in the menu as part of a command. Rather than changing the menu
caption every time the current selection changes, wouldn't it be easier
to simply set the caption to the currently selected name just before the
menu is displayed?

Visual Basic does allow you to do this. For example, if you have an Edit
menu that contains a Copy command, you can modify the Copy command's
Caption property in the Edit menu's Click event. The Edit menu's Click
event occurs before the menu is displayed. Unfortunately, Windows has
already calculated the width of the menu at this point. If the new text
for the caption is longer that the width of the menu, the text will be
cut off.

We can solve this problem by using a subclassing control to intercept
the WM_INITMENUPOPUP message. This message is sent before a drop down
menu is displayed and, significantly, before the width of the menu has
been calculated. The INITMENU project demonstrates this technique.

The value you assign to the Result parameter, which MsgHook passes to
the Message event handler, will be returned to Windows. Like the wParam
and lParam paramters, the meaning of the value returned depends on the
actual message being sent. However, most messages, including
WM_MENUSELECT, simply use a return value of 0 to indicate that your
program processed the message.


10. DETECTING SYSTEM COLOR CHANGES (SYSCOLOR)
Often when painting custom elements on your forms, you want to use the
default system colors so they will blend in nicely with the appearance
of the rest of the screen. Windows offers the GetSysColor API call to
retrieve any of the colors which the user can set in Control Panel for
items such as buttons, titlebars, borders, and so on. But, what if the
user alters their color preferences while your program is running? For
performance reasons, you may decide that it's best to store the system
colors in an array, so you can draw immediately with them rather than
calling the GetSysColor API repeatedly.

Hooking the WM_SYSCOLORCHANGE provides notification whenever the system
colors change.  This message is closely followed with a WM_PAINT message
which will fire the Form_Paint event in your project. By retrieving each
of the system colors during the hooked Message event (see the SYSCOLOR
project), the color array is refreshed prior to the painting. There is
no need to invoke the original window procedure as Visual Basic has never
reacted to this message.

One other point of interest is the way the array of colors is initially
filled. Rather than duplicate the looping code, SendMessage is employed
to fire the Message event just set up during the Form_Load event.


11. FORCING AN APP TO REMAIN MINIMIZED (MINAPP)
Some applications don't need a windowed user interface. These are
typically written to process large quantities of data in the background,
or to sit idly by monitoring and reacting to system events. If you've
written such an application, you may decide that its best for it to
remain minimized either as an icon or in the Windows 95 taskbar, but
Visual Basic doesn't provide a convenient means of doing so. If a form's
WindowState is reset to Minimized whenever a Form_Resize event occurs,
there's still an ugly flash as the form first restores to Normal or
Maximized.

Hooking the WM_QUERYOPEN message (see the MINAPP project) provides a
means for your form to be notified before its state is altered. An
application can notify Windows that the icon may be opened by returning a
non-zero value, or prevent the icon from opening by returning zero. To
implement this technique in Visual Basic, simply return zero in the
Result parameter when the Message event is fired. There is no need to
invoke the original window procedure.

One precaution to observe is to not perform any actions which would cause
an activation or alter the focus while processing this message. To
provide some degree of user interaction with your iconized application,
implement the code presented in the SYSCMD project to add one or several
menu options to the form's system menu.


12. PREVENTING A WINDOW FROM BEING SIZED OR MOVED (WINPOSCH)
Just before a window gets sized or moved, Windows sends it a
WM_WINDOWPOSCHANGING message that includes information about the new
window position. A window procedure can inspect the information about the
new position and even modify it.

The WM_WINDOWPOSCHANGING message uses the lParam parameter to hold the
address of (or pointer to) a WINDOWPOS user-defined type (see the
WINPOSCH project). While Visual Basic doesn't support pointers, the
Windows API provides a function called hmemcpy which can be used to copy
data from one location to another. Using hmemcpy, this example copies the
data from the address specified by lParam to a Visual Basic variable of
type WINDOWPOS. Note that the code declares two hmemcpy parameters As
Any. This is done to provide maximum flexibility but also means that
Visual Basic is not able to verify that the correct data types are sent.
Care should be taken when incorporating hmemcpy in your own applications,
as it can be a little tricky.

After using hmemcpy, we end up with a copy of the WINDOWPOS data
structure in a Visual Basic variable. This data structure contains
information about the new window position. If this information is
modified, the changes will affect how the window is moved. Setting the
SWP_NOSIZE and SWP_NOMOVE bits of the flags element of the WINDOWPOS
structure prevents any moving or sizing at all. This example, sets
these bits and then calls hmemcpy once again to copy the data structure
back.

This project contain some additional statements to detect if the window
is minimized. If the window is minimized, the program allows the window
to be sized normally. Apparently, when a window gets this message as the
result of a window becoming unminimized, the form's WindowState will
already indicate that the form is not an icon. Therefore, the code also
keeps track of the WindowState for the last time the WM_WINDOWPOSCHANGING
message was received. If you feel like experimenting, you can take these
conditional statements out and see how the form behaves when you minimize
it.
