我正在使用自动化测试应用程序,但有时我想通过批处理文件启动该应用。 当我运行“process.WaitForInputIdle(100)”时,会出现以下错误信息:
“WaitForInputIdle失败。这可能是因为进程没有图形界面。”
如何确定进程是否具有图形界面?
“WaitForInputIdle失败。这可能是因为进程没有图形界面。”
如何确定进程是否具有图形界面?
请查看Environment.UserInteractive,该方法可以确定进程是否拥有界面,例如服务不具有用户交互性。
您还可以查看Process.MainWindowHandle,该方法将告诉您是否存在图形界面。
这两个检查的结合应该涵盖所有可能性。
你可以简单地尝试并捕获异常:
Process process = ...
try
{
process.WaitForInputIdle(100);
}
catch (InvalidOperationException ex)
{
// no graphical interface
}
WaitForInputIdle
函数。 - Dirk VollmarWaitForInputIdle
函数在任何四种错误情况下都会返回WAIT_FAILED
。 - Dirk Vollmar我在考虑这条路线,虽然还是有些丑陋,但试图避免异常。
Process process = ...
bool hasUI = false;
if (!process.HasExited)
{
try
{
hasUI = process.MainWindowHandle != IntPtr.Zero;
}
catch (InvalidOperationException)
{
if (!process.HasExited)
throw;
}
}
if (!process.HasExited && hasUI)
{
try
{
process.WaitForInputIdle(100);
}
catch (InvalidOperationException)
{
if (!process.HasExited)
throw;
}
}
使用此类来读取进程主模块的 PE 头: https://gist.github.com/ahmedosama007/bfdb8198fe6690d17e7c3db398f6d725
使用以下代码来检测进程模块子系统:
Dim peReader = New PEHeaderReader("C:\Windows\notepad.exe")
Dim subsystem As PEHeaderReader.ImageSubSystem
If peReader.Is32BitHeader Then '32-bit
subsystem = peReader.OptionalHeader32.Subsystem
Else '64-bit
subsystem = peReader.OptionalHeader64.Subsystem
End If
'https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32
If subsystem = PEHeaderReader.ImageSubSystem.IMAGE_SUBSYSTEM_WINDOWS_GUI Then
Console.WriteLine("GUI")
ElseIf subsystem = PEHeaderReader.ImageSubSystem.IMAGE_SUBSYSTEM_WINDOWS_CUI Then
Console.WriteLine("Console")
Else
Console.WriteLine("Other Subsystem")
End If
Console.ReadLine()
MainWindowHandle
之外,可以枚举进程线程,并通过P/Invokes检查它们是否引用可见窗口。这似乎很好地捕捉到第一个检查遗漏的任何窗口。private Boolean isProcessWindowed(Process externalProcess)
{
if (externalProcess.MainWindowHandle != IntPtr.Zero)
{
return true;
}
foreach (ProcessThread threadInfo in externalProcess.Threads)
{
IntPtr[] windows = GetWindowHandlesForThread(threadInfo.Id);
if (windows != null)
{
foreach (IntPtr handle in windows)
{
if (IsWindowVisible(handle))
{
return true;
}
}
}
}
return false;
}
private IntPtr[] GetWindowHandlesForThread(int threadHandle)
{
results.Clear();
EnumWindows(WindowEnum, threadHandle);
return results.ToArray();
}
private delegate int EnumWindowsProc(IntPtr hwnd, int lParam);
private List<IntPtr> results = new List<IntPtr>();
private int WindowEnum(IntPtr hWnd, int lParam)
{
int processID = 0;
int threadID = GetWindowThreadProcessId(hWnd, out processID);
if (threadID == lParam)
{
results.Add(hWnd);
}
return 1;
}
[DllImport("user32.Dll")]
private static extern int EnumWindows(EnumWindowsProc x, int y);
[DllImport("user32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
[DllImport("user32.dll")]
static extern bool IsWindowVisible(IntPtr hWnd);