是否可以编写一个Windows应用程序,在另一个Windows应用程序中选择文本时获取通知?

时间:2012-03-07 17:08:35

标签: c# c++ windows winapi

我很好奇是否可以编写一个程序来监控我的文本选择。一种可能的用途是编写编辑器/ IDE不可知代码格式化程序:

  1. 启动应用程序/服务P,并以某种方式挂钩到窗口中,以便在任何窗口中选择文本时收到通知。
  2. 推出了其他一些应用程序A.
  3. 用户选择A。
  4. 中的文字
  5. P会收到所选文本的通知。
  6. - >我很乐意这么做......

3 个答案:

答案 0 :(得分:6)

如果不了解将要使用的每个控件/应用程序的具体知识,这是不可能的,因为他们可以以不同方式处理/处理它。

答案 1 :(得分:3)

我认为你不能注册任何类型的钩子。我认为你需要经常轮询“聚焦”或选定的窗口。

您可以使用Windows自动化API执行此操作,据我所知,这超过了旧的Accesibility API: http://msdn.microsoft.com/en-us/library/ms747327.aspx

我已使用此API自动执行GUI测试。我有点生疏,所以我不确定,但我有理由相信你可以用它来做你想做的事情。基本上,API允许您使用桌面上的根遍历自动化对象树。每个自动化元素往往是某种窗口控件,不同的控件实现不同的模式。您还可以获取鼠标光标下方的元素,并可能直接进入当前选中/聚焦的元素。

之后我注意到TextPattern类有一个GetSelection()方法,该方法记录为“检索与当前文本选择或选择相关联的不相交文本范围的集合”。我敢打赌,文本框的自动化对象实现了TextPattern。 http://msdn.microsoft.com/en-us/library/system.windows.automation.textpattern.aspx

答案 2 :(得分:3)

此代码可帮助您在焦点窗口中获取聚焦控制文本,我希望有所帮助:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TextFocusedns 
{
    public partial class TextFocusedFrm : Form
    {
        #region APIs

        [DllImport("user32.dll")]
        public static extern bool GetCursorPos(out Point pt);

        [DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern IntPtr WindowFromPoint(Point pt);

        [DllImport("user32.dll", EntryPoint = "SendMessageW")]
        public static extern int SendMessageW([InAttribute] System.IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
        public const int WM_GETTEXT = 13;

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        internal static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        internal static extern IntPtr GetFocus();

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern int GetWindowThreadProcessId(int handle, out int processId);

        [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        internal static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);
        [DllImport("kernel32.dll")]
        internal static extern int GetCurrentThreadId();

        [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);

        #endregion

        private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer() { Interval = 100, Enabled = true };

        public TextFocusedFrm()
        {
            InitializeComponent();
        }

        private void TextFocusedFrm_Load(object sender, EventArgs e)
        {
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            try
            {
                MultiLineTextBox.Text = GetTextFromFocusedControl();
            }
            catch (Exception exp)
            {
                MultiLineTextBox.Text += exp.Message;
            }
        }

        //Get the text of the focused control
        private string GetTextFromFocusedControl()
        {
            try
            {
                int activeWinPtr = GetForegroundWindow().ToInt32();
                int activeThreadId = 0, processId;
                activeThreadId = GetWindowThreadProcessId(activeWinPtr, out processId);
                int currentThreadId = GetCurrentThreadId();
                if (activeThreadId != currentThreadId)
                    AttachThreadInput(activeThreadId, currentThreadId, true);
                IntPtr activeCtrlId = GetFocus();

                return GetText(activeCtrlId);
            }
            catch (Exception exp)
            {
                return exp.Message;
            }
        }

        //Get the text of the control at the mouse position
        private string GetTextFromControlAtMousePosition()
        {
            try
            {
                Point p;
                if (GetCursorPos(out p))
                {
                    IntPtr ptr = WindowFromPoint(p);
                    if (ptr != IntPtr.Zero)
                    {
                        return GetText(ptr);
                    }
                }
                return "";
            }
            catch (Exception exp)
            {
                return exp.Message;
            }
        }

        //Get the text of a control with its handle
        private string GetText(IntPtr handle)
        {
            int maxLength = 512;
            IntPtr buffer = Marshal.AllocHGlobal((maxLength + 1) * 2);
            SendMessageW(handle, WM_GETTEXT, maxLength, buffer);
            string w = Marshal.PtrToStringUni(buffer);
            Marshal.FreeHGlobal(buffer);
            return w;
        }
    }
}