.NET (C#):当您只有进程句柄或 PID 时获取子窗口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/79111/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
.NET (C#): Getting child windows when you only have a process handle or PID?
提问by shea241
Kind of a special case problem:
一种特殊情况的问题:
- I start a process with
System.Diagnostics.Process.Start(..)
- The process opens a splash screen -- this splash screen becomes the main window.
- The splash screen closes and the 'real' UI is shown. The main window (splash screen) is now invalid.
- I still have the Process object, and I can query its handle, module, etc. But the main window handle is now invalid.
- 我开始一个过程
System.Diagnostics.Process.Start(..)
- 该过程会打开一个闪屏——这个闪屏成为主窗口。
- 启动画面关闭并显示“真实”用户界面。主窗口(启动画面)现在无效。
- 我还有 Process 对象,我可以查询它的句柄、模块等。但是现在主窗口句柄无效了。
I need to get the process's UI (or UI handle) at this point. Assume I cannot change the behavior of the process to make this any easier (or saner).
此时我需要获取进程的 UI(或 UI 句柄)。假设我无法更改流程的行为以使其更容易(或更理智)。
I have looked around online but I'll admit I didn't look for more than an hour. Seemed like it should be somewhat trivial :-(
我在网上环顾四周,但我承认我没有找一个多小时。看起来应该有点微不足道:-(
采纳答案by MB.
If you don't mind using the Windows API, you could use EnumWindowsProc
, and check each of the handles that that turns up using GetWindowThreadProcessId
(to see that it's in your process), and then maybe IsWindowVisible
, GetWindowCaption
and GetWindowTextLength
to determine which hWnd
in your process is the one you want.
如果您不介意使用 Windows API,则可以使用EnumWindowsProc
, 并检查使用的每个句柄GetWindowThreadProcessId
(以查看它是否在您的进程中),然后也许IsWindowVisible
,GetWindowCaption
并GetWindowTextLength
确定hWnd
您的进程中的哪个是你要。
Though if you haven't used those functions before that approach will be a real pain, so hopefully there's a simpler way.
虽然如果您之前没有使用过这些功能,那么这种方法将是一个真正的痛苦,所以希望有一种更简单的方法。
回答by ageektrapped
回答by Ash
@ageektrapped is on the right track, however FindWindow
will not search child windows.
@ageektrapped 在正确的轨道上,但FindWindow
不会搜索子窗口。
For that you will need to use FindWindowEx
为此,您将需要使用 FindWindowEx
回答by blackwing
From what I understand MainWindowHandle
property of the process you are starting is not valid. If that's the case, you can use FindWindow
function (from Win32 SDK) which returns the window handle you need. All you need is the class name of target application's main window. You can obtain it using Spy++ or Winspector. You also need to ensure you have the right window by checking that window's process id using GetWindowThreadProcessId
.
据我了解MainWindowHandle
,您开始的过程的属性无效。如果是这种情况,您可以使用FindWindow
返回您需要的窗口句柄的函数(来自 Win32 SDK)。您所需要的只是目标应用程序主窗口的类名。您可以使用 Spy++ 或Winspector获取它。您还需要通过使用GetWindowThreadProcessId
.
At last, I have to say I am not an expert on Win32 and there might be a better solution for your case.
最后,我不得不说我不是 Win32 专家,对于您的情况可能有更好的解决方案。
回答by GregUzelac
You may find that if you call .Refresh() that you get the new top-level window.
您可能会发现,如果您调用 .Refresh() ,您将获得新的顶级窗口。
回答by GregUzelac
Use Process.GetProcessById(proc.Id); where proc was your splash screen. Works for me.
使用 Process.GetProcessById(proc.Id); proc 是您的启动画面。为我工作。
Now, how do you get to main window properties in System.Windows.Forms to give it focus w/o using win32? After all .net is supposed to be a one-stop solution - is it not?
现在,您如何获得 System.Windows.Forms 中的主窗口属性以在不使用 win32 的情况下为其提供焦点?毕竟 .net 应该是一站式解决方案 - 不是吗?
回答by Marcus Erickson
Somewhere in the code, the "real" main window is created. You can just save the window handle at that time and then after the splash screen closes you can set Application.MainWindow to the real window.
在代码中的某处,创建了“真正的”主窗口。你可以在那个时候保存窗口句柄,然后在启动画面关闭后你可以将 Application.MainWindow 设置为真实窗口。
回答by Matt Ellis
The MainWindowHandle property is cached after it is first accessed which is why you don't see it changing even after the handle becomes invalid. GregUzelac's information is correct. Calling Proces.Refresh will causes the next call to Process.MainWindowHandle to re-do the logic to find a new main window handle. Michael's logic also works because the new Process doesn't have a cached version of the MainWindowHandle.
MainWindowHandle 属性在第一次访问后被缓存,这就是为什么即使在句柄无效后您也看不到它的变化。GregUzelac 的信息是正确的。调用 Proces.Refresh 将导致下一次调用 Process.MainWindowHandle 重新执行逻辑以查找新的主窗口句柄。Michael 的逻辑也有效,因为新 Process 没有 MainWindowHandle 的缓存版本。
回答by Giova
Thank you for your answers. Thanks to you here, I figured out how to know if the main window of a process is in front or not:
谢谢您的回答。多亏了你,我想出了如何知道进程的主窗口是否在前面:
N.B : of course this needs System.Diagnostic and System.Runtime.Interrop
注意:当然这需要 System.Diagnostic 和 System.Runtime.Interrop
public bool IsWindowActive(Int32 PID)
{
return IsWindowActive(Process.GetProcessById(PID));
}
[DllImport("user32.dll")]
private static extern
IntPtr GetForegroundWindow();
public bool IsWindowActive(Process proc)
{
proc.Refresh();
return proc.MainWindowHandle.Equals(GetForegroundWindow());
}