Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在后台运行Mono应用程序时,是否可以检测到缺少控制台?_C#_Mono - Fatal编程技术网

C# 在后台运行Mono应用程序时,是否可以检测到缺少控制台?

C# 在后台运行Mono应用程序时,是否可以检测到缺少控制台?,c#,mono,C#,Mono,我有一个.NET 4.5控制台应用程序,我正在CentOS上使用Mono运行。代码以以下内容结束: Console.ReadLine(); 如果我以交互方式运行应用程序,那么它的行为与我预期的一样,Console.ReadLine()等待键盘输入,但是,如果我使用nohup在后台运行应用程序 nohup mono Program.exe > Program.log & 然后Program.log显示Console.ReadLine()会导致一个奇怪的异常: System.Una

我有一个.NET 4.5控制台应用程序,我正在CentOS上使用Mono运行。代码以以下内容结束:

Console.ReadLine();
如果我以交互方式运行应用程序,那么它的行为与我预期的一样,Console.ReadLine()等待键盘输入,但是,如果我使用nohup在后台运行应用程序

nohup mono Program.exe > Program.log &
然后Program.log显示Console.ReadLine()会导致一个奇怪的异常:

System.UnauthorizedAccessException: Access to the path "/home/user/[Unknown]" is denied.
  at System.IO.FileStream.ReadData (IntPtr handle, System.Byte[] buf, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0
  at System.IO.FileStream.ReadInternal (System.Byte[] dest, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0
  at System.IO.FileStream.Read (System.Byte[] array, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0
  at System.IO.StreamReader.ReadBuffer () [0x00000] in <filename unknown>:0
  at System.IO.StreamReader.ReadLine () [0x00000] in <filename unknown>:0
  at System.IO.UnexceptionalStreamReader.ReadLine () [0x00000] in <filename unknown>:0
  at System.IO.SynchronizedReader.ReadLine () [0x00000] in <filename unknown>:0
  at System.Console.ReadLine () [0x00000] in <filename unknown>:0
  at Program1.Program.Main (System.String[] args) [0x00000] in <filename unknown>:0
System.UnauthorizedAccessException:对路径“/home/user/[Unknown]”的访问被拒绝。
在System.IO.FileStream.ReadData(IntPtr句柄,System.Byte[]buf,Int32偏移量,Int32计数)[0x00000]中:0
在System.IO.FileStream.ReadInternal(System.Byte[]dest,Int32偏移量,Int32计数)[0x00000]中:0
在System.IO.FileStream.Read(System.Byte[]数组,Int32偏移量,Int32计数)[0x00000]中:0
位于:0中的System.IO.StreamReader.ReadBuffer()[0x00000]处
位于:0中的System.IO.StreamReader.ReadLine()[0x00000]处
位于System.IO.UnexceptionalStreamReader.ReadLine()[0x00000]中:0
在0中的System.IO.SynchronizedReader.ReadLine()[0x00000]处
位于:0中的System.Console.ReadLine()[0x00000]
在0中的Program1.Program.Main(System.String[]args)[0x00000]处
很明显,我可以捕获并悄悄地忽略异常,但我很好奇,是否有可能检测到我没有控制台的事实,从而改变我的应用程序的行为?

您可以查看-(mono也支持此功能-)

UserInteractive属性为Windows进程或 像IIS这样运行时没有用户界面的服务。如果这个属性 如果为false,则不要显示模式对话框或消息框,因为存在 没有供用户交互的图形用户界面


经过一段时间的试验,这似乎适合我:

if (Console.In is StreamReader) {
    Console.WriteLine("Interactive"); 
} else {
    Console.WriteLine("Background"); 
}

不确定它是否适用于所有可能的stdin重定向等,但就我的目的而言,它已经足够好了。

基本上我通常想知道的是:

  • 它是否作为服务运行
  • 它是否作为控制台运行
我猜你的问题也是关于这个。。。我会把食谱写下来,因为我花了太长时间才弄清楚所有的细节

设置项目

最简单的方法是创建一个
windows服务
C#应用程序,然后在
Program.cs
中开始黑客攻击

基本上我在这里做的是:

  • 如果是单声道,检查TTY是否已连接->控制台,单声道
  • 如果是Windows,请选中UserInteractive
  • 如果它是交互式的,那么就分配一个控制台,这样它就可以工作了
  • 如果这不起作用,我们就假设一个控制台应用程序
代码如下:

public static ProgramType ProgramType
{
    get
    {
        if (!programType.HasValue)
        {
            try
            {
                if (Type.GetType("Mono.Runtime") != null)
                {
                    // It's a console application if 'bool Mono.Unix.Native.Syscall.isatty(0)' in Mono.Posix.dll
                    var monoPosix = System.Reflection.Assembly.Load("Mono.Posix, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756");
                    Type syscallType = monoPosix.GetType("Mono.Unix.Native.Syscall");
                    var method = syscallType.GetMethod("isatty");
                    bool isatty = (bool)method.Invoke(null, new object[] { 0 });

                    if (isatty)
                    {
                        programType = ProgramType.MonoConsole;
                    }
                    else
                    {
                        programType = ProgramType.MonoService;
                    }
                }
                else
                {
                    if (Environment.UserInteractive)
                    {
                        programType = ProgramType.WindowsConsole;
                    }
                    else
                    {
                        programType = ProgramType.WindowsService;
                    }
                }
            }
            catch
            {
                programType = ProgramType.Unknown;
            }
        }
        return programType.Value;
    }
}

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();

[DllImport("kernel32", SetLastError = true)]
static extern bool AttachConsole(int dwProcessId);

[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);


/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
    switch (ProgramType)
    {
        case ProgramType.WindowsConsole:
            {
                // WindowsConsole application
                //
                // Get a pointer to the forground window. The idea here is that
                // IF the user is starting our application from an existing console
                // shell, that shell will be the uppermost window. We'll get it
                // and attach to it

                IntPtr ptr = GetForegroundWindow();

                int u;
                GetWindowThreadProcessId(ptr, out u);

                try
                {
                    Process process = Process.GetProcessById(u);

                    if (process.ProcessName == "cmd")
                    {
                        // Is the uppermost window a cmd process?
                        AttachConsole(process.Id);
                    }
                    else
                    {
                        // No console AND we're in console mode ... create a new console.
                        AllocConsole();
                    }

                    // Console is now accessible.
                    NubiloSoft.Util.Logging.Sink.Console.Register();

                    // Arguments?

                    StartConsoleService();
                }
                finally
                {
                    FreeConsole();
                }
            }
            break;

        case ProgramType.MonoConsole:
            {
                // Console is now accessible.
                NubiloSoft.Util.Logging.Sink.Console.Register();

                // Arguments?
                StartConsoleService();
            }
            break;

        case ProgramType.MonoService:
        case ProgramType.WindowsService:
            {
                // Start service
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]
                {
                    new Service1()
                };
                ServiceBase.Run(ServicesToRun);
            }
            break;

        default:
            Console.WriteLine("Unknown CLR detected. Running as console.");
            {
                // Console is now accessible.
                NubiloSoft.Util.Logging.Sink.Console.Register();

                // Arguments?
                StartConsoleService();
            }
            break;
    }
}
公共静态程序类型ProgramType
{
得到
{
如果(!programType.HasValue)
{
尝试
{
if(Type.GetType(“Mono.Runtime”)!=null)
{
//如果Mono.Posix.dll中的“bool Mono.Unix.Native.Syscall.isatty(0)”,则它是一个控制台应用程序
var monoPosix=System.Reflection.Assembly.Load(“Mono.Posix,Version=4.0.0.0,Culture=neutral,PublicKeyToken=0738eb9f132ed756”);
类型syscallType=monoPosix.GetType(“Mono.Unix.Native.Syscall”);
var method=syscallType.GetMethod(“isatty”);
bool isatty=(bool)method.Invoke(null,新对象[]{0});
如果(isatty)
{
programType=programType.MonoConsole;
}
其他的
{
programType=programType.MonoService;
}
}
其他的
{
if(Environment.UserInteractive)
{
programType=programType.WindowsConsole;
}
其他的
{
programType=programType.WindowsService;
}
}
}
抓住
{
programType=programType.未知;
}
}
返回programType.Value;
}
}
[DllImport(“kernel32.dll”,SetLastError=true)]
静态外部布尔alloconsole();
[DllImport(“kernel32.dll”,SetLastError=true)]
静态外部bool FreeConsole();
[DllImport(“内核32”,SetLastError=true)]
静态外部布尔附件控制台(int dwProcessId);
[DllImport(“user32.dll”)]
静态外部IntPtr GetForegroundWindow();
[DllImport(“user32.dll”,SetLastError=true)]
静态外部单元GetWindowThreadProcessId(IntPtr hWnd,out int lpdwProcessId);
/// 
///应用程序的主要入口点。
/// 
静态void Main()
{
开关(程序类型)
{
案例ProgramType.WindowsConsole:
{
//Windows控制台应用程序
//
//找一个指向圆形窗口的指针。这里的想法是
//如果用户从现有控制台启动我们的应用程序
//贝壳,那贝壳将是最上面的窗户。我们会找到它的
//并依附于它
IntPtr ptr=GetForegroundWindow();
国际大学;
GetWindowThreadProcessId(ptr,out u);
尝试
{
Process=Process.GetProcessById(u);
if(process.ProcessName==“cmd”)
{
//最上面的窗口是cmd进程吗?
AttachConsole(process.Id);
}
其他的
{
//没有控制台,我们处于控制台模式…创建一个新控制台。
allocsole();
}
//控制台现在可以访问。