C# Tutorials and offshore development in India
    Tutorials   Resources   Forum   Reviews   Communities   Interview   Jobs   Projects   Training   Your Ad Here    
Silverlight Games | Mentor | Code Converter | Articles | Code Factory | Computer Jokes | Members | Peer Appraisal | IT Companies | Bookmarks | Polls | Revenue Sharing | Lobby | Gift Shop |


Prizes & Awards
My Profile



Active Members
TodayLast 7 Days more...






Resources » Articles » General »

Subclassing


Posted Date: 07 May 2004    Resource Type: Articles    Category: General
Author: sanyam aggarwalMember Level: Bronze    
Rating: 1 out of 5Points: 7



Subclassing Wizardry

This article teaches you subclassing with Visual Basic 6.0. Though .NET is the latest version, the concepts learnt in this article can easily be applied to .NET projects.

Introduction to subclassing

To begin with, subclassing is the the process of intercepting messages before they are passed to the actual window. This means that we can take action of our choice rather than the window whose is going to receive the message. Every window in WindowsOS has a function which receives messages for that window and takes action based upon different types of messages.Subclassing involves specifying a custom function which will receive all messages before they are sent to the original message handler.

In C++, whenever we create a window, we register its class. The structure used is WNDCLASSEX which is like following:

Public Type WndClassEx          
           cbSize as long
           style as long
           lpfnWndProc as long
            . . . .
End Type

Only lpfnWndproc parameter is important because it points to address of function which receives all messages for the specified window. Our purpose in Subclassing is  to point this lpfnWndProc to our custom function so that we receive all the window notifications-here comes the role of SetWindowLong API function and AddressOf Operator in Visual Basic.

The SetWindowLong API function changes an attribute of the specified window. Among other possible things, it allows to modify the function which is going to receive notifications. We pass it the handle whose attribute we want to change, what attribute we want to change and the new attribute. In our case we are going to use GWL_WNDPROC which sets a new address for the window procedure and returns the AddressOf default message handler for the window which we later pass to CallWindowProc as described later.

The new Attribute must be AddressOf a function (in a BAS module because Visual Basic allows us to have function Address for only function in a BAS module) with following declaration which I explain later:

Public Function (ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

'Add custom functions here

End function

where hwnd is the handle of window for which we are receiving messages, uMsg is the message received presently, wParam and lParam are additional information associated with a message. A common beginners mistake is to write the above function as:

Public Function (hwnd As Long, uMsg As Long, wParam As Long, lParam As Long) As Long

'Add custom functions here

End function


Noticed the mistake? It simple! We have omitted the ByVal keyword due to which we are receiving the actual address of these parameters and trying to access any one of these result in GPF! Another mistake is to forget to specify the return type of function as Long which causes VB to crash. So watch out!

So since we are through with the concepts, we start to take a look at how to begin Subclassing. We start off with a simple example and then build on something useful.

But I need to clear one more concept before we begin off-we don't process all window messages we get. The messages we don't process must be passed back to Default message handler for the window otherwise unexpected results occur. So for this we use CallWindowProc API function which call the default message handle for the window and looks like this:

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long,
ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

where lpPrevFunction is the addressOf default message handler for the window which we got by SetWindowLong API function and the rest of the parameter correspond to the parameters we receive in out custom message handler..

Open a new Standard EXE project

1)Add two command buttons to the form. Name one as "cmdStartSubClass" and its caption to "Start Subclassing".
Name the other as  "cmdStopSubClass" and its caption to "Stop Subclassing".

2)Add a BAS Module and add the Following Code:

Option Explicit

'API Decalrations
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal
nIndex As Long, ByVal dwNewLong As Long) As Long

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As
Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Public Const GWL_WNDPROC = (-4) 'constant in SetWindowLong
Public pFunction As Long 'pointer to default function

Public Function SubClassForm(frmHwnd As Long)

'Start Subclassing the Form
pFunction = SetWindowLong(frmHwnd, GWL_WNDPROC, getFuncAddress(AddressOf WndProc))
End Function

Private Function getFuncAddress(pAddress As Long) As Long
'just pass whatever was received
getFuncAddress = pAddress
End Function

Private Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As
Long) As Long

'Just Print the uMsg,wParam and lParam
Debug.Print "Message: " & uMsg & " wParam: " & wParam & " lParam: " & lParam

'Call the Default message handler
WndProc = CallWindowProc(pFunction, hwnd, uMsg, wParam, lParam)
End Function

Public Function StopSubclass(frmHwnd As Long)

'Stop Subclassing
SetWindowLong frmHwnd, GWL_WNDPROC, pFunction
End Function


3)Now add the following Code to Form:

Option Explicit

Private Sub cmdStartSubClass_Click()

'Start subclassing the Form
SubClassForm Me.hwnd
End Sub

Private Sub cmdStopSubClass_Click()

'Stop subclassing the form
StopSubclass Me.hwnd
End Sub


Thats It!!

Run the project and click the button with caption "Start Subclassing" and notice the Immediate window. You will see a list of all the messages you form is receiving and their wParam and lParam values.

Though it does not do anything usefult, but it was still useful to get started. I am not going to explain
the above code as I have already done in preceding paragraphs and you can follow it with the help of
Comments.

One interesting thing you might have skipped in this excitement is that you can subclass any window which exposes hWnd property-that is TextBoxes,PictureBoxes,TreeViews etc!!!

And moreover the Basic Procedure to start Subclassing each of them is same-so you will see this code in any application using SubClassing.




Responses

Author: Nam Nguyen    30 Jun 2004Member Level: Bronze   Points : 0
It does not seem to work in VB.NET.
The AddressOf operator can not convert to Long, because Long is not a delegate type.


Author: Paul Talbot    27 Aug 2004Member Level: Bronze   Points : 0
Nam,

To work around the AddressOf problem you have, you need to create a Delegate for the API Call,
don't forget to overload the SetWindowLong object or you will not be able to do standard
Long calls.

Delegate Function SetWindowLongProc( _
ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" ( _
ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As SetWindowLongProc) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" ( _
ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long


Then change the function below to look like this

Public Function SubClassForm(frmHwnd As Long)
'Start Subclassing the Form
pFunction = SetWindowLong(frmHwnd, GWL_WNDPROC, AddressOf WndProc)
End Function

Hope this helps.

Paul


Feedbacks      
Popular Tags   What are tags ?   Search Tags  
Sign In to add tags.
(No tags found.)

Post Feedback


This is a strictly moderated forum. Only approved messages will appear in the site. Please use 'Spell Check' in Google toolbar before you submit.
You must Sign In to post a response.
Next Resource: How to get months name from month digit?
Previous Resource: Code Access Security (CAS)
Return to Discussion Resource Index
Post New Resource
Category: General


Post resources and earn money!
 
Related Resources



dotNet Slackers

About Us    Contact Us    Privacy Policy    Terms Of Use