检测应用程序是否显示自己的控制台窗口或在其他窗口中运行

3
我想检测应用程序是否显示自己的控制台窗口,还是在其他控制台中运行(例如作为批处理文件的一部分)。我知道这可能发生的两种情况是当应用程序从资源管理器启动或从 Visual Studio 执行时。
我想这样做的原因是,如果应用程序已经显示了它自己的窗口,那么我可以让它在运行后暂停,否则它很可能是批处理脚本的一部分,并且应该正常退出。
这个是否可行?

1
检查父进程。当从批处理文件(或控制台窗口)执行时,它将具有cmd.exe作为父进程,但在从shell运行时则不会。顺便说一句,当从VS中运行时,我认为VS负责保持该窗口打开,应用程序本身并不知道这一点。 - Adriano Repetti
在我的经验中,VS不会保持父窗口打开(针对2005和2008版本)。 - We Are All Monica
1
只有在非调试模式(Ctrl+F5)下,VS 才会保留父窗口的打开状态。当你进行调试(F5)时,它将立即关闭而不需要你自己编写处理代码。 - Louis Ingenthron
2个回答

3

通常,正确的做法是允许一个标志作为参数传入,告知程序应该在“安静模式”下运行。这样批处理文件将使用该参数调用它(例如,“myprogram.exe /Q”),它将运行并立即退出。如果只是双击运行,那么该参数将不存在,程序将正常运行。


这样做是可行的,但在大多数情况下,我更希望程序默认情况下“正确处理”。无论如何,我可能最终会添加一个选项,例如--pause={yes,no,error} - We Are All Monica

2

继Adriano的评论之后,是的,通过检查父进程是可能的。您需要根据父进程进行一些启发式处理,我认为有些情况可能不准确。此代码查看父进程:

    static void Main(string[] args)
    {
        Process p = Process.GetCurrentProcess();
        ParentProcessUtilities pInfo = new ParentProcessUtilities();
        int l;
        int error = NtQueryInformationProcess(p.Handle, 0, ref pInfo, Marshal.SizeOf(typeof(ParentProcessUtilities)), out l);
        if (error == 0)
        {
            var parent = Process.GetProcessById(pInfo.InheritedFromUniqueProcessId.ToInt32());
            Console.WriteLine("My parent is: {0}", parent.ProcessName);
        }
        else
        {
            Console.WriteLine("Error occured: {0:X}", error);
        }
        Console.ReadKey();
    }


    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);

}

[StructLayout(LayoutKind.Sequential)]
public struct ParentProcessUtilities
{
    // These members must match PROCESS_BASIC_INFORMATION
    internal IntPtr Reserved1;
    internal IntPtr PebBaseAddress;
    internal IntPtr Reserved2_0;
    internal IntPtr Reserved2_1;
    internal IntPtr UniqueProcessId;
    internal IntPtr InheritedFromUniqueProcessId;
}

根据我的测试,父进程可能是以下之一:
  • 在VS中以Debug模式运行时,父进程为devenv.exe
  • 未使用调试运行时,父进程为cmd
  • 从命令提示符中运行时,父进程为cmd
  • 如果从PowerShell中调用,则父进程为powershell
  • 如果在Windows资源管理器中双击,则父进程为Explorer
正如您所想象的那样,其他进程可能会以不同的方式调用您的程序,除了我提到的这些方式,您需要在代码中进行处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接