|
|
Comments and Discussions
|
|
 |

|
BTW, this code works great under XP. Under Vista, an error occurs whenever the service is stopped: Error 1061: The service cannot accept control message at this time. Any advice on fixing this error?
thanks again for the good work
jgates
|
|
|
|

|
The latest version addresses this issue and it should be resolved. Please let me know if it persists. See my post "NEW RELEASE!" for more info.
|
|
|
|

|
Just wondering, is there a OnCustomCommand(int) Method exposed ? and if not can it be implemented
i have many services which use it for custome control of the services (like starting and stoping diffrent components of the service)
|
|
|
|
|

|
You can use the baseServiceControlHandler Function > All msgs go there > It's possible to forward all Messages >128 and <255 to a custom event / delegate
|
|
|
|

|
This was added in the lastest version. See my post titled "NEW RELEASE!" for more info.
|
|
|
|

|
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:
string processPath = Process.GetCurrentProcess().MainModule.FileName;
if (processPath != null && processPath.Length > 0) {
System.IO.FileInfo fi = new System.IO.FileInfo(processPath);
|
|
|
|

|
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]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Services\HoytSoft Example Service]
"EventMessageFile"="C:\\WINDOWS\\Microsoft.NET\\Framework\\v1.1.4322\\EventLogMessages.dll"
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Services\Services]
"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 linethis.log.Source = this.displayName; replace it withthis.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.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
Sometimes the service classes provided by Visual Studio don't give you the control you need, so why not build your own? And while you're at it, why not make it self-installing? The base class provided gives you full control of the Win32 Services API from a convenient base class and attribute.
| Type | Article |
| Licence | CPOL |
| First Posted | 5 Oct 2005 |
| Views | 100,016 |
| Bookmarked | 86 times |
|
|