Home All Groups Group Topic Archive Search About

Long process might fail...how to implement a timeout?

Author
21 Sep 2005 8:00 PM
YYZ
I've got a situation where in my program, at the start of it, I need to
instantiate an object (third party -- I have no control over it) and
then tell it to connect to its data source (again, no control over it).

It boils down to just 2 lines of code:

Set goSession = New Session
goSession.StartOffline sUserId, sPassWord

Basically, I have a form built that uses a class from vbaccelerator.com
to show an animation, and it keeps going even though those 2 calls can
take up to 30 seconds a piece to complete.  So, the user is happi(er)
because they get more than an hourglass to see that things are working.

However, sometimes the call to instantiate the object will fail (after
a LONG time, like a few minutes).  I know from experience that if it
takes longer than 45 seconds, it isn't going to work.  So, if that is
the case, I'd like to kill all the timers and things on the form and
unload it.

I tried adding a timer to the form to basically kill everything on the
form after 45 seconds, but that event doesn't get fired, running in IDE
or compiled, ever.

Any ideas on how I can basically simulate (or actually do) 2 processes
so that I can kill one if things aren't going to work out?

Thanks for any and all ideas, and I didn't explain things correctly,
I'll gladly provide more information.

Matt

Author
21 Sep 2005 10:29 PM
Ken Halter
"YYZ" <matt.da***@gmail.com> wrote in message
news:1127332810.082269.136310@o13g2000cwo.googlegroups.com...
> I've got a situation where in my program, at the start of it, I need to
> instantiate an object (third party -- I have no control over it) and
> then tell it to connect to its data source (again, no control over it).
>
> It boils down to just 2 lines of code:
>
> Set goSession = New Session
> goSession.StartOffline sUserId, sPassWord
>

Don't suppose you have the code for that 'Session' object eh? Any other way
to predict whether or not it'll fail? Once you make the call, if the Session
object doesn't expose 'Cancel' functionality, you're basically at its mercy
until it returns.

--
Ken Halter - MS-MVP-VB - http://www.vbsight.com
DLL Hell problems? Try ComGuard - http://www.vbsight.com/ComGuard.htm
Please keep all discussions in the groups..
Author
22 Sep 2005 1:34 PM
YYZ
> Don't suppose you have the code for that 'Session' object eh?

No, I dont' have the code.  It is a COM obejct created by a company who
also has a full blown application -- the Session object is just a way
to create our own forms and things that can do operations on their
database.  It's just a way to extend their product and allow
customization while still maintaining the integrity of their database.
Did that make sense?

> Any other way to predict whether or not it'll fail?

I can't think of any other way to predict if it will fail, but I'm only
about 3 days into using this object.  Maybe something will come up
later on.

I am going to try Someone's suggestion of an activeX exe -- for some
reason I had it in my head that I couldn't pass complex objects between
them...bad assumption!

Matt
Author
22 Sep 2005 12:35 AM
Someone
If you don't have the source for that object(Session), then here is one
solution. VB is not multi threaded so you have to make a work around. One
way is to divide it into Client/Server. The client is your current standard
EXE, and the server is an ActiveX EXE. This ActiveX EXE takes your request
and creates and waits for Session to finish, then notifies your EXE. This
ActiveX will have a hidden form and a Timer. You add a reference to this
ActiveX EXE to your current project and create a variable that points to it
like the following example:

Public SessionAgent As clsSessionAgent

Set SessionAgent = New clsSessionAgent

SessionAgent.StartSession ' This returns immediately
t = Timer
Do While Abs(Timer - t) > 45 And Not SessionAgent.Done
    DoEvents ' Or not
Loop
If Not SessionAgent.Done Then
    ' Timed out
    Set SessionAgent = Nothing
    '
    '
Else
    ' Success
    Set goSession = SessionAgent.GetSession
End If

In the ActiveX EXE, the code will look like this:

' In Module1
Public DoStartSession As Boolean
Public SessionEstablished As Boolean
Public Session1 As Session

' In Form1
Private Sub Timer1_Timer()
    If DoStartSession Then
        DoStartSession = False
        Set Session1 = New Session
        SessionEstablished = True
    End If
End Sub

' In clsSessionAgent

Public Sub StartSession()
    SessionEstablished  = False
    DoStartSession = True
End Sub

Public Property Get Done() As Boolean
    Done = SessionEstablished
End Property

' Gets the session after it has been established
Public Property Get GetSession() As Session
    GetSession = Session1
End Property

In this setup, the ActiveX EXE will "hang" in the Timer event until Session
object is created, leaving your App to do other things.

Here are some useful articles that explain some of what I am suggesting:

How To Create a DCOM Client/Server Application by Using Visual Basic
http://support.microsoft.com/default.aspx?scid=kb;en-us;266717

How To Create a DCOM Client/Server with Events by Using Visual Basic
http://support.microsoft.com/default.aspx?scid=kb;en-us;267836




Show quoteHide quote
"YYZ" <matt.da***@gmail.com> wrote in message
news:1127332810.082269.136310@o13g2000cwo.googlegroups.com...
> I've got a situation where in my program, at the start of it, I need to
> instantiate an object (third party -- I have no control over it) and
> then tell it to connect to its data source (again, no control over it).
>
> It boils down to just 2 lines of code:
>
> Set goSession = New Session
> goSession.StartOffline sUserId, sPassWord
>
> Basically, I have a form built that uses a class from vbaccelerator.com
> to show an animation, and it keeps going even though those 2 calls can
> take up to 30 seconds a piece to complete.  So, the user is happi(er)
> because they get more than an hourglass to see that things are working.
>
> However, sometimes the call to instantiate the object will fail (after
> a LONG time, like a few minutes).  I know from experience that if it
> takes longer than 45 seconds, it isn't going to work.  So, if that is
> the case, I'd like to kill all the timers and things on the form and
> unload it.
>
> I tried adding a timer to the form to basically kill everything on the
> form after 45 seconds, but that event doesn't get fired, running in IDE
> or compiled, ever.
>
> Any ideas on how I can basically simulate (or actually do) 2 processes
> so that I can kill one if things aren't going to work out?
>
> Thanks for any and all ideas, and I didn't explain things correctly,
> I'll gladly provide more information.
>
> Matt
>
Author
22 Sep 2005 1:36 PM
YYZ
> If you don't have the source for that object(Session), then here is one
> solution. VB is not multi threaded so you have to make a work around. One
> way is to divide it into Client/Server. The client is your current standard
> EXE, and the server is an ActiveX EXE. This ActiveX EXE takes your request
> and creates and waits for Session to finish, then notifies your EXE.

Thanks for that -- like I mentioned to Ken, I didn't realize that an
ActiveX EXE can take and return complex objects...I don't know where I
got that idea, but it was a bad assumption!

Thanks for the advice, and I'll try it out this morning.

Matt
Author
22 Sep 2005 4:00 PM
Someone
> Thanks for that -- like I mentioned to Ken, I didn't realize that an
> ActiveX EXE can take and return complex objects...I don't know where I
> got that idea, but it was a bad assumption!

You could pass a lot of things. Like stdPicture(Picture1.Picture), ADO's
Recordsets and the data inside it. DCOM takes care of all of this. When you
pass something by reference, DCOM transfers the information back and forth.
See the following articles which may come in handy later:

How To Implement Visual Basic COM Objects Returning Recordsets
http://support.microsoft.com/default.aspx?scid=kb;en-us;224424

INFO: Passing ADO Recordsets in Visual Basic Procedures
http://support.microsoft.com/default.aspx?scid=kb;en-us;193871

How To Create ADO Disconnected Recordsets in VBA/C++/Java
http://support.microsoft.com/default.aspx?scid=kb;en-us;184397

You may want to include GetProcessID method that calls
GetCurrentProcessId(), so you could terminate the ActiveX EXE process.
However, I don't recommend it. It could destabilize your application, plus
it would generate a runtime error like "Method X in Object Y failed".

I suspect that you will get an error when you try to release the ActiveX EXE
by the following statement or it could take time:

Set SessionAgent = Nothing

You could instead start a new session with a different variable. Since you
are going to run on some strange problems, you may want to look at App
object properties and methods that control some aspects of ActiveX projects.
Check all properties that begin with OLE.

Also, I forgot to mention that you must set Instancing property to SingleUse
for clsSessionAgent. I think that it start a new EXE for each object
created, but I am not sure.

Finally, you may want to study the Coffee2 sample in MSDN. It shows you how
to fire an event in a certain client object. The Coffee sample in the other
hand(simpler), will fire an event in all client objects "simultaneously".
Here is a link to a document about the sample and walkthroughs. You will
find the sample files in your MSDN's CD.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vb98/html/vbsmpCoffeeCoffeeCoffee.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon98/html/vbconasynchronouscallbackseventsinking.asp

I used Coffee2 sample as a template to allow multiple ActiveX DLL clients to
share one DB connection to the database. The ActiveX EXE keeps the
connection open 24/7 and responds to clients' requests as long as their is 1
client running. After the last client release the reference, the ActiveX EXE
process is unloaded from memory. The drawback from this method is if the
ActiveX EXE is executing a long query, the clients have to wait. I solved
this in my case by making 2 connections, one is cnSlow(for long queries) and
another cnQuick(for a single record).


Show quoteHide quote
"YYZ" <matt.da***@gmail.com> wrote in message
news:1127396219.151336.270620@g14g2000cwa.googlegroups.com...
>> If you don't have the source for that object(Session), then here is one
>> solution. VB is not multi threaded so you have to make a work around. One
>> way is to divide it into Client/Server. The client is your current
>> standard
>> EXE, and the server is an ActiveX EXE. This ActiveX EXE takes your
>> request
>> and creates and waits for Session to finish, then notifies your EXE.
>
> Thanks for that -- like I mentioned to Ken, I didn't realize that an
> ActiveX EXE can take and return complex objects...I don't know where I
> got that idea, but it was a bad assumption!
>
> Thanks for the advice, and I'll try it out this morning.
>
> Matt
>
Author
22 Sep 2005 3:04 PM
YYZ
Alright, I did what you gave me, and it all works great, except one
thing.  It all connects and is all happy, but after I set the active x
exe to nothing, then the session variable can't be used anymore.  It
claims to not be nothing, but yet I can't access even the simplest
property on it.  Here is a quick little example:

<all of your idea above has worked fine, now I'm going to use it>
Set goSession = cConn.GetSession()    'All ok to here
debug.Print goSession.IsConnected      ' Prints True, which is good.
Set cConn = nothing
debug.print goSession.IsConnected      ' Errors out with "Automation
Error  The remote procedure call failed."

I think that when the activex exe ends, then the session object is
destroyed.

Is this because I'm doing something wrong with the activex exe, or
could it be that the session object somehow grabs onto the process id
(not sure of terminology here) and then see that the process ended, so
it kills itself, even though I have ANOTHER process that wants to keep
it alive?

My question is really, can this be fixed, do you think, or is this
another limitation of the object that I'm using, in which case there is
no solution?

Matt
Author
22 Sep 2005 3:14 PM
YYZ
I got it to work by actually creating the object in the main program,
and then setting the session object in the activex exe to the one I had
already created -- creation only takes time the first time after a user
starts their computer.  Connecting the session is the one that will
most likely be the point at which things fail, and your program helps
me determine that.

Thanks for your help -- looks like that object somehow ties itself to
the thread or process that created it, so I can't just pass around
references as easily as I'd like.

Matt