Using the Interop Forms Toolkit in VFP9 - IV
True Multithreading in VFP
In this 4th part I will describe here a way of
obtaining true multi threading with VFP and the Interop Toolkit Usercontrol. As
you know this is impossible in VFP alone although there are some ways of
achieving this through COM and use of timers.
The method for doing this has been adapted from the code found here:
http://www.codeproject.com/KB/vb-interop/VB6InteropToolkit2.aspx
You should also read this article thoroughly.
So fire up VB 2005 Express and create a new
Interop User Control project..See here for how. Name it MultiThreadedControl. Rename the
InteropUserControl.vb to bbInteropUserControl.vb
Open the control in design mode and add the following 3
objects to the user control:
Label -> change the Name property to LabelMessage
Progressbar
Backgroundwoker (found under components)
Arrange them so the control looks like this:
Now double click the control to open the code
window, and type in the following code as shown or copy and paste the code in
green below.
'Please enter any new
code here, below the Interop code
Public Event StartEvent(ByVal StartEventText As String)
Public Event FinishAsyncEvent(ByVal EndEventText As String)
Public Sub StartProcessing()
Try
' commented out see explanation later on
'RaiseEvent
StartEvent("Starting .NET process ...")
Me.BackgroundWorker1.RunWorkerAsync()
Catch
End Try
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object,
_
ByVal e As System.ComponentModel.DoWorkEventArgs) _
Handles BackgroundWorker1.DoWork
'wait for a while
Static prog As Integer = 0
' moved from SUB above. See explanation below.
RaiseEvent
StartEvent("Starting .NET process ...") While (prog < 100)
System.Threading.Thread.Sleep(250)
prog = prog
+ 2
Me.BackgroundWorker1.ReportProgress(prog)
End While
prog = 0
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender
As System.Object, _
ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
Handles BackgroundWorker1.ProgressChanged
Me.LabelMessage.ForeColor =
Color.Red
Me.LabelMessage.Text = "Working
in background..."
Me.LabelMessage.Visible = True
Me.ProgressBar1.Value =
e.ProgressPercentage
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal
sender As System.Object, _
ByVal e As
System.ComponentModel.RunWorkerCompletedEventArgs) _
Handles BackgroundWorker1.RunWorkerCompleted
Me.LabelMessage.Visible = False
RaiseEvent
FinishAsyncEvent("Background Interop User Control process finished.")
End Sub
Private Sub BackgroundWorker_Load(ByVal sender As
System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Me.ProgressBar1.Value = 0
Me.LabelMessage.Visible = False
End Sub
End Class
Correct any errors in your typing.
Make sure the backgroundworker has had the appropriate events set:
Also make sure that you turn on progress
checking as shown below:

That's it for the net part. Now build your
solution and an ActivexDll will be created called MultiThreadedControl.DLL and
will appear as an activex in VFP.
Switch over to VFP now and create a new form. Add objects and set their
properties as shown:
Edit2 is an editbox that is made ReadOnly and
the disabled BaclColor set to yellow.
Our Usercontrol is added at the bottom in the usual way an activex is added.
Now lets get on with the VFP side code.
In the button.click event add code as shown to first clear the editbox out,
then display a message and finally to kick off the background process. As you
type you can see Intellisense takes over and displays the Sub we exposed in
.Net
Public Sub StartProcessing()
Now you need to hook in the 2 events we exposed:
Public Event StartEvent(ByVal StartEventText As
String)
Public Event FinishAsyncEvent(ByVal EndEventText As String)
So doubleclick on the Interop control and select the StartEvent from the list.
You can see that VFP adds the appropriate parameter statement. Add code as
shown to broadcast the start event.
Funnily enough I was unable to get this event to
fire although the code to start the process does work.
Later on - Correction
It appears that you cannot raise an event within an exposed Method in a .NET COM if you call that method directly. You can only Raise the event if the trigger is within .Net.
In the code above :
Public Sub StartProcessing()
Try
RaiseEvent
StartEvent("Starting .NET process ...")
Me.BackgroundWorker1.RunWorkerAsync()
Catch
End Try
End Sub
I am calling the exposed SUB StartProcessing from my button and this in turn is Raising the StartEvent. This does not work in VFP and .NET.
So move the Event into the method that actually does the work. That is triggered within .NET and you can raise the event there.
RaiseEvent
StartEvent("Starting .NET process ...")
While (prog < 100)
System.Threading.Thread.Sleep(250)
prog = prog
+ 2
Me.BackgroundWorker1.ReportProgress(prog)
End While
Why this happens is anyone's guess but happen it does. Go figure.
![]()
Also add code to handle the FinishAsyncEvent as shown:
Before we finish, make sure the form has these
properties set:
Your form is ready to run. So just go ahead and
run the form. Type something in the Topmost editbox. Then click the process
button to kick off the background process in another thread.

You will find that you can continue typing in
the Editbox and do other things, while the process runs. Feedback on its
progress can be seen by the progress bar. Once the process has completed, you
are notified by the FinishAsyncEvent firing. This causes our final piece
of code to run and displays the message in the yellow editbox.

And there you have it. True Multithreading in
VFP with .Net. But why stop there. How about adding another MultiThreading
component. Below is an image of a form - multi2.scx, running 2 processes while
allowing you to type and do other processes.
In the next article I hope to show how you can spawn
multiple processes in separate threads using COM and a .Net MultiThreadFactory
object.
The complete source code for the above can be downloaded from the attachment link below:
Comment Notification
If you would like to receive an email when updates are made to this post, please register here
Subscribe to this post's comments using