9

当运行在Visual Studio控制台应用程序,根据您的设置,它会在程序退出之后添加提示:如何检测“按任意键继续...”会显示?

按任意键继续。 。 。

我发现如何检测我是否在调试器下运行(使用Debugger.IsAttached),但它没有帮助。按CTRL-F5开始不调试将此标志设置为false,但仍显示提示

我想检测到这一点,因为我想显示自己的消息并等待按键,但不是按键检查的两倍

我不想跟我一般的Visual Studio设置渣土。如果我可以在这个项目中禁用它,可以检查到源代码控制,那也可以。

什么机制来追加该提示,以及如何检测呢?

或者我该如何禁用它每个项目,并检查此更改源代码控制?

回答

6

下面的代码添加到控制台应用程序:

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 “” 你的应用程序文件名 “&暂停”

所以不可能在完全管理的方式达到目标;因为它是在应用程序域下的NOT

在这里我们使用的WMI的管理方式来枚举进程,并封装非托管WINAPI s到终止ProcessThread S,因为ProcessThread不应该是正常中止;它提供了一些用于只读的东西。

如上所述,应用程序是由特定的命令行产生的;它会有单线程创建单个进程签名,所以我们使用Single()方法检索该线程并终止它。

当我们在现有的命令提示符下启动应用程序时,它与开始时没有调试一样。此外,当开始调试时,申请过程由devenv.exe创建。它有很多线程,我们知道并且不会中止任何线程,只是提示并等待按键。这种情况类似于通过双击或从上下文菜单开始应用程序。这样,应用程序进程由系统shell创建,通常为Explorer.exe,并且它也有很多线程。

事实上,如果我们可以成功地中止线程,那意味着我们有权杀死父进程。但我们做不需要需要。我们只需要中止唯一的线程,当没有更多的线程时,进程会自动终止进程。通过识别调用进程是否为%comspec%来杀死父进程是另一种做同样事情的方式,但这是一个危险的过程。因为生成应用程序的进程可能会有其他线程,它们具有任意数量的线程,所以创建的进程匹配%comspec%。你可能会粗心大意地杀死一个关键流程的工作,或者增加检查流程是否可以被杀死的复杂性。所以我认为单线程创建单个进程作为我们的父进程的签名是安全的杀/中止。

WMI是现代的,一些WINAPI可能会在将来被弃用。但是这种构图的真正原因在于其简单性。旧的Tool Help Library像将ProcessThread转换为System.Threading.Thread那样复杂。使用LINQ和扩展方法,我们可以使代码更简单,更具语义。

+0

看起来很有希望。在分配奖金后会接受一段时间。 –

+0

啊..谢谢。赏金是由我开始的,只能奖给别人,我正在寻找更好的答案。 –

+0

@ MerlynMorgan-Graham:我错过了宽限期.. –

2

听起来就像是由pause命令提供此提示。该命令由Visual Studio自动添加。

当你运行你的项目的Visual Studio之外,没有任何理由“检测”这一命令。您可以放心地假定它不会被添加到您的程序中。这意味着你可以继续添加任何你想要的提示,类似于:

Console.WriteLine("Press any key..."); 
Console.Read(); 

See this question.

+0

对这个机制很好的回答,事实证明,这不是我的问题中最有用的部分,除非我找到一种方法来检测它是否正在发生。你知道如何检测我的应用程序是否被这种方式包装?我想检测这个,因为我不想禁用VS功能,并且我不想被提示两次来终止我的应用程序。 –

+0

我做了一个编辑,这有帮助吗?我对命令行和C#不熟悉,不知道您是否可以确定当前程序是否以'pause'作为参数被调用。 –

1

该消息没有任何与您的程序。您可以将任何您喜欢的内容添加到您的程序中,如果要从命令提示符运行它,它将以与它相同的方式执行。

Visual Studio显示它的目的是向您显示它的执行已完成运行,因此您知道它已正确结束。如果你想跳过它,你可以尝试“无需调试即可运行”(或类似的东西;它只是在“使用调试器运行”之下)。

+0

Ctrl-F5是“无需调试即可开始”的快捷方式。将编辑我的问题澄清。 –

+0

@Merlyn - 然后尝试另一个 - 我知道它跳过了其中一个“按任意键”(有/无调试)。反正它应该。 – Rook

+0

因此,虽然我同意“医生,当我这样做时手臂疼痛”,但是“不要这样做”情绪,我也很好奇,如果可能的话,以及如何检测提示是否会显示。 –

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; 
} 
+0

我喜欢这个答案比接受的更好,因为它不需要等到按下任何键后约500毫秒。 –

0

使用命令 系统(“暂停”)

当给出此提示。

即使我面临这个问题。您可以使用conio.h下的函数_getch()来等待按键。

所以,你可以使用下面的代码:

 cout<<"your message here" 
     _getch() 

这将等待按键和显示自己的提示。

0

这是由visual studio添加的“暂停”命令的输出。如果你看到这个,程序结束。对于应用程序来说,它可能会检测到自己已经结束。我认为这不合逻辑。

+0

目标是做相反的事情 - 检测如果你不是由VS托管,因此应该提出一个暂停机制,并避免如果你由VS托管的双暂停。 –

相关问题