Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#复制粘贴多次不起作用_C# - Fatal编程技术网

C#复制粘贴多次不起作用

C#复制粘贴多次不起作用,c#,C#,在Visual C#中,我尝试从多个文本框(一次一个)中提取文本并将其粘贴到记事本中。我通过复制到剪贴板、alt制表符,然后粘贴到记事本中,然后再粘贴到其他文本框中来实现这一点。该代码代表了这一理念: subBox1.SelectAll(); subBox1.Copy(); SendKeys.Send("%{TAB}"); // alt+tab SendKeys.Send("^v"); // paste SendKeys.Send("{TAB}"); // tab

在Visual C#中,我尝试从多个文本框(一次一个)中提取文本并将其粘贴到记事本中。我通过复制到剪贴板、alt制表符,然后粘贴到记事本中,然后再粘贴到其他文本框中来实现这一点。该代码代表了这一理念:

subBox1.SelectAll();
subBox1.Copy();
SendKeys.Send("%{TAB}");    // alt+tab
SendKeys.Send("^v");        // paste
SendKeys.Send("{TAB}");     // tab

subBox2.SelectAll();
subBox2.Copy();
SendKeys.Send("^v");
SendKeys.Send("{TAB}");

subBox3.SelectAll();
subBox3.Copy();
SendKeys.Send("^v");
SendKeys.Send("{TAB}");
如您所见,这将从三个文本框(名为subBox1、2和3)复制和粘贴。但是,由于某些原因,只有最后一个文本框的内容被复制过来。如果我注释掉第三个文本框,也会发生这种情况……在这种情况下,只有第二个文本框的内容被复制。我尝试过使用SelectAll()和Copy(),正如您在这里看到的,以及Clipboard类。两者都有相同的问题

例如,如果文本框的内容分别是“asdf”、“qwer”和“zxcv”,那么我看到的所有内容都是“zxcv”三次

知道为什么会这样吗?我已经被困在这个问题上一个小时了,不知道发生了什么


非常感谢

SendKeys不会等待其他应用程序处理您发送的按键,因此当记事本开始处理您的按键时,您的程序已经将子框3的文本复制到其他文本的顶部

你需要改用

同样,您也可以使用如下方式代替发送Alt+Tab:

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

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);

// ... 

SetForegroundWindow(FindWindow(null, "Untitled - Notepad"));

我会使用SendMessage获得更准确的结果。要使用SendMessage,首先需要记事本文本区域的有效窗口句柄。这可以通过多种方式完成,但我更喜欢使用简单的子查找函数

您将需要以下命名空间导入和PInvoke声明:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;

//pinvoke
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

[DllImport("user32.dll")]
private static extern int GetWindowTextLength(IntPtr hWnd);

[DllImport("user32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hParent, delChildWndProc callback, IntPtr lpParam);
//delegate callback for EnumChildWindows:
[return:MarshalAs(UnmanagedType.Bool)]
private delegate bool delChildWndProc(IntPtr hWnd, IntPtr lParam);
现在,转到子窗口查找。基本上与FindWindowEx类似,但我想写我自己的,它可以检索多个窗口,这很好。它使用以下包装类来描述调用之间的信息:

private class WindowLookup
{
    public string LookupName { get; private set; }
    public List<IntPtr> MatchedChildren { get; private set; }
    public int Depth { get; set; }
    public int MaxDepth { get; set; }

    public WindowLookup(string lookup, int maxdepth)
    {
        this.MatchedChildren = new List<IntPtr>();
        this.LookupName = lookup;
        this.MaxDepth = maxdepth;
        if (this.MaxDepth > 0)
            this.MaxDepth++; //account for the depth past the parent control.
        this.Depth = 0;
    }
}

现在,我把代码放在一个循环的中间,通过当时运行的每个记事本进程的“编辑”窗口。现在我们有了一个有效的窗口句柄,我们可以使用SendMessage向它发送内容。特别是追加文本。我编写了以下函数来处理向遥控器追加文本:

private static void AppendWindowText(IntPtr hWnd, string text)
{
    if (hWnd != IntPtr.Zero)
    {
        //for your reference, 0x0E (WM_GETTEXTLENGTH), 0xB1 (EM_SETSEL), 0xC2 (EM_REPLACESEL)
        int len = SendMessage(hWnd, 0x000E, IntPtr.Zero, IntPtr.Zero).ToInt32();
        var unmanaged = Marshal.StringToHGlobalAuto(text);
        SendMessage(hWnd, 0x00B1, new IntPtr(len), new IntPtr(len));
        SendMessage(hWnd, 0x00C2, IntPtr.Zero, unmanaged);
        Marshal.FreeHGlobal(unmanaged);
    }
}
现在我们有了AppendWindowText函数,您可以在上面的嵌套循环(我将注释放在这里)中添加函数调用:

就在这里。这是一个有点冗长的回答,但最终这种方法比使用SendKeys和聚焦窗口等方法可靠得多。您永远不需要失去自己应用程序的焦点

如果您有任何问题,请随时发表评论,我会尽我所能回答

干杯,
J

编辑:一些参考资料:




嗯,现在alt选项卡不起作用了。我试着把alt标签也保持为“Send”。知道为什么它不能正常工作吗?不确定是否要在alt tab中使用SendKeys。显然,没有内置的方法切换到另一个应用程序。我会使用FindWindow+setforegroundindow native calls.Edited。Alt tab是非常不可靠的-你假设记事本是列表中的下一个应用程序。SetForeGroundindow稍微好一点。非常感谢您的时间。不幸的是,这有点难以承受。这是我第一天使用Visual C以及任何Windows API类型的东西。我刚开始一个我认为很简单的项目,让我的脚湿了。但是,在设置窗口焦点的所有问题上,我认为我现在有点头晕。这是公平的,如果你从未处理过C++中的Win32表单编程,SDEN消息可能相当少。您可以选择使用
AppActivate
设置焦点窗口,然后进行粘贴。如果你愿意,我可以用上面的代码编写一个单次使用的函数,你可以简单地调用
AppendTextToNotepad(text)
,这样你就可以在空闲时学习其他代码,但仍然有一个工作可靠的应用程序。如果很容易实现,那就太好了!我想在这一点上,我也不确定在哪里粘贴代码,我还没有完全理解,哈哈。请告诉我它去哪里了。再次感谢!要是有一个私人信息系统就好了。完成工作后,我将在注释中链接一个粘贴链接。@PlanetLotus这是我编写的一个包装类:现在,在Visual Studio中,go
Project>>添加类
使用
MessageWrapper
作为类名。VS生成文档后,删除
名称空间XXXXXX{
和最后一个右大括号之间的所有内容。然后粘贴到我链接的代码中。您应该得到如下结果:。
var notepads = Process.GetProcessesByName("notepad");
if (notepads.Length > 0)
{
    foreach(var notepad in notepads) //iterate through all the running notepad processes. Of course, you can filter this by processId or whatever.
    {
        foreach(var edit in FindAllWindows(notepad.MainWindowHandle, "Edit"))
        {
            //next part of the code will go here, read on.
        }

    }
}
private static void AppendWindowText(IntPtr hWnd, string text)
{
    if (hWnd != IntPtr.Zero)
    {
        //for your reference, 0x0E (WM_GETTEXTLENGTH), 0xB1 (EM_SETSEL), 0xC2 (EM_REPLACESEL)
        int len = SendMessage(hWnd, 0x000E, IntPtr.Zero, IntPtr.Zero).ToInt32();
        var unmanaged = Marshal.StringToHGlobalAuto(text);
        SendMessage(hWnd, 0x00B1, new IntPtr(len), new IntPtr(len));
        SendMessage(hWnd, 0x00C2, IntPtr.Zero, unmanaged);
        Marshal.FreeHGlobal(unmanaged);
    }
}
AppendWindowText(edit, "Some text here");