【问题标题】:C#/.NET: Detect whether program is being run as a service or a console application [duplicate]C#/.NET:检测程序是作为服务运行还是作为控制台应用程序运行[重复]
【发布时间】:2008-10-16 09:16:11
【问题描述】:

我有一个可以作为控制台应用程序和服务运行的 C#/.NET 程序。 目前我给它一个命令行选项以作为控制台应用程序启动,但我想避免这种情况。

是否可以以编程方式检测我的程序是否作为服务启动?

如果它是纯 Win32,我可以尝试使用 StartServiceCtrlDispatcher 作为服务启动,如果返回 ERROR_FAILED_SERVICE_CONTROLLER_CONNECT,则返回到控制台,但 System.ServiceProcess.ServiceBase.Run() 如果失败,则会弹出一个错误对话框,然后直接返回而没有向程序发出错误信号。

有什么想法吗?

【问题讨论】:

  • 也许 OP 不知道这是一个骗局,因为已经回答的问题的名字很糟糕。

标签: c# .net service


【解决方案1】:

Environment.UserInteractive 会变魔术。

【讨论】:

  • 如果服务在 Windows XP 上运行并设置了“允许此服务与桌面交互”怎么办?
  • 它会停止变魔术,就是这样:)
  • 这也会在各种 Cygwin shell 等下中断。您需要使用 WMI 强制正确执行此操作。
  • 在没有“交互式终端”开关的情况下在 Docker 中作为进程运行时,它并没有真正发挥任何作用。 Console.ReadKey 会失败,但 Environment.UserInteractive 返回 true。
  • 不会的!在 LocalSystem 上下文 psexec -s YourApp.exeEnvironment.UserInteractive == false 中运行您的应用程序
【解决方案2】:

拉斯穆斯,this is the earlier question

从答案看来,最流行的方法是使用简单的命令行选项,或者尝试在 try catch 块中访问控制台对象(在服务中,控制台未附加到进程并尝试访问它会抛出一个例外)。

或者,如果您在测试/调试服务时遇到问题,请将代码移动到单独的 dll 程序集中并创建单独的测试工具(winforms/console 等)。

(刚刚注意到乔纳森在问题的末尾添加了他的解决方案。)

【讨论】:

    【解决方案3】:

    可能想试试 Process 对象的 SessionId 属性。根据我的经验,如果进程正在运行服务,则 SessionId 设置为 0。

    【讨论】:

    • 这种方法简单、快速、可靠。它不会告诉您您的进程是 服务,还是仅仅作为服务的子进程运行,但这确实有效(请注意,它仅适用于 Vista 及更高版本 - 在此之前第一个用户登录会话也将是会话 ID 为零并与服务共享)。
    【解决方案4】:

    我还没有尝试过,但Process.GetCurrentProcess 可能会有所帮助 - 在控制台模式下,进程名称将与可执行文件相同,而我希望(再次,请检查!)在运行时作为一项服务,它会有所不同。

    【讨论】:

    • 我认为该进程(通常)仍然是同一个 exe 本身,除非您特意通过 svchost.exe 或类似的方式重新托管...
    • 可能很难从我现在的办公桌上测试:(
    • 至少在 mono 下,进程名称确实会更改为执行实体(即,如果使用 mono-service 运行,则该进程现在称为 mono-service)。没有尝试过作为 Windows 服务
    【解决方案5】:
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);
    const int STD_OUTPUT_HANDLE = -11;
    
    IntPtr iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    
    if (iStdOut == IntPtr.Zero)
    
    {    
        app.RunAsWindowsService = true;
    
    }
    
    // Run as Service
    if (runAsWindowsService)                                
    {
         // .....
         ServiceBase.Run(myService);
    }
    else 
    {
        // Run as Console
        // Register Ctrl+C Handler...
    }
    

    【讨论】:

    • 如果服务在交互模式下运行,这是否有效?
    【解决方案6】:

    使用来自this answer 的ParentProcessUtilities 结构来查找父进程,您可以这样做:

    static bool RunningAsService() {
        var p = ParentProcessUtilities.GetParentProcess();
        return ( p != null && p.ProcessName == "services" );
    }
    

    请注意,父进程的进程名称不包含扩展名“.exe”。

    【讨论】:

      【解决方案7】:

      我不知道这是否可行,但您可能想尝试使用带有this 代码的 PInvoke 并检查父级是否为“services.exe”。

      【讨论】:

        【解决方案8】:

        我最终通过检查Console.IsErrorRedirected 来检测我是否在控制台应用程序中。它为控制台应用程序返回“false”,为我测试的非控制台应用程序返回“true”。我也可以使用IsOutputRedirected

        我想在某些情况下这些可能不准确,但这对我来说效果很好。

        【讨论】:

        • 如果控制台应用程序从控制台启动并且输出被重定向或管道(> 或 |),则 IsOutputRedirected 将为真。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-04
        • 2021-09-04
        • 1970-01-01
        • 1970-01-01
        • 2018-12-11
        相关资源
        最近更新 更多