Visual studio 如何检测“是否”;按任意键继续&引用;将显示什么?
在Visual Studio中运行控制台应用程序时,根据您的设置,它将在程序退出后添加提示: 按任意键继续 我已经找到了如何检测我是否在调试器下运行的方法(使用Visual studio 如何检测“是否”;按任意键继续&引用;将显示什么?,visual-studio,ide,console-application,visual-studio-debugging,Visual Studio,Ide,Console Application,Visual Studio Debugging,在Visual Studio中运行控制台应用程序时,根据您的设置,它将在程序退出后添加提示: 按任意键继续 我已经找到了如何检测我是否在调试器下运行的方法(使用debugger.IsAttached),但它没有帮助。按CTRL-F5启动而不调试将此标志设置为false,但仍显示提示 我想检测到这一点,因为我想显示我自己的消息并等待按键,但不进行双重按键检查 我不想破坏我的Visual Studio常规设置。如果我可以用一种可以签入源代码管理的方式来禁用这个项目,那也可以 使用什么机制附加此提示,
debugger.IsAttached
),但它没有帮助。按CTRL-F5启动而不调试将此标志设置为false
,但仍显示提示
我想检测到这一点,因为我想显示我自己的消息并等待按键,但不进行双重按键检查
我不想破坏我的Visual Studio常规设置。如果我可以用一种可以签入源代码管理的方式来禁用这个项目,那也可以
使用什么机制附加此提示,以及如何检测它
或者如何根据项目禁用它,并将此更改检查到源代码管理中?听起来此提示是由
暂停
命令提供的。此命令由Visual Studio自动添加
在Visual Studio之外运行项目时,没有理由“检测”此命令。您可以放心地假设它不会添加到您的程序中。这意味着您可以继续添加所需的任何提示,类似于:
Console.WriteLine("Press any key...");
Console.Read();
该消息与您的程序无关。您可以向您的程序中添加任何您喜欢的内容,并且如果您从命令提示符下运行它,它将以相同的方式执行
VisualStudio显示它的目的是向您显示它的执行已完成运行,以便您知道它已正确结束。如果您想跳过它,您可以尝试“不调试运行”(或类似的内容;它就在“使用调试器运行”的下方)。将以下代码添加到控制台应用程序:
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);
}
}
公共静态类扩展{
[DllImport(“kernel32.dll”)]
静态外部IntPtr OpenThread(uint-dwDesiredAccess、bool-bInheritHandle、uint-dwThreadId);
[DllImport(“kernel32.dll”)]
静态外部bool TerminateThread(IntPtr hThread,uint dwExitCode);
公共静态进程GetParentProcess(此进程x){
返回(
从(新的ManagementObjectSearcher(“根\\CIMV2”,“从Win32_进程中选择*)).Get().Cast()中的
其中(uint)it[“ProcessId”]==x.Id
选择Process.GetProcessById((int)(uint)it[“ParentProcessId”])
).First();
}
公共静态IEnumerable GetChildProcess(此进程x){
返回(
从(新的ManagementObjectSearcher(“根\\CIMV2”,“从Win32_进程中选择*)).Get().Cast()中的
其中(uint)it[“ParentProcessId”]==x.Id
选择Process.GetProcessById((int)(uint)it[“ProcessId”])
);
}
公共静态无效中止(此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);
}
}
类程序{
静态void Main(字符串[]参数){
//…(您的代码可能在这里)
试一试{
Process.GetCurrentProcess().GetParentProcess().Threads.Cast().Single().Abort();
}
捕获(无效操作异常){
}
控制台。写入(“仅按键继续…”);
Console.ReadKey(true);
}
}
所以,我们期待的一切现在都完成了。我认为这是解决问题的办法。它可以在windowsxpsp3
下工作,我想它可以在较新的Windows操作系统上工作。在VisualStudio下,应用程序始终是一个衍生过程。在旧的Visual C++ 6中,IDE通过调用<代码> VCSPAWN.exe < /C>来生成。在Visual Studio 2010中,应用程序在不进行调试的情况下启动时使用以下命令行运行:
%comspec%/c“您的应用程序文件名”&暂停
因此,以全面管理的方式实现目标是不可能的;因为它不是应用程序域下的
这里我们使用WMI
的托管方式来枚举进程,并封装非托管的WINAPI
s来终止ProcessThread
s,因为ProcessThread
通常不应该中止;它像只读的东西一样提供
如上所述,应用程序是使用特定的命令行生成的;它需要一个线程创建一个进程签名,因此我们使用single()
方法检索该线程并终止它
当我们在现有的命令提示符下启动应用程序时,它与启动而不调试的场景完全相同。此外,启动调试时,应用程序进程由devenv.exe
创建。它有很多线程,我们知道它不会中止任何线程,只需提示并等待按键。这种情况类似于双击或从上下文菜单启动应用程序。通过这种方式,应用程序进程由系统shell创建,通常是Explorer.exe
,它也有很多线程
事实上,如果我们能够成功中止线程,这意味着我们有权终止父进程。但我们确实不需要这样做。我们只需要中止唯一的线程,当进程没有更多线程时,系统会自动终止进程。通过识别调用进程是%comspec%
来终止父进程是做同样事情的另一种方法,但这是一个危险的过程。因为生成应用程序的进程可能有其他线程,这些线程的数量可以是任意的,因此创建一个与%comspec%
匹配的进程。您可能会粗心大意地终止流程中的关键工作,或者只是增加了检查流程是否可以安全终止的复杂性。所以我认为<强>单
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;
}
cout<<"your message here"
_getch()
if (Debugger.IsAttached)
{
Console.Write("Press any key to continue . . . ");
Console.ReadKey();
}