3

我正在开发批处理引擎,因为我们有一个第三方软件,它是一个需要批量运行的客户端软件

我使用此代码来枚举进程 ID

public IEnumerable<int> EnumerateProcessWindowHandles(int processId)
{
    var handles = new List<IntPtr>();
    try
    {
        foreach (ProcessThread thread in Process.GetProcessById(processId).Threads)
            Win32.EnumThreadWindows(thread.Id,
                                    (hWnd, lParam) =>
                                        {
                                            handles.Add(hWnd);
                                            return true;
                                        }, IntPtr.Zero);

    }
    catch (Exception e) {}
    return handles.Select(h => (int)h);
}

然后这段代码获取每个窗口的文本

public string GetText(int hWnd)
{
    // Allocate correct string length first
    int length = Win32.GetWindowTextLength(hWnd);
    var sb = new StringBuilder(length + 1);
    Win32.GetWindowText(hWnd, sb, sb.Capacity);
    return sb.ToString();
}

从服务执行程序时,永远找不到我正在寻找的窗口,如果我从控制台程序启动它,它可以工作。如果我尝试从服务中启动 calc.exe,我会得到计算器窗口,因此可以从服务中获取窗口。从我的服务收听 calc.exe 时的输出

2013-04-16 13:52:09; 冗长的;23000; 1728; 5592; 批次:窗口hwnd:8454324;标题:计算器

2013-04-16 13:52:09; 冗长的;23000; 1728; 5592; 批次:窗口hwnd:393910;标题:

2013-04-16 13:52:09; 冗长的;23000; 1728; 5592; 批次:窗口hwnd:328806;标题:GDI+ 窗口

2013-04-16 13:52:09; 信息; 23000; 1728; 5592; 批次:显示的计算器

并在收听我的真实应用程序时输出

2013-04-16 14:25:16; 冗长的;23000; 5076; 5140; 批次:窗口hwnd:524976;标题:.NET-BroadcastEventWindow.2.0.0.0.218f99c.0

2013-04-16 14:25:16; 冗长的;23000; 5076; 5140; 批次:窗口hwnd:524978;标题:GDI+ 窗口

2013-04-16 14:25:16; 冗长的;23000; 5076; 5140; 批次:窗口hwnd:590366;标题:

2013-04-16 14:25:16; 冗长的;23000; 5076; 5140; 批次:窗口hwnd:787088;标题:

2013-04-16 14:25:16; 冗长的;23000; 5076; 5140; 批次:窗口hwnd:656044;标题:

2013-04-16 14:25:16; 冗长的;23000; 5076; 5140; 批次:窗口hwnd:721578;标题:

2013-04-16 14:25:16; 冗长的;23000; 5076; 5140; 批次:窗口hwnd:590926;标题:

正如您所看到的,大多数 hwnd 都是无标题的,如果我也这样做,但从控制台模式我得到

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:66672;标题:MSCTFIME UI

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:328694;标题:

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:328754;标题:

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:197656;标题:

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132122;标题:

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132178;标题:.NET-BroadcastEventWindow.2.0.0.0.218f99c.0

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132100;标题:MSCTFIME UI

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132186;标题:默认输入法

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132176;标题:GDI+ 窗口

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:197654;标题:默认输入法

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132144;标题:

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132142;标题:

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132140;标题:默认输入法

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:459078;标题:任务进度

2013-04-16 14:21:08; 冗长的;23000; 4864; 4120; 控制台:窗口hwnd:132078;标题:默认输入法

我得到更多的 hwnd 和更多的标题,我感兴趣的窗口是任务进度

这可以解决吗?我正在起诉 Process.Start 以启动该过程

4

1 回答 1

0

我假设您使用的是 Vista 或更高版本,因为早期版本不会出现此问题。正如@Damien_The_Unbeliever 所说,这是一个会话 0 隔离问题。

这可以解决吗?我正在起诉 Process.Start 以启动该过程

在会话 0 即启动第三方应用程序(您无法控制其代码)通常是一个坏主意。

  • 您不知道该应用程序是否设计为在会话 0 的限制下运行。
  • 安全问题,因为您可以通过此会话对系统造成更大的损害。

使用CreateProcessAsUser将 STARTUPINFO 的 lpDesktop 成员设置为“Winsta0\\default”和通过CreateEnvironmentBlock获得的环境块。有关如何从 C# 调用这些,请参阅这篇文章

您可以通过WTSQueryUserToken获取用户令牌,并且会话 ID 可通过WTSEnumerateSessions或 SERVICE_CONTROL_SESSIONCHANGE 消息提供给服务。

如您所见,大多数 hwnd 是无标题的,

您无法检索窗口文本的原因是因为 Windows 通过发送 WM_GETTEXT 消息来执行此操作(请参阅msdn上的备注部分),当然它不能这样做,因为您的引擎位于服务桌面上。

您可以在服务中解决此问题,方法是在一个单独的线程中执行您的操作,在该线程上您使用用户的桌面调用了SetThreadDesktop(请注意,请参阅备注中的警告)。

于 2013-04-16T19:01:35.583 回答