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

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

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

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

有任何想法吗?

拉斯穆斯, 这是早先的问题 。

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

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

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

Environment.UserInteractive将发挥魔力。

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

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

使用此答案中关于查找父进程的ParentProcessUtilities结构,您可以执行以下操作:

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

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

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

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

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

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