捕获从其他应用程序输入的文本

时间:2015-08-21 02:30:04

标签: c# winapi

我正在开发一个窗口应用程序来读取C#在屏幕上的任何应用程序上输入的文本。 我使用的是Win32 API,如下所示 - 我在Google上找到的解决方案:

private const int WM_GETTEXTLENGTH = 0x000E;
private const int WM_GETTEXT = 0x000D;

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, StringBuilder lParam);

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

public Terminal() 
{
    InitializeComponent();

    IntPtr pFoundWindow = GetForegroundWindow();

    IntPtr notepad = FindWindow("notepad", null);
    IntPtr editx = FindWindowEx(notepad, IntPtr.Zero, "edit", null);
    int length = SendMessage(editx, WM_GETTEXTLENGTH, 0, 0);
    StringBuilder text = new StringBuilder(length);
    int hr = SendMessage(editx, WM_GETTEXT, length, text);
    Console.WriteLine(text);
}

但这只是从记事本中读取现有文本。 在任何程序,任何窗口上打字时,我该如何阅读文字?

1 个答案:

答案 0 :(得分:3)

示例中的以下代码

IntPtr notepad = FindWindow("notepad", null);

这意味着获取一个名为notepad的流程句柄。

以下一个

IntPtr editx = FindWindowEx(notepad, IntPtr.Zero, "edit", null);

也表示您尝试从记事本中找到窗口句柄,窗口标题为editedit窗口是记事本的可编辑区域。

如果您要使您的应用程序适合任何过程,则无法声明您的目标是源代码。换句话说,您需要另一种方法来指定要获取文本的窗口。

我的建议是:您需要以下Windows API才能在运行时获取目标窗口。

例如,您可以使用SetWindowsHookEx在应用程序外部获取鼠标事件,然后在用户单击目标窗口时触发回调。接下来,触发回调函数,您可以使用GetCursorPos获取鼠标位置,并使用WindowFromPoint获取您想要读取其文本的窗口。

<强>更新

我提供了我的其他项目的示例代码,并为您挑选了一些有用的部分。

    /// <summary>
    /// A hook handle for grabbing mouse click, used to get the position of target window.
    /// </summary>
    private IntPtr _hook = IntPtr.Zero;

    //button click event
    private void selectWindow_Click(object sender, EventArgs e)
    {
        if (_hook != IntPtr.Zero)
            return;
        using (Process p = Process.GetCurrentProcess())
        {
            using (ProcessModule m = p.MainModule)
            {
                _hook = SafeNativeMethods.SetWindowsHookEx(SafeNativeMethods.WH_MOUSE_LL, hookCallback, SafeNativeMethods.GetModuleHandle(m.ModuleName), 0);
            }
        }
    }

    /// <summary>
    /// Callback method of mouse hook.
    /// </summary>
    private IntPtr hookCallback(int code, IntPtr w, IntPtr l)
    {
        if (code >= 0 && (WMessages)w == WMessages.WM_LBUTTONDOWN)
        {
            CPoint pt;
            SafeNativeMethods.GetCursorPos(out pt);
            //hey man! the _windowHandle is what you need
            _windowHandle = SafeNativeMethods.WindowFromPoint(pt);
            SafeNativeMethods.UnhookWindowsHookEx(_hook);
            _hook = IntPtr.Zero;
            //...and do your stuff here!
        }
        return SafeNativeMethods.CallNextHookEx(_hook, code, w, l);
    }

而def。 Windows API

    /// <summary>
    /// Window Hook ID 14 - Low level mouse proc.
    /// </summary>
    internal const int WH_MOUSE_LL = 14;

    /// <summary>
    /// Get the window handle from a specified point.
    /// </summary>
    /// <param name="point">Specified point</param>
    /// <returns>Window handle</returns>
    [DllImport("user32.dll", SetLastError = true)]
    internal static extern IntPtr WindowFromPoint(CPoint point);

    /// <summary>
    /// Register a hook.
    /// </summary>
    /// <param name="idHook">Hook type</param>
    /// <param name="lpfn">Function pointer</param>
    /// <param name="hMod">Module ID</param>
    /// <param name="dwThreadId">Thread ID</param>
    /// <returns>Hook handle</returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

    /// <summary>
    /// Unregister a hook.
    /// </summary>
    /// <param name="hhk">Hook handle</param>
    /// <returns>Successful</returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool UnhookWindowsHookEx(IntPtr hhk);

    /// <summary>
    /// Call next hook (if needed).
    /// </summary>
    /// <param name="hhk">Hook handle</param>
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

    /// <summary>
    /// Get moudle handle by module name.
    /// </summary>
    /// <param name="lpModuleName">Module name</param>
    /// <returns>Module handle</returns>
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern IntPtr GetModuleHandle(string lpModuleName);

    /// <summary>
    /// Get current cursor position.
    /// </summary>
    /// <param name="lpPoint">Output position</param>
    /// <returns>Successful</returns>
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool GetCursorPos(out CPoint lpPoint);

更新2

我忘记了CPoint struct lol。

/// <summary>
/// Win32 POINT structure.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct CPoint
{
    public int x;
    public int y;
}