Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Threads in VB

Status
Not open for further replies.

Themuppeteer

Programmer
Apr 4, 2001
449
BE

Hello,

I have the following problem:

- I go to my db to get some date,
- I do my recordcmd.execute,
- this takes a while, and the user gets the impression
that the system is frozen.
I want to solve this by letting some sort of image
moving or somthing so that the user knows he has to be
patient because the system is busy.
I think I need to put my recordcmd.execute in a thread.

Is this the way to do this ? and how do I do this ?
Does anyone know another way ?

ps: I'm working with MsChart, and while you're waiting, the program shows a white screen (size of the Mschart). I've already tried hiding first and after loading showing it again but that still gives me that blank screen.

Thnx.
 
No threading required, just the DoEvents command. Doevents allows other processes to run while waiting for a process to complete.

So you could have:

Call DrawGraph
DoEvents

frmWaiting.Show
DoEvents

Bill Paton
william.paton@ubsw.com

Check out
 
Thnx Bill,
I've already tried DoEvents,
but the problem is, in the frmWaiting I want an animation to happen (I have a little moon spinning around)
So on the frmWaiting form I placed a timer, and it lets the moon spin around.My frmWaiting form works perfect seperately.

But this is what happens when I add the form to my project:
- Data transfer starts
- frmWaiting is shown on screen
- The timer starts on frmWaiting and the moon changes once
from position (frmNr becomes 1) but then it stops and
waits till the data transfer is completed, whereafter it
continues spinning (while the form is already
invisible).I have already tried to put a doEvents
in my Sub tmrTimer_Timer() proc. but it still doesn't
work.


' the code of frmWaiting
Public frmNr As Integer
Private Sub tmrTimer_Timer()
frmNr = frmNr + 1
If frmNr > 8 Then
frmNr = 1
End If
imgMaantje(0).Picture = imgMaantje(frmNr).Picture
Me.Refresh
End Sub
Private Sub Form_Load()
frmNr = 0
imgMaantje(0).Move imgMaantje(0).Left + 2300, imgMaantje(0).Top - 1500
imgMaantje(0).Visible = True
tmrTimer.Enabled = True

End Sub

 
Ah, not that simple eh?

OK, maybe you do need some sort of threading.

You could try and have the Data transfer as a separate process by shelling it. You would need a way of letting your main app. know when the shelled process had finished. This could be controlled by a simple flag on an ACCESS table. On start of shelled process flag is set to true and then set to false by the Unload event. Your waiting form would poll the table and when the flag is false then unloads and draws the chart of the transferred local data.

If you don't want to use a flag on the table you could check for the existance of your shelled process in the task list. There is some code for this in the FAQ area.

I hope this helps.

Bill Paton
william.paton@ubsw.com

Check out
 
Actually, what DoEvents does is to relinquish control of the cuurent thread (remember that VB is single threaded) and allow it to process any pending messages in the current process' event queue. DoEvents, in my opinion, is a command that should only be used when absolutly neccesary (such as allowing a screen to refresh while performing an intense looping function) since it raises several other issues that have been addresses here in a previous thread.
WP recommendation of a seperate process is a good one and can be used to simulate multiple threading. Just remember however if you are going to mmake a call to a COM interface on an ActiveX EXE to get you data, the call will be synchronous and your current app will still be locked. If you simply shell out the command the call can then be made asynchronously, but you still need a way to get the data back into your own process space.
Another option to consider, if you are using ADO for your data access is to use ADO's built it asynchronous processing to get the data that you need. ADOwill fire an event that your app can respond to when it has its data and then you can use it. In the meantime, your application will not be locked up at all.
Finally, VB.Net (when released) will give us a free threading model which will make issues like this go away (while giving birth to a whole new realm of issues if developers are not careful). Personally, I can hardly wait to get the production version of VB.Net when it is ready. Until then, you will have to rely on C++ to do multithreading. - Jeff Marler B-)
 
Write an Active X exe class to do that work, It will run in its own thread
 
Collin,
Yes, you are correct when you state that an ActiveX EXE will wun in its own thread. This is an excellent method to imitate multi-threading in VB6 - of course, this is assuming that you don't mind the overhead of creating multiple processes.
The real trick here however is how to start the function call. Remember that the call to an out of process COM server (i.e. ActiveX Exe) is still a synchronous call and that call will lock up the first thread while you are waiting for the call to return. To build upon your idea of the ActiveX Exe, consider using MSMQ as a go between for the 2 processes. Process 1 would deposit a message/job request into MSMQ and then go back to whatever it needed to do . . . in the meantime, process 2 would see the message, extract it and then begin processing the request. - Jeff Marler B-)
 
Why not populate the recordset asynchronosly? (Did I spell that correct? :)

Code:
rs.Open "Select * From tblSomeTable", cnn, , , adAsyncFetch

Then execute the Moon-code until the FetchComplete event occurs.

Note that you must declare your recordset using the WithEvents keyword to gain access to the events.

Good Luck!
-Mats Hulten
 
MatsHulten brings up a very good point (and one that I touched upon in this thread 4 posts ago). If the ONLY thing you need asynchronous processing for is Data Access (reading and/or writing), just use ADO. This way, everything is still inprocess and the app should perform better than it would having to make serveral cross-process calls.
Also as MatsHulten suggested, use WithEvents in your variable declarations so that ADO can inform you when it has completed. - Jeff Marler B-)
 
Alternatively you could try the follwing within your ActiveX.exe to imitate Java out-of-process style threading model in VB.
I use this.

This will give you a 'real' asynchronous effect.

' ==============================================================
' FileName: mStart.bas
' Author: SP McMahon
' Date: 2 February 2000
'
' This BAs module gives you the code you need to implement the
' Java out-of-process style threading model in VB. Just
' add it to an ActiveX EXE, reference Runnable.TLB and then
' do this in your ActiveX EXE:
'
' Implements Runnable
'
' Public Sub Start()
' mStart.Start Me
' End Sub
'
' Private Sub IRunnable_Start()
' ' Do your code here. It will run async against
' ' the calling app.
' End Sub
'
'
' based on the Codeflow sample © 1997 Microsoft
' from Microsoft. Microsoft has no warranty,
' obligations or liability for any code used here.
'
' ==============================================================


' To prevent object going out of scope whilst the timer fires:
Private Declare Function CoLockObjectExternal Lib "ole32" ( _
ByVal pUnk As IUnknown, ByVal fLock As Long, _
ByVal fLastUnlockReleases As Long) As Long

' Timer API:
Private Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, _
ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) _
As Long
Private Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, _
ByVal nIDEvent As Long) As Long

' Collection of Runnable items to start:
Private m_colRunnables As Collection
' The ID of our API Timer:
Private m_lTimerID As Long

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


 
Appologies... you also need a type library that goes with this.
Runnable.tlb.. If you want it I can mail it.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top