Solved

Asynchronous Function Calls

Posted on 2001-07-04
27
574 Views
Last Modified: 2008-02-01
Hi,

Is it possible, without the use of a timer, to make asynchronous calls to an activeX exe. Both the main app and the activeX exe are vb programs, but I don't want the main app to wait for the completion of the activeX exe's function call.

So, for example, if the activeX exe had a sub called test_sub which takes 5 minutes to execute, can the main app call it and return immediately, leaving the activeX exe to process the request?

Thanks,

Zaphod.
0
Comment
Question by:Z_Beeblebrox
  • 9
  • 9
  • 5
  • +3
27 Comments
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 6252863
Actually, timers is the easiest option...

You could try to use the "old" DDE technique, but i prefer the timers...

Cheers
0
 
LVL 3

Expert Comment

by:RodStephens
ID: 6253028
To expand on the Timers answer, give the ActiveX EXE a timer. When the public method is called, have it enable the timer and return.

When the timer fires, the ActiveX EXE disables the timer and does its thing. When it finishes, it raises an event so the main program knows what happened.

Note that the ActiveX EXE must not raise any errors while running from the timer. At that point, the main program cannot catch the error so the ActiveX EXE will crash. If it needs to notify the main program of an error, it should raise an Error _event_ rather than throwing an error.
0
 
LVL 15

Expert Comment

by:ameba
ID: 6253915
Instead of using:
    Timer1.Enabled = True
and then writting code in
    Sub Timer1_Timer()

you can use:
    frmCD.Show
and write code in frmCD's event:
    Sub Form_Activate()

or:
    pic1.SetFocus
and write code in:
    Sub pic1_GotFocus()

or you can avoid VB Timer control by using SetTimer/KillTimer APIs in a class /module (a bit hardcore)


Sample ActiveX which uses Form_Activate:
"Non modal common dialog" (15 pts)
http://www.experts-exchange.com/jsp/qShow.jsp?ta=visualbasic&qid=20137309
0
 
LVL 1

Expert Comment

by:khampton
ID: 6254459
Since the caller is in a different process space than the activeX.exe - you are ASYNCHRONOUS!!!!

The answer to your question is YES.  This is default. (Test it and see.  Put a timer on each one and disply the current time and use doevents to refresh. You will see that both timers are refreshing thus proving that you are automatically in async mode).

 You would have to set up another scheme if you wanted to make the two activities synchronous. You would have to use a polling technique or a call back technique, etc. But this is going outside the scope of your question...

0
 
LVL 15

Expert Comment

by:ameba
ID: 6254572
> you are ASYNCHRONOUS!!!!
I am not!    :-)
0
 
LVL 4

Expert Comment

by:Nazdor
ID: 6255137
khampton - works fine if all you are doing is displaying the time, but if you have a process which takes 5 minutes, it will freeze the rest of the thread until complete.  Eg, have two timers that fill a listbox with lots of values, start the second half-way through the first, it will 'cut-in' and the first will stop loading the listbox until the second has finished then continue - this is not asynchronous, this is interupts.
0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6255943
Hi,

Maybe I wasn't clear enough. What I am looking for is a way for one app to call a method in an activeX exe app without waiting for that function to complete, and without using timers.

For example, if the activeX exe had a class called class1 with the following method

Sub Test()
Do While True
Loop
End Sub

and the main app called it thus:
Dim c as class1
c.test
msgbox "done"

The msgbox should come up instantly, despite the fact that the activeX exe is in an infinite loop. A cheap example but I hope it illustrates the point.

Zaphod.
0
 
LVL 4

Expert Comment

by:Nazdor
ID: 6256094
Perhaps the reason you got lots of responses involving timers is because what you are asking isn't possible without them.

There's no easy 'fork()' function in VB although you could use CreateThread() to start a new thread, but that's not exactly easy and VB doesn't like it very much (something to do with not being COM compliant).

0
 
LVL 15

Expert Comment

by:ameba
ID: 6256112
>Sub Test()
>   Do While True
>   Loop
>End Sub

Sub Test()
  ' Do While True        ' this code has been moved
  ' Loop                 ' this code has been moved
   FormX.Show
End Sub

' FormX (FormX is in ActiveX project)
Private Sub Form_Activate()
   Do While True
   Loop
End Sub
0
 
LVL 15

Expert Comment

by:ameba
ID: 6256141
Or, in one sentence:
- move code which does the 'real work' from Sub Test to some non-blocking event.
0
 
LVL 1

Expert Comment

by:khampton
ID: 6258149
I still have to say that the activeX.exe is asynchronous!  The example that Nazdor gives freezes the first app because its hogging resources BUT ITS ON A SEPERATE THREAD!!!  

So, if you insert a sleep API call or a doevents in the processing loops, you will be able to run both apps!

Z Beeblebrox:  Try this:

Put a doevents in the loop. (I generally don't recommend doevents as a rule).  Or try putting in a sleep API call for say 55 ms.   I think this will verify that you are running on 2 seperate threads.
0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6258164
Hi khampton,

I realize that they are running in different *processes* but the problem this that the parent makes an out of process synchronous call to the child. So while the child is processing, if you try to do anything on the parent, you get the message "The application (whatever) is not responding... wait or retry" (not those exact words). It is this situation that I am trying to avoid. If I call a sub in an activeX exe there is no return value, and I don't want to wait for it to finish, then I should be able to just call that sub and then continue on, even if that sub takes hours to complete, it should have no effect on the parent app. From the comments so far, it seems that there are only two ways to do this, either by using a timer, or using an event that gets generated indirectly from the code (ie. form_activate). I know form load event won't work, but what other events are there that I can use?

Zaphod.
0
 
LVL 1

Expert Comment

by:khampton
ID: 6262046
Here is a trick:

Give the ActiveX.exe a routine that will collect parameters from the caller.  (how long to process before resting (Call this ProcessDuration), how long to rest (call this RestingDuration)).

Pass this info from the class interface to a form (in the same project) with 2 timers on it: The MasterTimer and the ProcessingTimer.

The MasterTimer will activate the processingTimer. The ProcessingTimer will run for the ProcessDuration then it will quit until it is reactivated.

 


 sub ProcessTimer_timer()
   static bVal as boolean
   bVal = not bVal
   if bVal = false then
      ProcessTimer.Enabled = false'quit for now
      exit sub
   end if

     'do some real work here....
      '
      '
 end sub

  Since the Master timer is on a longer loop (ProcessDuration + RestingDuration) control should be passed back to the caller until its time to activite the ProcessingTimer again... (It's the Master Timer to reactivate the ProcessingTimer - ie: if ProcessingTimer.enabled = false then ProcessingTimer.enabled = true)

You can of course skip the form and use a timer class.  Thats just a little bit more complicated but its real cool...

Hope this helps.


0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Expert Comment

by:khampton
ID: 6262552
I'm sorry, you asked how to do it without timers.  I must also appologize - the way you are calling the ActiveX.exe is Sychronous (I was thinking of something else - I've been working too many hours, etc.)

If you get MSDN, you may find the following article interesting:

"Reduce Long Waits with Threads".

It details how to write a generic thread manager.

P.S. Don't try to multithread a VB application EXCEPT by using ActiveX.exe's...Lots of warnings out there about this.  Best to use C++.

Ok, if you are interested in a Timer Class that will let you have the functionality of a timer without having a form, let me know and I will post the code.
0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6310972
So the answer is that there is no way, so who do I give the points to?

Zaphod.
0
 
LVL 15

Expert Comment

by:ameba
ID: 6311660
>So the answer is that there is no way
Is it?  You didn't read all posts, did you?
0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6315384
Sorry about that ameba. You can have the points if you can tell me an event that I can use that does not require a form, so that I can use this to run a function without disturbing the user interface.

Zaphod.
0
 
LVL 1

Expert Comment

by:khampton
ID: 6317641
I really think the formless timer, originally mentioned by
ameba, is the way to go.

If you want to create a class that will function as a "formless" timer - see: Q231298 from MSDN or the MS-Knowledgebase. It will give you the exact code you need.

Also, you may know that you can put code in an ActiveX.exe that will detect if it is running in standalone mode. That means that you can shell it with a commandline.

(That is something that I do often and thus my mistake of insisting the ActiveX.exe was asynchronous).


0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6318172
Hi,

The code in that Q will not work, since it busy-waits for the timer to expire. To do asynchronous calling, I will need a call back method. Something like posting a message to a form would work, except that I don't want to have to have a form. Is there any other api call which I can call which will call back write away or nearly so?

Zaphod.
0
 
LVL 1

Expert Comment

by:khampton
ID: 6319237
I thought the timer was used just to launch the activex.exe and then return.  

I agree that a call back would be very useful.  I don't think you can use callbacks within vb code.  C++ uses callbacks to notify a basic module function.  Thus, you can write a simple routine in c++ to create the timer, etc and make a callback to your basic module when done.  

But this is visual basic land so I'm not sure this is what you had in mind.
0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6319696
I looked at the code in that KBQ you mentioned, and in it, the way it does the timer is it loops until it expires. So where can I put this code? I need something that I can put in the activeX exe which will somehow initiate another function asynchronously. How? The standard form timer has the timer event, but the code you suggested has no events...

Zaphod.
0
 
LVL 1

Expert Comment

by:khampton
ID: 6319986
You would put the code in a class in the ActiveX.exe.

You would need 2 timers (the formless variety).

The first timer just launches the main processing routine and returns control back to the caller. Thus the asynchronous call.

The 2nd timer (in the ActiveX.Exe) monitors the progress via polling.  When the processing is done, it raises an event to the caller.

So, in other words, you create the activex.exe by using the withevents keyword:

Dim withevents objX as MyObjectNameAndClass

Lets Say that the event name is ProcTerminated(Reason as string)

Your activex.exe would raiseevent ProcTerminated("SUCCESS") for a good return or

ProcTerminated("FAIL-TIMEOUT")  

ETC.

0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6320337
There seems to be a break down in communications here. First, I don't need to notify the caller that the operation is complete. So I only need one timer. But I still don't see how I can do what you suggest with the first timer. How exactly does it launch the main processing routing and return control back to the caller?

Zaphod.
0
 
LVL 1

Accepted Solution

by:
khampton earned 50 total points
ID: 6322641
You are right - communication breakdown...

As I mentioned previously, you can put a statement in your ActiveX.exe to detect if it was started up via standalone mode:

 If App.StartMode = vbSModeStandalone Then .....

Thus, as I mentioned previously, you can shell the .exe from your caller:

ret = Shell("MyActiveX.exe",0)

WHAT COULD BE EASIER?
 
(actually, its usually more of a problem to wait until the .exe is finished before proceding but luckily, thats not what you want to do).

The reason I mentioned the App.StartMode is because your ActiveX.exe could also be invoked as an object and you need to use a different method in the ActiveX.exe to handle this!


OK - now I will give you an example of a formless timer.  In this example I use a form just for display purposes.  I'm sure you can figure out how to implement this without the form:

1) Create a project with a form and a module.  In the module put:

Option Explicit

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 timerID As Long

Public Sub Timer_CBK(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, _
    ByVal SysTime As Long)
    ' In this example just display the system time in a label control
    Form1.Label1 = SysTime
End Sub


2) In the form put a command button and a label.  Add the code:

Option Explicit

Private Sub Command1_Click()
' the first two arguments must be zero
timerID = SetTimer(0, 0, 500, AddressOf Timer_CBK)
End Sub

Private Sub Form_Unload(Cancel As Integer)
KillTimer 0, timerID'must kill or a GPF will result!!!!!
End Sub


NOW, AFTER YOU VERIFY THIS WORKS, WRAP IT IN A CLASS (optional).  PUT A KILL TIMER SUB IN IT.  MAKE SURE YOU KILL THE TIMER IN THE TERMINATE EVENT.  

------------

Now that we are past that, all you need do is test to see if your ActiveX.exe is invoked as an object.  IF SO, start the timer routine.  Control will return back to the caller.  The timer routine should call your processing sub.  THIS IS A ONE TIME CALL SO IMMEDIATLY KILL THE TIMER.


Hop this helps...
0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6324546
Now that is what I am looking for. I don't know where the standalone stuff came from, but the timer function with the callback Timer_CBK should work. I will give it a try tonight.

Zaphod.
0
 
LVL 1

Expert Comment

by:khampton
ID: 6324635
>>. I don't know where the standalone stuff came from...

I mentioned in an earlier comment that you could detect if the activex.exe was shelled (or run from a prompt).

I assume that you realize that ActiveX.exe programs can be run as a standalone application or as an object.  An example of this would be MS-Word.

0
 
LVL 7

Author Comment

by:Z_Beeblebrox
ID: 6325154
Heh, another breakdown in communication. What I was trying to say is that I don't know what that has to do with the problem at hand, but nonetheless I do know about standalone activeX exe. Anyways, I tried it and your answer seems to work.

Thanks,

Zaphod.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Is an IP address in a Range 22 72
Excel object stays open 19 65
Microsoft Access combo box help 2 30
MS Date Picker 64 bit 32 bit issue 12 43
Introduction In a recent article (http://www.experts-exchange.com/A_7811-A-Better-Concatenate-Function.html) for the Excel community, I showed an improved version of the Excel Concatenate() function.  While writing that article I realized that no o…
This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

760 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

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now