剪贴板的内容仅在我使用MessageBox.Show(“...”)后才可用

时间:2013-11-07 16:01:05

标签: c# .net winforms user32

我有一个应用程序,在热键组合后它实际上“发送”一个Ctrl + C到前台窗口,将所选文本发送到剪贴板。然后我需要从剪贴板中获取文本。这样做的代码如下:

[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

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

[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);

private void CopyHighlighted()
{
    uint KEYEVENTF_KEYUP = 2;
    byte VK_CONTROL = 0x11;
    SetForegroundWindow(GetForegroundWindow());
    keybd_event(VK_CONTROL, 0, 0, 0);
    keybd_event(0x43, 0, 0, 0); 
    keybd_event(0x43, 0, KEYEVENTF_KEYUP, 0);
    keybd_event(VK_CONTROL, 0x9d, KEYEVENTF_KEYUP, 0);

    bool containsStuff = (Clipboard.ContainsAudio() || Clipboard.ContainsFileDropList() || Clipboard.ContainsImage() || Clipboard.ContainsText());

    //The behavior changing MessageBox:
    //MessageBox.Show("the clipboard contains some data: " + containsStuff.ToString());

    string rawNumber = Clipboard.GetText();
    MessageBox.Show("raw contents of clipboard " + Environment.NewLine + rawNumber);
}

如果注释了MessageBox,我会得到一个弹出窗口,上面写着“剪贴板包含一些数据:False”。这是非常奇怪的,因为下一个弹出窗口说“剪贴板的原始内容Clipboard.ContainsText()返回false ...但确定rawNumber确实包含预期的文本。

但是当我评论第一个MessageBox时,我只获得了1个弹出窗口(正如预期的那样),但它只说“剪贴板的原始内容”而rawNumber是一个空字符串。

为什么包含此中间MessageBox会导致我能够获取剪贴板文本?为什么在此之前Clipboard.ContainsText()返回false? <_ 1}}可以帮助您理解这一点,以及让它与NO MessageBox配合使用会很棒。

3 个答案:

答案 0 :(得分:0)

尝试检查Clipboard Sequence Number更改:

定义导入:

[DllImport("user32.dll")]
static extern uint GetClipboardSequenceNumber();

使用它:

System.Threading.Thread.Sleep(5000);   // Give me time to switch windows
uint KEYEVENTF_KEYUP = 2;
byte VK_CONTROL = 0x11;
SetForegroundWindow(GetForegroundWindow());
keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event(0x43, 0, 0, 0);
keybd_event(0x43, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0x9d, KEYEVENTF_KEYUP, 0);

uint startClip = GetClipboardSequenceNumber();
uint nextClip = startClip;

while (nextClip == startClip)
{
    nextClip = GetClipboardSequenceNumber();
}

string rawNumber = Clipboard.GetText();
MessageBox.Show("raw contents of clipboard " + Environment.NewLine + rawNumber);

您应该在非ui线程中执行此操作,然后将其作为事件。您可能还想限制此代码,以便不会经常调用API。

答案 1 :(得分:0)

当我用这个简单的代码将鼠标移动到我的PictureBox时,我正在用记事本(以及其他各种应用程序)复制一些东西:

    private void pictureBox1_MouseEnter(object sender, EventArgs e)
    {
        SendKeys.SendWait("^c");
        if (Clipboard.ContainsText())
        {
            label1.Text = Clipboard.GetText();
        }
    }

使用管理员帐户运行Windows 8.1 x64。

答案 2 :(得分:0)

keybd_event将事件放入队列中,但在代码完成之前不会处理它们。如果你把

Application.DoEvents();

在keydb_event调用之后,应该处理键盘事件。我怀疑Thread.Sleep()不起作用,因为它只是睡觉,但不处理等待事件。

第一次调用MessageBox确实允许事件运行,因此在MessageBox之后,剪贴板中有东西。使用SendKeys.SendWait()将起作用,但SendKeys.Send不会,因为SendWait等待处理键盘事件,而SendKeys.Send不会。