Re: Windows Service Help



Oops, I must be getting tired - I completely ignored the other half of your question in my last response.

Debugging services: the part more annoying than writing them. Basically, since a Windows service cannot be started directly within the IDE this is where that batch file I was talking about earlier comes into play. At the end of this message I've included an older version of the batch file I've been using for years when working on these services. Hopefully it'll alleviate some of the headaches you'll run into when working with Windows services.

You'll need to manually start the service, and then attach the debugger to the process like you said earlier. Also, if you're running the service under another account (system accounts included) make sure you check the box for "Show processes from all users" so you'll be able to see the service when it's running. Another note about Vista - if you're using Vista and the service is under a system or other user account you'll need to run Visual Studio as administrator or disable the UAC). If you want to debug the setup and teardown methods (OnStart and OnStop) of your service, you'll need to add a line in the method(s) to pause the thread temporarily to give you enough time to attach the debugger. I typically pause the thread for 10 seconds to give myself enough time. That's what the /debug switch is for you'll see in the bottom of the batch file i've included. I just checked the args when the service was starting to see if it's included in there, and if so pause the thread. Just don't pause it too long - if the service doesn't start fast enough Windows kills the process - sometimes even when you're trying to debug it.

Just copy everything from inside the block of asterisks (excluding the line of asterisks) into a .bat file. You'll only need to modify the first few lines of the batch file to get it to work with your service you wrote. This will handle uninstalling any existing version of the service you have on the machine, copying the new build, and running installutil on the new service as well as starting the service for you. If nothing else it'll give you a good starting point for your own file like this. Just put the file in the folder with your .*proj file.
*************************************************************************************

@echo off

set INSTALL_FOLDER=MyService
set EXECUTABLE_NAME=MyService.exe
set DOTNET_VERSION=2.0.50727
set SERVICE_NAME=MyService
set SERVICE_DESC=My First Service!
set COPYRIGHT_NOTICE=You won't need this more than likely

set INSTALL_PATH=%PROGRAMFILES%\%INSTALL_FOLDER%
set FULL_PATH=%PROGRAMFILES%\%INSTALL_FOLDER%\%EXECUTABLE_NAME%

cls
echo %SERVICE_DESC% Installer
echo %COPYRIGHT_NOTICE%
echo.

if [%1] == [/?] goto ShowSyntax
if [%1] == [?] goto ShowSyntax
if [%1] == [-?] goto ShowSyntax

if not exist "%SYSTEMROOT%\Microsoft.NET\Framework\v%DOTNET_VERSION%\InstallUtil.exe" goto NoDotNet
goto StartUninstall

:NoDotNet
echo The Microsoft .NET Framework v%DOTNET_VERSION% was not found on this machine.
echo Please install the framework before continuing with the installation.
goto FinishBatch

:StartUninstall
if not exist "%FULL_PATH%" goto StartInstall
echo.
echo ***********************************
echo * STOPPING THE SERVICE *
echo ***********************************
net stop %SERVICE_NAME%
echo.

if /I [%1] == [/s] goto ExitBatch

echo.
echo ***********************************
echo * UNINSTALLING PREVIOUS *
echo ***********************************
echo.
%SYSTEMROOT%\Microsoft.NET\Framework\v%DOTNET_VERSION%\InstallUtil /u "%FULL_PATH%"
echo.

if /I [%1] == [/u] goto RemoveFolder

:StartInstall
echo.
echo ***********************************
echo * COPYING THE NEW BUILD *
echo ***********************************
echo.
if exist "%INSTALL_PATH%" goto BeginCopying
md "%INSTALL_PATH%"

:BeginCopying
if /I [%1] == [/r] goto CopyRelease
if /I [%2] == [/r] goto CopyRelease

copy /y ".\bin\Debug\*.*" "%INSTALL_PATH%"
echo.
echo.
echo ***********************************
echo * SWAPPING CONFIG FILES *
echo ***********************************
echo.
del "%INSTALL_PATH%\connections.config"
ren "%INSTALL_PATH%\development.config" "connections.config"

goto FinishedCopyingBuild

:CopyRelease
copy /y ".\bin\Release\*.*" "%INSTALL_PATH%"

:FinishedCopyingBuild
echo.
echo.
echo ***********************************
echo * INSTALLING BUILD *
echo ***********************************
echo.
%SYSTEMROOT%\Microsoft.NET\Framework\v%DOTNET_VERSION%\InstallUtil "%FULL_PATH%"
del *.InstallLog
echo.
echo.

if /I [%1] == [/n] goto BypassStartup

echo ***********************************
echo * STARTING THE SERVICE *
echo ***********************************
echo.
if /I [%1] == [/r] goto StartRelease

net start %SERVICE_NAME% /debug
goto ExitBatch

:StartRelease
net start %SERVICE_NAME%
goto ExitBatch

:BypassStartup
echo ***********************************
echo * BYPASSING STARTUP *
echo ***********************************
goto ExitBatch

:ShowSyntax
echo Installs the %SERVICE_DESC% to the machine.
echo.
echo INSTALL [OPTION]
echo.
echo /S Forces the service to stop.
echo.
echo /U Uninstalls the service from the installation folder.
echo.
echo /N Bypasses startup for the service and only copies and installs
echo the service to the machine.
echo.
echo /R Copies the release build to the installation folder.
echo.
goto FinishBatch

:RemoveFolder
echo ***********************************
echo * REMOVING INSTALLATION FOLDER *
echo ***********************************
echo.
echo.
rd /s /q "%INSTALL_PATH%"
goto ExitBatch

:ExitBatch
echo | time | find "current"
echo | date | find "current"
echo.

:FinishBatch

*************************************************************************************

"Jeff Winn" <jwinn@xxxxxxxxxx> wrote in message news:BD9BB36B-29C1-4F7F-90ED-2036626B3C6B@xxxxxxxxxxxxxxxx
There's more to installing services than simply deploying the executable on the target machine. I didn't get too in depth on the installation, but in order for a service to be deployed and registered on the target machine you must have an installer class in there.

Deep within the System.Configuration.Install.Installer class there's some pinvoke operations that open the ServiceControlManager (SCM) used by Windows for service/device management and perform the installation into Windows. One of the things you need to do when installing services is in your MSI package you will need to create custom installer actions that tell the service to execute the installers that are located in your project. That's what the [RunInstaller(true)] attribute is for you see decorating your ProjectInstaller class below. Without the custom action being executed the service may be copied to the machine, but the service will not be registered with the computer.

If you really need to deploy services and you don't want to pay for the pro version of that software you mentioned, you might want to just use the setup projects that come with Visual Studio. Somehow I have the feeling the software isn't going to install the service properly unless you buy the upgraded version.

As for your question regarding testing, yes you will need the ProjectInstaller class in your service for the InstallUtil.exe to properly register the service on the machine.

"dm3281" <dm3281@xxxxxxxxxx> wrote in message news:645E16B7-372A-4689-9B6D-7DAE216FD40B@xxxxxxxxxxxxxxxx
Thanks for the quick response, Jeff.

I tried using AdvancedInstaller and it's relatively easy. Of course, only the professional version supports installing services, but all I have to do is browse for the .EXE and give it a service name/description and it will create an MSI. Very cool. I assume if I use this approach, then I can remove the "Installer" project that was added within VS as that isn't needed since I won't be using InstallUtil or anything, but maybe I should leave it for the cases where I want to manually test???



Now, off to another related topic.

What is the best way to debug a Windows service?

I plan on writing a program that scan foldres for XML files, procsess the XML files, then insert into SQL the information. This will run within a timer loop every 5 minutes or so.

I was thinking that I should write a console application first and create a class for my program. This way I can get everything tested and working.

I was then thinking I could create another project for my service program and add my class from my console project???

I'm not sure how I can actually debug this one I have it all within a service. I was under the impression that I could install the service, open VS and attach to the running process after setting my breakpoint and life would be good. But I do not appear to be able to step thru the code or anything. I assume I'm doing something wrong here....






"Jeff Winn" <jwinn@xxxxxxxxxx> wrote in message news:256034FB-49CB-471B-B7C4-9BEFCFDDFF1E@xxxxxxxxxxxxxxxx
Going to do my best to answer the questions - though you seem to have quite a few. I've put a block of asterisks at the end of my response since this is going to be quite large after answering everything. If you have any other questions please feel free to ask. I work with Windows services a lot. :o)

Why do I need to rename my project to the service name?
You don't, I do it to keep everything consistent.


Why do I need to set the "ServiceName" property to my service name?
Because Windows uses this when registering the service, and they must be unique. Also, if we're on the same page, this is the value used as your service name when writing events to the event log. Though I could be wrong, I'm not 100% sure which property you're talking about.


Why do I need to set a property within my code to the service name?
See above.


Are all these required or am I just doing this for consistency purposes?
They're required. If you provide incorrect information the service will have problems when registering. Which will usually throw an exception that you'll be able to see if you're registering the service with InstallUtil at the command prompt.


It pops up a dialoge asking me for service credentials. I'm not sure why because I've defined them within my "ProjectInstaller.cs". But I was getting this prior to setting any properties under the "ProjectInstaller.cs" file. Why do I get this?
Windows services run under a non-interactive user account on the machines. Typically when a service is first created in Visual Studio the default settings require a user account the service will run as. You can change this by opening your ProjectInstaller.cs file (double click it to bring up the designer) and select your processInstaller component that should be visible. If you want the service to run as a system account just change the account to the account type you want. Be cautious about doing this, the system accounts have unrestricted rights to the machine the service is running on. The ServiceAccount.User enum requires if the Username and Password properties on the component aren't set, when the service is being installed the account information must be prompted. The reason you have to give the full account (including domain/machine name) is because the service needs the entire credential when it's starting.


If I wanted to use a tool such as AdvancedInstaller from http://www.caphyon.com/, what would I need to do? Would I need any of these propteries set within the "ProjectInstallerDesigner.cs" file?
Does AdvancedInstaller allow me to browse to the .EXE, add it to my package, and then allow me to hardcode or prompt the user for what they want?
What's the best way to do this?
This would be a question better suited to be asked by the software vendor. I typically just use the Setup project available within Visual Studio for deploying services.

NOTE: InstallUtil will not be available on your target machines as it is not included with the .NET Framework. You will need to use an installer package to get the service registered on the deployment machine. Also, about that - you will need to use a custom installer action pointed to your service executable to get the installer package to register your service. The System.Configuration.Install.Installer class (which is the base class for the ProjectInstaller) you made, handles registering the service with the machine. You can use .NET Reflector if you want to actually take a look at the code in the class how it uses the Win32 API and pinvoke if you're interested in looking under the hood. :o)


After the service is installed, I appear to have two services:

SimpleService2
Hello-World

SimpleService2 won't start.
Hello-World starts and appears to work as expected. I can pause, etc. without issue and items are appearing in event log.

Executing "InstallUtil -u WindowsService2.exe" appears to get rid of both services.

I assume SimpleService2 is appearing because that is the name that I use within the "SimpleService.cs" file??
This would be a result of not using a consistent service name throughout the service. My suggestion would be to do a Find All within the IDE and search for "SimpleService2" throughout your application and make sure it's updated to the proper service name.


I assume the crendtial dialogue is coming from this service and not Hello-World because it appears to have the correct credentials.

How do I get rid of the dialoge all together?
See the above answer on the project installer.


How do I get rid of "SimpleService" installation, since it appears to not work anyway.
Change the service name in your application back to the original value, register the service again and finally remove it again. This will get the old service removed from the machine (hopefully) so it won't be listed.

HINT: When working with Windows services I have found it best to create a batch file to install and uninstall the services into the program files folder on my machine when testing. When InstallUtil is executed against the service assembly the configuration in that executable is what is used during the install/uninstall process. If you build the software before uninstalling the old version this is what can result.

**************************************************************************
**************************************************************************

"dm3281" <dm3281@xxxxxxxxxx> wrote in message news:43589E36-DA5F-4D59-98DC-72F7BE943462@xxxxxxxxxxxxxxxx
I'm really starting to hate writing services -- or trying to, anyway.

Why do I need to rename my project to the service name?

Why do I need to set the "ServiceName" property to my service name?

Why do I need to set a property within my code to the service name?

Are all these required or am I just doing this for consistency purposes?

Now for my real question/problem:

I have written this service and have this in my "SimpeService.cs":

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

namespace WindowsService2
{
public partial class SimpleService : System.ServiceProcess.ServiceBase
{
private System.Timers.Timer timer;

/// <summary>
/// Required deisgner variable
/// </summary>


public SimpleService()
{
// This call is required by the Windows.Forms Component Designer
InitializeComponent();

this.timer = new System.Timers.Timer();
this.timer.Enabled = true;
timer.Interval = 5000;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
CanPauseAndContinue = true;
this.ServiceName = "Hello-World Service";

}

void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
EventLog.WriteEntry("Hello World!");
//throw new Exception("The method or operation is not implemented.");
}

protected override void OnStart(string[] args)
{
// TODO: Add code here to start your service.
EventLog.WriteEntry("Hello-World Service Started");
timer.Enabled = true;
}

protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
EventLog.WriteEntry("Hello-World Service Paused");
timer.Enabled = false;
}

protected override void OnPause()
{
EventLog.WriteEntry("Hello-World Service paused");
timer.Enabled = false;
}

protected override void OnContinue()
{
EventLog.WriteEntry("Hello-World Service continued");
timer.Enabled = true;
}

}
}


This is in my "ProjectInstaller.cs" and I have set the service properties, etc:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace WindowsService2
{
[RunInstaller(true)]
public partial class ProjectInstaller : Installer
{
private ServiceInstaller serviceInstaller;
private ServiceProcessInstaller processInstaller;

public ProjectInstaller()
{
InitializeComponent();

processInstaller = new ServiceProcessInstaller();
serviceInstaller = new ServiceInstaller();

// Service will run under system account
processInstaller.Account = ServiceAccount.LocalSystem;

// Service will have Start Type of Manual
serviceInstaller.StartType = ServiceStartMode.Manual;
serviceInstaller.ServiceName = "Hello-World Service";
Installers.Add(serviceInstaller);
Installers.Add(processInstaller);
}
}
}

My "Program.cs" has no changes:

using System.Collections.Generic;
using System.ServiceProcess;
using System.Text;

namespace WindowsService2
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;

// More than one user Service may run within the same process. To add
// another service to this process, change the following line to
// create a second service object. For example,
//
// ServicesToRun = new ServiceBase[] {new Service1(), new MySecondUserService()};
//
ServicesToRun = new ServiceBase[] { new SimpleService() };

ServiceBase.Run(ServicesToRun);
}
}
}

Now, when I compiel the above, it all compiles fine.

I then jump to Admin Command Prompt and do a "installutil WindowsService2.exe" and it does the following:

It pops up a dialoge asking me for service credentials. I'm not sure why because I've defined them within my "ProjectInstaller.cs". But I was getting this prior to setting any properties under the "ProjectInstaller.cs" file. Why do I get this?

The format of the credentials appears to only accept "machinename\username" and nothing else. It took me a while to figure this out! Arrghhh

After the service is installed, I appear to have two services:

SimpleService2
Hello-World

SimpleService2 won't start.
Hello-World starts and appears to work as expected. I can pause, etc. without issue and items are appearing in event log.

Executing "InstallUtil -u WindowsService2.exe" appears to get rid of both services.

I assume SimpleService2 is appearing because that is the name that I use within the "SimpleService.cs" file??

I assume the crendtial dialogue is coming from this service and not Hello-World because it appears to have the correct credentials.

How do I get rid of the dialoge all together?

How do I get rid of "SimpleService" installation, since it appears to not work anyway.

Any help would be appreciated.








.



Relevant Pages

  • RE: KB947742 Install issues
    ... but this patch is not playing nicely. ... Windows installer version is 3.01.4000.1832. ... @ECHO Please be patient as these patches will take a few moments to ...
    (microsoft.public.windowsupdate)
  • Re: [Full-disclosure] hidden users on windows?
    ... Account' with this line: ... > @echo HideUserXP.bat ... > Windows dialog box by pressing Ctrl + Alt + Delete twice. ... The User Account Manager in the ...
    (Full-Disclosure)
  • Re: Apple Remote Desktop root vulneravility
    ... This exploit involves sending a unix command as root to install a package that was copied to /tmp/. ... If you are trying to run a remote install script such as the Adobe Silent installer, use the lock screen feature in ARD. ... trap 'cd "$"' EXIT ... echo "This version of MacOS is not supported." ...
    (Bugtraq)
  • Apple Remote Desktop root vulneravility
    ... If you are trying to run a remote install script such as the Adobe Silent installer, use the lock screen feature in ARD. ... trap 'cd "$"' EXIT ... echo "This version of MacOS is not supported." ...
    (Bugtraq)
  • Re: Apple Remote Desktop root vulneravility
    ... If you are trying to run a remote install script such as the Adobe Silent installer, use the lock screen feature in ARD. ... # umount any previous mounted installer images ... trap 'cd "$"' EXIT ... echo "This version of MacOS is not supported." ...
    (Bugtraq)