我有一个C#/ .NET程序,既可以作为控制台应用程序运行,也可以作为服务运行。 目前我给它一个命令行选项来启动作为控制台应用程序,但我想避免这种情况。
是否可以通过编程方式检测我的程序是否作为服务启动?
如果它是纯Win32,我可以尝试使用StartServiceCtrlDispatcher作为服务启动,如果它返回ERROR_FAILED_SERVICE_CONTROLLER_CONNECT则回退到控制台,但System.ServiceProcess.ServiceBase.Run()如果失败则弹出errordialog然后返回向程序发出错误信号。
有什么想法吗?
答案 0 :(得分:27)
答案 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。
我想有些情况下这些不准确,但这对我来说效果很好。