Event handling with Activex EXE

I'm using an ActiveX EXE that generates events to other applications. What I want to know is how I can make the ActiveX EXE regain control BEFORE its clients finish to handle an event raised by it.
For example: when the ActiveX EXE raises an user defined event and one of its clients has a MsgBox in the event handling routine, the ActiveX remains frozen until the user clicks the OK button. I don't want this!!! What I want is: the ActiveX EXE raises the event and continues working, no matter what its clients do with the event.
Is there a way to do this?
mfogacciAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

sivanpCommented:
Try this:
In the ActiveExe project, add a form and put on it a timer control.
Init the timer control with this properties:
interval=1
enabled=false
In the the timer event put all the things you want to execute after the raise event, and disabled the timer control.
In the sub where you are raising the event, before you are calling the raiseevent, write:
<form name>.<timer control>.enabled=true

I think that it will work.I don't have here vb so I am apologize of not checking it first.
0
mfogacciAuthor Commented:
This will not work.
I can't do anything before raising the event. The clients will handle the event and deal with it. I can't "execute all the things" before raising the event simply because the ActiveX EXE don't know what to do, only its clients do.
0
sivanpCommented:
The raiseevent will accur first!
When you call the timer, the activeEXE execute the raiseevent immidiatlly after it.
After 1/1000 seconds (as you set the interval of the timer) the 'other things' will start to execute.

This is the way of doing asynchronic methods in Vb.
0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

Erick37Commented:
If you are running the program from the IDE, try compiling BOTH projects and see if the problem persists.  Events behave differently once compiled.  This is true for UserControls and may also apply to ActiveX EXEs.

http://support.microsoft.com/support/kb/articles/Q237/2/86.ASP

http://support.microsoft.com/support/kb/articles/Q177/9/96.ASP
0
mfogacciAuthor Commented:
sivanp: the problem is not if the raiseevent will occur first or second. The problem is that the 'other things' must be in the client code and not in the ActiveX EXE code. And if I raise the event and the clients code stops the execution waiting for user response, the ActiveX will be stopped too.
Erick37: I already compiled both projects and the problem persists.
Both of you: thanks for the comments, anyway.
0
Erick37Commented:
Show the dialog box non-modal?
0
mfogacciAuthor Commented:
It could be a palliative, but I can have other types of time-consuming tasks, like a database query. The MsgBox was only an example.
0
manojaminCommented:
use Threading model.

i.e. raise all the events in the new thread. Pseudo code...

at the point where you need to raise the event,

CareateThread with somestartupfunction
command execution will come back here immediately...
go ahead here...


the startup function
raiseevent
close the thread

hope this helps you...

OR

at the point where you need to raise the event,

timer.enabled = true
timer.interval = 100
wait for(120 milliseconds)
go ahead here..

in the timer event
timer.enabled = false
raiseevent
0
mfogacciAuthor Commented:
This seems to be a good solution. I have one little problem (excuse my ignorance): how do I create a thread?
Thanks...
0
manojaminCommented:
'Thread declaration and startup function

Option Explicit

Public Type PARAM_TYPE
    lValue As Long
End Type

Public Declare Function CreateThread Lib "kernel32" _
    (ByVal lpThreadAttributes As Long, _
    ByVal dwStackSize As Long, _
    ByVal lpStartAddress As Any, _
    ByRef lpParameter As Any, _
    ByVal dwCreationFlags As Long, _
    ByRef lpThreadId As Long) As Long

Public Function myThreadFunc(ByRef lpParam As PARAM_TYPE) As Long
    'RaiseEvent yourevent
End Function


'at the point where you want to raise event

    Dim hThreadId As Long
    Dim stParam As PARAM_TYPE
    stParam.lValue = 1
    myThreadHandle = CreateThread(0, 0, AddressOf myThreadFunc, stParam, 0, hThreadId)
'continue your code here. this is async function
0
mfogacciAuthor Commented:
manojamin, I REALLY appreciate your help, but I'm still in trouble here. I'm receiving an error from VB ("Invalid use of AddressOf operator"). According to VB Help I can use AddressOf only for Functions that are in a .bas module, but if I put myThreadFunc in a .bas module I can't raise an event from it. How can I solve this?
Thanks...
0
manojaminCommented:
let me work on it, I will come back to you... (just trying to put the extra parameter in the thread function with the class object supplied into it, so that .bas thread function should be able to raise event...)

Let me try (you should try too!)
0
mfogacciAuthor Commented:
I've already tried, but I can access only the methods and properties of the class. I still can't raise events.
0
manojaminCommented:
use setting global variable

for exaple,

g_MyClassObj as object

just before you call CreateThraed

g_MyClassObj = Me 'me here is calss object

in the Thread function,

g_MyClassObj.RaiseEvent

try it if it works!!

0
mfogacciAuthor Commented:
Unfortunately it doesn't work. I can only access methods and properties, not events.
0
TheAnswerManCommented:
Why don't you just add a class that has a Non modal messagebox.  You can use that in your Event Code modules.  
Yes yes yes, it would require that discipline be used, but it does work.
0
manojaminCommented:
Set g_MyClassObj = Me 'me here is calss object

in the class add

Public Sub CallBackMe()
   RaiseEvent yourevent
End Sub

in the thread function
MyClassObj.CallMe



0
manojaminCommented:
make that

in the thread function
MyClassObj.CallBackMe
0
mfogacciAuthor Commented:
manojamin: now I can compile without errors, but when I run, the ActiveX server crashes. Placing breakpoints I could observe that the Thread is created and the CallBackMe function is called but at the time that CallBackMe tries to raise the event, the crash occurs. I already tried to make the EXE files and run outside VB, but the result is the same.

TheAnswerMan: Like I said to Erick37 above, it could be a palliative, but I can have other types of time-consuming tasks, like a database query. The MsgBox was only an example.
0
manojaminCommented:
Mine even raises the event, goes back to the threadfunction and come back from there too! but at the end it DOES CRASH!!

I am trying to figured out... may be tomorrow...

0
AnswerTheManCommented:
it's known that procedure that raises a user defined event does not RETURN until
the event procedure (even on other component, other thread) - ends. !!!

that's just logical. the event procedure on the main app should not be accessed again until it's finished execution.

FROM MSDN :
""Caution:   Any time you temporarily yield the processor within an
event procedure, make sure the procedure is not executed again from
a different part of your code before the first call returns;
this could cause unpredictable results.
""

it can be ByPassed by creating another ActivexEXE that each event will be raised to a NEW instance of it. of course, you'll have to maintain a continues check upon those objects activity and destroy each one after ends its event handling.
this is VB eqvivalent to CreateThread.
tracking those objects can be done by having some public Boolean in them that will tell if the event procedure has terminated. they should be kept in some collection and be accessed every now and then in order to destroy those who ended their job.


As for concept :
1.
you are contradicting yourself when you give a MsgBox example.
A MsgBox goal is to halt system. you can't use it and complain about system hanging....(although, using the above suggstion - you can have all screen filled with MsgBoxes).
if you want just to alert the user without halting the system - write your own MsgBox which will be Not Modal form.
2.
i'm a heavy user of ActiveX EXE. in fact - i write almost everything as ActiveX EXE.
we talking THREADS here. the benefit is letting the system do all the black work of tasks, threads and events.
i use to make most activities *IN* the component code and *NOT* in the main app which is just a starter.
i see no point in LIGHT usage of component and calling the main app for every little gap. the component should be capable of doing whatever you want to call the app for, or call another component that will also run in his own thread.
what's the point of many threads running and calling one misrable thread alltogheter ?
0
mfogacciAuthor Commented:
manojamin: I will be waiting... Thanks!

AnswerTheMan: I'm not contradicting myselft at all. What I have is a real situation. I didn't explain it before because I wanted to be short, but I will do now.
My ActiveX EXE is a communication server that sends and receives messages via TCP/IP to other machines. It is raised by other component that makes the interface with the user. Sometimes, the interface must wait for some response from the user or do time-consuming tasks like database queries, in response of messages received. At this ocasions, the communication server MUST continue sending and receiving messages in background.
0
manojaminCommented:
I am am trying but no luck yet!

meanwhile, why don't you look at this site, it has what you need with different approch (as AnswerTheMan has suggested before, i.e. Modal and ModalLess forms, Timer etc...)

Creating an ActiveX EXE Component
http://msdn.microsoft.com/library/devprods/vs6/vbasic/vbcon98/vbconcreatingoleserver.htm

Read the whole document, go through the Topics...

I will keep continue to try my method!
0
manojaminCommented:
Wow!

Read this,

Performance of Visual Basic Multithreaded ActiveX Servers
http://msdn.microsoft.com/library/techart/msdn_multinvb.htm

It looks like that it is using the way I approched in different way...
0
manojaminCommented:
I think what we are missing is the word "Friend" in CallMe!
0
manojaminCommented:
I have tested the last comment code and IT DOES WORK!!!!!!

Add these two APIs in the module...


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

Wow!

Read this,

Performance of Visual Basic Multithreaded ActiveX Servers
http://msdn.microsoft.com/library/techart/msdn_multinvb.htm 

It looks like that it is using the way I approched in different way...

0
manojaminCommented:
'Here is the code if you want to test...

'Form1.frm

Private WithEvents myObj As Class1
Private Sub Command1_Click()
    myObj.Asynchronous_SelectionSort ("Test me")
End Sub
Private Sub Form_Load()
    Set myObj = New Class1
End Sub
Private Sub Form_Terminate()
    Set myObj = Nothing
End Sub
Private Sub myObj_SortComplete(vntSortedData As Variant)
    MsgBox vntSortedData
End Sub



'Module1.bas

Option Explicit

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

Public g_vntUnsortedData As Variant
Public g_objSort As Class1
Public g_TimerID As Long
Public Sub EnableOneShot(ByVal ulTime As Long)
    g_TimerID = SetTimer(0, 0, ulTime, AddressOf TimerCallback)
End Sub
Public Sub TimerCallback(ByVal hwnd As Long, ByVal uMsg As Long, _
                         ByVal idEvent As Long, ByVal dwTime As Long)
   
    'Kill the timer - we do not need it any more.
    KillTimer 0, g_TimerID
   
    'Use selection sort to sort the Global array.
    'SelectionSort g_vntUnsortedData
   
    'Raise the event to indicate sort is finished.
    g_objSort.FireSortComplete g_vntUnsortedData
   
    'Cleanup and exit.
    Set g_objSort = Nothing
   
End Sub


'Calss1.cls

'This is the event raised when the sort computation is complete.
Public Event SortComplete(vntSortedData As Variant)
'Below is the method called by the client to perform the asynchronous sort.
Public Sub Asynchronous_SelectionSort(vntUnsortedData As Variant)
    'Cache the array to be sorted.
    g_vntUnsortedData = vntUnsortedData

    'Cache the instance of this object.
    Set g_objSort = Me
   
    'Enable the Timer to fire in 100 ms – in the Timer event we do the work.
    EnableOneShot 100
    Debug.Print "after event"
End Sub
'This function will be called by a module-level function where
'the sort actually takes place.
Friend Sub FireSortComplete(vntSortedData As Variant)
    RaiseEvent SortComplete(vntSortedData)
End Sub


'hope this helps you...
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mfogacciAuthor Commented:
I think this works!
I have worked on another solution, that is similar: the ActiveX server raises the event normally. The client, at the event handling, put all the parameters received in a event queue and starts a timer with 1ms interval, doing nothing else. This releases the ActiveX server.
At the timer event, the client handle the event.
Is almost the same solution, but with the timer at the other side. It also works well.
Thanks for helping me. I believe that your help worth the 200 points or even more.
See you...
0
manojaminCommented:
Glad it worked and solved your problem...
0
DalinCommented:
Viewed
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.