Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get active window text (and send more text to it)

Tags:

c#

pinvoke

winapi

I'm creating a small utility in C#, that will add some text to an active textbox when a global hotkey is pressed, it's a type of auto complete function. I have my global hotkey working, but now I don't know how to get the current text in the active textbox (if the active window is a textbox that is.) What I've tried so far is to use

a. GetForegroundWindow and then using that handle calling GetWindowText. This gave me the window title of the active window, not the textbox contents.

b. GetActiveWindow and using that handle to call GetWindowText. That gives me no text at all.

Here's an example of what I've done

[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());
}

So, any ideas on how to achieve this?

Edit 28.01.2009: So, I found out how to do this. This is what I used:

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();
    }
}

Some notes about this. The example waits for 5 seconds before doing anything, giving you the chance to give focus to some edit window. In my real app I'm using a hotkey to trigger this, but that would just confuse this example. Also, in production code you should check the return values of the win32 calls to see if they succeeded or not.

like image 370
Einar Egilsson Avatar asked Jan 26 '09 11:01

Einar Egilsson


2 Answers

It's reasonable to send keystrokes if you aware of active window and focused input field. See http://www.pinvoke.net/default.aspx/user32/keybd_event.html for API.

like image 54
sinm Avatar answered Oct 24 '22 17:10

sinm


Please check, even em_replacesel message may not work across different process, You might need to use WM_COPYDATA or by calling window procedure as given in the url,

http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.smartphone.developer&tid=4e3a9289-9355-4af7-a5b9-84f1aa601441&cat=&lang=&cr=&sloc=en-us&p=1

like image 33
lakshmanaraj Avatar answered Oct 24 '22 16:10

lakshmanaraj