Start windows service on install without setup project - c#

I have developed a windows service, but need it to start automatically on install. Problem is that every tutorial I found is showing me through the Setup Project. There is a fantastic 3 part tutorial HERE that I used to convert my app to a service, but I don't have the Setup Project in my other project types. Can I do this programatically or is there a way I can get the Setup Project project type?

In your Installer class, add a handler for the AfterInstall event. You can then call the ServiceController in the event handler to start the service.
public ServiceInstaller()
{
//... Installer code here
this.AfterInstall += new InstallEventHandler(ServiceInstaller_AfterInstall);
}
void ServiceInstaller_AfterInstall(object sender, InstallEventArgs e)
{
using (ServiceController sc = new ServiceController(serviceInstaller.ServiceName))
{
sc.Start();
}
}
Now when you run InstallUtil on your installer it will install and then start up the service.
MSDN link for more details

I believe Topshelf project has built-in service Installer/Uninstaller. when integrated in the application, it can be installed as a service through simple command from application itself, for example we can easily install and start myService.exe with myService.exe install start command.
we can simply create a self installing service, here is an Example:
public class ServiceClass
{
public ServiceClass()
{
}
public void Start() { }
public void Stop() { }
}
public class Program
{
public static void Main(string[] args)
{
//we can simply install our service by setting specific commands for same or install it directly from command line or from another process
if (args.Length == 0)
{
var processName = Process.GetCurrentProcess().ProcessName + ".exe";
var install = Process.Start(processName, "install start");
install.WaitForExit();
return;
}
HostFactory.Run(x =>
{
x.Service<ServiceClass>(s =>
{
s.ConstructUsing(name => new ServiceClass());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.RunAsLocalSystem();
x.SetDescription("Topshelf Host");
x.SetDisplayName("TopShelf");
x.SetServiceName("TopShelf");
});
}
}
you can get Topshelf through PM> Install-Package Topshelf Nuget command.

Best thing to do is to add on the Installer Projects Extension!
The Setup project type was deprecated after VS 2010, but following feedback Microsoft have brought back a new version for VS 2013.
Install the new Installer Projects Extension from Microsoft: https://visualstudiogallery.msdn.microsoft.com/9abe329c-9bba-44a1-be59-0fbf6151054d
This should work for any non-express version of Visual Studio 2013 (including the new free Community Edition SDK)
Then you can just follow the same instructions as for the VS 2010 setup projects :)
There isn't an easy option for VS2012 (you could try an installer with WiX I guess, but thats a lot to learn!)
I'm not sure if InstallShield LE (free version for VS2012) would work for this situation, but you could give it a try.
You can always change the startup type of a service after installation remember. (Control Panel -> Administrative Tools -> Services -> right click service -> Properties -> change "Startup Type" to "Automatic" )

If you are targeting Windows 7 and up, Powershell is installed by default. One option is to run a simple powershell script which installs the service, starts it, and sets the service to start automatically if the machine is rebooted:
InstallUtil yourService.exe
Start-Service yourService
Set-Service yourService -startuptype "Automatic"

Related

New WIn UI project crashes

I have installed the winui extension to Visual Studio 19. I created a new project using the Win UI desktop template. I have built the two projects created (one is the package). I try to run the project before adding any code and it immediately crashes at start up. The error is
COMException: Class not registered (0x80040154 (REGDB_E_CLASSNOTREG))
The error occurs at the last line of this subroutine (marked with **)
public static class Program
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.UI.Xaml.Markup.Compiler"," 0.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.STAThreadAttribute]
static void Main(string[] args)
{
global::WinRT.ComWrappersSupport.InitializeComWrappers();
**global::Microsoft.UI.Xaml.Application.Start((p) => {
var context = new global::Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext(global::Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());**
global::System.Threading.SynchronizationContext.SetSynchronizationContext(context);
new App();
});
}
}
I'm at a loss to fix the error.
I managed to solve the problem. with the help of this post
https://gitmemory.com/issue/microsoft/microsoft-ui-xaml/5054/845542110
I need to deploy the solution. (Go to solution properties, Configuration and check the build and deploy boxes.
Deploy the package application.
Set the package application to the Startup project.
run the project.

trying to create windows service from console application but it will not install

I am trying to use this tutorial from microsoft.... here
I cannot get installutil to install it... I keep getting "Remove InstallState file because there are no installers."
There is clearly an installer in the exe.... here is the installer as it exists in my code:
// Provide the ProjectInstaller class which allows
// the service to be installed by the Installutil.exe tool
[RunInstaller(true)]
public class ProjectInstaller : Installer
{
private ServiceProcessInstaller process;
private ServiceInstaller service;
public ProjectInstaller()
{
process = new ServiceProcessInstaller();
process.Account = ServiceAccount.LocalSystem;
service = new ServiceInstaller();
service.ServiceName = "WCFWindowsServiceSample";
Installers.Add(process);
Installers.Add(service);
}
}
}
This is pretty annoying at this point. If someone could look at the Microsoft article which is pretty simple I would appreciate any help. With the installer there, I don't know why the installutil will not find it.
Yes I am running a visual studio command prompt as an administrator to do this.
Oddly to fix this I needed to move the installer to a new cs file and that did it. I simply created a new class file and moved the exact same class from the main file to this other file and it installed ok. It doesn't make sense to me but this is a workaround for those who may be interested.

How to run a setup from another setup?

I have a solution with 3 modules. Windows, Web, and Windows Service. I want to create one parent setup that runs three child setup packages regarding to the user choose.
I created a setup project as the following:
I created a library that contains InstallerHelper which is inherited from Installer class
I added the following code:
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
FileInfo fileInfo = new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
string sProgram = Path.Combine(fileInfo.DirectoryName, "Setup1.msi");
Process p = Process.Start(sProgram);
p.WaitForExit();
}
catch (Exception exc)
{
Context.LogMessage(exc.ToString());
throw;
}
}
The problem is that the windows installer refuses to run multiple instances of windows installer and throws the following error:
Another installation is in progress. You must complete that
installation before continuing this one.
Is my approach correct? Is ther another way to run another setup and the parent setup should wait all of them with one Finish click?.
You can use Wix Burn to create a setup package contained multiple application installers (msi/exe):
Wix Toolset: Building Installation Package Bundles
Neil Sleightholm's Blog: WiX Burn – tips/tricks

How to create an installer for a .net Windows Service using Visual Studio

How do I create an installer for a Windows Service that I have created using Visual Studio?
In the service project do the following:
In the solution explorer double click your services .cs file. It should bring up a screen that is all gray and talks about dragging stuff from the toolbox.
Then right click on the gray area and select add installer. This will add an installer project file to your project.
Then you will have 2 components on the design view of the ProjectInstaller.cs (serviceProcessInstaller1 and serviceInstaller1). You should then setup the properties as you need such as service name and user that it should run as.
Now you need to make a setup project. The best thing to do is use the setup wizard.
Right click on your solution and add a new project: Add > New Project > Setup and Deployment Projects > Setup Wizard
a. This could vary slightly for different versions of Visual Studio.
b. Visual Studio 2010 it is located in: Install Templates > Other Project Types > Setup and Deployment > Visual Studio Installer
On the second step select "Create a Setup for a Windows Application."
On the 3rd step, select "Primary output from..."
Click through to Finish.
Next edit your installer to make sure the correct output is included.
Right click on the setup project in your Solution Explorer.
Select View > Custom Actions. (In VS2008 it might be View > Editor > Custom Actions)
Right-click on the Install action in the Custom Actions tree and select 'Add Custom Action...'
In the "Select Item in Project" dialog, select Application Folder and click OK.
Click OK to select "Primary output from..." option. A new node should be created.
Repeat steps 4 - 5 for commit, rollback and uninstall actions.
You can edit the installer output name by right clicking the Installer project in your solution and select Properties. Change the 'Output file name:' to whatever you want. By selecting the installer project as well and looking at the properties windows, you can edit the Product Name, Title, Manufacturer, etc...
Next build your installer and it will produce an MSI and a setup.exe. Choose whichever you want to use to deploy your service.
I follow Kelsey's first set of steps to add the installer classes to my service project, but instead of creating an MSI or setup.exe installer I make the service self installing/uninstalling. Here's a bit of sample code from one of my services you can use as a starting point.
public static int Main(string[] args)
{
if (System.Environment.UserInteractive)
{
// we only care about the first two characters
string arg = args[0].ToLowerInvariant().Substring(0, 2);
switch (arg)
{
case "/i": // install
return InstallService();
case "/u": // uninstall
return UninstallService();
default: // unknown option
Console.WriteLine("Argument not recognized: {0}", args[0]);
Console.WriteLine(string.Empty);
DisplayUsage();
return 1;
}
}
else
{
// run as a standard service as we weren't started by a user
ServiceBase.Run(new CSMessageQueueService());
}
return 0;
}
private static int InstallService()
{
var service = new MyService();
try
{
// perform specific install steps for our queue service.
service.InstallService();
// install the service with the Windows Service Control Manager (SCM)
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
}
catch (Exception ex)
{
if (ex.InnerException != null && ex.InnerException.GetType() == typeof(Win32Exception))
{
Win32Exception wex = (Win32Exception)ex.InnerException;
Console.WriteLine("Error(0x{0:X}): Service already installed!", wex.ErrorCode);
return wex.ErrorCode;
}
else
{
Console.WriteLine(ex.ToString());
return -1;
}
}
return 0;
}
private static int UninstallService()
{
var service = new MyQueueService();
try
{
// perform specific uninstall steps for our queue service
service.UninstallService();
// uninstall the service from the Windows Service Control Manager (SCM)
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
}
catch (Exception ex)
{
if (ex.InnerException.GetType() == typeof(Win32Exception))
{
Win32Exception wex = (Win32Exception)ex.InnerException;
Console.WriteLine("Error(0x{0:X}): Service not installed!", wex.ErrorCode);
return wex.ErrorCode;
}
else
{
Console.WriteLine(ex.ToString());
return -1;
}
}
return 0;
}
Nor Kelsey, nor Brendan solutions does not works for me in Visual Studio 2015 Community.
Here is my brief steps how to create service with installer:
Run Visual Studio, Go to File->New->Project
Select .NET Framework 4, in 'Search Installed Templates' type 'Service'
Select 'Windows Service'. Type Name and Location. Press OK.
Double click Service1.cs, right click in designer and select 'Add Installer'
Double click ProjectInstaller.cs. For serviceProcessInstaller1 open Properties tab and change 'Account' property value to 'LocalService'. For serviceInstaller1 change 'ServiceName' and set 'StartType' to 'Automatic'.
Double click serviceInstaller1. Visual Studio creates serviceInstaller1_AfterInstall event. Write code:
private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
using (System.ServiceProcess.ServiceController sc = new
System.ServiceProcess.ServiceController(serviceInstaller1.ServiceName))
{
sc.Start();
}
}
Build solution. Right click on project and select 'Open Folder in File Explorer'. Go to bin\Debug.
Create install.bat with below script:
:::::::::::::::::::::::::::::::::::::::::
:: Automatically check & get admin rights
:::::::::::::::::::::::::::::::::::::::::
#echo off
CLS
ECHO.
ECHO =============================
ECHO Running Admin shell
ECHO =============================
:checkPrivileges
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges )
:getPrivileges
if '%1'=='ELEV' (shift & goto gotPrivileges)
ECHO.
ECHO **************************************
ECHO Invoking UAC for Privilege Escalation
ECHO **************************************
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs"
ECHO UAC.ShellExecute "!batchPath!", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs"
"%temp%\OEgetPrivileges.vbs"
exit /B
:gotPrivileges
::::::::::::::::::::::::::::
:START
::::::::::::::::::::::::::::
setlocal & pushd .
cd /d %~dp0
%windir%\Microsoft.NET\Framework\v4.0.30319\InstallUtil /i "WindowsService1.exe"
pause
Create uninstall.bat file (change in pen-ult line /i to /u)
To install and start service run install.bat, to stop and uninstall run uninstall.bat
For VS2017 you will need to add the "Microsoft Visual Studio 2017 Installer Projects" VS extension. This will give you additional Visual Studio Installer project templates. https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects#overview
To install the windows service you can add a new setup wizard type project and follow the steps from Kelsey's answer https://stackoverflow.com/a/9021107/1040040
InstallUtil classes ( ServiceInstaller ) are considered an anti-pattern by the Windows Installer community. It's a fragile, out of process, reinventing of the wheel that ignores the fact that Windows Installer has built-in support for Services.
Visual Studio deployment projects ( also not highly regarded and deprecated in the next release of Visual Studio ) do not have native support for services. But they can consume merge modules. So I would take a look at this blog article to understand how to create a merge module using Windows Installer XML that can express the service and then consume that merge module in your VDPROJ solution.
Augmenting InstallShield using Windows Installer XML - Windows Services
IsWiX Windows Service Tutorial
IsWiX Windows Service Video

How can I register a winservice?

How can I register a windows service within c#.net?
Have a look at these
Creating a Basic Windows Service in
C#
Creating a Windows Service with C#
Creating a Windows Service in C#
To find out if the service is already installed, get the list of services that are installed, and see if yours is in it:
bool existsAlready = System.ServiceProcess.ServiceController.GetServices()
.Where(service => service.ServiceName == yourServiceName)
.Any();
To actually install it, you have to create an installer object and tell it your executable and service name. Something like:
ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller
{
Account = ServiceAccount.LocalService
};
string executablePath = String.Format("/assemblypath={0}", "yourprogram.exe"));
InstallContext context = new InstallContext(null, new[] { executablePath });
var installer = new ServiceInstaller
{
Context = context,
DisplayName = yourServiceName,
Description = yourServiceName,
ServiceName = yourServiceName,
StartType = ServiceStartMode.Automatic,
Parent = serviceProcessInstaller,
};
installer.Install(new System.Collections.Specialized.ListDictionary());
This is more or less all that InstallUtil.exe would do with your classes if you did it the documented way.
To start or stop a service, use the ServiceController class.
Have a look at Writting Windows Service
Here (Easiest language to create a windows service) is a step-by-step set of instructions for creating a Windows service in C#. Steps 6-9 show how to prepare your service to be registered with the local machine. Step 9 discusses how to use InstallUtil.exe to install your service.
To take it a step further, you can refer to the step-by-step instructions here (How to make a .NET Windows Service start right after the installation?) in order to have your Windows service install itself from the command line, i.e., without having to use InstallUtil.exe. For example, to install the service, you'd use this
MyService.exe /install
To uninstall, you'd do this
MyService.exe /uninstall
How do you register a Windows Service during installation? question tells us about this great step-by-step tutorial:
Walkthrough: Creating a Windows Service Application in the Component Designer.
There are several ways. It depends on the context:
1) You can create a Windows Installer package to do this for production. I believe a Visual Studio setup project will do this.
2) For development, installutil.exe should do it, as Svetlozar Angelov already said.
3) If you really need to customise the installation somehow you can write your own .NET code to do it. Look at the System.ServiceProcess.ServiceInstaller class.

Categories