Delegates in VB.NET

Asynchronous Callbacks

Delegates can also be used as CallBacks. CallBacks are used in many Windows API calls. You pass in a function pointer to the API call. When the API call gets finished with it's job, it then “calls back” to the function via the function pointer you passed it. This allows your code to know when the API call is done.

The framework provides an easy way to use a delegate with an API that needs a callback. Here's how. You can define and pass a delegate as a native function pointer several ways. Here are two. First we declare our delegate and the API call we want to make.

Public Delegate Function MyDelegateCallBack( ByVal hwnd As Integer,_
 ByVal lParam As Integer ) As Boolean
Declare Function EnumWindows Lib "user32" ( ByVal x As MyDelegateCallBack,_
 ByVal y As Integer ) As Integer

We then define our function that we want to be called by the EnumWindows API call as it finds windows.

Public Function EnumOutput( ByVal hwnd As Integer , ByVal lParam As Integer ) As Boolean
Console.WriteLine(hwnd)
Return True
End Function

And last our test code that makes the call to EnumWindow.

Dim del As MyDelegateCallBack
del = New MyDelegateCallBack(AddressOf EnumOutput)
EnumWindows(del, 0)

We declare our delegate variable and then pass it to EnumWindows, which calls it every time it finds a new window. The test code could also be written like this:

EnumWindows(AddressOf EnumOutput, 0) 

The shorter form creates a delegate for you and passes it to EnumWindows.

To pass multiple delegates to CallBacks is just as easy. You can't use the short form of the CallBack delegate as shown above, since you need to combine delegates. In this example the definition of EnumWindows changes along with our test code. Here is the whole example.

Public Delegate Function MyDelegateCallBack( ByVal hwnd As Integer , _
ByVal lParam As Integer ) As Boolean
Declare Function EnumWindows Lib "user32" ( ByVal x As [Delegate], _
ByVal y As Integer ) As Integer
Private Sub btnButton1_Click( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnButton1.Click
Dim del As MyDelegateCallBack
Dim del2 As MyDelegateCallBack

del = New MyDelegateCallBack(AddressOf EnumOutput)
del2 = New MyDelegateCallBack(AddressOf EnumOutput2)

Dim delAll As [Delegate]
delall = MulticastDelegate.Combine(del,del2)

EnumWindows(delAll, 0)
End Sub

Public Function EnumOutput( ByVal hwnd As Integer , _
 ByVal lParam As Integer ) As Boolean
Console.WriteLine(hwnd)
Return True
End Function
Public Function EnumOutput2( ByVal hwnd As Integer , _
ByVal lParam As Integer ) As Boolean
Console.WriteLine( "Found HWND" )
Return True
End Function

You will notice that we use a generic delegate for the first parameter of EnumWindows. This is necessary because we want to pass a multicast delegate to it. We add a new function called EnumOutput2, with the same signature as EnumOutput, and create another delegate that points to it. After creating our multicast delegate, delAll, we use it to pass to EnumWindows. The output shows that both functions get called for each window found. Be careful when doing this. Since EnumWindows takes a generic delegate, you are responsible for passing in functions with the correct signature that it expects.

Now that we know how a CallBack works, we will take a look at how to implement one of our own and call it asynchronously. Like always, we start by defining a delegate.

Public Delegate Sub MyAsyncDelegate() 

Next we will show our test code and delegate functions together and analyze them

Private Sub MyWorker()
System.Threading.Thread.Sleep(2000)
Debug.WriteLine( "MyWorker Done!" )
End Sub
Private Sub ImDone( ByVal ar As System.IAsyncResult)
Debug.WriteLine( "AsyncDelegate is done" )
End Sub
Private Sub btnButton1_Click( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnButton1.Click
Dim del As MyAsyncDelegate
del = New MyAsyncDelegate(AddressOf MyWorker)

Dim cb As AsyncCallback = New AsyncCallback(AddressOf ImDone)
Dim oState As Object

Dim ar As IAsyncResult = del.BeginInvoke(cb, oState)
Debug.WriteLine( "After Delegate BeginInvoke" )
End Sub

If you look at our two delegate functions, you will see that the MyWorker function is the target of our normal MyAsyncDelegate. The other function, ImDone, takes a parameter of a System.IAsyncResult. This is the signature you need for the class AsyncCallback.

An AsyncCallback delegate allows you to call a function asynchronously. It takes a parameter of the results. In our test code you will see that we have created a variable named, cb, for our AsyncCallback. This is the delegate that will get called when our function is done.

Next we declare a variable, called ar, of the IAsyncResult type and set it equal to our normal delegate's BeginInvoke method. This method takes a Callback delegate and an object that represents its state. This call returns immediately. The framework does all the work of making the call to MyWorker on another thread for you.

When MyWorker finishes, we get our asynchronous sub's output of AsyncDelegate Done. If you examine the whole output, you will see that the asynchronous call return immediately, then the MyWorker sub finishes, and finally the ImDone sub is called.

  After Delegate BeginInvoke
MyWorker Done!
AsyncDelegate is done

In our example, we have done all the work locally behind a form, but one could easily define a method that took a delegate for a callback. Instead of defining your delegate variable locally, you would use the passed in one as the target of the AsyncCallback object. After setting up, you would call your internal delegate to do the work and return processing to the calling sub. As your delegate worked, it calls the AsyncCallback whenever you decide to notify the client.

Hopefully this article will help you understand delegates and how VB.NET uses them. When applied correctly, they can make your programming very generic and able to handle many different situations. Good luck and happy coding!

You might also like...

Comments

About the author

John Spano United States

John Spano cofounder and CTO of NeoTekSystems, a Greenville, South Carolina technology consulting company. NeoTekSystems offers IT consulting, custom programming, web design and web hosting. We ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“You can stand on the shoulders of giants OR a big enough pile of dwarfs, works either way.”