如何将字符串发送到其他应用程序(包括 Microsoft Word)

发布于 2024-12-27 02:50:10 字数 898 浏览 2 评论 0原文

我试图实现这一点,但没有得到好的结果。我使用 GetForegroundWindow()、AttachThreadInput(uint,uint,bool) 和 GetFocus() 函数将字符串发送到另一个窗口。它适用于记事本、写字板和其他应用程序,但不适用于 Microsoft Word。

int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
bool b = AttachThreadInput(remoteThreadId, currentThreadId, true);
int focused = GetFocus();
int d = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
b = AttachThreadInput(remoteThreadId, currentThreadId, false);
SendMessage(focused , WM_GETTEXT, builder.Capacity, builder);
clip = builder.ToString();

//Text operations...

SendMessage(focused, WM_SETTEXT, 0, builder);

这是我的代码,但它不适用于Word。我知道Word使用自定义控件,但我认为应该有另一种方法来处理这个问题。

例如: Windows 语音识别将文本发送到每个具有焦点的应用程序,即使它是 Word。我不认为他们手动输入。

我想使用 SendInputs 函数,但我不知道如何实现。

I was trying to accomplish this but did not get good results. I used GetForegroundWindow(), AttachThreadInput(uint,uint,bool) and GetFocus() functions to send the strings to another window. It works with Notepad, Wordpad and other applications, but not with Microsoft Word.

int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
bool b = AttachThreadInput(remoteThreadId, currentThreadId, true);
int focused = GetFocus();
int d = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
b = AttachThreadInput(remoteThreadId, currentThreadId, false);
SendMessage(focused , WM_GETTEXT, builder.Capacity, builder);
clip = builder.ToString();

//Text operations...

SendMessage(focused, WM_SETTEXT, 0, builder);

That's the code I have, but it doesn't work with Word. I know that Word uses Custom Controls, but I think there should be another way to handle this.

For example:
Windows Speech Recognition sends text to every application which has focus even if it is Word. I don't think they made the inputs manually.

I thought to use the SendInputs function but I don't know how to make that.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温暖的光 2025-01-03 02:50:10

检查以下是否有效;您只需要调用SendString。这应该适用于任何可以接收其窗口当前处于活动状态的文本的应用程序。

除第一种方法外的所有代码均由 pinvoke.net 提供。

/// <summary>
/// Synthesizes keystrokes corresponding to the specified Unicode string,
/// sending them to the currently active window.
/// </summary>
/// <param name="s">The string to send.</param>
public static void SendString(string s)
{
    // Construct list of inputs in order to send them through a single SendInput call at the end.
    List<INPUT> inputs = new List<INPUT>();

    // Loop through each Unicode character in the string.
    foreach (char c in s)
    {
        // First send a key down, then a key up.
        foreach (bool keyUp in new bool[] { false, true })
        {
            // INPUT is a multi-purpose structure which can be used 
            // for synthesizing keystrokes, mouse motions, and button clicks.
            INPUT input = new INPUT
            {
                // Need a keyboard event.
                type = INPUT_KEYBOARD,
                u = new InputUnion
                {
                    // KEYBDINPUT will contain all the information for a single keyboard event
                    // (more precisely, for a single key-down or key-up).
                    ki = new KEYBDINPUT
                    {
                        // Virtual-key code must be 0 since we are sending Unicode characters.
                        wVk = 0,

                        // The Unicode character to be sent.
                        wScan = c,

                        // Indicate that we are sending a Unicode character.
                        // Also indicate key-up on the second iteration.
                        dwFlags = KEYEVENTF_UNICODE | (keyUp ? KEYEVENTF_KEYUP : 0),

                        dwExtraInfo = GetMessageExtraInfo(),
                    }
                }
            };

            // Add to the list (to be sent later).
            inputs.Add(input);
        }
    }

    // Send all inputs together using a Windows API call.
    SendInput((uint)inputs.Count, inputs.ToArray(), Marshal.SizeOf(typeof(INPUT)));
}

const int INPUT_MOUSE = 0;
const int INPUT_KEYBOARD = 1;
const int INPUT_HARDWARE = 2;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_UNICODE = 0x0004;
const uint KEYEVENTF_SCANCODE = 0x0008;
const uint XBUTTON1 = 0x0001;
const uint XBUTTON2 = 0x0002;
const uint MOUSEEVENTF_MOVE = 0x0001;
const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
const uint MOUSEEVENTF_LEFTUP = 0x0004;
const uint MOUSEEVENTF_RIGHTDOWN = 0x0008;
const uint MOUSEEVENTF_RIGHTUP = 0x0010;
const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020;
const uint MOUSEEVENTF_MIDDLEUP = 0x0040;
const uint MOUSEEVENTF_XDOWN = 0x0080;
const uint MOUSEEVENTF_XUP = 0x0100;
const uint MOUSEEVENTF_WHEEL = 0x0800;
const uint MOUSEEVENTF_VIRTUALDESK = 0x4000;
const uint MOUSEEVENTF_ABSOLUTE = 0x8000;

struct INPUT
{
    public int type;
    public InputUnion u;
}

[StructLayout(LayoutKind.Explicit)]
struct InputUnion
{
    [FieldOffset(0)]
    public MOUSEINPUT mi;
    [FieldOffset(0)]
    public KEYBDINPUT ki;
    [FieldOffset(0)]
    public HARDWAREINPUT hi;
}

[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
    public int dx;
    public int dy;
    public uint mouseData;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
    /*Virtual Key code.  Must be from 1-254.  If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0.*/
    public ushort wVk;
    /*A hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE, wScan specifies a Unicode character which is to be sent to the foreground application.*/
    public ushort wScan;
    /*Specifies various aspects of a keystroke.  See the KEYEVENTF_ constants for more information.*/
    public uint dwFlags;
    /*The time stamp for the event, in milliseconds. If this parameter is zero, the system will provide its own time stamp.*/
    public uint time;
    /*An additional value associated with the keystroke. Use the GetMessageExtraInfo function to obtain this information.*/
    public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
    public uint uMsg;
    public ushort wParamL;
    public ushort wParamH;
}

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

[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

Check whether the following works; you just need to call SendString. This should work for any application that can receive text whose window is currently active.

All code except the first method is courtesy of pinvoke.net.

/// <summary>
/// Synthesizes keystrokes corresponding to the specified Unicode string,
/// sending them to the currently active window.
/// </summary>
/// <param name="s">The string to send.</param>
public static void SendString(string s)
{
    // Construct list of inputs in order to send them through a single SendInput call at the end.
    List<INPUT> inputs = new List<INPUT>();

    // Loop through each Unicode character in the string.
    foreach (char c in s)
    {
        // First send a key down, then a key up.
        foreach (bool keyUp in new bool[] { false, true })
        {
            // INPUT is a multi-purpose structure which can be used 
            // for synthesizing keystrokes, mouse motions, and button clicks.
            INPUT input = new INPUT
            {
                // Need a keyboard event.
                type = INPUT_KEYBOARD,
                u = new InputUnion
                {
                    // KEYBDINPUT will contain all the information for a single keyboard event
                    // (more precisely, for a single key-down or key-up).
                    ki = new KEYBDINPUT
                    {
                        // Virtual-key code must be 0 since we are sending Unicode characters.
                        wVk = 0,

                        // The Unicode character to be sent.
                        wScan = c,

                        // Indicate that we are sending a Unicode character.
                        // Also indicate key-up on the second iteration.
                        dwFlags = KEYEVENTF_UNICODE | (keyUp ? KEYEVENTF_KEYUP : 0),

                        dwExtraInfo = GetMessageExtraInfo(),
                    }
                }
            };

            // Add to the list (to be sent later).
            inputs.Add(input);
        }
    }

    // Send all inputs together using a Windows API call.
    SendInput((uint)inputs.Count, inputs.ToArray(), Marshal.SizeOf(typeof(INPUT)));
}

const int INPUT_MOUSE = 0;
const int INPUT_KEYBOARD = 1;
const int INPUT_HARDWARE = 2;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_UNICODE = 0x0004;
const uint KEYEVENTF_SCANCODE = 0x0008;
const uint XBUTTON1 = 0x0001;
const uint XBUTTON2 = 0x0002;
const uint MOUSEEVENTF_MOVE = 0x0001;
const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
const uint MOUSEEVENTF_LEFTUP = 0x0004;
const uint MOUSEEVENTF_RIGHTDOWN = 0x0008;
const uint MOUSEEVENTF_RIGHTUP = 0x0010;
const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020;
const uint MOUSEEVENTF_MIDDLEUP = 0x0040;
const uint MOUSEEVENTF_XDOWN = 0x0080;
const uint MOUSEEVENTF_XUP = 0x0100;
const uint MOUSEEVENTF_WHEEL = 0x0800;
const uint MOUSEEVENTF_VIRTUALDESK = 0x4000;
const uint MOUSEEVENTF_ABSOLUTE = 0x8000;

struct INPUT
{
    public int type;
    public InputUnion u;
}

[StructLayout(LayoutKind.Explicit)]
struct InputUnion
{
    [FieldOffset(0)]
    public MOUSEINPUT mi;
    [FieldOffset(0)]
    public KEYBDINPUT ki;
    [FieldOffset(0)]
    public HARDWAREINPUT hi;
}

[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
    public int dx;
    public int dy;
    public uint mouseData;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
    /*Virtual Key code.  Must be from 1-254.  If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0.*/
    public ushort wVk;
    /*A hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE, wScan specifies a Unicode character which is to be sent to the foreground application.*/
    public ushort wScan;
    /*Specifies various aspects of a keystroke.  See the KEYEVENTF_ constants for more information.*/
    public uint dwFlags;
    /*The time stamp for the event, in milliseconds. If this parameter is zero, the system will provide its own time stamp.*/
    public uint time;
    /*An additional value associated with the keystroke. Use the GetMessageExtraInfo function to obtain this information.*/
    public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
    public uint uMsg;
    public ushort wParamL;
    public ushort wParamH;
}

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

[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
慢慢从新开始 2025-01-03 02:50:10

Word 不使用响应 WM_TEXT 的标准编辑控件。要将文本插入 Word,您可以使用 SendInput 伪造输入,或 COM 自动化,或 UI 自动化

最后一个选项,UI 自动化,将是我的选择,也是 MS 现在希望您这样做的方式。

Word doesn't use a standard edit control that responds to WM_TEXT. To poke text into Word you could use SendInput to fake input, or COM automation, or UI Automation.

The last of these options, UI Automation, would be my choice and is the way MS intend you to do this nowadays.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文