HAPPY PLANET- TUTORIAL
The future belongs to those who believe in the beauty of their dreams.
  Cosmos of Happiness
  >Happy Planet
  - Happiness
  - Science
  - Mind Technology
  - Meta Physics
  - Dream
  - Meditation
  - Intuition
  - Philosophy
  - Psychology
  - Creativity
  - Telepathy
  - Great Scientists
  - Dream Dictionary
  - Miscellaneous
  - Games
  - Links
     
  >Special Features
  - Intelligence
  - Security
  - Tutorial
   
  >Powered by 
   

 

 

  Welcome to Happy Planet - Tutorial Section  
 

"Deep in the sea are riches beyond compare.
But if you seek safety, it is on the shore."

API (Application Program Interface)

Callbacks

A callback is a function you write and tell Windows to call for some reason. You create your own function with a specified number and type of parameters, then tell Windows that this function should be called for some reason and its parameters filled with some info you need. Then Windows calls you function, you handle the parameters and exit from the function returning some kind of value.

A typical use of callbacks is for receiving a continuous stream of data from Windows. Here is the declaration of a function that requires a callback:

Declare Function EnumWindows Lib "User32" _

ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long

The first parameter is the address of your callback function, and the second is a whatever value you want. This value will be passed to your function, so that you know what it is called for.

VB 5.0 has provided a useful operator called AddressOf which returns the address of a function. It may be used only in front of a parameter when you call a function and uses like

FuncP = AddressOf MyFunction

are wrong and cause error. So, you must call EnumWindows like that:

Success& = EnumWindows(AddressOf cbFunc, 58&)

You must also write the callback function. There are different type of callbacks that have a different sets of parameters. Description of this parameter can be found in a SDK Help file or MS SDK documentation. Here is the declaration for the callback:

Function cbFunc (ByVal Hwnd, ByVal lParam) as Long

Here is a sample of callbacks:

Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _

(ByVal hwnd As Long, ByVal lpString As String, _

ByVal cch As Long) As Long

Success& = EnumWindows(AddressOf cbFunc, 58&)

Function cbFunc (ByVal Hwnd, ByVal lParam) as Long

If lParam = 58 then 'enum windows

Str$ = Space(255) 

Ret& = GetWindowText(Str$, Len(Str$))

Debug.Print Left(Str$, Ret&)

End If

End Function

This sample enumerates the captions of all windows (no childs).

The Window Procedure

Windows does not know anything about events. These are shipped in VB to hide the actual way Windows informs your window that something is happening with him. VB gently serves as a interpreter and translates the Windows language into VBs.

But the reallity is different and you will soon face it. Imagine you want to know when the user highlights you menu item (not press, just highlight). VB does not provide such event, but you've seen how other programs display some text in the statusbar as you browse their menus. If they can, why you don't.

OK, here is the rough reallity. Each window has a special procedure called window procedure. It is actually a callback function. This function is sent a message any time something happens with you window. Thus a message (WM_COMMAND) is sent when the use highlights a menu item.

Why then I can't see this message? This is because VB creates the window procedure instead of you. When Windows sends a message, this procedure dispatches it to a certain event and converts its parametrs into some easier to use parameters of the event. But, in some cases this procedures just ignores some messages and can't receive the actual input. If you really need to get this message, you must subclass your window, which discussed in another topic.

Here is the declaration of a calback window procedure:

Function WindowProc(ByVal Hwnd As Long, ByVal wMsg As Long, _

ByVal wParam As Long, ByVal lParam As Long) As Long

The first parameter specifies the window handle, wMsg is a message identifier (like WM_COMMAND or WM_MOUSEMOVE), wParam and lParam are 32-bit values which meaning depends on the type of message sent.

SubClassing

When you have already used the maximum VB offers you and want to do something more, or just want to know something more about what's going on with your window, now or then you will find the advantages of subclassing.

Subclassing refers to changing the active window procedure with a new one. Now this new procedure will receive all messages coming to your window before the old one. But the old procedure still exists, it's not lost. If you do not process a given message, you should call the old procedure to process it.

Subclassing is done by calling SetWindowLong. This function changes a specified attribute of the given window. Here is its declaration:

Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _

(ByVal hwnd As Long, ByVal nIndex As Long, _

ByVal dwNewLong As Long) As Long

The first parameter specifies the window to be subclassed, the second should be GWL_WNDPROC (-4) and the third should be the address of the new window procedure. See Callbacks and The Window Procedure.

This function will be called literally every time your window has the focus and something is going on and in some other cases (like changing some system parameter by another process).

SetWindowLong return 0 if an error occurs, or the address of the old window procedure. This address is especially important and you should save it in a variable or else. It is used to call the old function when you do not process a message (in fact you will process less than 1% of all message and will let the old procedure handle the rest).

Calling the old window procedure is accomplished by CallWindowProc API function. Here is the declaration:

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

The first parameter is the address of the old procedure and rest are just the same as the four parameter you receive. Note that you may change some of the values to control the message process. For example, when you receive WM_MOUSEMOVE, you get the coordinates of the mouse from lParam and change them to some other coordinates. Then the old window procedure will think the mouse is not where it is actually and may for example show a tooltip of some distant control or do some other funny things.

The ruturn value you specify is also meaningful. It depends on the message sent.

It is very important to return the original window procedure before ending you program. It is usually done in Form_Unload. Here is how:

Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProcAddress)

If you miss this line when starting your program through VB, the result is a crash of VB and loss of any unsaved data. Be careful.

Here is a simple example of subclassing:

Dim oldWndProc As Long

Private Sub Form_Load()

oldWndProc = SetWindowLong(Me.Hwnd, GWL_WNDPROC, AddressOf MyWndProc)

End Sub

Private Sub Form_Unload()

Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProc)

End Sub

Function MyWndProc(ByVal Hwnd As Long, ByVal wMsg as Long, _

ByVal wParam As Long, ByVal lParam As Long)

Debug.Print wMsg & " " & wParam & " " & lParam

Ret& = CallWindowProc(oldWndProc, Hwnd, wMsg, wParam, lParam)

End Function

Handling Parameters

Sometimes the functions do not return the information you need the way you want it. Typical example is combining two integer(2-byte) values specifying the mouse position into one 4-byte value. Another case is telling you that if bit 29 is on it means something. Also, you may receive a Long value that is the address of a structure.

Combining or separating values does not need any description. APIMacro.bas you may find on our site (www.geocities.com/SiliconValley/Lab/1632/) contains all functions you need to have.

To check if bit N of Value is on use the following:

If Value and (2^N) then ...

To set a bit on:

Value = Value Or 2^N

To set a bit off:

Value = Value And Not 2^N

If you set and get the state of a bit you know beforehand, its much faster to replace 2^10 with 1024. This way VB won't have to calculate it itself (VB "hates" ^).

If you receive a pointer to a type, then you must do a bit more. To get the info, you use CopyMem function. Here is the declaration:

Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" _

(pDest As Any, pSource As Any, ByVal ByteLen As Long)

If you receive a pointer to RECT type in the Long variable Addr, use the following:

Dim Info As Rect

Call CopyMem(Info, ByVal Addr, len(Info))

Note the ByVal keyword. Now, if you need to put the information back, use:

Call CopyMem(ByVal Addr, Info, Len(Info))

Closing Words

I hope this tutorial has helped you understand how to control the power of API functions and how to use them properly. But BEWARE! It's like the fire, you let him out of control and you are lost. And, of course, never forget that VB is designed for easy and safe programing and API foes straight against. If you are looking for more control and power, better move to VC++ or Delphi.

To expand your knowledge of APIs and get some expeience, be sure to take a look at the sample on this site (www.geocities.com/SiliconValley/Lab/1632/). Almost all of them are dedicated to API and its advantages.

Also, if you have any questions, something has left misunderstood, or whatever it is, be sure to e-mail. I'll try to solve your problem.

Good luck, happy exploring the API !!!

-by Invincible(psycho@nepalimail.com)

 
     
  Back to Tutorial>>  
 
           
   
 
Copyright © Happy Planet. All rights reserved. webmaster
 
1