Deseo enviar una entrada de teclado a una ventana en otro proceso, sin llevar esa ventana al primer plano. Puedo usar PostMessage
para falsificar WM_KEYDOWN
y WM_KEYUP
; todo lo que necesito saber es qué identificador de ventana debe recibir la entrada del teclado, es decir, algo así como GetFocus, pero para otra aplicación no activa.Llamando a GetGUIThreadInfo a través de P/Invoke
La API GetGUIThreadInfo parece prometedora: devuelve hwndFocus
para otra aplicación. Pero no he tenido suerte de hacerlo funcionar desde C# en mi sistema operativo de 64 bits. He copiado (y luego modificado) las declaraciones de pinvoke.net, pero todo lo que recibo es un código de error genérico (más detalles a continuación).
Estoy configurando cbSize antes de llamar a GetGUIThreadInfo, por lo que he evitado el problema potencial más obvio.
Estoy ejecutando Vista de 64 bits, por lo que no sé si el problema es que no estoy usando la API correctamente, o que funciona de manera diferente en 64 bits - Todavía tengo que encontrar un muestra de código que dice específicamente que funciona con éxito en Win64.
Aquí hay un código de muestra. Estoy usando GetWindowThreadProcessId as recommended, así que no creo que el problema tiene que ver con la mezcla de los ID de hilo con hilo maneja:
[StructLayout(LayoutKind.Sequential)] internal struct Rect { public int Left; public int Top; public int Right; public int Bottom; } [StructLayout(LayoutKind.Sequential)] internal class GuiThreadInfo { public int cbSize; public uint flags; public IntPtr hwndActive; public IntPtr hwndFocus; public IntPtr hwndCapture; public IntPtr hwndMenuOwner; public IntPtr hwndMoveSize; public IntPtr hwndCaret; public Rect rcCaret; } [DllImport("user32.dll")] internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport("user32.dll", SetLastError = true)] internal static extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui); IntPtr GetFocusedHandleFromProcessWithWindow(IntPtr window) { var threadId = GetWindowThreadProcessId(window, IntPtr.Zero); var info = new GuiThreadInfo(); info.cbSize = Marshal.SizeOf(info); if (!GetGUIThreadInfo(threadId, ref info)) throw new Win32Exception(); return info.hwndFocus; }
window
es un identificador de ventana válida; GetWindowThreadProcessId
devuelve un identificador de hilo distinto de cero. Pero la llamada a GetGUIThreadInfo
siempre devuelve false
, y el mensaje de excepción siempre es "El parámetro es incorrecto".
Sólo en caso de que el problema era que GetGUIThreadInfo
alguna manera no tiene una versión de 64 bits, He intentado cambiar todos los 8 bytes IntPtr
s en los GuiThreadInfo
declaración a 4 bytes int
s, pero todavía tiene el mismo error.
¿Alguien tiene una muestra de C# en funcionamiento de GetGUIThreadInfo
en Win64? O bien, ¿hay alguna otra manera de encontrar cuál sería el manejador de la ventana del niño enfocada en otra aplicación, sin activar esa aplicación?
Ouch. Tienes razón, no puedo creer que me haya perdido eso. Punto de etiqueta: esto solucionó el problema inmediato, pero luego surgió otro problema; así que mi objetivo final de "obtener un control centrado en otros procesos" sigue abierto. ¿Debo editar esta pregunta, o aceptar esta respuesta y luego escribir una nueva pregunta? –
En este caso, la pregunta es realmente acerca de invocar GetGUIThreadInfo, por lo que probablemente debería votar como útil y marcarla como la respuesta. Es posible que también desee editar el título para describir esta pregunta de manera más específica. A continuación, agregue una nueva pregunta sobre el problema más general, que incluye qué ... –
... su requisito subyacente es y lo que ha intentado hasta ahora. En general, debe editar una pregunta para agregar información o claridad para no cambiar lo que se está pidiendo. –