|
Your code uses registry APIs to set the description, but it's probably better to use the ChangeServiceConfig2 API instead. This snippet of code should be enough to make it work:
At around line 617 in ServiceBase.cs in baseInstall():
ServicesAPI.CloseServiceHandle(sc_handle);
return false;
}
+
+ ServicesAPI.SERVICE_DESCRIPTION info = new ServicesAPI.SERVICE_DESCRIPTION();
+
+ info.lpDescription = Description;
+ if (Description == null)
+ info.lpDescription = "";
+ ServicesAPI.ChangeServiceConfig2A(sv_handle, ServicesAPI.InfoLevel.SERVICE_CONFIG_DESCRIPTION, ref info);
ServicesAPI.CloseServiceHandle(sv_handle);
ServicesAPI.CloseServiceHandle(sc_handle);
-
-
-
-
-
-
-
-
-
-
return true;
} catch {
And in ServiceAPI.cs near line 48:
int dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup,
int lpdwTagId, string lpDependencies, string lpServiceStartName,
string lpPassword, string lpDisplayName);
! [DllImport("advapi32.dll", CharSet = CharSet.Ansi, PreserveSig = true)]
public static extern bool ChangeServiceConfig2A(
! IntPtr hService, InfoLevel dwInfoLevel,
[MarshalAs(UnmanagedType.Struct)] ref SERVICE_DESCRIPTION lpInfo);
! [DllImport("advapi32.dll", CharSet = CharSet.Ansi, PreserveSig = true)]
public static extern bool ChangeServiceConfig2A(
! IntPtr hService, InfoLevel dwInfoLevel,
[MarshalAs(UnmanagedType.Struct)] ref SERVICE_FAILURE_ACTIONS lpInfo);
[DllImport("advapi32.dll")]
public static extern int OpenServiceA(
int hSCManager, string lpServiceName, ACCESS_TYPE dwDesiredAccess);
Not sure if specifying the charset specifically matters much, but the first parameter needs to be changed from int to IntPtr in the ChargeServiceConfig2 functions.
These changes appeared to work on my machine, but I have not tested it anywhere else.
-- modified at 19:18 Saturday 22nd July, 2006
|
|
|
|
|
This was fixed in the latest version. Please see my post titled "NEW RELEASE!" for more information.
|
|
|
|
|
I'm using SharpDevelop Beta 3 to run the project and I'm not sure if it's the HotySoft code or SharpDevelop not setting the command line arguments correctly, but there's a better way to get the full file path of a running process.
In ServiceBase.cs on lines 76-78 and 91-93 you may want to replace those lines with the following:
<br />
string processPath = Process.GetCurrentProcess().MainModule.FileName;<br />
if (processPath != null && processPath.Length > 0) {<br />
System.IO.FileInfo fi = new System.IO.FileInfo(processPath);<br />
|
|
|
|
|
That sounds odd since the OS usually passes in the path of the executable as the first argument every time you run a program. If it works, though, then that's all that matters! (c: Good job! Did you create a sharp develop project? If you haven't changed the namespaces, I'd be interested in putting up a version of it on the web. Thanks!
|
|
|
|
|
This was fixed in the latest version. Please see my post titled "NEW RELEASE!" for more information.
|
|
|
|
|
This looks like a very nice system to use. Debugging services is difficult when you have to reinstall the service everytime.
However I dont understand the debugmode used in you ServiceProcess. How can I run the application as a real service? The debug property is readonly and always returns true if I build and run the app using debug or release mode.
It will log the start and initialise events, but I cannot run the service (Error 1053: The service did not respond to the start or control request in a timely fashion.).
So how do I switch to a real service from a 'fake' console app?
|
|
|
|
|
"Debug mode" unfortunately was a poor name for that property. (c: Perhaps "RunningAsConsoleApp" might be more descriptive. That property will return false when it's being run as a service - that is, when it's started through the SCM and using start, stop, pause, etc. As for that error, I frequently got that message and others like it. The other messages left for this article describe similar problems and resolutions and might be beneficial. Please make sure you're using the most recent version by downloading it from my own website: http://www.hoytsoft.org/serviceBase.aspx[^]. That has frequently solved most people's issues.
Thanks for your interest and I hope it all works out for you!
|
|
|
|
|
Thanks for your reply. I am using the latest version from your website. Even your simple example application has this problem. Runs fine as console application, but cannot start as a service. I tried this in VS2003 and VS2005 with both debug and release modes but no luck.
I keep trying, I like the idea of a service which is still debugable.
|
|
|
|
|
First of all after reading the article and looking at the source files : thanks for sharing this great code !
I downloaded the latest version (Rev3) from the hoytsoft.org website and compiled it in Release version on XP Pro with VS2003. I then ran the HoytSoft.Example.exe from the command line with the i argument to install it as a service. Using the Service Control Panel, I was able to start, pause, resume and stop the service.
However, the service did not write any entry at all in the Windows Event Log (I used the Windows Event Viewer to check it). Looking at the source code of the example service, I was expecting to see a lot of entries ...
What could I have done wrong ? Thanks for helping me out here !
|
|
|
|
|
Hi Mark - Thanks! (c:
There could be problems with your event log - it could be full, in which case the code (depending on your point of view) gracefully fails to log anything. If it's not full, then check your logs for one named "Services" since all log entries are placed there (this is configurable in the Service attribute using the LogName property). If you changed the name of the log after already installing the service and generating log entries, then Windows can be finicky about it. It seems to prefer applications to keep using the same log every time. (It can be remedied through the registry, though). Honestly, I am not entirely sure what's causing you the log entry errors (it simply uses the normal .NET framework's logging classes). Have you stepped through the code and found the specific point at which it fails? That would sure help me to pinpoint the problem. (c: Thanks for your interest!
|
|
|
|
|
David,
Thanks for your quick reaction !
"Services" !!! I was looking into the "Application" log. I didn't even know you could force the Event Log to create other logs then the tree basic ones. Learned something new here !
I tried to add the LogName property with as value "Application" to the example service code but at run time (installing the service), that generated an exception. Looking to the ServiceBase source code, I think I cannot just add the attribute, but I will have to at least add a constructing method which takes it as an argument. Isn't it ?
In any case, thanks again for sharing this great code and responding so quickly to my post.
Mark
|
|
|
|
|
This is what I was referring to in my previous post about Windows being finicky - once an application is associated with a log, Windows doesn't like you changing it. The attribute works as-is when the app first writes a log entry. That is, the app associates itself with a specific log and then windows expects it to be the same every time. If it changes, it will throw you that exception. The solution is to edit the registry at:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Services You will see a string value called "Sources" - delete that or delete the contents of it and then restart the service with the "Applications" log name. Your attribute declaration should look something like:
[Service(
"HoytSoft_ExampleService",
DisplayName = "HoytSoft Example Service",
Description = "Isn't this just absolutely amazing?",
ServiceType = ServiceType.Default,
ServiceAccessType = ServiceAccessType.AllAccess,
ServiceStartType = ServiceStartType.AutoStart,
ServiceErrorControl = ServiceErrorControl.Normal,
ServiceControls = ServiceControls.Default,
LogName = "Application"
)]
public class ExampleService : HoytSoft.ServiceProcess.ServiceBase {
...
}
After deleting the registry entry and re-running the service, you'll see log entries appear under "Application." If this was done from the very start (e.g. when first ran on a new system), you will not have any of these problems. Good luck - let me know how it turns out! (c:
-- modified at 12:26 Wednesday 14th December, 2005
|
|
|
|
|
David,
Unfortunaltely, the registry key you are pointing me at does not contain a string value called Sources. Here is what it contains :
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Services]<br />
<br />
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Services\HoytSoft Example Service]<br />
"EventMessageFile"="C:\\WINDOWS\\Microsoft.NET\\Framework\\v1.1.4322\\EventLogMessages.dll"<br />
<br />
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Services\Services]<br />
"EventMessageFile"="C:\\WINDOWS\\Microsoft.NET\\Framework\\v1.1.4322\\EventLogMessages.dll"
I tried removing the whole Services key with its two subkeys and their string values. That removed the Services entry from the Event Viewer. I then installed the service as compiled like you mention. I started, paused, resumed and stopped it, but saw no entries appearing in the Application log. However, it created a "HoytSoft Example Service" key under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application, but that didn't seem to be enough ...
I then unistalled the service, removed the created registry key and re-installed the original service. And ... SURPRISE ... the Services log was created again into the Event Log Viewer and contained all entries created before by the service compiled with the LogName = "Application" set ....
So, my problem remains. Hopefully you can still help me solving this because the service I need to write has to absolutely log into the Application log.
Thanks in advance,
Mark
|
|
|
|
|
|
David,
The result is the same, whether I remove it manually or programmatically.
My guess, without an indeep look into your code, is that, even with the LogName property set as you indicated, there are still some traces of a LogName = "Services" elsewhere in the code that force the use of a spooky event log. The entries made into that log only become visible in the event viewer after thruthfully creating the "Services" log.
I you can agree with this and find any solution to it, please post it. I maybe looking into it more deeply within a week or two.
PS : Development and testing is done on a XP Pro SP2 machine.
Regards,
Mark
|
|
|
|
|
1.Before doing the following, make a change to ServiceAttribute.cs so that it support
'LogName' argument, then use like this : (This will then log into 'Application' log file)
[Service(
"HoytSoft_ExampleService",
DisplayName = "HoytSoft Example Service",
Description = "Isn't this just absolutely amazing?",
ServiceType = ServiceType.Default,
ServiceAccessType = ServiceAccessType.AllAccess,
ServiceStartType = ServiceStartType.AutoStart,
ServiceErrorControl = ServiceErrorControl.Normal,
ServiceControls = ServiceControls.Default,
LogName = "Application"
)]
2.Find out 'Helper Methods' region ( In ServiceBase.cs ),
where checklog() function has a line
this.log.Source = this.displayName; replace it with
this.log.Source = this.name; ( Because 'Source' should be service name.),
then it will work fine.
Just try it. It works.
If you want to use custom EventLog file, just read MSDN... it helps .
No matter how you use this, make sure that EventLog file exist first,
then you will log any messages as you wish.
-----------------------------------------------------------------------
I'm interested in any kinds of computer programming, so are you, right?
|
|
|
|
|
Hi
First of all, 5 out of 5!!! The service base is awesome! To bad about my debug attribute not working, as I thought that is quite nice to have, atleast still works when you build in VS.
Whenever I try to pause or stop the service I get the following error.
Could not pasuse the service on your local computer. The service did not return an error. This could be an internal Windows error or an internal service error.
There's not much code in my servicer so far only logging to even viewer which is working.
When I click stop a second time it finally stops the service, only after it times out while stopping, but does stop.
Could you please lead me in the correct direction to resolve this issue.
Thanks
Quinton
|
|
|
|
|
Hi Quinton,
This looks like another problem with hosting the ServiceBase in a class library instead of the executable itself. I did some more testing and believe I have it fixed. The code project article does not have the latest updates since I did it today. Please go to http://www.hoytsoft.org/serviceBase.aspx[^] to download the latest version (revision 3) and see the changes I've made. Apparently a callback from the service API was not working correctly, but should be fixed now. The delegate I was using for the service control handler callback was going out of scope and therefore garbage collected and then not around when the SCM tried to use the callback. So it should work as expected now!
|
|
|
|
|
I will give it try using the new code.
Thanks.
|
|
|
|
|
Hi
I have been using the service now, and havn't had any issues. I am even executing unsafe code now within it and it's still 100% stable. I am using this service in a project. Its a TIF file comparing service, that monitors a folder compares signatures of images and splits a TIF accordingly. I am concidering writing my first article around this current project.
Regards
Quinton
|
|
|
|
|
Hi there!
First: Seems to be a great piece of code!
My problem is: I tried to use it (Windows XP Home SP2) and got nothing but an error.
When I first ran the service from within SharpDevelop, I got an error after some seconds (cause the service was running in the console-window). The service was installed anyway and I could also manipulate it from within the appropriate Manager (I have no idea how this one is called in English).
I then looked around in the source a bit...when I tried to run the .exe file in (bin/Debug) I get the following error:
"Application has genetated an exception that could not be handled.
Process id=0xe88, Thread id=0xedc (3804)"
and the app terminates.
What's the problem? (I do not have any idea about services in .NET at all...)
Greets - Soykaf
|
|
|
|
|
You were probably running the first version of the program. I maintain an updated version on my website: http://www.hoytsoft.org/serviceBase.aspx. Please download the latest version from there and your problem should be pretty much fixed.
So what's the cause of your error? Well, if it's as I expect, it's by design. In the first version, the program did not auto-detect if you're running it as a console app or as a service. You could switch the console version on or off by setting the "Debug" property in the Service attribute. It would look like:
using System;
using HoytSoft.Service.Attributes;
namespace MyServices {
[Service(
"HoytSoft_TestService",
...
<code>Debug = true</code>
)]
public class TestService : HoytSoft.Service.ServiceBase {
...
}
}
Setting it to true will skip the service setup procedure and execute your program directly as normal. If you tried to start it up without this flag set to true in Sharp Develop, it would set up all the service entries with the windows API and I believe it used to throw a ServiceStartupException to inform you that you're not running it in Debug mode.
Again, an upgrade to the latest version should avoid the problem. Best of luck!
-- modified at 19:25 Wednesday 12th October, 2005
|
|
|
|
|
Nice article. Sure seems to be a lot simpler than trying to use the Visual Studio service installer that Microsoft discusses. Thanks for sharing.
I noticed that the code posted here has a copyright notice in ServiceBase.cs, but the same code posted on your website doesn't. I was considering using your code to make it easier to install an IP address monitoring service that I had written, but now I'm unsure.
What are the terms of your copyright ?
Is the code posted here a derivative work of the code on your website ? Does it remain un-copyrighted ?
Is only this one file in the project protected by your copyright ?
Steven J. Ackerman, Consultant
ACS, Sarasota, FL
http://www.acscontrol.com
http://spaces.msn.com/members/sjackerman
steve@acscontrol.com
|
|
|
|
|
Thanks for your interest! Just a note - the code on the website is actually more up to date than the code project article. I've been meaning to update the code project's version for the past few days but haven't been able to. The latest version auto-detects if you're running it as a service or console program and runs it accordingly. Also, please be aware that since it's self-installing, it implies that the person running it has the proper security permissions to install a service.
As for the copyright notice, thanks for letting me know - I hadn't realized I'd left it out. Please preserve the copyright notice as seen in the code project article when using the code from hoytsoft.org. I will be sure to make that fix ASAP. Please also note the disclaimer to the left of every page on hoytsoft.org and abide by those rules.
You may use the code in any way you like, including modification, as long as the original notice is left intact. Any derivative work should include the original notice in its header or about box as appropriate.
ServiceBase.cs is the only copyrighted file since ServicesAPI.cs was mostly taken from another article that I can't seem to find. Good luck on your project and I'd be happy to know how it turns out for you! If you have any bug fixes, please post them here. Thank you!
|
|
|
|
|