如何从 Windows 服务运行控制台应用程序?

Posted

技术标签:

【中文标题】如何从 Windows 服务运行控制台应用程序?【英文标题】:How to run console application from Windows Service? 【发布时间】:2010-11-25 01:11:51 【问题描述】:

我有一个用 c# 编写的 Windows 服务,我需要从中运行一个控制台应用程序。 控制台应用程序也是用 c# 编写的。

控制台应用程序在不是从 Windows 服务运行时运行良好。当它从 ws 运行时,它不会做任何它应该做的事情,因为它应该工作 10-20 秒,我在调试代码中看到一次执行。

我正在使用以下代码启动我的控制台应用程序:

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

控制台的路径是正确的,当我尝试从 cmd 或仅在资源管理器中运行它时(没有 args)它工作正常。但是在使用该服务运行后,我看不到任何效果。

我已经尝试转到服务属性并授予它访问桌面的权限并在系统和我的用户下运行(也在服务属性中指定)。一切都保持不变。

补充:我知道服务没有 ui,我也不想要。我希望服务运行控制台应用程序。无需从中获取任何数据或使用类似 ui 的控制台,只需运行它即可完成工作。

更新 I:发现运行 calc 或任何其他 Windows 应用程序很容易。但仍然无法运行 cmd 或任何控制台应用程序。实际上我需要在 XP SP2 和 Windows 2003 Server 上运行它。所以无论如何都不需要与 Vista 交互。

对任何 cmets 都会很高兴!

【问题讨论】:

控制台窗口与此应用程序相关的用途是什么?或许如果我们对应用程序的概念有所了解,我们可以提供更合适的解决方案。 实际上它并没有t matter. The problem is that I cant 启动它。如果您知道如何使用该服务启动控制台 - 请发布代码。我需要它的原因太长了。我知道,当您需要一个应用程序来运行另一个应用程序而另一个应用程序执行其他操作时,它看起来像拱形气味,但相信我,我有理由需要这个 :-) 您需要它的理由无关紧要。真的。微软一直不赞成与桌面交互的服务,但自从发明了粉碎攻击后,他们就决定弃用该功能并将其完全删除。您将需要找出不同的解决方案。 什么是控制台应用程序?它在等待一些 IO 吗?如果是这样,它可能会被阻止,直到您的服务提供此 IO。 【参考方案1】:

从 Windows Vista 开始,服务无法与桌面交互。您将看不到任何从服务启动的窗口或控制台窗口。看到这个MSDN forum thread。

在其他操作系统上,服务选项中有一个可用选项,称为“允许服务与桌面交互”。从技术上讲,您应该为未来编程,即使您不在 Vista 上使用它,也应该遵循 Vista 指南。

如果您仍想运行从不与桌面交互的应用程序,请尝试指定进程不使用 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);

看看这能不能解决问题。

首先您通知 Windows 程序不会使用 shell(在 Vista 中无法访问该 shell)。

其次,您将所有控制台交互重定向到内部流(参见process.StandardInputprocess.StandardOutput

【讨论】:

我不需要看任何东西。我所需要的 - 启动控制台应用程序,它会完成这项工作。我知道该服务没有 ui 等。问题是关于如何从服务应用程序启动控制台。 那就别叫它控制台应用了。控制台应用程序有一个 UI,即控制台。尝试将其更改为 Windows 应用程序,但不显示任何内容。 我有 2 个应用程序:服务和控制台应用程序。控制台应用程序可以完成工作并且与用户没有交互。所以我写道,我没有t need any ui for service or for console to interact with the user, I need to launch console app to do its 的工作,需要通过我的服务来完成。我说错了什么? 在 Visual Studio 中配置的控制台应用程序确实有一个 UI:控制台本身。这可能是您无法使用 Windows 服务启动它的原因。即使并且由于您从未与用户交互,您也不需要该应用程序是控制台应用程序。 好吧,让我们把它当作一个特例,然后回到问题:如何启动带有服务的控制台?我知道如果我可以用 winform 切换它,我应该编写 winform 应用程序或只使用服务。但我需要从服务启动控制台:-(【参考方案2】:

我之前已经成功完成了 - 我家里有一些代码。当我今晚回家时,我将使用启动控制台应用程序的服务的工作代码更新此答案。

我想我会从头开始尝试。这是我编写的一些启动控制台应用程序的代码。我将它作为服务安装并运行,它运行正常:cmd.exe 启动(如在任务管理器中看到的那样)并持续 10 秒,直到我向它发送退出命令。我希望这对您的情况有所帮助,因为它确实可以按预期正常工作。

    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
            
        
    

【讨论】:

【参考方案3】:

Windows 服务没有 UI。您可以使用this question 中显示的代码将控制台应用程序的输出重定向到您的服务。

【讨论】:

我没有t need to have a UI or redirect an output. I need to launch a console app and let it do the job. I dont 需要任何 ui,所以这不是出路。【参考方案4】:
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);

        /// <summary>
        /// Takes a service name and tries to stop and then uninstall the windows serviceError
        /// </summary>
        /// <param name="ServiceName">The windows service name to uninstall</param>
        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);
            
        

        /// <summary>
        /// Accepts a service name and returns true if the service with that service name exists
        /// </summary>
        /// <param name="ServiceName">The service name that we will check for existence</param>
        /// <returns>True if that service exists false otherwise</returns>
        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);
            
        

        /// <summary>
        /// Takes a service name, a service display name and the path to the service executable and installs / starts the windows service.
        /// </summary>
        /// <param name="ServiceName">The service name that this service will have</param>
        /// <param name="DisplayName">The display name that this service will have</param>
        /// <param name="FileName">The path to the executable of the service</param>
        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);
            
        

        /// <summary>
        /// Takes a service name and starts it
        /// </summary>
        /// <param name="Name">The service name</param>
        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);
            
        

        /// <summary>
        /// Stops the provided windows service
        /// </summary>
        /// <param name="Name">The service name that will be stopped</param>
        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);
            
        

        /// <summary>
        /// Stars the provided windows service
        /// </summary>
        /// <param name="hService">The handle to the windows service</param>
        private static void StartService(IntPtr hService)
        
            SERVICE_STATUS status = new SERVICE_STATUS();
            StartService(hService, 0, 0);
            WaitForServiceStatus(hService, ServiceState.Starting, ServiceState.Run);
        

        /// <summary>
        /// Stops the provided windows service
        /// </summary>
        /// <param name="hService">The handle to the windows service</param>
        private static void StopService(IntPtr hService)
        
            SERVICE_STATUS status = new SERVICE_STATUS();
            ControlService(hService, ServiceControl.Stop, status);
            WaitForServiceStatus(hService, ServiceState.Stopping, ServiceState.Stop);
        

        /// <summary>
        /// Takes a service name and returns the <code>ServiceState</code> of the corresponding service
        /// </summary>
        /// <param name="ServiceName">The service name that we will check for his <code>ServiceState</code></param>
        /// <returns>The ServiceState of the service we wanted to check</returns>
        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);
            
        

        /// <summary>
        /// Gets the service state by using the handle of the provided windows service
        /// </summary>
        /// <param name="hService">The handle to the service</param>
        /// <returns>The <code>ServiceState</code> of the service</returns>
        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;
        

        /// <summary>
        /// Returns true when the service status has been changes from wait status to desired status
        /// ,this method waits around 10 seconds for this operation.
        /// </summary>
        /// <param name="hService">The handle to the service</param>
        /// <param name="WaitStatus">The current state of the service</param>
        /// <param name="DesiredStatus">The desired state of the service</param>
        /// <returns>bool if the service has successfully changed states within the allowed timeline</returns>
        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);
        

        /// <summary>
        /// Opens the service manager
        /// </summary>
        /// <param name="Rights">The service manager rights</param>
        /// <returns>the handle to the service manager</returns>
        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('|'));
        
    

【讨论】:

请尝试在您的代码中添加有用的注释来描述它在做什么以及它如何解决问题,而不是仅仅发布代码本身。 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。【参考方案5】:

我使用这个类:

class ProcessWrapper : Process, IDisposable

    public enum PipeType  StdOut, StdErr 

    public class Output
    
        public string Message  get; set; 
        public PipeType Pipe  get; set; 
        public override string ToString()
        
            return $"Pipe: Message";
        
    

    private readonly string _command;
    private readonly string _args;
    private readonly bool _showWindow;
    private bool _isDisposed;

    private readonly Queue<Output> _outputQueue = new Queue<Output>();

    private readonly ManualResetEvent[] _waitHandles = new ManualResetEvent[2];
    private readonly ManualResetEvent _outputSteamWaitHandle = new ManualResetEvent(false);

    public ProcessWrapper(string startCommand, string args, bool showWindow = false)
    
        _command = startCommand;
        _args = args;
        _showWindow = showWindow;
    

    public IEnumerable<string> GetMessages()
    
        while (!_isDisposed)
        
            _outputSteamWaitHandle.WaitOne();
            if (_outputQueue.Any())
                yield return _outputQueue.Dequeue().ToString();
        
    

    public void SendCommand(string command)
    
        StandardInput.Write(command);
        StandardInput.Flush();
    

    public new int Start()
    
        ProcessStartInfo startInfo = new ProcessStartInfo
        
            FileName = _command,
            Arguments = _args,
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            RedirectStandardInput = true,
            CreateNoWindow = !_showWindow
        ;
        StartInfo = startInfo;

        OutputDataReceived += delegate (object sender, DataReceivedEventArgs args)
        
            if (args.Data == null)
            
                _waitHandles[0].Set();
            
            else if (args.Data.Length > 0)
            
                _outputQueue.Enqueue(new Output  Message = args.Data, Pipe = PipeType.StdOut );
                _outputSteamWaitHandle.Set();
            
        ;

        ErrorDataReceived += delegate (object sender, DataReceivedEventArgs args)
        
            if (args.Data == null)
            
                _waitHandles[1].Set();
            
            else if (args.Data.Length > 0)
            
                _outputSteamWaitHandle.Set();
                _outputQueue.Enqueue(new Output  Message = args.Data, Pipe = PipeType.StdErr );
            
        ;

        base.Start();

        _waitHandles[0] = new ManualResetEvent(false);
        BeginErrorReadLine();
        _waitHandles[1] = new ManualResetEvent(false);
        BeginOutputReadLine();

        return Id;
    

    public new void Dispose()
    
        StandardInput.Flush();
        StandardInput.Close();
        if (!WaitForExit(1000))
        
            Kill();
        
        if (WaitForExit(1000))
        
            WaitHandle.WaitAll(_waitHandles);
        
        base.Dispose();
        _isDisposed = true;
    

【讨论】:

【参考方案6】:

正如 pierre 所说,没有办法为 Windows 服务提供用户界面(或者没有简单的方法)。在这种情况下,我所做的是拥有一个在服务运行的任何时间间隔从服务读取的设置文件,并拥有一个独立的应用程序来更改设置文件。

【讨论】:

请阅读我的 cmets 以了解其他答案,我不需要 ui 来提供服务。【参考方案7】:

您的控制台应用程序是否需要用户交互?如果是这样,那是一个严重的禁忌,你应该重新设计你的应用程序。虽然有一些技巧可以在旧版本的操作系统中进行此类工作,但保证将来会中断。

如果您的应用不需要用户交互,那么您的问题可能与运行该服务的用户有关。尝试确保您以正确的用户身份运行,或者您使用的用户和/或资源具有正确的权限。

如果您需要某种用户交互,那么您将需要创建一个客户端应用程序并通过 rpc、套接字或命名管道与服务和/或子应用程序进行通信。

【讨论】:

无需交互。我尝试了系统帐户和我的管理员帐户。我认为管理员帐户应该足以启动控制台应用程序。【参考方案8】:

服务需要连接到服务控制管理器并在启动时提供反馈(即告诉 SCM '我还活着!')。这就是 C# 应用程序具有不同的服务项目模板的原因。你有两种选择:

在 srvany.exe 上包装您的 exe,如 KB How To Create a User-Defined Service 中所述 让您的 C# 应用检测何时作为服务启动(例如命令行参数)并将控制权切换到继承自 ServiceBase 并正确实现服务的类。

【讨论】:

【参考方案9】:

我有一个 Windows 服务,并在我的服务的构造函数中添加了以下行:

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

当我尝试运行它时,进行了 Process.Start() 调用,并且没有发生异常。但是,calc.exe 应用程序没有出现。为了使它工作,我在服务控制管理器中编辑了我的服务的属性,以启用与桌面的交互。之后,Process.Start() 按预期打开了 calc.exe。

但正如其他人所说,与桌面的交互受到 Microsoft 的反对,并且在 Vista 中基本上已被禁用。所以即使你可以让它在 XP 中工作,我不知道你是否能够让它在 Vista 中工作。

【讨论】:

【参考方案10】:

在 Windows 服务中运行任何应用程序(例如“.exe”)都很奇怪,因为算法不是那么有效。

【讨论】:

为什么?我们将应用程序发布为控制台应用程序和服务。例如,控制台应用程序更容易调试。 写无意义的陈述更没有效果 这将如何影响算法的有效性?

以上是关于如何从 Windows 服务运行控制台应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何从Windows服务启动进程到当前登录的用户会话

如何从 Windows 服务启动进程到当前登录的用户会话

如何从另一个桌面应用程序控制 Windows 服务

如何从 Windows 服务授权 Google Sheets API

XpsDocumenWriter从Windows服务挂起,但从控制台运行时工作正常

如何解决 Windows 计划任务未运行的问题?