0

I've been working on a program that uses mouse and keyboard simulation and often has to grab/set clipboard data.

I've ran into the problem apparently many people runs into, the clipboard is being used by another process so "Clipboard.SetDataObject" throws the exception "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);
        }
    }

I tried a few solutions as the code above shows but eventually the error pops up again. This time I decided to go full ham on it and got the process name of the process using the clipboard..
This is what the console showed:

Process using Clipboard: Idle

How is Idle.exe using the clipboard?
Can I even kill that process to release the clipboard?
Am I doing something wrong?

In the end, I just want to be able to do clipboard operations without failures. Ctrl+c and Ctrl+v never fails, why does my c# code does?

More info:
The data i'm passing into the clipboard is "-0.09261441" or similar numbers.
The error always occurs on the catch{...} part.

[SOLVED] Thanks to Hans, I was able to figure it out. I misinterpreted the tip and sample code on pinvoke. Those two clipboard operations in that try{}catch{} were apparently conflicting in some way. The proper way would have been to use try{}catch{try{}catch{}} which I didn't use and didn't test.

My problems seems to have solved themselves for now when I commented out the second clipboard operation.

JMC17
  • 371
  • 1
  • 3
  • 9
  • Idle exe didn't dispose the pointers intPtr. try to dispose IntPtr using IDisposable pattern, Example: http://stackoverflow.com/questions/6093449/proper-intptr-use-in-c-sharp – M.Hassan Jul 17 '16 at 18:06
  • Hmm, i'm not sure I understand the logic behind it or its implementation. I tried adding "Marshal.FreeHGlobal(ClipWindow);" right after the "if (ClipWindow!=null){...}" section but the same error popped up. I'm starting to think i'm doing something wrong since the error is happening 100% of the time. – JMC17 Jul 17 '16 at 18:19
  • 1
    You have to interpret 0 as "it failed", not as "the Idle process uses it". Using 1 variable to store 2 values could be one way to get it to fail, I guess. You in effect use the thread id, not the process id. – Hans Passant Jul 17 '16 at 18:30
  • Oh wow you're right, it was reporting 0. Now it's not getting the error everytime, it's back to normal (about once in a dozen operation) I still need to figure out the rest though, I updated the code above. Still getting errors just not as often! – JMC17 Jul 17 '16 at 18:38
  • You did not fix the problem, it is your wid variable that you are using wrong. Don't use the return value of GetWindowThreadProcessId(). – Hans Passant Jul 17 '16 at 18:45
  • Alright, I just changed that. I updated the code above too. Still crashing at least once every dozen operations! Same error "Requested Clipboard operation did not succeed." and GetOpenClipboardWindow() returned 0 – JMC17 Jul 17 '16 at 19:30

1 Answers1

1

I created a Dispossable class with your code(with some change), and filled the missing methods and run without problem and no hang. I test in a winform application.

I call the method from the button and copy from one textbox , and paste the value in another textbox and the result of paste is valid without hanging. Note how i disposed the handle automatic by making the class inherit from IDisposable.

try this code

 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);
}
M.Hassan
  • 10,282
  • 5
  • 65
  • 84
  • Despite having already solved my problem, I will look into this code, try it out and will do my best to understand everything. Thank you for your input! – JMC17 Jul 17 '16 at 19:49