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