C#/.NET:检测程序是作为服务还是作为控制台应用程序运行

C#/.NET:检测程序是作为服务还是作为控制台应用程序运行,c#,.net,service,C#,.net,Service,我有一个C#/.NET程序,可以作为控制台应用程序和服务运行。 目前,我给它一个命令行选项,以作为控制台应用程序启动,但我希望避免这种情况 是否可以通过编程方式检测我的程序是否作为服务启动 如果它是纯Win32,我可以尝试使用StartServiceCtrlDispatcher作为服务启动,如果它返回错误\u失败\u服务\u控制器\u连接,则返回控制台,但是System.ServiceProcess.ServiceBase.Run()会在失败时弹出一个错误对话框,然后返回而不向程序发出错误信号

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

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

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


有什么想法吗?

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

Rasmus

从答案来看,最流行的方法似乎是使用简单的命令行选项,或者尝试在try-catch块中访问Console对象(在服务中,控制台未连接到进程,尝试访问它会引发异常)

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


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

将发挥神奇的作用。

我不知道这是否有效,但您可能希望尝试使用PInvoke代码并检查父进程是否为“services.exe”。

使用ParentProcessUtilities结构,从关于查找父进程,您可以执行以下操作:

static bool RunningAsService(){
var p=ParentProcessUtilities.GetParentProcess();
返回(p!=null&&p.ProcessName==“服务”);
}

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

我通过检查来检测我是否在控制台应用程序中。对于控制台应用程序,它返回“false”,对于我测试的非控制台应用程序,它返回“true”。我也可以用


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

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

我认为进程本身(通常)仍然是相同的exe,除非您特意通过svchost.exe或类似的方式重新主持…从我当前的办公桌上可能很难测试:(至少在mono下,进程名称会更改为执行实体(即,如果使用mono服务运行,则该进程现在称为mono服务)。尚未尝试作为windows服务。如果该服务在windows XP上运行且设置了“允许此服务与桌面交互”怎么办?它将停止执行魔术,就是这样:)这在各种Cygwin Shell等下也会中断。您需要使用WMI强制来正确执行此操作。在没有“interactive terminal”开关的Docker中作为进程运行时,它不会真正发挥任何作用。Console.ReadKey将失败,但Environment.UserInteractive返回true。它不会!在LocalSystem上下文
psexec中运行您的应用程序-s YourApp.exe
Environment.UserInteractive==false
如果服务在交互模式下运行,则此操作是否有效?如果从控制台启动控制台应用程序并重定向或管道化输出(>或|),则IsOutputRedirected将为true。可能OP不知道这是一个重复,因为已经回答的问题有一个可怕的名称。此方法简单、快速、可靠。它不会告诉您流程是服务还是仅作为服务的子项运行,但这确实有效(请注意,它仅适用于Vista及以上版本-在此之前,第一个用户登录会话的会话ID为零,并与服务共享)。
[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...
}