咨询区
Stefan Steiger
我有一个 Console 程序,它主要用来重启 IIS 以及删除临时文件,我现在期望它启动后隐藏自身,我在网上找了下面这段代码做了隐藏。
static void Main(string[] args)
{var currentProcess = System.Diagnostics.Process.GetCurrentProcess();Console.WriteLine(currentProcess.MainWindowTitle);IntPtr hWnd = currentProcess.MainWindowHandle;//FindWindow(null, "Your console windows caption"); //put your console window caption hereif (hWnd != IntPtr.Zero){//Hide the windowShowWindow(hWnd, 0); // 0 = SW_HIDE}
}
但这段代码还是有点问题,在启动时会看到 窗口
一瞬间从显示到隐藏,这不是我想要的效果,我希望它能够实现完全隐藏,请问我该如何实现?
回答区
Richard
如果你的 Console 不需要诸如 Console.WriteLine()
这类输出流,我建议你直接在构建应用程序的时候将 程序类型
改成 Windows Application
,截图如下:
接下来可以使用如下 C# 代码。
static void Main(string[] args){for (int i = 0; i < int.MaxValue; i++){File.AppendAllText("C:\\SosexUst.log", $"i={i} {Environment.NewLine}");Thread.Sleep(1000);}}
可以发现,log文件已经在不断的写入了。
它的本质就是修改了 .exe
的PE头,这样应用程序启动后就不按照 Console 默认的会话走了。
abatishchev
可以调用 win32 api
实现,参考如下代码:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeConsole();[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern IntPtr GetStdHandle([MarshalAs(UnmanagedType.I4)]int nStdHandle);// see the comment below
private enum StdHandle
{StdIn = -10,StdOut = -11,StdErr = -12
};void HideConsole()
{var ptr = GetStdHandle((int)StdHandle.StdOut);if (!CloseHandle(ptr))throw new Win32Exception();ptr = IntPtr.Zero;if (!FreeConsole())throw new Win32Exception();
}
可以参考 github:https://github.com/abatishchev/reg2run/blob/master/ManualConsole.cs 了解更多和 console 有关的 api 接口。
点评区
Richard
大佬这种方案挺好的,对了,要想看 PE 头,可以用 PPEE.exe
小工具查看。
可以看到,其实指的是 PE 头中的 SubSystem
字段。