¿Cómo ejecutar una aplicación de consola desde el servicio de Windows?

Tengo un servicio de Windows, escrito en c # y necesito ejecutar una aplicación de consola. Aplicación de consola también escrita en c #.

La aplicación de consola se ejecuta correctamente cuando se ejecuta no desde el servicio de Windows. Cuando se ejecuta desde ws no hace nada que debería y como debería funcionar durante 10-20 segundos que veo en el código de depuración se ejecuta a la vez.

Estoy comenzando mi aplicación de consola con el siguiente código:

proc.Start(fullPathToConsole, args); proc.WaitForExit(); 

el camino a la consola es correcto y cuando bash ejecutarlo desde el cmd o simplemente en el explorador (sin args) funciona bien. Pero después de correr con el servicio no veo ningún efecto.

Ya traté de ir a propiedades de servicio y darle acceso al escritorio y ejecutar tanto en el sistema como en mi usuario (también especificado en las propiedades del servicio). Todo permanece igual.

ADICIÓN: sé que el servicio no tiene ui y no quiero uno. Quiero que el servicio ejecute la aplicación de la consola. No es necesario obtener ningún dato o usar esta consola como ui, simplemente ejecutarlo para hacer su trabajo.

ACTUALIZAR I: descubrió, ejecutar calc o cualquier otra aplicación de Windows es fácil. Pero aún no se puede ejecutar cmd o cualquier aplicación de consola. En realidad, necesito ejecutarlo en XP SP2 y Windows 2003 Server. Por lo tanto, no es necesario que interactúes con Vista de todos modos.

Estaría encantado de cualquier comentario!

A partir de Windows Vista, un servicio no puede interactuar con el escritorio. No podrá ver ninguna ventana o ventanas de consola que se inicien desde un servicio. Vea este hilo del foro de MSDN .

En otro sistema operativo, hay una opción disponible en la opción de servicio llamada “Permitir que el servicio interactúe con el escritorio”. Técnicamente, debe progtwigr para el futuro y debe seguir la guía de Vista, incluso si no lo usa en Vista.

Si aún desea ejecutar una aplicación que nunca interactúa con el escritorio, intente especificar el proceso para no usar el shell.

 ProcessStartInfo info = new ProcessStartInfo(@"c:\myprogram.exe"); info.UseShellExecute = false; info.RedirectStandardError = true; info.RedirectStandardInput = true; info.RedirectStandardOutput = true; info.CreateNoWindow = true; info.ErrorDialog = false; info.WindowStyle = ProcessWindowStyle.Hidden; Process process = Process.Start(info); 

Mira si esto funciona.

Primero informa a Windows que el progtwig no usará el shell (que es inaccesible en Vista para el servicio).

En segundo lugar, redirige la interacción de todas las consolas a la transmisión interna (consulte process.StandardInput y process.StandardOutput .

Lo he hecho antes con éxito. Tengo un código en casa. Cuando llegue a casa esta noche, actualizaré esta respuesta con el código de trabajo de un servicio que inicia una aplicación de consola.

Pensé en probar esto desde cero. Aquí hay un código que escribí que inicia una aplicación de consola. Lo instalé como un servicio y lo ejecuté y funcionó correctamente: se inicia cmd.exe (como se ve en el Administrador de tareas) y vive durante 10 segundos hasta que le envíe el comando de salida. Espero que esto ayude a su situación, ya que funciona correctamente como se espera aquí.

  using (System.Diagnostics.Process process = new System.Diagnostics.Process()) { process.StartInfo = new System.Diagnostics.ProcessStartInfo(@"c:\windows\system32\cmd.exe"); process.StartInfo.CreateNoWindow = true; process.StartInfo.ErrorDialog = false; process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.UseShellExecute = false; process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; process.Start(); //// do some other things while you wait... System.Threading.Thread.Sleep(10000); // simulate doing other things... process.StandardInput.WriteLine("exit"); // tell console to exit if (!process.HasExited) { process.WaitForExit(120000); // give 2 minutes for process to finish if (!process.HasExited) { process.Kill(); // took too long, kill it off } } } 

Los Servicios de Windows no tienen UI. Puede redirigir el resultado de una aplicación de consola a su servicio con el código que se muestra en esta pregunta .

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.ServiceProcess; using System.Runtime.InteropServices; namespace SystemControl { class Services { static string strPath = @"D:\"; static void Main(string[] args) { string strServiceName = "WindowsService1"; CreateFolderStructure(strPath); string svcPath = @"D:\Applications\MSC\Agent\bin\WindowsService1.exe"; if (!IsInstalled(strServiceName)) { InstallAndStart(strServiceName, strServiceName, svcPath + " -k runservice"); } else { Console.Write(strServiceName + " already installed. Do you want to Uninstalled the Service.Y/N.?"); string strKey = Console.ReadLine(); if (!string.IsNullOrEmpty(strKey) && (strKey.StartsWith("y")|| strKey.StartsWith("Y"))) { StopService(strServiceName); Uninstall(strServiceName); ServiceLogs(strServiceName + " Uninstalled.!", strPath); Console.Write(strServiceName + " Uninstalled.!"); Console.Read(); } } } #region "Environment Variables" public static string GetEnvironment(string name, bool ExpandVariables = true) { if (ExpandVariables) { return System.Environment.GetEnvironmentVariable(name); } else { return (string)Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment\").GetValue(name, "", Microsoft.Win32.RegistryValueOptions.DoNotExpandEnvironmentNames); } } public static void SetEnvironment(string name, string value) { System.Environment.SetEnvironmentVariable(name, value); } #endregion #region "ServiceCalls Native" public static ServiceController[] List { get { return ServiceController.GetServices(); } } public static void Start(string serviceName, int timeoutMilliseconds) { ServiceController service = new ServiceController(serviceName); try { TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds); service.Start(); service.WaitForStatus(ServiceControllerStatus.Running, timeout); } catch(Exception ex) { // ... } } public static void Stop(string serviceName, int timeoutMilliseconds) { ServiceController service = new ServiceController(serviceName); try { TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds); service.Stop(); service.WaitForStatus(ServiceControllerStatus.Stopped, timeout); } catch { // ... } } public static void Restart(string serviceName, int timeoutMilliseconds) { ServiceController service = new ServiceController(serviceName); try { int millisec1 = Environment.TickCount; TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds); service.Stop(); service.WaitForStatus(ServiceControllerStatus.Stopped, timeout); // count the rest of the timeout int millisec2 = Environment.TickCount; timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2 - millisec1)); service.Start(); service.WaitForStatus(ServiceControllerStatus.Running, timeout); } catch { // ... } } public static bool IsInstalled(string serviceName) { // get list of Windows services ServiceController[] services = ServiceController.GetServices(); // try to find service name foreach (ServiceController service in services) { if (service.ServiceName == serviceName) return true; } return false; } #endregion #region "ServiceCalls API" private const int STANDARD_RIGHTS_REQUIRED = 0xF0000; private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010; [Flags] public enum ServiceManagerRights { Connect = 0x0001, CreateService = 0x0002, EnumerateService = 0x0004, Lock = 0x0008, QueryLockStatus = 0x0010, ModifyBootConfig = 0x0020, StandardRightsRequired = 0xF0000, AllAccess = (StandardRightsRequired | Connect | CreateService | EnumerateService | Lock | QueryLockStatus | ModifyBootConfig) } [Flags] public enum ServiceRights { QueryConfig = 0x1, ChangeConfig = 0x2, QueryStatus = 0x4, EnumerateDependants = 0x8, Start = 0x10, Stop = 0x20, PauseContinue = 0x40, Interrogate = 0x80, UserDefinedControl = 0x100, Delete = 0x00010000, StandardRightsRequired = 0xF0000, AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig | QueryStatus | EnumerateDependants | Start | Stop | PauseContinue | Interrogate | UserDefinedControl) } public enum ServiceBootFlag { Start = 0x00000000, SystemStart = 0x00000001, AutoStart = 0x00000002, DemandStart = 0x00000003, Disabled = 0x00000004 } public enum ServiceState { Unknown = -1, // The state cannot be (has not been) retrieved. NotFound = 0, // The service is not known on the host server. Stop = 1, // The service is NET stopped. Run = 2, // The service is NET started. Stopping = 3, Starting = 4, } public enum ServiceControl { Stop = 0x00000001, Pause = 0x00000002, Continue = 0x00000003, Interrogate = 0x00000004, Shutdown = 0x00000005, ParamChange = 0x00000006, NetBindAdd = 0x00000007, NetBindRemove = 0x00000008, NetBindEnable = 0x00000009, NetBindDisable = 0x0000000A } public enum ServiceError { Ignore = 0x00000000, Normal = 0x00000001, Severe = 0x00000002, Critical = 0x00000003 } [StructLayout(LayoutKind.Sequential)] private class SERVICE_STATUS { public int dwServiceType = 0; public ServiceState dwCurrentState = 0; public int dwControlsAccepted = 0; public int dwWin32ExitCode = 0; public int dwServiceSpecificExitCode = 0; public int dwCheckPoint = 0; public int dwWaitHint = 0; } [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerA")] private static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, ServiceManagerRights dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "OpenServiceA", CharSet = CharSet.Ansi)] private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceRights dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "CreateServiceA")] private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceRights dwDesiredAccess, int dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword); [DllImport("advapi32.dll")] private static extern int CloseServiceHandle(IntPtr hSCObject); [DllImport("advapi32.dll")] private static extern int QueryServiceStatus(IntPtr hService, SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll", SetLastError = true)] private static extern int DeleteService(IntPtr hService); [DllImport("advapi32.dll")] private static extern int ControlService(IntPtr hService, ServiceControl dwControl, SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll", EntryPoint = "StartServiceA")] private static extern int StartService(IntPtr hService, int dwNumServiceArgs, int lpServiceArgVectors); ///  /// Takes a service name and tries to stop and then uninstall the windows serviceError ///  /// The windows service name to uninstall public static void Uninstall(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr service = OpenService(scman, ServiceName, ServiceRights.StandardRightsRequired | ServiceRights.Stop | ServiceRights.QueryStatus); if (service == IntPtr.Zero) { throw new ApplicationException("Service not installed."); } try { StopService(service); int ret = DeleteService(service); if (ret == 0) { int error = Marshal.GetLastWin32Error(); throw new ApplicationException("Could not delete service " + error); } } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scman); } } ///  /// Accepts a service name and returns true if the service with that service name exists ///  /// The service name that we will check for existence /// True if that service exists false otherwise public static bool ServiceIsInstalled(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr service = OpenService(scman, ServiceName, ServiceRights.QueryStatus); if (service == IntPtr.Zero) return false; CloseServiceHandle(service); return true; } finally { CloseServiceHandle(scman); } } ///  /// Takes a service name, a service display name and the path to the service executable and installs / starts the windows service. ///  /// The service name that this service will have /// The display name that this service will have /// The path to the executable of the service public static void InstallAndStart(string ServiceName, string DisplayName, string FileName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect | ServiceManagerRights.CreateService); try { string strKey = string.Empty; IntPtr service = OpenService(scman, ServiceName, ServiceRights.QueryStatus | ServiceRights.Start); if (service == IntPtr.Zero) { service = CreateService(scman, ServiceName, DisplayName, ServiceRights.QueryStatus | ServiceRights.Start, SERVICE_WIN32_OWN_PROCESS, ServiceBootFlag.AutoStart, ServiceError.Normal, FileName, null, IntPtr.Zero, null, null, null); ServiceLogs(ServiceName + " Installed Sucessfully.!", strPath); Console.Write(ServiceName + " Installed Sucessfully.! Do you want to Start the Service.Y/N.?"); strKey=Console.ReadLine(); } if (service == IntPtr.Zero) { ServiceLogs("Failed to install service.", strPath); throw new ApplicationException("Failed to install service."); } try { if (!string.IsNullOrEmpty(strKey) && (strKey.StartsWith("y") || strKey.StartsWith("Y"))) { StartService(service); ServiceLogs(ServiceName + " Started Sucessfully.!", strPath); Console.Write(ServiceName + " Started Sucessfully.!"); Console.Read(); } } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scman); } } ///  /// Takes a service name and starts it ///  /// The service name public static void StartService(string Name) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus | ServiceRights.Start); if (hService == IntPtr.Zero) { ServiceLogs("Could not open service.", strPath); throw new ApplicationException("Could not open service."); } try { StartService(hService); } finally { CloseServiceHandle(hService); } } finally { CloseServiceHandle(scman); } } ///  /// Stops the provided windows service ///  /// The service name that will be stopped public static void StopService(string Name) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus | ServiceRights.Stop); if (hService == IntPtr.Zero) { ServiceLogs("Could not open service.", strPath); throw new ApplicationException("Could not open service."); } try { StopService(hService); } finally { CloseServiceHandle(hService); } } finally { CloseServiceHandle(scman); } } ///  /// Stars the provided windows service ///  /// The handle to the windows service private static void StartService(IntPtr hService) { SERVICE_STATUS status = new SERVICE_STATUS(); StartService(hService, 0, 0); WaitForServiceStatus(hService, ServiceState.Starting, ServiceState.Run); } ///  /// Stops the provided windows service ///  /// The handle to the windows service private static void StopService(IntPtr hService) { SERVICE_STATUS status = new SERVICE_STATUS(); ControlService(hService, ServiceControl.Stop, status); WaitForServiceStatus(hService, ServiceState.Stopping, ServiceState.Stop); } ///  /// Takes a service name and returns the ServiceState of the corresponding service ///  /// The service name that we will check for his ServiceState /// The ServiceState of the service we wanted to check public static ServiceState GetServiceStatus(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, ServiceName, ServiceRights.QueryStatus); if (hService == IntPtr.Zero) { return ServiceState.NotFound; } try { return GetServiceStatus(hService); } finally { CloseServiceHandle(scman); } } finally { CloseServiceHandle(scman); } } ///  /// Gets the service state by using the handle of the provided windows service ///  /// The handle to the service /// The ServiceState of the service private static ServiceState GetServiceStatus(IntPtr hService) { SERVICE_STATUS ssStatus = new SERVICE_STATUS(); if (QueryServiceStatus(hService, ssStatus) == 0) { ServiceLogs("Failed to query service status.", strPath); throw new ApplicationException("Failed to query service status."); } return ssStatus.dwCurrentState; } ///  /// Returns true when the service status has been changes from wait status to desired status /// ,this method waits around 10 seconds for this operation. ///  /// The handle to the service /// The current state of the service /// The desired state of the service /// bool if the service has successfully changed states within the allowed timeline private static bool WaitForServiceStatus(IntPtr hService, ServiceState WaitStatus, ServiceState DesiredStatus) { SERVICE_STATUS ssStatus = new SERVICE_STATUS(); int dwOldCheckPoint; int dwStartTickCount; QueryServiceStatus(hService, ssStatus); if (ssStatus.dwCurrentState == DesiredStatus) return true; dwStartTickCount = Environment.TickCount; dwOldCheckPoint = ssStatus.dwCheckPoint; while (ssStatus.dwCurrentState == WaitStatus) { // Do not wait longer than the wait hint. A good interval is // one tenth the wait hint, but no less than 1 second and no // more than 10 seconds. int dwWaitTime = ssStatus.dwWaitHint / 10; if (dwWaitTime < 1000) dwWaitTime = 1000; else if (dwWaitTime > 10000) dwWaitTime = 10000; System.Threading.Thread.Sleep(dwWaitTime); // Check the status again. if (QueryServiceStatus(hService, ssStatus) == 0) break; if (ssStatus.dwCheckPoint > dwOldCheckPoint) { // The service is making progress. dwStartTickCount = Environment.TickCount; dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if (Environment.TickCount - dwStartTickCount > ssStatus.dwWaitHint) { // No progress made within the wait hint break; } } } return (ssStatus.dwCurrentState == DesiredStatus); } ///  /// Opens the service manager ///  /// The service manager rights /// the handle to the service manager private static IntPtr OpenSCManager(ServiceManagerRights Rights) { IntPtr scman = OpenSCManager(null, null, Rights); if (scman == IntPtr.Zero) { try { throw new ApplicationException("Could not connect to service control manager."); } catch (Exception ex) { } } return scman; } #endregion #region"CreateFolderStructure" private static void CreateFolderStructure(string path) { if(!System.IO.Directory.Exists(path+"Applications")) System.IO.Directory.CreateDirectory(path+ "Applications"); if (!System.IO.Directory.Exists(path + "Applications\\MSC")) System.IO.Directory.CreateDirectory(path + "Applications\\MSC"); if (!System.IO.Directory.Exists(path + "Applications\\MSC\\Agent")) System.IO.Directory.CreateDirectory(path + "Applications\\MSC\\Agent"); if (!System.IO.Directory.Exists(path + "Applications\\MSC\\Agent\\bin")) System.IO.Directory.CreateDirectory(path + "Applications\\MSC\\Agent\\bin"); if (!System.IO.Directory.Exists(path + "Applications\\MSC\\AgentService")) System.IO.Directory.CreateDirectory(path + "Applications\\MSC\\AgentService"); string fullPath = System.IO.Path.GetFullPath("MSCService"); if (System.IO.Directory.Exists(fullPath)) { foreach (string strFile in System.IO.Directory.GetFiles(fullPath)) { if (System.IO.File.Exists(strFile)) { String[] strArr = strFile.Split('\\'); System.IO.File.Copy(strFile, path + "Applications\\MSC\\Agent\\bin\\"+ strArr[strArr.Count()-1], true); } } } } #endregion private static void ServiceLogs(string strLogInfo, string path) { string filePath = path + "Applications\\MSC\\AgentService\\ServiceLogs.txt"; System.IO.File.AppendAllLines(filePath, (strLogInfo + "--" + DateTime.Now.ToString()).ToString().Split('|')); } } } 

Como dijo Pierre, no hay forma de tener una interfaz de usuario para un servicio de Windows (o una forma sencilla). Lo que hago en ese tipo de situación es tener un archivo de configuración que se lee desde el servicio en cualquier intervalo en que opere el servicio y tener una aplicación independiente que realice cambios en el archivo de configuración.

¿Su aplicación de consola requiere interacción del usuario? Si es así, es un no-no serio y debería rediseñar su aplicación. Si bien hay algunos hacks para hacer este tipo de trabajo en versiones anteriores del sistema operativo, está garantizado que se romperá en el futuro.

Si su aplicación no requiere la interacción del usuario, entonces tal vez su problema esté relacionado con el usuario con el que se está ejecutando el servicio. Intente asegurarse de que se ejecuta como el usuario correcto o de que el usuario y / o los recursos que está utilizando tienen los permisos adecuados.

Si necesita algún tipo de interacción con el usuario, deberá crear una aplicación cliente y comunicarse con el servicio y / o la sub-aplicación a través de rpc, sockets o named pipes.

Es necesario que los servicios se conecten con el Administrador de control de servicios y brinden comentarios al inicio (es decir, díganle a SCM ‘¡estoy vivo!’). Es por eso que la aplicación C # tiene una plantilla de proyecto diferente para los servicios. Tienes dos alternativas:

  • envuelva su exe en srvany.exe, como se describe en KB Cómo crear un servicio definido por el usuario
  • haga que su aplicación C # detecte cuándo se inicia como un servicio (por ejemplo, parámetro de línea de comando) y cambie el control a una clase que herede de ServiceBase e implemente adecuadamente un servicio.

Tengo un servicio de Windows y agregué la siguiente línea al constructor para mi servicio:

 using System.Diagnostics; try { Process p = Process.Start(@"C:\Windows\system32\calc.exe"); } catch { Debugger.Break(); } 

Cuando intenté ejecutar esto, se realizó la llamada Process.Start () y no se produjo ninguna excepción. Sin embargo, la aplicación calc.exe no apareció. Para que funcione, edité las propiedades de mi servicio en el Administrador de control de servicios para permitir la interacción con el escritorio. Después de hacer eso, Process.Start () abrió calc.exe como se esperaba.

Pero como han dicho otros, la interacción con el escritorio está mal vista por parte de Microsoft y, en esencia, se ha desactivado en Vista. Entonces, incluso si puede hacer que funcione en XP, no sé si podrá hacer que funcione en Vista.

Ejecutar en Servicios de Windows cualquier aplicación como, por ejemplo, “.exe” es extraña porque el algoritmo no es tan efectivo.