从WPF DataGrid复制粘贴数据时,OpenClipboard失败

Ars*_*ray 68 c# wpf clipboard datagrid copy-paste

我有一个使用datagrid的WPF应用程序.该应用程序运行正常,直到我安装Visual Studio 2012和Blend + SketchFlow预览.现在,当我尝试使用Ctrl+ C(在任何应用程序中)将数据从网格复制到剪贴板时,我得到以下异常:

System.Runtime.InteropServices.COMException (0x800401D0): OpenClipboard Failed (Exception from HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN))
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode, IntPtr errorInfo)
   at System.Windows.Clipboard.Flush()
   at System.Windows.Clipboard.CriticalSetDataObject(Object data, Boolean copy)
   at System.Windows.Controls.DataGrid.OnExecutedCopy(ExecutedRoutedEventArgs args)
   at System.Windows.Controls.DataGrid.OnExecutedCopy(Object target, ExecutedRoutedEventArgs args)
   at System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.Input.CommandManager.ExecuteCommandBinding(Object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding)
   at System.Windows.Input.CommandManager.FindCommandBinding(CommandBindingCollection commandBindings, Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
   at System.Windows.Input.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
   at System.Windows.Input.CommandManager.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.UIElement.OnExecutedThunk(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object target)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.RoutedCommand.ExecuteImpl(Object parameter, IInputElement target, Boolean userInitiated)
   at System.Windows.Input.RoutedCommand.ExecuteCore(Object parameter, IInputElement target, Boolean userInitiated)
   at System.Windows.Input.CommandManager.TranslateInput(IInputElement targetElement, InputEventArgs inputEventArgs)
   at System.Windows.UIElement.OnKeyDownThunk(Object sender, KeyEventArgs e)
   at System.Windows.Input.KeyEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndKeyboardInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawKeyboardActions actions, Int32 scanCode, Boolean isExtendedKey, Boolean isSystemKey, Int32 virtualKey)
   at System.Windows.Interop.HwndKeyboardInputProvider.ProcessKeyAction(MSG& msg, Boolean& handled)
   at System.Windows.Interop.HwndSource.CriticalTranslateAccelerator(MSG& msg, ModifierKeys modifiers)
   at System.Windows.Interop.HwndSource.OnPreprocessMessage(Object param)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
   at System.Windows.Interop.HwndSource.OnPreprocessMessageThunk(MSG& msg, Boolean& handled)
   at System.Windows.Interop.HwndSource.WeakEventPreprocessMessage.OnPreprocessMessage(MSG& msg, Boolean& handled)
   at System.Windows.Interop.ComponentDispatcherThread.RaiseThreadMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.Run()
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()
Run Code Online (Sandbox Code Playgroud)

这真的很烦人.

我在这里以及网络上的各个位置都看到过这个问题的一些参考,没有真正的解决方案.

我可以验证在Visual Studio中引发此异常时剪贴板是否已锁定,因为我无法复制粘贴消息(必须将其写入文件).此外,在复制过程开始之前未锁定剪贴板.

如何解决这个问题呢?

kus*_*lip 87

我们使用的是.NET 4.0.我们遇到了同样的问题,但是在注销系统之后,代码一段时间以来工作正常.

最后我们找到了替代方案.

如果要将字符串复制到剪贴板,

string data = "Copy This"
Run Code Online (Sandbox Code Playgroud)

直到现在我使用以下方法

Clipboard.SetText(data);
Run Code Online (Sandbox Code Playgroud)

它一次又一次地失败了.然后我查看了可用于在剪贴板类的剪贴板中设置文本的其他方法,并尝试了以下方法:

Clipboard.SetDataObject(data);
Run Code Online (Sandbox Code Playgroud)

它工作:).我再也没遇到过这个问题.

  • 很好.我使用的是.NET 4.5,问题仍然存在.似乎如果我在ListView中重新选择一个项目,那么确实会发生此错误,但我不知道为什么. (4认同)
  • 我使用WPF和.NET 4.5(而不是4.5.1),这个问题解决了!:-) (2认同)
  • SetDataObject 在这里效果很好。SetText 抛出异常,但另一个没有。谢谢! (2认同)

Ale*_*ese 72

这是WPF剪贴板处理程序中的一个错误.您需要在Application.DispatcherUnhandledException事件中处理未处理的异常.

将此属性添加到ApplicationApp.xaml中的元素

DispatcherUnhandledException="Application_DispatcherUnhandledException"
Run Code Online (Sandbox Code Playgroud)

将此代码添加到App.xaml.cs文件中

void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    var comException = e.Exception as System.Runtime.InteropServices.COMException;

    if (comException != null && comException.ErrorCode == -2147221040)
         e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)

  • @kushdilip是的,当您控制设置剪贴板数据的方法时,该解决方案很好,但当方法不在_your_代码中时,它没有帮助.例如WPF控件和第三方控件.如果您没有在某个地方的代码中实现错误修复,那么在.NET 4.0上它仍然会受到它的影响. (6认同)
  • SetText在4.5中没有修复,但使用SetDataObject似乎可以修复它 - 但是:我的程序将文件夹路径复制到剪贴板.它工作正常,但如果我在VS调试器中运行应用程序并转向.NET异常捕捉奇怪的事情发生.如果我粘贴到,例如,记事本它工作正常,但如果我粘贴到Windows资源管理器的位置框我的应用程序抛出COM异常"无效的FORMATETC结构(从HRESULT异常:0x80040064(DV_E_FORMATETC))".这只有在异常捕获时进行调试时才会发生,因此异常必须在某处捕获并处理,但它仍然很奇怪. (6认同)
  • Microsoft已在.NET 4.5中修复此问题,现在代码与Windows窗体程序集中的代码类似.剪贴板例程具有重试计数和延迟时间,而不是仅在无法访问剪贴板时失败. (5认同)
  • 我正在使用.NET 4.0并面临同样的问题.我不想'触摸App.xaml文件.这个问题有没有其他解决方案? (2认同)
  • 你为什么不想触摸app.xaml文件?您可以从其他地方订阅`Application.DispatcherUnhandledException`事件,但是您应该在应用程序加载时在App类中执行此操作.更多信息[这里](http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx) (2认同)
  • 即使在 .net 4.7.1 中,甚至使用“SetDataObject”,我也可以通过快速重复单击“复制”按钮来随意触发此异常。我将在我的所有 WPF 应用程序中包含此处理程序作为后备(不过,我不喜欢幻数,因此我还将包含 `const int CLIPBRD_E_CANT_OPEN = unchecked((int) 0x800401D0)`)。 (2认同)

小智 6

我也在应用程序中遇到问题,我将信息复制到剪贴板中,因为用户仔细阅读ListBox.复制的信息与所选项目相关,并允许他们将其(所述信息)粘贴到其他应用程序中以方便使用.偶尔我会在某些用户的系统上获得CLIPBRD_E_CANT_OPEN,但在其他用户的系统上则不会.

虽然我仍然无法修复争用,但我能够创建一些代码来查找导致争用的应用程序.我想至少分享这段代码,希望能帮到别人.我将添加我创建的using语句,属性和方法来查找罪魁祸首的Process对象.从Process项中,您可以获取进程的名称,PID,主窗口标题(如果有),以及其他可能有用的数据.这是我添加的代码行,没有调用它的代码.(注意:在代码片段下面,我还有一个要分享的内容):

using System.Diagnostics;               // For Process class
using System.Runtime.InteropServices;   // For DllImport's
Run Code Online (Sandbox Code Playgroud)

...

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetOpenClipboardWindow();

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
Run Code Online (Sandbox Code Playgroud)

...

    ///-----------------------------------------------------------------------------
    /// <summary>
    /// Gets the Process that's holding the clipboard
    /// </summary>
    /// <returns>A Process object holding the clipboard, or null</returns>
    ///-----------------------------------------------------------------------------
    public Process ProcessHoldingClipboard()
    {
        Process theProc = null;

        IntPtr hwnd = GetOpenClipboardWindow();

        if (hwnd != IntPtr.Zero)
        {
            uint processId;
            uint threadId = GetWindowThreadProcessId(hwnd, out processId);

            Process[] procs = Process.GetProcesses();
            foreach (Process proc in procs)
            {
                IntPtr handle = proc.MainWindowHandle;

                if (handle == hwnd)
                {
                    theProc = proc;
                }
                else if (processId == proc.Id)
                {
                    theProc = proc;
                }
            }
        }

        return theProc;
    }
Run Code Online (Sandbox Code Playgroud)

其他注意: 我改变了另一件事,简化了我的代码,从使用System.Windows.Clipboard转换为System.Windows.Forms.Clipboard(参见System.Windows.Forms.Clipboard类),因为后者有一个4-参数SetDataObject()方法,包括重试计数和重试延迟(以毫秒为单位).这至少从我的代码中删除了一些重试噪声.

你的里程可能会有所不同......加上可能会有副作用,我还没有偶然发现,所以如果有人知道它们,请评论.无论如何,我希望这证明对某人有用.

  • 使用System.Windows.Forms.Clipboard而不是System.Windows.Clipboard的+1.谢谢 (2认同)

pr0*_*g3r 6

我在WPF 4.0和4.5中也遇到过这个问题,因为我安装了TeraCopy(Windows 7,64位).每个Clipboard.SetText()都失败了System.Runtime.InteropServices.COMException.

我的第一个解决方案是卸载TeraCopy - 它有效,但我喜欢这个应用程序,所以我不得不寻找另一个解决方案来解决这个问题.解决方案是更换

Clipboard.SetText("my string");
Run Code Online (Sandbox Code Playgroud)

Clipboard.SetDataObject("my string");
Run Code Online (Sandbox Code Playgroud)

  • 如果将第二个参数设置为 true 以在应用程序退出后保留数据,则不会。看看这个:https://learn.microsoft.com/de-de/dotnet/api/system.windows.forms.clipboard.setdataobject?view=netframework-4.8#System_Windows_Forms_Clipboard_SetDataObject_System_Object_System_Boolean_ (2认同)