Solved

Help using the timer control

Posted on 2001-08-24
27
206 Views
Last Modified: 2008-02-01
Hi All!

I'm trying to write an SMS gateway program that supports more than 1 GSM Modems. So for example if i have 2 GSM Modems installed at comm port 1 and 2.

I need to check these 2 modems whether there's any new messages... so my method was to create 2 timer objects using late binding that will poll each of the modem

My question is, will these two timer events run concurrently or will it process the modem1 first followed by modem 2??

Thanks
0
Comment
Question by:boonhui78
  • 8
  • 5
  • 5
  • +6
27 Comments
 
LVL 1

Expert Comment

by:kdg2000
ID: 6421317
The events can be fulfilled together, only timer events it is necessary start in separate streams.
0
 
LVL 4

Expert Comment

by:wile_e_coyote
ID: 6421848
The two timer events will run concurrently.  Assuming that the "interval" property of both timers is equal, the timers will PROBABLY fire in the order in which they are enabled.  e.g. If timer1 is enabled first, then timer1's event will probably fire first.  However, your code should not depend on the order in which the timers fire.  

I assume that your goal is to ensure that your program gives each modem the same amount of attention.  It appears to me that your solution accomplishes that goal.
0
 
LVL 3

Accepted Solution

by:
adg earned 50 total points
ID: 6423138
Depends on what you mean by concurrently.  As wile_e_coyote mentions the timers will "run" concurrently but unless you are multi-threading, (which is tricky in VB6) only one port will be processed at a time.  If your timer kicks off processing on com1, processing on com2 won't run concurrently. It will wait for the processing on com1 to complete unless you explictly allow it.  The easy way to do this is with the "doevents" statement which is very slow and will probably cause you to drop data.  

If you are looking for decent thruput, I don't think this is a good solution.  
0
Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

 
LVL 4

Expert Comment

by:wile_e_coyote
ID: 6423201
Ooops!  Mea culpa: adq is correct.  Once one of the timer events fires, the code in the associated event handler is going to run to completion before the other timer event fires. As adq said DoEvents is a crude, but dangerous way around this.  Unfortunately, there isn't a real easy way to multi-thread in VB.

Next time, I'll wait for the caffine to take effect before I answer the question <g>
0
 
LVL 3

Expert Comment

by:adg
ID: 6423229
Thanks wile_e_coyote!

boonhui78, here is a small example to illustrate.  You can see that timer2 events are triggered but not actually processed until the next second (cause timer1 process is being greedy).

Option Explicit
Private Sub Command1_Click()
    Timer1.Enabled = False
    Timer2.Enabled = False
End Sub
Private Sub Form_Load()
    Timer1.Interval = 400
    Timer2.Interval = 100
End Sub
Private Sub Timer1_Timer()
    Dim s As String
    Debug.Print "Timer1 " & Time$
    s = Time$
    Do While s = Time$ ' hold control until next second
    Loop
End Sub
Private Sub Timer2_Timer()
    Debug.Print "Timer2 " & Time$
End Sub
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6425574
I think if you want two timer working concurrently, you could create the two timers with API:

http://support.microsoft.com/support/kb/articles/q180/7/36.asp?FR=0



0
 
LVL 12

Expert Comment

by:roverm
ID: 6426560
Richie is correct: You can only do this running API's:

place this in a module:

Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long

Public Timer1 As Long
Public Timer2 As Long

Public Sub TimerProc1()
    If Len(Form1.Label1.Caption) > 0 Then
        Form1.Label1.Caption = ""
    Else
        Form1.Label1.Caption = "Timer 1"
    End If
End Sub

Public Sub TimerProc2()
    If Len(Form1.Label2.Caption) > 0 Then
        Form1.Label2.Caption = ""
    Else
        Form1.Label2.Caption = "Timer 2"
    End If
End Sub

and this in a form:

Private Sub Command1_Click()
    Timer1 = SetTimer(0, 0, 100, AddressOf TimerProc1)
    Timer2 = SetTimer(0, 0, 60, AddressOf TimerProc2)
End Sub

Private Sub Form_Unload(Cancel As Integer)
    KillTimer 0, Timer1
    KillTimer 0, Timer2
End Sub

Place a commandbutton (Command1), and 2 labels (Label1 and Label2) on the form and run.

NOTE!!!: Do NOT end the program using the VB-IDE but using the close button of the form. Then the timers are killed !!

D'Mzzl!
RoverM
0
 
LVL 3

Expert Comment

by:adg
ID: 6427386
roverm, I don't think that works any better because it is still in a single-thread. I took your code and modified timerproc1 to hold control until the next second (as in my earlier example).  Timerproc2 is not kicked off until timerproc1 releases control.  

Boonhui78, are you using the MSCOMM control?  If so, why are you polling the ports? You could eliminate a layer of complexity by letting the control trigger the processing rather than trying to set timers.  Of course, you'll still be single-threading but that might not be a problem depending on your processing requirements...
0
 
LVL 3

Expert Comment

by:adg
ID: 6427389
Roverm, just out of curiosity, what does d'Mzzl mean?
0
 
LVL 12

Expert Comment

by:roverm
ID: 6427691
Boonhui78:
I think the to timers will work this way. It's just the way that you handle the events.
If you do lengthy coding in the Timer_Event then you could run into a problem, running a single thread.
But if you set a boolean whenever a GSM-call is detected and handle it in the normal code you should get a better result.
But, adg, I agree, to really do this right, you have to runs several threads.

D'Mzzl! (adg: GoodBye!)
RoverM
0
 

Author Comment

by:boonhui78
ID: 6429089
So is any1 able to show me a simple example to do this using threads?? btw i heard that vb has a very bad support for threads and it's very unsafe... is it true??

thanks,
eric
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6429278
Please, don't use "fake" multithread.
Take a look at:
http://www.desaware.com/articles/threadingL3.htm
0
 
LVL 3

Expert Comment

by:adg
ID: 6429873
Here's an example of multi-threading in VB6. It processes files, not ports, but the idea is the same.

As mentioned, multithreading in VB6 is tricky.  From what I've read, support for multithreading in VB.NET is much different (better, I hope) so be aware that this approach may not be maintainable in the long-run.  This cannot be tested from within the IDE.  You have to compile it and run it separately.  That is because the IDE is inherently single-threaded.    Note that this is an ACTIVEX EXE project not a standard EXE. See the program comments for   appropriate settings that are essential to making this work.  Note the use of timers in the ProcessFile to start the processing within the previously created threads.  Without that your threads will run sequentially.  You'll still have multiple threads (as proved by report record count which displays the thread id) but the startup of the second and third threads will be delayed.  Also note that sub main is automatically executed at the beginning of each thread (4 times in this example).  Since there is code that must only be done one time, the find window API is used to figure out if we are on the first thread or not.

All that being said, you might want to avoid the entire issue (if possible) by having an app that processes a single port and then running two instances of it.  I would recommend avoiding multi-threading in VB6 if you can.  One reason is that it is very difficult to communicate between threads without creating unintentional serializations,  it can be done but it is tricky.  (yes, even more tricky). You can spend a lot of time making VB6 do things that it doesn't do well.


' MainModule.bas

' ActiveX EXE Name = MTNF
' Startup Object = Sub Main
' Threading Model = Thread per Object
' Start Mode = Standalone
' !!! Must compile and run outside IDE !!!
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal
lpWindowName As String) As Long
Private frmMainThreadForm As MainThreadForm
Private Const PROC_CAPTION = "MTNF Main Thread Form"
Private Thread1  As ProcessFileObject

Sub Main()
   If 0 = FindWindow(vbNullString, PROC_CAPTION) Then
       'MsgBox "Main = " & Hex(App.ThreadID)
       Set frmMainThreadForm = New MainThreadForm ' create first form on pre-existing thread
       frmMainThreadForm.Caption = PROC_CAPTION
       Set frmMainThreadForm = Nothing 'don't need this reference, form loads itself and stays alive
until unloaded
   End If
End Sub

Public Sub CreateThreads()
  Set Thread1 = CreateObject("MTNF.ProcessFileObject")
  Thread1.ProcessFile "a.txt"
  '
  Set Thread1 = CreateObject("MTNF.ProcessFileObject")
  Thread1.ProcessFile "b.txt"
  '
  Set Thread1 = CreateObject("MTNF.ProcessFileObject")
  Thread1.ProcessFile "c.txt"
  Set Thread1 = Nothing
End Sub

Public Sub ReportRecordCount(FileName As String, RecCount As Long)
   MsgBox FileName & " contains " & CStr(RecCount) & " records. Reported by Thread " & Hex(App.ThreadID)
End Sub

==============================================
' MainThreadForm.frm

Private Sub Form_Initialize()
    Timer1.Interval = 100
End Sub

Private Sub Timer1_Timer()
   Timer1.Enabled = False
   CreateThreads
   Unload Me
End Sub

==============================================
' ProcessFileObject.cls

Private frmTimerForm As TimerForm
   
Private Sub Class_Initialize()
   'MsgBox "Worker = " & Hex(App.ThreadID)
End Sub

Public Sub ProcessFile(FileName As String)
   Set frmTimerForm = New TimerForm
   frmTimerForm.SetOwner Me
   frmTimerForm.StartTimer FileName
End Sub

Public Sub RecordCount(FileName As String)
   ' add project reference to Microsoft Scripting Runtime
   ' to use File System Objects
   Dim fso As New FileSystemObject
   Dim fil1 As File
   Dim ts As TextStream
   Set fil1 = fso.GetFile(FileName)
   Set ts = fil1.OpenAsTextStream(ForReading)
   ts.ReadAll
   ReportRecordCount FileName, ts.Line
   ts.Close
   Set frmTimerForm = Nothing
End Sub
==============================================
' TimerForm.frm

Private objOwner As ProcessFileObject
Private strFileName As String

Public Sub SetOwner(objRef As ProcessFileObject)
   Set objOwner = objRef
End Sub

Public Sub StartTimer(FileName As String)
   strFileName = FileName
   Timer1.Interval = 55
End Sub

Private Sub Timer1_Timer()
   Timer1.Enabled = False
   objOwner.RecordCount (strFileName)
   Set objOwner = Nothing
   Unload Me
End Sub
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6430044
One thing comes to  me:
Encapsulate code posted by Roverm and Me in an actice x dll, compile it and refrence in your project.
Create TWO instances of it as:

dim withevents Tmr1 as ClsTimer
dim withevents Tmr2 as ClsTimer

form_load
set Tmr1=new ClsTimer
set Tmr2=new ClsTimer
end sub

Those withevents are timer_timer event that belongs to Windowproc from the bas module.
I hope it works.
0
 
LVL 3

Expert Comment

by:adg
ID: 6430257
I think that code in a DLL (activex or otherwise) will always run on the calling thread.  So if the calling application is single-threaded, using unique instances of a DLL won't be an improvement in that it will still be single-threaded.  I've never actually tried it though - just an opinion.  
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6430695
They will run in same memory space, same thread? i don't know. Never did a try.
0
 
LVL 3

Expert Comment

by:adg
ID: 6430776
Yeah, I haven't tried it either but my understanding is that when creating an object from a DLL, the object is always in the same process and same thread as the caller regardless of the location of the DLL.  But creating an object from an ActiveX EXE can be same thread, or same process different thread, or even a different process.  And if the object is created in a different process it can even be on a different machine which I find amazing.
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6431990
so, creating an active x exe...?
0
 
LVL 3

Expert Comment

by:adg
ID: 6433225
so creating an active x exe, like the one I posted above, allows creating multiple threads in the same process without API calls.
0
 
LVL 12

Expert Comment

by:roverm
ID: 6441874
This is for using the COMM ports (up to 4 !) WITHOUT the MSComm control:

http://www.thescarms.com/vbasic/CommIO.asp

D'Mzzl!
RoverM
0
 
LVL 4

Expert Comment

by:wile_e_coyote
ID: 6441940
boonhui78

I suggest you reject my bogus answer and unlock the question so that other people have the opportunity to post their comments as answers.  Sorry about anwering so quickly (and inaccurately <g>)
0
 

Author Comment

by:boonhui78
ID: 6443334
Hi RoverM!

It's ok =)
Everyone here is learning rite??

Eric
0
 
LVL 12

Expert Comment

by:roverm
ID: 6443753
boohui78:
>>It's ok ??
What's ok ? Is your problem solved ?
0
 
LVL 12

Expert Comment

by:roverm
ID: 6483818
boohui78:
You did post a request for deletion.
Is your problem solved? Did any expert help you into the right direction ? If so: Can you close it by grading ?
Or can we PAQ it ?

D'Mzzl!
RoverM
0
 
LVL 3

Expert Comment

by:modder
ID: 6484764
monitoring this question

modder
Community Support Administrator @ Experts-Exchange
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7202498
Hi boonhui78,
It appears that you have forgotten this question. I will ask Community Support to close it unless you finalize it within 7 days. I will ask a Community Support Moderator to:

    Accept adg@hp's comment(s) as an answer.

boonhui78, if you think your question was not answered at all or if you need help, just post a new comment here; Community Support will help you.  DO NOT accept this comment as an answer.

EXPERTS: If you disagree with that recommendation, please post an explanatory comment.
==========
DanRollins -- EE database cleanup volunteer
0
 
LVL 5

Expert Comment

by:Netminder
ID: 7215999
Per recommendation, force-accepted.

Netminder
CS Moderator
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction While answering a recent question about filtering a custom class collection, I realized that this could be accomplished with very little code by using the ScriptControl (SC) library.  This article will introduce you to the SC library a…
When designing a form there are several BorderStyles to choose from, all of which can be classified as either 'Fixed' or 'Sizable' and I'd guess that 'Fixed Single' or one of the other fixed types is the most popular choice. I assume it's the most p…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question