Welcome to Foxite.COM Community Weblog Sign in | Join | Help

Bernard Bout

May the Fox be with you...




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:

Published Tuesday, April 15, 2008 3:00 PM by bbout
Attachment(s): VFPMultiThreaded.zip

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 RSS

Comments

# re: Using the Interop Forms Toolkit in VFP9 - IV @ Tuesday, April 15, 2008 10:42 AM

Good one Bernard, thank you for sharing it

Luis Navas

# re: Using the Interop Forms Toolkit in VFP9 - IV @ Wednesday, April 16, 2008 5:54 PM

Hi Bernard,

Thanks a lot for introducing the Interop Forms.
You're opening some really interesting doors.

For the purpose of Multithreading, have you already looked at Claude Fox's project ?

http://www.codeplex.com/mtmyvfp

Regards

Cesar

Hi Cesar

I have. It uses a VFP MT DLL. As I mentioned in my post, it is somewhat possible using a COM server.

This method is true multi threading since the whole process runs in a separate thread and there are callbacks also to show progress. Besides it will expose some of the VFP community to .NET which is not such a bad thing.
Bernard

Cesar

# re: Using the Interop Forms Toolkit in VFP9 - IV @ Monday, April 21, 2008 1:34 PM

Cool!

John Reviews

# re: Using the Interop Forms Toolkit in VFP9 - IV @ Thursday, April 24, 2008 12:52 PM

Thank you very much for the great tool,
And thanks a lot for sharing it.
Please keep the good things going.
Best Regards
Tarik

Tarik Alkathiri

What do you think?

(required) 
required 
(required) 
Powered by Community Server, by Telligent Systems