c# - Obtener texto de ventana activo(y enviarle más texto)
winapi pinvoke (2)
Estoy creando una pequeña utilidad en C #, que agregará algo de texto a un cuadro de texto activo cuando se presione una tecla de acceso rápido global, es un tipo de función de autocompletar. Tengo mi tecla de acceso rápida global funcionando, pero ahora no sé cómo obtener el texto actual en el cuadro de texto activo (si la ventana activa es un cuadro de texto). Lo que he intentado hasta ahora es usar
a. GetForegroundWindow y luego usar ese identificador llamando a GetWindowText. Esto me dio el título de la ventana activa, no el contenido de la caja de texto.
segundo. GetActiveWindow y utilizando ese identificador para llamar a GetWindowText. Eso no me da ningún texto en absoluto.
Aquí hay un ejemplo de lo que hice
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[ DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[ DllImport("user32.dll") ]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
static extern int GetActiveWindow();
public static void TestA() {
int h = GetForegroundWindow();
StringBuilder b = new StringBuilder();
GetWindowText(h, b, 256);
MessageBox.Show(b.ToString());
}
public static void TestB() {
int h = GetActiveWindow();
StringBuilder b = new StringBuilder();
GetWindowText(h, b, 256);
MessageBox.Show(b.ToString());
}
Entonces, ¿alguna idea sobre cómo lograr esto?
Editar 28.01.2009: Entonces, descubrí cómo hacer esto. Esto es lo que utilicé:
using System;
using System.Text;
using System.Runtime.InteropServices;
public class Example
{
[DllImport("user32.dll")]
static extern int GetFocus();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, int ProcessId);
[DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern int SendMessage(int hWnd, int Msg, int wParam, StringBuilder lParam);
const int WM_SETTEXT = 12;
const int WM_GETTEXT = 13;
public static void Main()
{
//Wait 5 seconds to give us a chance to give focus to some edit window,
//notepad for example
System.Threading.Thread.Sleep(5000);
StringBuilder builder = new StringBuilder(500);
int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
//AttachTrheadInput is needed so we can get the handle of a focused window in another app
AttachThreadInput(remoteThreadId, currentThreadId, true);
//Get the handle of a focused window
int focused = GetFocus();
//Now detach since we got the focused handle
AttachThreadInput(remoteThreadId, currentThreadId, false);
//Get the text from the active window into the stringbuilder
SendMessage(focused, WM_GETTEXT, builder.Capacity, builder);
Console.WriteLine("Text in active window was " + builder);
builder.Append(" Extra text");
//Change the text in the active window
SendMessage(focused, WM_SETTEXT, 0, builder);
Console.ReadKey();
}
}
Algunas notas sobre esto. El ejemplo espera 5 segundos antes de hacer cualquier cosa, dándole la oportunidad de enfocar una ventana de edición. En mi aplicación real, estoy usando una tecla de acceso rápido para activar esto, pero eso solo confundiría este ejemplo. Además, en el código de producción, debe verificar los valores devueltos de las llamadas win32 para ver si tuvieron éxito o no.
Es razonable enviar pulsaciones de teclas si conoce la ventana activa y el campo de entrada enfocado. Consulte http://www.pinvoke.net/default.aspx/user32/keybd_event.html para API.
Verifique, incluso el mensaje em_replacesel puede no funcionar en un proceso diferente, puede necesitar usar WM_COPYDATA o llamando al procedimiento de ventana como se indica en la url,