在Visual Studio中运行控制台应用程序时,根据您的设置,它会在程序退出后添加提示:
按任意键继续。 。
我已经找到了如何检测我是否在调试器下运行(使用Debugger.IsAttached
),但它没有帮助。按 CTRL-F5 到启动而不调试将此标记设置为false
,但仍显示提示。
我想检测到这一点,因为我想显示自己的消息并等待按键,但是不会加倍按键检查。
我不想使用我的常规Visual Studio设置。如果我可以用一种可以检查到源代码管理的方式为此项目禁用它,那也可以。
使用什么机制来附加此提示,以及如何检测它?
或者如何为每个项目禁用它,并将此更改检查为源代码管理?
答案 0 :(得分:7)
将以下代码添加到控制台应用程序:
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“”您的应用程序文件名“&amp; pause”
因此无法以完全管理的方式实现目标;因为它在应用程序域下是 NOT 。
这里我们使用WMI
的托管方式来枚举进程,并封装非托管WINAPI
以终止ProcessThread
,因为ProcessThread
不是假定的通常中止;它提供了像只读的东西。
如上所述,应用程序是使用特定的命令行生成的;它会 一个线程创建一个进程 签名,因此我们使用Single()
方法检索该线程并终止它。
当我们在现有命令提示符下启动应用程序时,它与 Start Without Debugging 的情况相同。此外,当开始调试时,应用程序进程由devenv.exe
创建。它有很多线程,我们知道并且不会中止任何线程,只是提示并等待按键。这种情况类似于双击启动应用程序或从上下文菜单启动应用程序。这样,应用程序进程由系统shell创建,通常为Explorer.exe
,并且它还有很多线程。
事实上,如果我们能够成功中止线程,则意味着我们有权杀死父进程。但我们需要 NOT 。我们只需要中止唯一的线程,当系统没有更多线程时,进程会自动终止。通过识别调用进程是%comspec%
来杀死父进程是另一种做同样事情的方法,但这是一个危险的过程。因为生成应用程序的进程可能具有其他线程,这些线程具有任意数量的线程,所以创建的进程与%comspec%
匹配。你可能会粗心地杀死一个重要的过程工作,或者只是增加检查过程是否可以安全杀死的复杂性。所以我认为 一个线程创建一个进程 作为我们父进程的签名,可以安全地终止/中止。
WMI
是现代的,WINAPI
中的一些可能会在将来被弃用。但这种构成的真正原因在于它的简单性。旧的Tool Help Library
非常复杂,就像将ProcessThread
转换为System.Threading.Thread
一样。使用LINQ和扩展方法,我们可以使代码更简单,更具语义。
答案 1 :(得分:2)
听起来这个提示是由pause
命令提供的。此命令由Visual Studio自动添加。
在Visual Studio外部运行项目时,没有理由“检测”此命令。您可以放心地假设它不会添加到您的程序中。这意味着你可以继续添加你想要的任何提示,类似于:
Console.WriteLine("Press any key...");
Console.Read();
答案 2 :(得分:2)
以下是一段应该执行此操作的代码:
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;
}
答案 3 :(得分:1)
该消息与您的程序无关。您可以向程序添加任何您喜欢的程序,如果您从命令提示符运行它,它将以与它相同的方式执行。
Visual Studio显示它是为了向您显示其执行已完成运行,因此您知道它已正确结束。如果你想跳过它,你可以尝试“无需调试运行”(或类似的东西;它就在“使用调试器运行”下面。)
答案 4 :(得分:0)
命令时会给出此提示 系统(“暂停”)
被使用。
即使我遇到了这个问题。您可以使用conio.h下的函数_getch()来等待按键。
所以你可以使用以下代码:
cout<<"your message here"
_getch()
这将等待按键并显示您自己的提示。
答案 5 :(得分:0)
这是由visual studio添加的“pause”命令的输出。如果你看到这个,程序就结束了。这就是一个问题,例如应用程序可能检测到它自身已经结束。我认为这不合逻辑。
答案 6 :(得分:0)
将无助于检测,但是如果您将其添加到Main
的末尾,则在连接调试器(F5)的情况下运行时会添加相同的提示:
if (Debugger.IsAttached)
{
Console.Write("Press any key to continue . . . ");
Console.ReadKey();
}
实际上,它与Ctrl + F5对& pause
的作用相同