R
Ross Presser
OK, I've been researching this problem and can't find a definitive answer
yet.
The situation is one that seems to have come up a few times to different
folks. I am writing an application that will function as a windows service
and will also present a GUI to the user. I don't want "Interact with
desktop"; I want the same exe to run as a normal non-interactive service
when started properly by the service control manager, or instead to run as
a quiet winforms app (it will load a tray icon) if started by the user.
The idea is not new; I know of many programs outside the dotnet world that
behave this way. For example, VNC. winvnc.exe, if started with no
arguments by a user, it will attempt to start the service; if started with
-install, it will install the service; if started with -remove, it will
remove it; if started with -servicehelper, it will provide a tray icon for
setting configuration; and if started by the service controller, obviously,
it runs as a service. Prime95 is another example.
I have code already that can either run as a service or provide the tray
icon; it just can't make the decision yet. Modified from msdn:
'-------------------------------------------------------------
Public Class UserService1
Inherits System.ServiceProcess.ServiceBase
Public Sub New()
Me.ServiceName = "UserService1"
Me.CanStop = True
Me.AutoLog = True
End Sub
Shared Sub Main()
If Running_As_Service()
System.ServiceProcess.ServiceBase.Run(New UserService1)
Else
TrayIconApp.Run() ' this is in another module in my project
' trust me, it works right, no problem with that part
End If
End Sub
Protected Overrides Sub OnStart(ByVal args() As String) ...
Protected Overrides Sub OnStop(ByVal args() As String) ...
Private Function Running_As_Service() As Boolean
' This is what I have trouble with.
Return True
End Class
'------------------------------------------------------------------------
What I'm having trouble with is what to put in Running_As_Service().
There seem to be several approaches:
- use a commandline argument to control operation, espoused by
http://tinyurl.com/ddckz
Also used in the autogenerated code for a C++ windows service (i.e., To
install the service, type: "foo.exe -Install"). I'm willing to fall back
on this if I have to.
- Get the process id of the current process and use System.Management to
query the service database using the ProccId as search criteria. This idea
from http://tinyurl.com/94vp7 . This seems promising but I haven't tried it
yet.
- Some people suggest relying on something happening in On_Start(), however
that seems off the mark to me, as we have to figure out what to do in main,
BEFORE On_Start gets raised.
- Someone suggested using a servicecontroller to query the status of this
service. If it's "pending" then it's a fair bet that we're the service; if
it's "stopped" or "running" or "paused" or anything else then it's certain
we're not. I'm leery of this idea as it seems time-sensitive; if the user
clicked the app while the service was still starting up, it would get
confused.
- It seems like it should be possible to examine the parent process that
launched me, and if it is the service control manager then I'm a service,
else not. However I can't find any code to accomplish this.
I'd be grateful for any help or ideas you could offer.
yet.
The situation is one that seems to have come up a few times to different
folks. I am writing an application that will function as a windows service
and will also present a GUI to the user. I don't want "Interact with
desktop"; I want the same exe to run as a normal non-interactive service
when started properly by the service control manager, or instead to run as
a quiet winforms app (it will load a tray icon) if started by the user.
The idea is not new; I know of many programs outside the dotnet world that
behave this way. For example, VNC. winvnc.exe, if started with no
arguments by a user, it will attempt to start the service; if started with
-install, it will install the service; if started with -remove, it will
remove it; if started with -servicehelper, it will provide a tray icon for
setting configuration; and if started by the service controller, obviously,
it runs as a service. Prime95 is another example.
I have code already that can either run as a service or provide the tray
icon; it just can't make the decision yet. Modified from msdn:
'-------------------------------------------------------------
Public Class UserService1
Inherits System.ServiceProcess.ServiceBase
Public Sub New()
Me.ServiceName = "UserService1"
Me.CanStop = True
Me.AutoLog = True
End Sub
Shared Sub Main()
If Running_As_Service()
System.ServiceProcess.ServiceBase.Run(New UserService1)
Else
TrayIconApp.Run() ' this is in another module in my project
' trust me, it works right, no problem with that part
End If
End Sub
Protected Overrides Sub OnStart(ByVal args() As String) ...
Protected Overrides Sub OnStop(ByVal args() As String) ...
Private Function Running_As_Service() As Boolean
' This is what I have trouble with.
Return True
End Class
'------------------------------------------------------------------------
What I'm having trouble with is what to put in Running_As_Service().
There seem to be several approaches:
- use a commandline argument to control operation, espoused by
http://tinyurl.com/ddckz
Also used in the autogenerated code for a C++ windows service (i.e., To
install the service, type: "foo.exe -Install"). I'm willing to fall back
on this if I have to.
- Get the process id of the current process and use System.Management to
query the service database using the ProccId as search criteria. This idea
from http://tinyurl.com/94vp7 . This seems promising but I haven't tried it
yet.
- Some people suggest relying on something happening in On_Start(), however
that seems off the mark to me, as we have to figure out what to do in main,
BEFORE On_Start gets raised.
- Someone suggested using a servicecontroller to query the status of this
service. If it's "pending" then it's a fair bet that we're the service; if
it's "stopped" or "running" or "paused" or anything else then it's certain
we're not. I'm leery of this idea as it seems time-sensitive; if the user
clicked the app while the service was still starting up, it would get
confused.
- It seems like it should be possible to examine the parent process that
launched me, and if it is the service control manager then I'm a service,
else not. However I can't find any code to accomplish this.
I'd be grateful for any help or ideas you could offer.