Default path for Windows Service

  • Thread starter Thread starter Anil Gupte
  • Start date Start date
A

Anil Gupte

I wrote my Windows Service first as a regular Windows Exe because it is
easier to debug. In that I used

AppDir = Application.ExecutablePath.Substring(0,
Application.ExecutablePath.LastIndexOf("\")) ' Where this application
Excutable sits

Now, when I am converting it to a Service, what path can I use? Or can I
specify a path in the service to always use as a data path? I would prefer
the former because I do not know the layout of the target computer.
 
I wrote my Windows Service first as a regular Windows Exe because it is
easier to debug. In that I used

AppDir = Application.ExecutablePath.Substring(0,
Application.ExecutablePath.LastIndexOf("\")) ' Where this application
Excutable sits

Now, when I am converting it to a Service, what path can I use? Or can I
specify a path in the service to always use as a data path? I would prefer
the former because I do not know the layout of the target computer.

Try the WMI class to get Windows Default path

Imports System.Management
Public Class wmi
Private objOS As ManagementObjectSearcher
Private objCS As ManagementObjectSearcher
Private objMgmt As ManagementObject
Private m_strComputerName As String
Private m_strManufacturer As String
Private m_StrModel As String
Private m_strOSName As String
Private m_strOSVersion As String
Private m_strSystemType As String
Private m_strTPM As String
Private m_strWindowsDir As String


Public Sub New()

objOS = New ManagementObjectSearcher("SELECT * FROM
Win32_OperatingSystem")
objCS = New ManagementObjectSearcher("SELECT * FROM
Win32_ComputerSystem")
For Each objMgmt In objOS.Get


m_strOSName = objMgmt("name").ToString()
m_strOSVersion = objMgmt("version").ToString()
m_strComputerName = objMgmt("csname").ToString()
m_strWindowsDir = objMgmt("windowsdirectory").ToString()
Next

For Each objMgmt In objCS.Get
m_strManufacturer = objMgmt("manufacturer").ToString()
m_StrModel = objMgmt("model").ToString()
m_strSystemType = objMgmt("systemtype").ToString
m_strTPM = objMgmt("totalphysicalmemory").ToString()
Next
End Sub

Public ReadOnly Property ComputerName()
Get
ComputerName = m_strComputerName
End Get

End Property
Public ReadOnly Property Manufacturer()
Get
Manufacturer = m_strManufacturer
End Get

End Property
Public ReadOnly Property Model()
Get
Model = m_StrModel
End Get

End Property
Public ReadOnly Property OsName()
Get
OsName = m_strOSName
End Get

End Property

Public ReadOnly Property OSVersion()
Get
OSVersion = m_strOSVersion
End Get

End Property
Public ReadOnly Property SystemType()
Get
SystemType = m_strSystemType
End Get

End Property
Public ReadOnly Property TotalPhysicalMemory()
Get
TotalPhysicalMemory = m_strTPM
End Get

End Property

Public ReadOnly Property WindowsDirectory()
Get
WindowsDirectory = m_strWindowsDir
End Get

End Property
Public ReadOnly Property FontDirectory()
Get
FontDirectory = m_strWindowsDir & "\font".ToUpper
End Get
End Property
End Class
 
Well that might be all very well if the OP wanted the path to the Windows
directory.

But he doesn't. He wants the path of the directory where the
application/service executable resides.
 
An easier way than using the SubString and LastIndexOf methods is:

AppDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath)

If you include a reference to System.Windows.Forms in your service then you
can still use that. You can include that reference without having to include
a form.

An alternative is:

System.Reflection.Assembly.GetExecutingAssembly().Location

which, with some Imports ... can be written as:

AppDir = Path.GetDirectoryName([Assembly].GetExecutingAssembly().Location)
 
Thanx, I will try that.

--
Anil Gupte
www.keeninc.net
www.icinema.com

Stephany Young said:
An easier way than using the SubString and LastIndexOf methods is:

AppDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath)

If you include a reference to System.Windows.Forms in your service then
you can still use that. You can include that reference without having to
include a form.

An alternative is:

System.Reflection.Assembly.GetExecutingAssembly().Location

which, with some Imports ... can be written as:

AppDir =
Path.GetDirectoryName([Assembly].GetExecutingAssembly().Location)


Anil Gupte said:
I wrote my Windows Service first as a regular Windows Exe because it is
easier to debug. In that I used

AppDir = Application.ExecutablePath.Substring(0,
Application.ExecutablePath.LastIndexOf("\")) ' Where this application
Excutable sits

Now, when I am converting it to a Service, what path can I use? Or can I
specify a path in the service to always use as a data path? I would
prefer the former because I do not know the layout of the target
computer.
 
Anil said:
I wrote my Windows Service first as a regular Windows Exe because it is
easier to debug.

Better still, put your "processing" into a class. Then you can
instantiate and run it from either a Service or, say, a Console
application. Even /easier/ to debug. :-)
In that I used
AppDir = Application.ExecutablePath.Substring(0,
Application.ExecutablePath.LastIndexOf("\"))

Have you come across System.IO.Path yet?
Now, when I am converting it to a Service, what path can I use?

I use this:

Dim sExeFile as String _
= System.Reflection.Assembly.GetEntryAssembly().Location
Dim sExeDir as String _
= System.IO.Path.GetDirectory( sExeFile )
I would prefer the former because I do not know the layout
of the target computer.

HTH,
Phill W.
 
Better still, put your "processing" into a class. Then you can
instantiate and run it from either a Service or, say, a Console
application. Even /easier/ to debug. :-)

I am having a problem getting the service to start and I cannot debug it. I
installed it on a different computer using installutil.exe In the Services
list, it appears, and I can hit start. However, I get a message saying
something to the effect that ther service started and then stopped and that
this was typical of services that "have nothing to do". Mine should do
something! My code looks like this:

Imports System.ServiceProcess
Imports System.Data.OleDb
Imports WMEncoderLib

#Region " Component Designer generated code "

Public Class MediaEncoderService
Inherits System.ServiceProcess.ServiceBase
Dim WithEvents MediaEncoder As WMEncoder
Protected Overrides Sub OnStart(ByVal args() As String)
MediaEncode()
End Sub
Private Sub MediaEncode()
etc...
End Sub
End Class

So, I can't debug it because it won't even start. The install gives no
errors. I am stumped.....
P.S. The onstop event is empty...

Thanx,
 
Anil said:
I am having a problem getting the service to start and I cannot debug it. I
installed it on a different computer using installutil.exe In the Services
list, it appears, and I can hit start. However, I get a message saying
something to the effect that ther service started and then stopped and that
this was typical of services that "have nothing to do".

Some thoughts about Services:

When they are started, the Service Control infrastructure calls your
OnStart method. This must return within a fixed time interval, or the
Service gets reported as "failing to start".
Don't call your "main processing" directly from OnStart.

You [normally] have to provide a loop construct to keep the service
running. This doesn't happen automatically as it does in a Windows
Forms app.

If you have large "units of work", watch out for OnStop.
The Service Control infrastructure calls your OnStop routine, which
allows you to "clean up" what the service is doing. When you return
from OnStop, the infrastructure tears down your service process, no
matter what it might still be doing.

Here's how I do it:

Sub OnStart()
tmrStarter.Start()
End Sub

Private Sub tmrStarter_Elapsed( ...
' Kill the Timer - we don't need it again
tmrStarter.Stop()

m_bShutdownComplete = False
Do While Not m_bShutdownRequested
DoProcessing()
System.Threading.Thread.Sleep( a_while )
Loop
m_bShutdownComplete = True
End Sub

Sub OnStop()
m_bShutdownRequested = True
Do While Not m_bShutdownComplete
System.Threading.Thread.Sleep( 1000 )
Loop
' Return from OnStop and your process gets torn down!
End Sub

Private m_bShutdownRequested as Boolean
Private m_bShutdownComplete as Boolean

Private Sub DoProcessing()
' Do the useful work here

' If you have any loop constructs, you can include tests of
' m_bShutdownRequested, so that your service can respond
' quickly to stop requests.
End Sub

HTH,
Phill W.
 
Hmm, OK, a couple of issues.

1. My service will not even start. I tried putting a msgbox in the OnStart
event to see if would do anything at all, but even that did not show. That
means it is not even reaching the OnStart event. I am sure it will run my
main process fine if it gets there or at least I can start debugging -
question is how to make it get there.

2. I do have a timer in the code, but I am not sure I want to kill it. I
want the timer to start the main process every 10 minutes (it checks to see
if a file has been uploaded and if found, runs the encoder on it). Another
thing, do I have to start the timer in the OnStart even of the service?

Thanx,
--
Anil Gupte
www.keeninc.net
www.icinema.com

Phill W. said:
Anil said:
I am having a problem getting the service to start and I cannot debug it.
I installed it on a different computer using installutil.exe In the
Services list, it appears, and I can hit start. However, I get a message
saying something to the effect that ther service started and then stopped
and that this was typical of services that "have nothing to do".

Some thoughts about Services:

When they are started, the Service Control infrastructure calls your
OnStart method. This must return within a fixed time interval, or the
Service gets reported as "failing to start".
Don't call your "main processing" directly from OnStart.

You [normally] have to provide a loop construct to keep the service
running. This doesn't happen automatically as it does in a Windows Forms
app.

If you have large "units of work", watch out for OnStop.
The Service Control infrastructure calls your OnStop routine, which allows
you to "clean up" what the service is doing. When you return from OnStop,
the infrastructure tears down your service process, no matter what it
might still be doing.

Here's how I do it:

Sub OnStart()
tmrStarter.Start()
End Sub

Private Sub tmrStarter_Elapsed( ...
' Kill the Timer - we don't need it again
tmrStarter.Stop()

m_bShutdownComplete = False
Do While Not m_bShutdownRequested
DoProcessing()
System.Threading.Thread.Sleep( a_while )
Loop
m_bShutdownComplete = True
End Sub

Sub OnStop()
m_bShutdownRequested = True
Do While Not m_bShutdownComplete
System.Threading.Thread.Sleep( 1000 )
Loop
' Return from OnStop and your process gets torn down!
End Sub

Private m_bShutdownRequested as Boolean
Private m_bShutdownComplete as Boolean

Private Sub DoProcessing()
' Do the useful work here

' If you have any loop constructs, you can include tests of
' m_bShutdownRequested, so that your service can respond
' quickly to stop requests.
End Sub

HTH,
Phill W.
 
Anil said:
1. My service will not even start. I tried putting a msgbox in the OnStart
event to see if would do anything at all, but even that did not show. That
means it is not even reaching the OnStart event.

Not necessarily.
If a Windows Service displays a MsgBox, it gets shown on a "virtual
desktop" that is reserved for system processes. No user can get to see
this "desktop", so the service process would seem to hang (this is why
ASP doesn't have a MsgBox function).
At least it used to - Windows may be "clever" enough now to catch the
MsgBox and write it into the Event log instead.
I am sure it will run my main process fine if it gets there or at least
I can start debugging - question is how to make it get there.

Put a Sleep(15000) into OnStart. That will give you enough time to
attach the debugger to the running [service] process when you start it.
2. I do have a timer in the code, but I am not sure I want to kill it.
I want the timer to start the main process every 10 minutes.

And if your "real" processing takes longer than 10 minutes, what then?
Do you want two instances of the routine running at the same time?
it will.

Personally, I /only/ use the Timer to "sidestep" out of OnStart and to
launch a continuously running process with Sleep call in it for the
"gaps" between bouts of doing stuff. I've had problems where a missing
dependent assembly can cause the Timer-invoked routine to fail to load
but, since this method is invoked from the innards of the Framework,
there's no easy way to catch the resulting Exception.
With a coded loop, a simple Try .. Catch does the job.
Another thing, do I have to start the timer in the OnStart even of
the service?

Yes. Start and Stop timers explicitly; that way you can clearly see
what's going on.

HTH,
Phill W.
 
How do I put a Sleep(15000) in there? Do I need to create a thread and then
use thread.sleep()?

Thanx,
--
Anil Gupte
www.keeninc.net
www.icinema.com

Phill W. said:
Anil said:
1. My service will not even start. I tried putting a msgbox in the
OnStart event to see if would do anything at all, but even that did not
show. That means it is not even reaching the OnStart event.

Not necessarily.
If a Windows Service displays a MsgBox, it gets shown on a "virtual
desktop" that is reserved for system processes. No user can get to see
this "desktop", so the service process would seem to hang (this is why ASP
doesn't have a MsgBox function).
At least it used to - Windows may be "clever" enough now to catch the
MsgBox and write it into the Event log instead.
I am sure it will run my main process fine if it gets there or at least
I can start debugging - question is how to make it get there.

Put a Sleep(15000) into OnStart. That will give you enough time to attach
the debugger to the running [service] process when you start it.
2. I do have a timer in the code, but I am not sure I want to kill it. I
want the timer to start the main process every 10 minutes.

And if your "real" processing takes longer than 10 minutes, what then?
Do you want two instances of the routine running at the same time?
it will.

Personally, I /only/ use the Timer to "sidestep" out of OnStart and to
launch a continuously running process with Sleep call in it for the "gaps"
between bouts of doing stuff. I've had problems where a missing dependent
assembly can cause the Timer-invoked routine to fail to load but, since
this method is invoked from the innards of the Framework, there's no easy
way to catch the resulting Exception.
With a coded loop, a simple Try .. Catch does the job.
Another thing, do I have to start the timer in the OnStart even of
the service?

Yes. Start and Stop timers explicitly; that way you can clearly see
what's going on.

HTH,
Phill W.
 
Anil said:
How do I put a Sleep(15000) in there? Do I need to create a thread and then
use thread.sleep()?

You main process /is/ a thread.

System.Threading.Thread.Sleep( 15000 )

is all you need.

HTH,
Phill W.
 
Thanx! I fixed this problem anyway, but thanx for teaching me something new
(even though it is obvious to you, it is new to me :-))
 
Back
Top