C# WPF 访问剪切板报错

如果剪贴板操作失败(例如 HRESULT 0x800401D0 (CLIPBRD_E_CANT_OPEN) 错误),则会引发相应的 ExternalException (,这是一种 ExternalException) 。

由于 Win32 OpenClipboard API 全局运行,因此编写良好的应用程序应在完成剪贴板操作后立即调用相应的 CloseClipboard API。 否则,在同一会话中运行的其他应用程序将无法访问剪贴板函数。

在 WPF 中,通常以无提示方式忽略对剪贴板的访问。 However, applications can opt to receive an ExternalException upon failure by setting the ShouldThrowOnCopyOrCutFailure flag to true. 但是,选择接收异常还要求应用程序通过 a CommandBinding处理Cut和 Copy RoutedUICommands,然后将该绑定应用到应用程序中的所有 TextBoxBase 控件 (TextBoxRichTextBox) 。 应用程序应确保处理 CommandBinding 执行处理程序中复制和剪切操作产生的 ExternalException。

以上来自微软官方解释

代码:

[DllImport("user32.dll")]
private static extern IntPtr CloseClipboard();

注:调用此方法时,最好做个1秒的等待,因为调用之后真正的释放是有时间的,或者做一个Retry

 

    /// <summary>
    /// 
    /// </summary>
    public static class ClipboardHelper
    {
        [DllImport("user32.dll")]
        private static extern IntPtr CloseClipboard();

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr GetOpenClipboardWindow();

        [DllImport("user32.dll", SetLastError = true)]
        static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        /// <summary>
        /// 获取进程信息
        /// </summary>
        /// <returns></returns>
        public static Process GetProcessLockingClipboard()
        {
            int processId;
            GetWindowThreadProcessId(GetOpenClipboardWindow(), out processId);
            return Process.GetProcessById(processId);
        }

        /// <summary>
        /// 清理剪切板,避免异常
        /// </summary>
        public static void ClearClipboard()
        {
            try
            {
                CloseClipboardMethod();
            }
            catch (Exception ex)
            {
                //记录日志

                try
                {
                    CloseClipboardMethod();
                }
                catch (Exception ex2)
                {
                    //忽略
                }
            }
        }

        public static void CloseClipboardMethod()
        {
            CloseClipboard();
            System.Windows.Clipboard.Clear();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public static void SetImage(BitmapSource image)
        {
            try
            {
                SetImageMethod(image);
            }
            catch (Exception ex)
            {
                //记录日志
                try
                {
                    var process = GetProcessLockingClipboard();
                    if (process != null)
                    {
                       var msg =$"占用剪切板的进程:{process.Id}、{process.ProcessName}";
                       //记录占用剪切板的进程信息
                    }
                    SetImageMethod(image);
                }
                catch (Exception ex1)
                {
                    //忽略
                }
            }
        }

        /// <summary>
        /// 复制逻辑
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        private static void SetImageMethod(BitmapSource image)
        {
               ClearClipboard();
            //结束之后等待一下,等进程真正的结束再继续下一步
            Thread.Sleep(1000);
            //将图片放入到剪切板
            System.Windows.Clipboard.SetImage(image);
        }
    }                                  

 


 

posted @ 2022-08-16 14:51  苏秦与真相  阅读(796)  评论(0编辑  收藏  举报