我有一个.NET 4.5控制台应用程序,我使用Mono在CentOS上运行。代码完成:
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
我显然可以抓住并静静地忽略该异常,但我很想知道是否有可能检测到我没有控制台这样的事实,从而改变了我的应用程序的行为?
答案 0 :(得分:2)
经过一些实验后,这似乎可以帮我完成工作:
if (Console.In is StreamReader) {
Console.WriteLine("Interactive");
} else {
Console.WriteLine("Background");
}
不确定它是否适用于所有可能的stdin重定向等等,但它对我的目的来说效果很好。
答案 1 :(得分:1)
您可以查看 - Environment.UserInteractive Property(单声道也支持{ - 3}})
对于Windows进程或a,UserInteractive属性报告为false IIS之类的服务,无需用户界面即可运行。如果这个属性 是假的,不要显示模态对话框或消息框,因为那里 没有用户与之交互的图形用户界面。
答案 2 :(得分:0)
基本上我通常想知道的是:
我想你的问题也是关于这一点......我只会写下食谱,因为我花了太长时间才弄明白所有的细节......
设置项目
最简单的方法是创建一个windows service
C#应用程序,然后开始攻击Program.cs
。
基本上我在这里做的是:
以下是代码:
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;
}
}
我通常使用默认的Service1在某个静态Startup
类上调用'Start'和'Stop'。它与StartConsoleService
的作用相同。由于暴露了ProgramType,因此您可以在需要时使用它。