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() メソッドを 2 回実行することもありました。システム クリップボードにはシングル スレッド アパートメントが必要であることはわかっています。これは私の問題の一部ですか?私はこれについて間違っていますか?他に利用できるテクニックはありますか?

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 に答える