在Visual Studio中运行控制台应用程序时,根据您的设置,它将在程序退出后添加提示:
按任意键继续 。 。 。
我已经找到了如何检测我是否在调试器下运行(使用Debugger.IsAttached
),但它没有帮助。按CTRL-F5开始不调试将此标志设置为false
,但仍显示提示。
我想检测这个,因为我想显示我自己的消息并等待按键,但不要加倍按键检查。
我不想破坏我的一般Visual Studio设置。如果我可以以可以检查到源代码管理的方式为此项目禁用它,那也可以。
使用什么机制来附加此提示,以及如何检测它?
或者如何为每个项目禁用它,并将此更改检查为源代码管理?
将以下代码添加到控制台应用程序:
public static class Extensions {
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern bool TerminateThread(IntPtr hThread, uint dwExitCode);
public static Process GetParentProcess(this Process x) {
return (
from it in (new ManagementObjectSearcher("root\\CIMV2", "select * from Win32_Process")).Get().Cast<ManagementObject>()
where (uint)it["ProcessId"]==x.Id
select Process.GetProcessById((int)(uint)it["ParentProcessId"])
).First();
}
public static IEnumerable<Process> GetChildProcesses(this Process x) {
return (
from it in (new ManagementObjectSearcher("root\\CIMV2", "select * from Win32_Process")).Get().Cast<ManagementObject>()
where (uint)it["ParentProcessId"]==x.Id
select Process.GetProcessById((int)(uint)it["ProcessId"])
);
}
public static void Abort(this ProcessThread x) {
TerminateThread(OpenThread(1, false, (uint)x.Id), 1);
}
}
然后像这样修改你的代码:
class Program {
static void Main(String[] args) {
// ... (your code might goes here)
try {
Process.GetCurrentProcess().GetParentProcess().Threads.Cast<ProcessThread>().Single().Abort();
}
catch(InvalidOperationException) {
}
Console.Write("Press ONLY key to continue . . . ");
Console.ReadKey(true);
}
}
所以,我们所期待的一切都已经完成了。我认为这是一种解决方案。它在Windows XP SP3
下工作,我想它可以用于较新的Windows操作系统。在Visual Studio下,应用程序始终是一个衍生过程。在较旧的Visual C ++ 6.0中,它由IDE通过调用VCSPAWN.EXE
生成;在Visual Studio 2010中,应用程序在启动时不使用调试时使用以下命令行运行:
“%comspec%”/ c“”您的应用程序文件名“&pause”
因此,无法以完全管理的方式实现目标;因为它不在应用程序域下。
在这里,我们使用WMI
的托管方式来枚举进程,并封装非托管的WINAPI
s来终止ProcessThread
s,因为ProcessThread
不应该被正常中止;它提供了像只读的东西。
如上所述,应用程序是使用特定的命令行生成的;它会有一个线程创建一个进程签名,所以我们使用Single()
方法来检索该线程并终止它。
当我们在现有命令提示符下启动应用程序时,它与Start Without Debugging相同。此外,在开始调试时,应用程序进程由devenv.exe
创建。它有很多线程,我们知道并且不会中止任何线程,只是提示并等待按键。这种情况类似于双击启动应用程序或从上下文菜单启动应用程序。这样,应用程序进程由系统shell创建,通常是Explorer.exe
,它也有很多线程。
实际上,如果我们可以成功中止线程,则意味着我们有权杀死父进程。但我们不需要。我们只需要中止唯一的线程,当系统没有更多线程时,进程会自动终止。通过识别调用进程是%comspec%
来杀死父进程是另一种做同样事情的方法,但这是一个危险的过程。因为产生应用程序的进程可能有其他线程,这些线程具有任意数量的线程,所以创建一个与%comspec%
匹配的进程。你可能会粗心地杀死一个重要的过程工作,或者只是增加检查过程是否可以安全杀死的复杂性。所以我认为单个线程创建一个进程作为我们父进程的签名,可以安全地终止/中止。
WMI
是现代的,一些WINAPI
s可能会在未来被弃用。但这种构成的真正原因在于它的简单性。旧的Tool Help Library
就像将ProcessThread
转换为System.Threading.Thread
一样复杂。使用LINQ和扩展方法,我们可以使代码更简单,更具语义。
听起来像这个提示是由pause
命令提供的。 Visual Studio自动添加此命令。
在Visual Studio外部运行项目时,没有理由“检测”此命令。您可以放心地假设它不会添加到您的程序中。这意味着你可以继续添加你想要的任何提示,类似于:
Console.WriteLine("Press any key...");
Console.Read();
这是一段应该做的代码:
class Program
{
static void Main(string[] args)
{
// do your stuff
if (!WasStartedWithPause())
{
Console.WriteLine("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
public static bool WasStartedWithPause()
{
// Here, I reuse my answer at http://stackoverflow.com/questions/394816/how-to-get-parent-process-in-net-in-managed-way
Process parentProcess = ParentProcessUtilities.GetParentProcess();
// are we started by cmd.exe ?
if (string.Compare(parentProcess.MainModule.ModuleName, "cmd.exe", StringComparison.OrdinalIgnoreCase) != 0)
return false;
// get cmd.exe command line
string cmdLine = GetProcessCommandLine(parentProcess);
// was it started with a pause?
return cmdLine != null & cmdLine.EndsWith("& pause\"");
}
public static string GetProcessCommandLine(Process process)
{
if (process == null)
throw new ArgumentNullException("process");
// use WMI to query command line
ManagementObjectCollection moc = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId=" + process.Id).Get();
foreach (ManagementObject mo in moc)
{
return (string)mo.Properties["CommandLine"].Value;
}
return null;
}
该消息与您的程序无关。您可以向程序添加任何您喜欢的程序,如果您从命令提示符运行它,它将以与它相同的方式执行。
Visual Studio显示它是为了向您显示其执行已完成运行,因此您知道它已正确结束。如果你想跳过它,你可以尝试“无需调试运行”(或类似的东西;它就在“使用调试器运行”下面)。
这是由visual studio添加的“pause”命令的输出。如果你看到这个,程序就结束了。这就是一个问题,例如应用程序可能检测到它自身已经结束。我认为这不符合逻辑。
命令系统(“暂停”)时给出此提示
用来。
即使我遇到了这个问题。您可以使用conio.h下的函数_getch()来等待按键。
所以你可以使用以下代码:
cout<<"your message here"
_getch()
这将等待按键并显示您自己的提示。
无法检测,但是如果你将它添加到Main
的末尾,当你运行调试器时会添加相同的提示(F5):
if (Debugger.IsAttached)
{
Console.Write("Press any key to continue . . . ");
Console.ReadKey();
}
它实际上与Ctrl + F5一样与& pause
相同