Как мне получить активное ChildWindow приложения?

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

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

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

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

Я действительно нашел способ сделать это, используя вызов 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, оно не работает.

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

Любые идеи? Спасибо


person Noyoudont    schedule 07.05.2009    source источник


Ответы (2)


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

person Rune Aamodt    schedule 11.05.2009

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

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

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

person Alex Jenter    schedule 14.05.2009