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

时间:2008-10-16 09:16:11

标签: c# .net service

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

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

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

有什么想法吗?

8 个答案:

答案 0 :(得分:27)

Environment.UserInteractive会发挥魔力。

答案 1 :(得分:6)

Rasmus,this is the earlier question

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

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

(注意到Jonathan在问题的最后添加了他的解决方案。)

答案 2 :(得分:4)

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

答案 3 :(得分:3)

[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...
}

答案 4 :(得分:3)

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

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

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

答案 5 :(得分:2)

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

答案 6 :(得分:1)

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

答案 7 :(得分:0)

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

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