Re: Write onto Active-X Control

Tech-Archive recommends: Fix windows errors by optimizing your registry

From: Mike D Sutton (EDais_at_mvps.org)
Date: 11/09/04


Date: Tue, 9 Nov 2004 19:09:24 -0000

Sorry for the delay in getting back to you on this, for some reason it was marked as already read

> Gee, how to i do that with VB? I know it's hard in VC.
> Do you have sample-code for subclassing a control in VB?

Here's an example that demonstrates subclassing in VB including managing the WM_PAINT message:
http://groups.google.co.uk/groups?selm=%23xpOoU0oEHA.3900%40TK2MSFTNGP10.phx.gbl

> Btw what is subclassing about, what does it mean?

The way Windows (OS) works is using the principle of windows (hWnd's) which encapsulate the functionality of whatever the window
needs to do, i.e. a button is a window, a text box is a window and so on. Applications are generally comprised of many windows
which can be set as 'children' of other windows so when you move the main application window for example, all it's controls move
with it.
The way the OS communicates with these windows is via messages which are deal with in a standard way for all windows known as the
message proc (processor/procedure.) The window is responsible for handling the messages that are sent to it within this window proc
however since there are hundreds of messages that the window may potentially need to respond to, there is a default window proc call
that can be called if the window doesn't need to perform any particular processing for a particular message.
The default window proc simply performs the bare minimum for the given message so if a window needs to perform anything additional
for any of the messages (such as a button clicking of typing text into a text box control) it performs it's own processing for those
particular messages.
In some cases though you want to perform additional processing (or in some cases override the current behaviour) in one or more of
these messages which is where subclassing comes in. When the OS wants to send a message to the window it asks it where it's window
proc handler method is then calls this function and passes the relevant information on to it (function pointers are something fairly
alien to VB, but if you've worked in C++, Java, Delphi etc then you may have come across them before.)
Since VB5 we've had the AddressOf operator which returns a pointer to the function enabling us to use API calls the require function
pointers including subclassing, however the operator only works in standard modules (.bas) - Don't worry why (if you really want to
know the ask) unfortunately you just have to use modules for your subclassing which can be a bit of a pain sometimes but you'll get
used to it.
To subclass the window we tell it that we're going to be handling it's messages by using the SetWindowLong() API call with the
GWL_WNDPROC flag and we're given a handle to the old window proc - this is important so be sure you retain it!
We pass the call a pointer to our own function which must match the function header of the standard window proc:

'***
Private Function WndProc(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
    ...
End Function
'***

The uMsg parameter holds the particular message that we're being sent so we can examine this parameter for the message we want to
deal with. The hWnd parameter is the handle to the window we're dealing with (this is so you can use the same window proc for
multiple windows but in this case it will only be for your one control so it's safe to ignore.)
The last two parameters hold information specific to the message, you can find out what they contain for a specific message by
searching on the MSDN.
For those messages that we wish to handle, we can provide our own processing here but for those messages that we're not interested
in we pass it back down to the previous window proc by use of the CallWindowProc() call using the parameters we've been passed (and
in some cases it may then pass that message down further to the default message proc). The idea here is that there are multiple
levels of message handling so all messages get dealt with but not necessarily in one place.

> I have the idea that I somehow link to the window-message queues
> of a window that may or may not belong to my own app and somehow
> take control of the action that happens if a certain message
> is coming in like e.g. WM_PAINT (sounds pretty much like hacking
> or 'hostile takeover' ...*eg* ).

If the window belongs to a different application then that complicates things further, you'd need to get into cross-process
subclassing which isn't possible (?) in VB.

> Is that what a bit of what subclassing means?
> How much code and how many working hours will I need for subclassing
> a MSChart-Object placed on VB-form? (I don't even know how to
> get the window-handle, there's no such property in terms of
> VB-properties....)

The subclassing code can be pretty much copied and pasted from the above link, in your window proc you _always_ call the previous
window proc so all messages are handled for you, however for the WM_PAINT handler you perform your additional drawing over the top.

> Interesting, probably a 'Line' in VB is actually a call of LineTo()
> at a certain time.

More than likely, however it has to go through VB's coordinate engine which adds additional overhead to the method.

> Can I also select a different pen? I need the labels/text to appear in a
> certain color and also a selected font with a defined size.

If you're performing the drawing then yes, however the text colour is defined by a property of the target DC which can be accessed
via the Get/SetTextColor() API calls. The font face and size is defined by the currently selected API font object.

> I've done some examples from Charles Petzold's Windows-Programming in C
> that use TextOut() and DrawText(). It wasn't that difficult.
> The problem for me is how to get handle to the DC and other handles that
> aren't exposed by VB. According to MSDN the hDC prop applies to Forms
> PictureBoxes UserControls and some Others, but not to MSChart.
> Or is a VB-Control also kind of a UserControl?

You can call GetDC() on the window handle, but be sure to pair it up with a ReleaseDC() call when you're done with it.

> But there is a property in VB that can set the default-scaling to pixels,
> isn't it? it goes like VBnnnn = vbPixels. I forgot the name of that property.

The ScaleMode property of controls that expose it sets the VB scaling mode, however this is ignored by the API. To set the API
scaling mode you can use the Get/SetMapMode() API calls. If you're getting into that though it may be an idea to have a quick read
through the DC article on my site, particularly the chapter that deals with mapping modes at the end.

> My goal is simply to display lines and bars on a 2D-plot and label datapoints
> and axises at any position of the plot, MSChart is buggy (The Datapoints-Collection
> only accepts index -1, this problem hasn't been fixed since 1998! And one cannot
> place the axis-label on top of the axis, because an axises have no location-object
> and the internal location is always centered. Thats very creepy because setting
> the units on top is the common way to do for scientific graphs)
>
> So would you think that it is better to subclass a control to achieve the
> things that it can't do on its own or is it better (and in the end less work)
> to write a fully new 'mini-chart-application' on my own?
> I've seen VB-Code that does charting using API in combination with normal VB
> drawing. It wasn't that much code (the vb-sample is called: "A Chart with
> Windows API", forgot where it was from). It only uses three API-Function
> (CreateFont, SelectObject and TextOut) to draw a nice little chart that has
> precise scaling an it also looks beautiful and very clean.
> I have the impression that i can do more without the MSChart control
> with less code. But maybe i am wrong. What do you think is subclassing easier
> or writing a self-made API-chart?

Personally I'd write my own as I'd have full control over it rather than having to 'patch' another solution.
Here's a recent thread which may be of some use to you when dealing with scale modes and drawing with the API:
http://groups.google.co.uk/groups?th=109820232e9bb0b1
Hope this helps,

    Mike

 - Microsoft Visual Basic MVP -
E-Mail: EDais@mvps.org
WWW: http://EDais.mvps.org/


Quantcast