【问题标题】:Windows Service configurationWindows 服务配置
【发布时间】:2015-04-30 09:21:28
【问题描述】:

问题:

我有一个 Windows 服务,我想以交互模式启动它。 我们的一些客户对服务没有经验,我们的服务需要配置成可以与桌面交互的方式。

从命令行我会这样配置它:

C:\Windows\system32>sc config myservice obj= LocalSystem type= 交互类型=自己的

由于程序是从配置 GUI 启动的,我想在 C# 中设置值:

ServiceController[] mySc = ServiceController.GetServices();

foreach (ServiceController sc in mySc)
{
    if (sc.DisplayName == "myservice")
    {

        if (sc.Status == ServiceControllerStatus.Stopped)
        {
            //sc.ServiceType <-- readonly so i can't set it
            sc.Start();

        }
        break;
    }
}

我发现唯一可行的方法是使用进程对象

var process = new Process();
var processStartInfo = new ProcessStartInfo(startpath);
arg += "all my arguments...";
processStartInfo.Arguments = arg;
processStartInfo.CreateNoWindow = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo = processStartInfo;
process.Start();
process.WaitForExit();

我的问题:

有没有办法通过 ServiceController 配置服务?我看到你可以通过sc.Start(args[])启动服务但是我没有找到可以传递的参数。

【问题讨论】:

  • 您想要一个可以显示弹出窗口等的 Windows 服务吗?
  • 没有服务应该能够访问文件系统
  • 而你通过使用进程实现了这一点,但你不想使用进程,你想使用 SC 对吗?
  • 实际上似乎有一种方法可以做到这一点。检查this SO post,得票最多的答案将引导您到blog post,其中包含配置win服务的帮助方法。您可以传递来配置它的参数之一是 - nServiceType 我相信这就是您要寻找的。​​span>
  • @Bongo 很高兴它有帮助!请更新您的问题,并提供一些您如何解决问题的详细信息、指向您提到的 SO 问题和博客文章的链接,以及您可能使用的一些代码,以供其他人将来参考。

标签: c# service


【解决方案1】:

在 Michael(参见上面的 cmets)提供的一篇文章的帮助下,我创建了一个类,使我能够配置服务。

我的代码主要是这篇博文的副本,有一些小的改动:Changing Start Mode of a Windows Service

这是我的班级:

 public static class C_ServiceControllerExtension
    {
        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern Boolean ChangeServiceConfig(
            IntPtr hService,
            UInt32 nServiceType,
            UInt32 nStartType,
            UInt32 nErrorControl,
            String lpBinaryPathName,
            String lpLoadOrderGroup,
            IntPtr lpdwTagId,
            [In] char[] lpDependencies,
            String lpServiceStartName,
            String lpPassword,
            String lpDisplayName);

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr OpenService(
            IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);

        [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr OpenSCManager(
            string machineName, string databaseName, uint dwAccess);

        [DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")]
        public static extern int CloseServiceHandle(IntPtr hSCObject);

        private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
        private const uint SERVICE_QUERY_CONFIG = 0x00000001;
        private const uint SERVICE_CHANGE_CONFIG = 0x00000002;
        private const uint SC_MANAGER_ALL_ACCESS = 0x000F003F;

        /// <summary>
        /// Changes the configuration of the service
        /// </summary>
        /// <param name="svc">Service controller</param>
        /// <param name="mode">ServiceStartMode || 0</param>
        /// <param name="type">ServiceType || 0</param>
        public static bool ChangeServiceConfiguration(this ServiceController svc, ServiceStartMode mode, ServiceType type)
        {
            uint uMode = SERVICE_NO_CHANGE;
            uint uType = SERVICE_NO_CHANGE;
            if (mode > 0) 
            {
                uMode = (uint)mode;
            }

            if (type > 0) 
            {
                uType = (uint)type;
            }

            var scManagerHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
            if (scManagerHandle == IntPtr.Zero)
            {
                throw new ExternalException("Open Service Manager Error");
            }

            var serviceHandle = OpenService(
                scManagerHandle,
                svc.ServiceName,
                SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);

            if (serviceHandle == IntPtr.Zero)
            {
                throw new ExternalException("Open Service Error");
            }

            var result = ChangeServiceConfig(
                serviceHandle,
                uType,
                uMode,
                SERVICE_NO_CHANGE,
                null,
                null,
                IntPtr.Zero,
                null,
                null,
                null,
                null);

            if (result == false)
            {
                int nError = Marshal.GetLastWin32Error();
                var win32Exception = new Win32Exception(nError);
                return false;
                //throw new ExternalException("Could not change service start type: " + win32Exception.Message);
            }

            CloseServiceHandle(serviceHandle);
            CloseServiceHandle(scManagerHandle);
            return true;
        }
    }

ChangeServiceConfiguration 方法是一个扩展方法,因此您可以直接在 ServiceController 上调用该方法。

我调用方法如下:

ServiceController[] mySc = ServiceController.GetServices();
bool startedServiceCorrect = false;
foreach (ServiceController sc in mySc)
{
    if (sc.DisplayName == "myservice")
    {
        if (sc.Status == ServiceControllerStatus.Stopped)
        {
            if (sc.ServiceType != (ServiceType.InteractiveProcess | ServiceType.Win32OwnProcess)) 
            {
                startedServiceCorrect = sc.ChangeServiceConfiguration(0, (ServiceType.InteractiveProcess | ServiceType.Win32OwnProcess));
            }
            try
            {
                sc.Start();
            }
            catch
            { 

                startedServiceCorrect = false;
            }
        }
        break;
    }
}

如果您使用的是 .Net 3.0 及更高版本,扩展方法应该可以开箱即用,但如果您使用的是 .Net2.0,那么您必须添加这个小命名空间,这样扩展方法才能正常工作: Extension Method C# 2.0

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class
         | AttributeTargets.Method)]
    public sealed class ExtensionAttribute : Attribute { }
}

【讨论】:

  • 我想我提供了所有的资源。如果我忘记提及您的代码,请添加评论
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多