Как получить активное ChildWindow приложения? - PullRequest
3 голосов
/ 07 мая 2009

У меня есть проблема: у меня есть обработчик главного окна определенного приложения, и я хочу смоделировать нажатие на это приложение ...

Я использую API-вызовы sendMessage / postMessage для этого. Причина, по которой я не использую функцию .Net SendKeys или keybd_event интерфейса win32, заключается в том, что они имитируют нажатие клавиш на глобальном уровне. В моем случае целевое приложение не является активным сверху (другое приложение может работать на более высоком уровне z, следовательно, охватывая целевое приложение).

Проблема с sendMessage и postMessage заключается в том, что вы должны передать обработчик точного дочернего окна, в котором вы хотите, чтобы клавиша была нажата. Например, в блокноте, если я отправляю ключ обработчику mainWindow, ничего не происходит, я должен отправить ключ обработчику дочернего окна, которое в основном состоит из белого холста, куда вы можете писать.

Проблема с обработчиком активного дочернего окна. Вначале я использовал вызовы API GetTopWindow или GetWindow (GW_CHILD), поскольку он возвращает самое активное дочернее окно. Я продолжал вызывать GetWindow (GW_CHILD) до тех пор, пока у меня не появилось дочернее окно, в котором больше не было дочерних окон. Это работает нормально для некоторых приложений, таких как блокнот или рисование. Однако в некоторых случаях (например, Firefox) это не работает. Причиной этого является то, что родительское окно имеет всю область Firefox, а его дочернее окно имеет открытую веб-страницу (например, Google). Поэтому, когда я запрашиваю самое активное дочернее окно основного окна, оно возвращает единственное дочернее окно, которое соответствует области веб-страницы. Это работает, только если это активное окно (например, если пользователь что-то пишет в текстовом поле определенной страницы). Но если активна, скажем, адресная строка, она не работает, потому что активное окно не дочернее окно, а фактически родительское ... и я не могу получить эту информацию программно.

Я действительно нашел способ сделать это, используя вызов API GetGUIThreadInfo, используя следующий код:

    // get thread of the main window handle of the process
    var threadId = GetWindowThreadProcessId(firefox.MainWindowHandle, IntPtr.Zero);

    // get gui info
    var info = new GUITHREADINFO();
    info.cbSize = (uint)Marshal.SizeOf(info);
    if (!GetGUIThreadInfo(threadId, out info))
        throw new Win32Exception();

    // send the letter W to the active window
    PostMessage(info.hwndActive, WM_KEYDOWN, (IntPtr)Keys.W, IntPtr.Zero);

И это работает очень хорошо: если адресная строка активна, она отправляет букву "W" в адресную строку. Если поисковый текстовый ящик Google активен, он отправляет ему букву "W" ... Отлично! Однако этот метод не может быть использован мной по простой причине: Если целевое приложение не является активным окном операционной системы, структура ThreadInfo становится пустой. Например, если я нацеливаюсь на Firefox, он работает, если Firefox активен (самое верхнее приложение, сфокусированное / активное), но если, скажем, блокнот находится поверх Firefox, он не работает, это не может получить активный обработчик окна.

Я знаю, что могу решить эту проблему, используя API-вызов setForegroundWindow для активации целевого приложения, а затем перехватить обработчик активного дочернего окна, но мне не хотелось выводить целевое приложение на передний план.

Я также пробовал другие методы, такие как вызовы API AttachThreadInput () и GetFocus (), которые также работают, но имеют ту же проблему: если целевое приложение не является активным приложением Windows, оно не работает.

Так что в основном мне нужно найти какой-нибудь способ получить обработчик для активного дочернего окна приложения, даже если это приложение не является активным сверху.

Есть идеи? Спасибо

Ответы [ 2 ]

1 голос
/ 11 мая 2009

Возможно, вы захотите проверить функцию EnumChildWindows .

0 голосов
/ 14 мая 2009

Если все остальное терпит неудачу, вот другая идея: Вы могли бы хотеть рассмотреть использование ловушек WH_CBT или WH_CALLWNDPROC, чтобы контролировать, какое дочернее окно целевого потока было сфокусировано последним.

Установите ловушку CBT (WH_CBT) и прослушайте уведомление HCBT_SETFOCUS. Или используйте перехват WH_CALLWNDPROC и прослушайте сообщение WM_SETFOCUS.

Не тратьте много времени на ловушку, иначе вы затормозите системные ресурсы. Просто сохраните необходимую информацию и опубликуйте собственное сообщение для последующей обработки.

...