C# 在后台运行Mono应用程序时,是否可以检测到缺少控制台?
我有一个.NET 4.5控制台应用程序,我正在CentOS上使用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
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();
}
//控制台现在可以访问。