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

C# 是否可以编写一个windows应用程序,在另一个windows应用程序中选择文本时获取通知?,c#,c++,windows,winapi,C#,C++,Windows,Winapi,我很好奇是否可以编写一个程序来监控我的文本选择。一种可能的用途是编写编辑器/IDE不可知代码格式化程序: 应用程序/服务P被启动,并以某种方式连接到窗口,以便在任何窗口中选择文本时收到通知 启动了另一个应用程序A 用户选择A中的文本 P将收到所选文本的通知 -->我很高兴能走到这一步。如果不了解将要使用的每个控件/应用程序,这是不可能的,因为它们都可以以不同的方式处理/处理它。我认为您无法注册任何类型的钩子。我认为您需要不断地对“聚焦”或选定的窗口进行投票 您可能可以使用Windows Auto

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

  • 应用程序/服务P被启动,并以某种方式连接到窗口,以便在任何窗口中选择文本时收到通知
  • 启动了另一个应用程序A
  • 用户选择A中的文本
  • P将收到所选文本的通知

  • -->我很高兴能走到这一步。

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

    我认为您无法注册任何类型的钩子。我认为您需要不断地对“聚焦”或选定的窗口进行投票

    您可能可以使用Windows Automation API来实现这一点,据我所知,它取代了旧的Accessibility API:

    我使用这个API来自动化GUI测试。我对它有点生疏,所以我不确定,但我有理由相信你可以用它来做你想做的事情。基本上,API允许您使用桌面上的根遍历自动化对象树。每个自动化元素往往是某种windows控件,不同的控件实现不同的模式。您还可以在鼠标光标下找到元素,也可以直接找到当前选定/聚焦的元素

    在此之后,我注意到TextPattern类有一个GetSelection()方法,该方法被记录为“检索与当前文本选择相关联的不相交文本范围的集合”。我打赌TextBox的自动化对象实现了TextPattern。

    此代码帮助您在聚焦窗口中获取聚焦控件文本,我希望这有助于:

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

    您是否真的希望在选择时收到通知,或者是否知道什么时候某些内容被复制到剪贴板上就足够了?这不是完全相同的事情,但可能很接近。您可以监视数据何时进入剪贴板。这对用户来说是一个额外的步骤,但可能都是一样的。。。看这个:+1喜欢这个问题,但我认为如果应用程序已经启动,它应该更有可能。