Idle.exe 已在使用剪贴板

Clipboard already in use by Idle.exe

我一直在开发一个使用鼠标和键盘模拟的程序,并且经常需要 grab/set 剪贴板数据。

我已经 运行 解决了这个问题,显然很多人都遇到过,剪贴板正在被另一个进程使用,所以 "Clipboard.SetDataObject" 抛出异常 "Requested Clipboard operation did not succeed."

       private void CheckSetClipboard(string s)
    {
        IntPtr ClipWindow = GetOpenClipboardWindow();
        if (ClipWindow != null && ClipWindow != (IntPtr)0)
        {
            uint wid;
            GetWindowThreadProcessId(ClipWindow, out wid);
            Process p = Process.GetProcessById((int)wid);
            Console.WriteLine("Process using Clipboard: " + p.ProcessName);
        } else {
            Console.WriteLine("ClipWindow:" + ClipWindow.ToString());
        }
            OpenClipboard(IntPtr.Zero);
            EmptyClipboard();
            CloseClipboard();
        try { Clipboard.SetDataObject(s, true, 10, 50); }
        catch{// Clipboard.SetDataObject(s, true, 10, 50);
        }
    }

我尝试了一些如上面代码所示的解决方案,但最终错误再次弹出。这次我决定全力以赴,并使用剪贴板获取进程的进程名称。
这是控制台显示的内容:

Process using Clipboard: Idle

Idle.exe 如何使用剪贴板?
我什至可以终止该进程以释放剪贴板吗?
我做错了什么吗?

归根结底,我只想能够无故障地进行剪贴板操作。 Ctrl+c 和 Ctrl+v 永远不会失败,为什么我的 C# 代码会失败?

更多信息:
我传递到剪贴板的数据是“-0.09261441”或类似的数字。
错误总是发生在 catch{...} 部分。

[已解决] 多亏了汉斯,我才能够弄明白。 我误解了 pinvoke 上的提示和示例代码。 try{}catch{} 中的这两个剪贴板操作在某种程度上显然是冲突的。正确的方法是使用 try{}catch{try{}catch{}} ,我没有使用也没有测试。

当我注释掉第二个剪贴板操作时,我的问题似乎暂时自行解决了。

我用你的代码创建了一个 Dispossable class(有一些变化),并填充了缺失的方法和 运行 没有问题,没有挂起。我在 winform 应用程序中测试。

我从按钮调用方法并从一个文本框中复制,然后将值粘贴到另一个文本框中,粘贴的结果是有效的,没有挂起。 请注意我是如何通过使 class 继承自 IDisposable 来自动处理句柄的。

试试这个代码

 class ClipboardUtility : IDisposable
{
    private bool disposed = false;

    //If the function succeeds, the return value is the handle to the window that has the clipboard open. 
    //If no window has the clipboard open, the return value is NULL. 
    //To get extended error information, call GetLastError. 

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

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

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

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool CloseClipboard();
    [DllImport("user32.dll")]
    static extern bool EmptyClipboard();

    private IntPtr ClipWindow;
    public void CheckSetClipboard(string s)
    {

        //IntPtr ClipWindow = GetOpenClipboardWindow();
          ClipWindow = GetOpenClipboardWindow();
        Console.WriteLine("handle IntPtr= {0}", ClipWindow);
        //  if (ClipWindow != null && ClipWindow != (IntPtr)0)
        if (ClipWindow != null )
        {
            Console.WriteLine("ClipWindow_" + ClipWindow.ToString());
            uint wid = GetWindowThreadProcessId(ClipWindow, out wid);
            Process p = Process.GetProcessById((int)wid);
            Console.WriteLine("Process using Clipboard: " + p.ProcessName);
        }
        else
        {
            Console.WriteLine("error: {0}", Marshal.GetLastWin32Error());
          //  Console.WriteLine("0 is not idle");
        }

        //Marshal.FreeHGlobal(ClipWindow);
        //OpenClipboard(IntPtr.Zero);
        //EmptyClipboard();
        //CloseClipboard();
        //Console.WriteLine("s: " + s);

        try
        {
            Clipboard.SetDataObject(s, true, 10, 50);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
           // Clipboard.SetDataObject(s, true, 10, 50);
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            CloseHandle(ClipWindow);

            ClipWindow = IntPtr.Zero;

            disposed = true;

        }
    }

    [DllImport("Kernal32")]
    private extern static Boolean CloseHandle(IntPtr handle);
}