У меня есть проблема: у меня есть обработчик главного окна определенного приложения, и я хочу смоделировать нажатие на это приложение ...
Я использую 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, оно не работает.
Так что в основном мне нужно найти какой-нибудь способ получить обработчик для активного дочернего окна приложения, даже если это приложение не является активным сверху.
Есть идеи?
Спасибо