首页 > 解决方案 > 如果我多次复制,WM_DRAWCLIPBOARD 和 WM_CHANGECBCHAIN 会占用大量内存。在我的程序 C#

问题描述

我使用剪贴板监视器。正因为如此,我注意到 wndproc 是内存泄漏,而没有放下垃圾收集。但是提到如果我复制某些内容,我需要更多的 CPU 来替代此代码以减少内存使用量?

我希望复制内存使用量不要太多,除了使用垃圾收集还有另一种选择吗?

这是我的代码。

[DefaultEvent(nameof(ClipboardChanged))]
public sealed class ClipboardMonitor : Control, IEquatable<ClipboardMonitor>
{
    private IntPtr nextClipboardViewer;

    public ClipboardMonitor()
    {
        BackColor = Color.Red;
        Visible = false;

        nextClipboardViewer = (IntPtr)SetClipboardViewer((int)Handle);
    }

    /// <summary>
    ///     Clipboard contents changed.
    /// </summary>
    public event EventHandler<ClipboardChangedEventArgs> ClipboardChanged;

    protected override void Dispose(bool disposing)
    {
        try
        {
            _ = ChangeClipboardChain(Handle, nextClipboardViewer);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

        base.Dispose(disposing);
    }

    protected override void WndProc(ref Message m)
    {
        // defined in winuser.h
        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;

        switch (m.Msg)
        {
            case WM_DRAWCLIPBOARD:
                {
                    OnClipboardChanged();
                    _ = SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    break;
                }
            case WM_CHANGECBCHAIN:
                {
                    if (m.WParam == nextClipboardViewer)
                    {
                        nextClipboardViewer = m.LParam;
                    }
                    else
                    {
                        _ = SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                        GC.Collect();
                        GC.WaitForPendingFinalizers();
                        GC.Collect();
                    }

                    break;
                }
            default:
                {
                    base.WndProc(ref m);
                    break;
                }
        }
    }

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

    [DllImport("User32.dll")]
    private static extern int SetClipboardViewer(int hWndNewViewer);

    private void OnClipboardChanged()
    {
        try
        {
            IDataObject iData = Clipboard.GetDataObject();
            ClipboardChanged?.Invoke(this, new ClipboardChangedEventArgs(iData));
        }
        catch (Exception e)
        {
            _ = MessageBox.Show(e.ToString());
        }
    }

    public bool Equals(ClipboardMonitor other)
    {
        throw new NotImplementedException();
    }
}

public sealed class ClipboardChangedEventArgs : EventArgs
{
    internal readonly IDataObject DataObject;

    internal ClipboardChangedEventArgs(IDataObject dataObject = null)
    {
        if (dataObject is null)
        {
            throw new ArgumentNullException(nameof(dataObject));
        }

        DataObject = dataObject;
    }
}

这是我现在的 wndproc 代码

    protected override void WndProc(ref Message m)
    {
        // defined in winuser.h
        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;

        switch (m.Msg)
        {
            case WM_DRAWCLIPBOARD:
                {
                    OnClipboardChanged();
                    _ = SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    break;
                }
            case WM_CHANGECBCHAIN:
                {
                    if (m.WParam == nextClipboardViewer)
                    {
                        nextClipboardViewer = m.LParam;
                    }
                    else
                    {
                        _ = SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                        GC.Collect();
                        GC.WaitForPendingFinalizers();
                        GC.Collect();
                    }

                    break;
                }
            default:
                {
                    base.WndProc(ref m);
                    break;
                }
        }
    }

让我知道我可以对这段代码进行哪些改进。

标签: c#memory-leaksgarbage-collectionclipboardwndproc

解决方案


推荐阅读