Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Asynchronous processing - Basics and a walkthrough with VB6/ VB.NET - I

0.00/5 (No votes)
23 Nov 2003 1  
Basics of asynchronous procedure and how-to with VB6 & .NET

Introduction

This article has come out more of my curiosity and penchant towards asynchronous processing, its basics and features. In this article, I shall try to cover these areas.

  1. Basics & the need for asynchronous processing
  2. Differences between synchronous and asynchronous processing
  3. How-to implement asynchronous processing in VB6 and in .NET, and in turn figure out how efficient it is in .NET.
  4. Conclusion

Consider this scenario � I would like to transfer a junk of files to some location as part of my application. Visual Basic offers APIs, file system object and many more, through which I can accomplish this. Say, I can just write CopyFile <SourceFile> <Destination> and loop it to transfer files. Yes, it would certainly work and is fine when the amount of the size of the files you transfer is less. When you try this with a huge file or more number of files, you will notice that the whole process is blocked when file transfer is in progress. You won�t be able to do anything else until the transfer is complete. Wouldn�t it be nice if the transfer happens at the background and you would be able to do any other operation (say any UI functions or even cancel the transfer operation) while the transfer is happening. This exactly is where the need arises for asynchronous processing.

The above said method is synchronous, where the main application thread is utilized for this transfer and until the operation is complete, this thread is not released for any other UI operations. (Even if you wish to cancel the transfer of files for some reason, you won�t be able to do).

And accomplishing this background processing is what we are focusing on � asynchronous processing, where the operation is carried out in a separate thread than that of the calling thread, leaving the main thread to do any other operation. This gives the user the control to do anything when processing (as transferring files). And the child thread created can callback the main thread to intimate when the transfer is complete or when an error occurs, on which the application can act accordingly.

Implementation

If you have evolved with the versions of VB, then you would not deny the fact that implementing asynchronous processing is not so straightforward. Versions later than VB 5 though provided the possibility of running VB applications multithreaded by using ActiveX EXEs, a counterpart to ActiveX DLLs. ActiveX DLLs are in-process routines which run in the same process as the calling application and hence work synchronously. In contrary, ActiveX EXEs are out-of-process routines, which run in a separate process and hence work asynchronously. (You can get an insight of in-process and out-of-process components and its features if you see any COM article).

Here, I shall try to explain to you the implementation of asynchronous processing dealt with VB and with VB.NET. I shall in turn take a small example, where a routine unnecessarily makes some delay (necessarily to explain the scenario here, though) through a sleep event.

With VB

Asynchronous components in VB, as we saw will be implemented with ActiveX EXE. (A project of ActiveX EXE type has to be created to develop an ActiveX EXE component). The basic steps involved in creating this would include:

  1. Including the procedure into an ActiveX EXE, and let them be private
  2. Include a wrapper method to call the private procedure, which needs to be run asynchronous. Well, the wrapper just doesn�t do this alone (which makes no difference between this and the original), but it also incorporates a timer that it enables. When the timer event fires, the original method is called.

Note: This sample that I�ve sketched is based on the example, which is available in vbaccelerator.com, which I�ve found by far as the best way to implement the ActiveX EXEs. I�ve tried to explain this piece of code in detail.

The idea of having a timer doesn�t mean that we are forced to use a form that can hold the timer. We can as well have a class, which provides the functionality of a timer. You can find this here and at many other sites, though I suggest the one mentioned.

Also, instead of directly referencing the object instance in the module, an error-free interface, Runnable, a type library that you will find in the MSDN�s CodeFlow sample is being used.

' This routine will call the method asynchronously. This uses a timer to

' fire the Runnable_Start() implementation, 

' which ensures we yield control back 

' to the caller before the processing starts. 

' This ensures that the processing runs 

' asynchronously to the client.

The class module will look like this (I�ve excluded the API�s and other declarations for readability of the core function)

cAsync.cls

' This is the wrapper routine, which in turn

' calls the original routine but within a 

' timer. This call would be asynchronous.

' You can call the Runnable_Start() directly 

' which would make the call synchronous.

 
Public Sub Start()
   If Not m_bRunning Then
      m_bRunning = True
      mStart.Start Me
   Else
      ' Just checking....

      Err.Raise 32540, App.EXEName & ".cAsync", "Already running."
   End If
End Sub
 
 
' A routine which makes some delay and 

' raises an event (Callback) to the calling 

' Function when the processing is complete or interrupted.

 
Private Sub Runnable_Start()
   Dim i As Long
   Dim bCancel As Boolean
   
   ' Begin work:

   Do
      SleepAPI 100
      i = i + 1
      RaiseEvent Status(i, bCancel)
   Loop While (i < m_lInterval) And Not bCancel
   
   ' Completion status:

   If i = m_lInterval Then
      ' Success:

      RaiseEvent Complete
   Else
      ' Failure:

      RaiseEvent Cancelled
   End If
   ' All done:

   m_bRunning = False   
End Sub

mStart.bas

(Callback interface is used, which in turn needs the address of the function, and this forces us to use a module which provides this option).

Private Sub TimerProc(ByVal lHwnd As Long, ByVal lMsg As Long, _
    ByVal lTimerID As Long, ByVal lTime As Long)
   Dim this As Runnable
   ' Enumerate through the collection, firing the

   ' Runnable_Start method for each item in it and

   ' releasing our extra lock on the object:

   With m_colRunnables
      Do While .Count > 0
         Set this = .Item(1)
         .Remove 1
         this.Start
         'Ask the system to release its lock on the object

         CoLockObjectExternal this, 0, 1
      Loop
   End With
   ' Remove the timer:

   KillTimer 0, lTimerID
   m_lTimerID = 0
End Sub
 
 
Public Sub Start(this As Runnable)
   ' Ask the system to lock the object so that

   ' it will still perform its work even if it

   ' is released

   CoLockObjectExternal this, 1, 1
   ' Add this to runnables:

   If m_colRunnables Is Nothing Then
      Set m_colRunnables = New Collection
   End If
   m_colRunnables.Add this
   ' Create a timer to start running the object:

   If Not m_lTimerID Then
      m_lTimerID = SetTimer(0, 0, 1, AddressOf TimerProc)
   End If
End Sub

This is a very basic sample of how to implement ActiveX EXE in the Visual Basic 6 environment.

This is the first part of this article that explains the basics of asynchronous processing and how it is implemented in VB6. I shall, in the next part of this article, give a solution in VB.NET, and explain how different it is and how sophisticated it is to develop the same.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here