0

我有一个应用程序捕获发送到窗体的 Windows 消息,并在对系统剪贴板进行更新时运行一个方法:

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_CLIPBOARDUPDATE:

            if (IsClipboardListenerOn)
                OnClipboardChanged();

            break;
    }

    base.WndProc(ref m);
}

在某些情况下,我不希望我的方法 ,OnClipboardChanged()运行。我的解决方案是设置一个静态全局变量IsClipboardListenerOn并根据需要切换它。这并没有完成工作,因为直到我的函数返回后才处理 Windows 消息,所以它总是正确的

private void some_event(object sender, EventArgs e)
{
    MainForm.IsClipboardListenerOn = false;

    // some code that makes the clipboard changed message fire

    MainForm.IsClipboardListenerOn = true;

   // when this returns the WM_CLIPBOARDUPDATE message gets caught
}

下一个想法是运行在线程上触发消息事件的代码,并等待线程返回以确保它在全局标志关闭时执行:

    Thread thread1 = new Thread(() => clipboard_stuff());
    thread1.SetApartmentState(ApartmentState.STA);

    MainForm.IsClipboardListenerOn = false;

    thread1.Start();        

    thread1.Join();
    MainForm.IsClipboardListenerOn = true;

但这也不起作用。事实上,有时它会执行我的 OnClipboardChanged() 方法两次。我知道系统剪贴板需要单线程单元;这是我的问题的一部分吗?我要解决这个问题了吗?还有其他一些我可以利用的技术吗?

4

2 回答 2

2

对,那是行不通的。Windows 正在等待您再次开始发送消息。一种解决方法是延迟将标志设置回 true,直到所有待处理的消息都发送完毕。这可以通过使用 Control.BeginInvoke() 方法优雅地完成。像这样:

private void some_event(object sender, EventArgs e)
{
    MainForm.IsClipboardListenerOn = false;
    // some code that makes the clipboard changed message fire
    //...
    this.BeginInvoke(new Action(() => MainForm.IsClipboardListenerOn = true));
}

假设 some_event() 是表单的成员。我猜 MainForm.BeginInvoke() 也会起作用。

于 2013-08-30T17:04:36.327 回答
0

听起来应该有一个比我要建议的更清洁的解决方案,但你知道他们说什么......如果它很愚蠢并且有效,那么它并不愚蠢。

如果您确定要触发您想忽略的剪贴板消息,请设置一个标志并将WndProc其关闭:

private void some_event(object sender, EventArgs e)
{
    MainForm.SkipNextClipboardMessage = true;
    // some code that makes the clipboard changed message fire
}

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_CLIPBOARDUPDATE: 
            if (SkipNextClipboardMessage)
                SkipNextClipboardMessage = false;
            else                    
                OnClipboardChanged();
            break;
    }
    base.WndProc(ref m);
}

另一个肯定会引起读者反感的可怕想法是像您在代码的第一个版本中所做的那样,并Application.DoEvents()在诱导您的剪贴板更改方法后添加一个调用以强制处理消息。

是的,是的,这是邪恶的,我会下地狱的,我知道。

于 2013-08-30T16:56:29.867 回答