Application.Run() In a Windows Service

W

Willy Denoyette [MVP]

Ben Voigt said:
no, don't enable "Interact with Desktop". That isn't needed for
processing the message queue, and is a very bad idea, not to mention no
longer allowed in Vista.


Agreed, this was only to make it easier for the OP to debug, once he got it
running he could reset this attribute.
It's a very bad idea to have Windows.Forms in Services in the first place,
it's clear that the OP is trying to use a .NET component that has a
dependency on Windows.Forms, (why, is just something the OP is not able to
answer I'm afraid).
It looks like this component needs a Window host (a HWND), maybe it creates
some hidden window or worse has a UI (a tray ICON or whatever), I really
wonder what kind component it is!
Note that you can still interact with the desktop in Vista, be it as an
interim solution for backward compatibility reasons :-(, anyway, Services on
Vista should not run Windows message loops either, everything that needs a
message loop doesn't belong in a Service.

Willy.
 
G

Guest

Thanks Willy. I have confirmed that it is a .net component. The component
does function when inside a windows service,however, not when multi
threading is involved.
 
W

Willy Denoyette [MVP]

Thanks Willy. I have confirmed that it is a .net component. The
component does function when inside a windows service,however, not when
multi threading is involved.

Please be more specific,
do you mean it's working from a single thread when running in a Service
process AND this without the need for Windows.Forms?
Is this a pure managed component, or does it have dependencies on other non
managed components like COM?
What kind of component is this and what's his role?
Is this components set documented, what does it say about threading?
What is do you mean with " it's not working when multiple threads are
involved"?
Did you try from a console application and noticed the same behavior? If you
did can you post the console apps. code?

Willy.
 
G

Guest

Thank you Willy for all of the assistance. I very much appreciate it. I've
been having a hell of a time with this.

Here is Windows Service (no threading) code that does work fine. The Envox
..net component answers OnIncomingCall. Everrything works fine with this
code...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using Envox.ADXVoice;

namespace WindowsService3
{
public partial class Service1 : ServiceBase
{
private ADXVoiceClass ADXVoice1 = null;

public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
ADXVoice1 = new ADXVoiceClass();
ADXVoice1.TrunkAssign(0);
ADXVoice1.IncomingCall += new
_IADXVoiceEvents_IncomingCallEventHandler(OnIncomingCall);
}

private void OnIncomingCall()
{
try
{
ADXVoice1.ClearDigits();
ADXVoice1.AnswerCall();
Play_Welcome_Message();
}
finally
{
if (ADXVoice1.TrunkState != DEV_STATE.DEV_STATE_Idle)
{
ADXVoice1.DisconnectCall();
}
}
}

private void Play_Welcome_Message()
{
ADXVoice1.PlayFile(@"e:\voxfiles\144.vox", null, "+", null,
null);
ADXVoice1.PlayFile(@"e:\voxfiles\145.vox", null, "+", null,
null);
}

protected override void OnStop()
{
}
}
}



Here is my multithreaded Windows Service code that does not work
(onincomingcall never executes). I require the 4 threads for the Envox .net
component to listen and answer calls on 4 different lines. This code does
not work for some reason...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using Envox.ADXVoice;

namespace WindowsService4
{
public partial class Service1 : ServiceBase
{
private LineHandler[] LineArray;

public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
StartApp();
}

private void StartApp()
{
int iFromTrunk = 0;
int iToTrunk = 14;

LineArray = new LineHandler[iToTrunk - iFromTrunk + 1];

for (int iTrunk = iFromTrunk; iTrunk <= iToTrunk; iTrunk++)
{
LineHandler Line = new LineHandler();
LineArray[iTrunk - iFromTrunk] = Line;
Line.iTrunk = iTrunk;
ThreadStart ts = new ThreadStart(Line.ProcessingThread);
Thread wrkThread = new Thread(ts);
Line.CurrentThread = wrkThread;
wrkThread.SetApartmentState(ApartmentState.STA); //default is
MTA
wrkThread.Name = iTrunk.ToString();
wrkThread.Start();
}
}

protected override void OnStop()
{
}

private class LineHandler
{
public int iTrunk = -1;
public Thread CurrentThread = null;
private ADXVoiceClass ADXVoice1 = null;
private delegate void TraceThreadSafe(string msg);

public void ProcessingThread()
{
int iThreadId = CurrentThread.GetHashCode();

ADXVoice1 = new ADXVoiceClass();
ADXVoice1.TrunkAssign(iTrunk);
ADXVoice1.IncomingCall += new
_IADXVoiceEvents_IncomingCallEventHandler(OnIncomingCall);

//Start message loop (keeps thread from exiting and allows
Envox .net component to process events, including state changes)
//Windows service aternate to application.run required
here...
//Application.Run();
}

private void OnIncomingCall()
{
try
{
ADXVoice1.ClearDigits();
ADXVoice1.AnswerCall();
Play_Welcome_Message();
}
finally
{
if (ADXVoice1.TrunkState != DEV_STATE.DEV_STATE_Idle)
{
ADXVoice1.DisconnectCall();
}
}
}

private void Play_Welcome_Message()
{
ADXVoice1.PlayFile(@"e:\voxfiles\144.vox", null, "+", null,
null);
ADXVoice1.PlayFile(@"e:\voxfiles\145.vox", null, "+", null,
null);
}
}


}
}


The above code, however, does function as a windows form whe using
paplication.run. I'd very much appreciate you comments or advice. Thank
you very much.
 
W

Willy Denoyette [MVP]

Thank you Willy for all of the assistance. I very much appreciate it.
I've been having a hell of a time with this.

Here is Windows Service (no threading) code that does work fine. The
Envox .net component answers OnIncomingCall. Everrything works fine with
this code...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using Envox.ADXVoice;

namespace WindowsService3
{
public partial class Service1 : ServiceBase
{
private ADXVoiceClass ADXVoice1 = null;

public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
ADXVoice1 = new ADXVoiceClass();
ADXVoice1.TrunkAssign(0);
ADXVoice1.IncomingCall += new
_IADXVoiceEvents_IncomingCallEventHandler(OnIncomingCall);
}

private void OnIncomingCall()
{
try
{
ADXVoice1.ClearDigits();
ADXVoice1.AnswerCall();
Play_Welcome_Message();
}
finally
{
if (ADXVoice1.TrunkState != DEV_STATE.DEV_STATE_Idle)
{
ADXVoice1.DisconnectCall();
}
}
}

private void Play_Welcome_Message()
{
ADXVoice1.PlayFile(@"e:\voxfiles\144.vox", null, "+", null,
null);
ADXVoice1.PlayFile(@"e:\voxfiles\145.vox", null, "+", null,
null);
}

protected override void OnStop()
{
}
}
}



Here is my multithreaded Windows Service code that does not work
(onincomingcall never executes). I require the 4 threads for the Envox
.net component to listen and answer calls on 4 different lines. This code
does not work for some reason...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using Envox.ADXVoice;

namespace WindowsService4
{
public partial class Service1 : ServiceBase
{
private LineHandler[] LineArray;

public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
StartApp();
}

private void StartApp()
{
int iFromTrunk = 0;
int iToTrunk = 14;

LineArray = new LineHandler[iToTrunk - iFromTrunk + 1];

for (int iTrunk = iFromTrunk; iTrunk <= iToTrunk; iTrunk++)
{
LineHandler Line = new LineHandler();
LineArray[iTrunk - iFromTrunk] = Line;
Line.iTrunk = iTrunk;
ThreadStart ts = new ThreadStart(Line.ProcessingThread);
Thread wrkThread = new Thread(ts);
Line.CurrentThread = wrkThread;
wrkThread.SetApartmentState(ApartmentState.STA); //default
is MTA
wrkThread.Name = iTrunk.ToString();
wrkThread.Start();
}
}

protected override void OnStop()
{
}

private class LineHandler
{
public int iTrunk = -1;
public Thread CurrentThread = null;
private ADXVoiceClass ADXVoice1 = null;
private delegate void TraceThreadSafe(string msg);

public void ProcessingThread()
{
int iThreadId = CurrentThread.GetHashCode();

ADXVoice1 = new ADXVoiceClass();
ADXVoice1.TrunkAssign(iTrunk);
ADXVoice1.IncomingCall += new
_IADXVoiceEvents_IncomingCallEventHandler(OnIncomingCall);

//Start message loop (keeps thread from exiting and allows
Envox .net component to process events, including state changes)
//Windows service aternate to application.run required
here...
//Application.Run();
}

private void OnIncomingCall()
{
try
{
ADXVoice1.ClearDigits();
ADXVoice1.AnswerCall();
Play_Welcome_Message();
}
finally
{
if (ADXVoice1.TrunkState != DEV_STATE.DEV_STATE_Idle)
{
ADXVoice1.DisconnectCall();
}
}
}

private void Play_Welcome_Message()
{
ADXVoice1.PlayFile(@"e:\voxfiles\144.vox", null, "+", null,
null);
ADXVoice1.PlayFile(@"e:\voxfiles\145.vox", null, "+", null,
null);
}
}


}
}


The above code, however, does function as a windows form whe using
paplication.run. I'd very much appreciate you comments or advice. Thank
you very much.


Sorry ,but I can't help you out if you don't answer my questions (see my
previous reply), also I didn't ask to post the service code, I asked for a
Console application. Anyway, as I said before, I'm pretty sure this .NET
component (if it's really not a AX Control) is hiding an unmanaged component
(guess, a COM ActiveX control from Envox), so again check this! Ask the
implementer of the .NET component, if you are not able to find this out
yourself. I can't possibly know what the NET wrapper (if any) is doing at
the thread level, whether it creates forms or not, the same is true for the
underlying control. All I can say is that if it's an AX control, forget it
to make it work from a Service, If you don't believe me , ask Envox whether
they support this to be run in a Windows Service, the answer will be NO.
One last question though, why do you want it to be run from a Service, why
can't you run it from a Windows application?

Willy.
 
W

Willy Denoyette [MVP]

Thank you Willy for all of the assistance. I very much appreciate it.
I've been having a hell of a time with this.

Here is Windows Service (no threading) code that does work fine. The
Envox .net component answers OnIncomingCall. Everrything works fine with
this code...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using Envox.ADXVoice;

namespace WindowsService3
{
public partial class Service1 : ServiceBase
{
private ADXVoiceClass ADXVoice1 = null;

public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
ADXVoice1 = new ADXVoiceClass();
ADXVoice1.TrunkAssign(0);
ADXVoice1.IncomingCall += new
_IADXVoiceEvents_IncomingCallEventHandler(OnIncomingCall);
}

private void OnIncomingCall()
{
try
{
ADXVoice1.ClearDigits();
ADXVoice1.AnswerCall();
Play_Welcome_Message();
}
finally
{
if (ADXVoice1.TrunkState != DEV_STATE.DEV_STATE_Idle)
{
ADXVoice1.DisconnectCall();
}
}
}

private void Play_Welcome_Message()
{
ADXVoice1.PlayFile(@"e:\voxfiles\144.vox", null, "+", null,
null);
ADXVoice1.PlayFile(@"e:\voxfiles\145.vox", null, "+", null,
null);
}

protected override void OnStop()
{
}
}
}



Here is my multithreaded Windows Service code that does not work
(onincomingcall never executes). I require the 4 threads for the Envox
.net component to listen and answer calls on 4 different lines. This code
does not work for some reason...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using Envox.ADXVoice;

namespace WindowsService4
{
public partial class Service1 : ServiceBase
{
private LineHandler[] LineArray;

public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
StartApp();
}

private void StartApp()
{
int iFromTrunk = 0;
int iToTrunk = 14;

LineArray = new LineHandler[iToTrunk - iFromTrunk + 1];

for (int iTrunk = iFromTrunk; iTrunk <= iToTrunk; iTrunk++)
{
LineHandler Line = new LineHandler();
LineArray[iTrunk - iFromTrunk] = Line;
Line.iTrunk = iTrunk;
ThreadStart ts = new ThreadStart(Line.ProcessingThread);
Thread wrkThread = new Thread(ts);
Line.CurrentThread = wrkThread;
wrkThread.SetApartmentState(ApartmentState.STA); //default
is MTA
wrkThread.Name = iTrunk.ToString();
wrkThread.Start();
}
}

protected override void OnStop()
{
}

private class LineHandler
{
public int iTrunk = -1;
public Thread CurrentThread = null;
private ADXVoiceClass ADXVoice1 = null;
private delegate void TraceThreadSafe(string msg);

public void ProcessingThread()
{
int iThreadId = CurrentThread.GetHashCode();

ADXVoice1 = new ADXVoiceClass();
ADXVoice1.TrunkAssign(iTrunk);
ADXVoice1.IncomingCall += new
_IADXVoiceEvents_IncomingCallEventHandler(OnIncomingCall);

//Start message loop (keeps thread from exiting and allows
Envox .net component to process events, including state changes)
//Windows service aternate to application.run required
here...
//Application.Run();
}

private void OnIncomingCall()
{
try
{
ADXVoice1.ClearDigits();
ADXVoice1.AnswerCall();
Play_Welcome_Message();
}
finally
{
if (ADXVoice1.TrunkState != DEV_STATE.DEV_STATE_Idle)
{
ADXVoice1.DisconnectCall();
}
}
}

private void Play_Welcome_Message()
{
ADXVoice1.PlayFile(@"e:\voxfiles\144.vox", null, "+", null,
null);
ADXVoice1.PlayFile(@"e:\voxfiles\145.vox", null, "+", null,
null);
}
}


}
}


The above code, however, does function as a windows form whe using
paplication.run. I'd very much appreciate you comments or advice. Thank
you very much.


I took a quick look at your code (the second case), and found that you don't
keep your threads running at all, all you are doing is create an instance of
ADXVoiceClass add an eventhandler and return from your thread procedure,
that means that the thread will most probably get collected at the next GC
run. That means that basically you don't have any of your 15 threads running
( that is pumping messages). At least you need to keep the thread running
and pump the queue (again STA threads need to pump the queue!!), for COM
messages only, you can do this by means of a pumping wait like :


public void ProcessingThread()
{
....
// pump COM messages once per second, in an endless loop!!
while(!Thread.CurrentThread.Join(new TimeSpan(0,0,1)));
}

for Windows messages you need Application.Run().

Willy.
 
W

Willy Denoyette [MVP]

ADXVoice1 = new ADXVoiceClass();
ADXVoice1.TrunkAssign(iTrunk);
ADXVoice1.IncomingCall += new
_IADXVoiceEvents_IncomingCallEventHandler(OnIncomingCall);

Oh, this ....
_IADXVoiceEvents
confirms what I've said before, the component is most certainly an ActiveX
control NOT a .NET component, the IADXVoiceEvents denotes COM
ConnectionPoint interface (probably a Windowless ATL Control interface) .
Following summarizes what you need to take care of when hosting such
control:
First, AX Controls are "Apartment" threaded, so you better initialize your
threads to enter an STA, else your objects will end on the default STA
thread created by COM.
Second, STA threads should to pump the message queue (COM message only),
this is required by the Finalizer thread, who runs in the MTA, to be able to
release the RCW when you're done with the object.
It's however not required by COM interop, as long as you don't need to
marshal across incomaptible apartments, and here you don't.
What you have to do is keep your threads pumping COM messages, this can be
achieved by calling a pumping wait.
For instance you could have a loop that calls Thread.Join with a timeout, or
better a Wait on an event with a timeout, this way you can do stuff like
detach your eventhandlers release the COM objects and stop your threads in
your service OnStop handler.

Following snippet, illustrates most of this, (not tested!)...

const int threads = 15;
ManualResetEvent[] mre = new ManualResetEvent[threads];
....

Thread[] t = new Thread[threads];
for (int i = 0; i < threads; i++)
{
signals = new ManualResetEvent(false);
t = new Thread(new
ParameterizedThreadStart(ProcessingThread),200000);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground=true;
t.Start(mre);
}

public void ProcessingThread(object shutdownEvent)
{
....
ADXVoice1.InCommingCall += new
_IADXVoiceEvents_InCommingCallEventHandler(OnIncomingCall);
// Wait 100 msec. for event to be set, leave the loop when set,
WaitOne pumps COM messages
while (!((ManualResetEvent)(shutdownEvent)).WaitOne(100, true))
;
// signaled to stop, detach handler and release COM object
ADXVoice1.InCommingCall -= new
_IADXVoiceEvents_InCommingCallEventHandler(OnIncomingCall);
Marshal.ReleaseComObject(ADXVoice1);
}
...
protected override void OnStop()
{
for (int n = 0; n < threads; n++)
mre[n].Set();
// Wait for threads to end.... use Join or whatever other
synchronization primitive,
// keeping in mind that you need to return from OnStop before the
SCM gets nervous
}
Willy.
 
G

Guest

Thank you very much, Willy. I really appreciate all of the help. I have
tried these and other methods to get this windows service functioning,
however, I've been unsuccessful. I think I'm going to have to assume that
this component just doesn't function as a multithreaded windows service.
Without threading I can the windows service to run properly so perhaps I can
just create 15 windows services (not perfered). I require this application
to run continually so windows service is the way to go. Alternatively I may
just have to have the multithreaded windows form app running in a terminal
service session (again not perfered). Anyways, I really appreciate all of
your help. Thank you very much.

Jay



Willy Denoyette said:
ADXVoice1 = new ADXVoiceClass();
ADXVoice1.TrunkAssign(iTrunk);
ADXVoice1.IncomingCall += new
_IADXVoiceEvents_IncomingCallEventHandler(OnIncomingCall);

Oh, this ....
_IADXVoiceEvents
confirms what I've said before, the component is most certainly an ActiveX
control NOT a .NET component, the IADXVoiceEvents denotes COM
ConnectionPoint interface (probably a Windowless ATL Control interface) .
Following summarizes what you need to take care of when hosting such
control:
First, AX Controls are "Apartment" threaded, so you better initialize your
threads to enter an STA, else your objects will end on the default STA
thread created by COM.
Second, STA threads should to pump the message queue (COM message only),
this is required by the Finalizer thread, who runs in the MTA, to be able
to release the RCW when you're done with the object.
It's however not required by COM interop, as long as you don't need to
marshal across incomaptible apartments, and here you don't.
What you have to do is keep your threads pumping COM messages, this can be
achieved by calling a pumping wait.
For instance you could have a loop that calls Thread.Join with a timeout,
or better a Wait on an event with a timeout, this way you can do stuff
like detach your eventhandlers release the COM objects and stop your
threads in your service OnStop handler.

Following snippet, illustrates most of this, (not tested!)...

const int threads = 15;
ManualResetEvent[] mre = new ManualResetEvent[threads];
...

Thread[] t = new Thread[threads];
for (int i = 0; i < threads; i++)
{
signals = new ManualResetEvent(false);
t = new Thread(new
ParameterizedThreadStart(ProcessingThread),200000);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground=true;
t.Start(mre);
}

public void ProcessingThread(object shutdownEvent)
{
....
ADXVoice1.InCommingCall += new
_IADXVoiceEvents_InCommingCallEventHandler(OnIncomingCall);
// Wait 100 msec. for event to be set, leave the loop when set,
WaitOne pumps COM messages
while (!((ManualResetEvent)(shutdownEvent)).WaitOne(100, true))
;
// signaled to stop, detach handler and release COM object
ADXVoice1.InCommingCall -= new
_IADXVoiceEvents_InCommingCallEventHandler(OnIncomingCall);
Marshal.ReleaseComObject(ADXVoice1);
}
...
protected override void OnStop()
{
for (int n = 0; n < threads; n++)
mre[n].Set();
// Wait for threads to end.... use Join or whatever other
synchronization primitive,
// keeping in mind that you need to return from OnStop before
the SCM gets nervous
}
Willy.
[/QUOTE]
 
W

Willy Denoyette [MVP]

Thank you very much, Willy. I really appreciate all of the help. I have
tried these and other methods to get this windows service functioning,
however, I've been unsuccessful. I think I'm going to have to assume that
this component just doesn't function as a multithreaded windows service.
Without threading I can the windows service to run properly so perhaps I
can just create 15 windows services (not perfered). I require this
application to run continually so windows service is the way to go.
Alternatively I may just have to have the multithreaded windows form app
running in a terminal service session (again not perfered). Anyways, I
really appreciate all of your help. Thank you very much.

Weird, If it works in a Forms application using multiple threads, it should
also work from a service, provided things are initialized correctly.
I would try to make it run from a console application, if this works, you
can schedule this application to start at boot time using the system
scheduler.

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top