0

After reading quite a bit on the clipboard being blocked when trying to use it, I tried using OpenClipboard() directly, to capture the clipboard and be able to use it from my window.

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
    }

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

    private int idx = 0;
    private void refresh_Tick(object sender, EventArgs e) {
        switch (idx++) {
        case 0:
                OpenClipboard(Handle);
                break;
        default:
                Clipboard.SetText(" ");
                break;
        }
    }
}

When using SetText, I will get the infamous error:

A first chance exception of type 'System.Runtime.InteropServices.ExternalException' occurred in System.Windows.Forms.dll
Additional information: Requested Clipboard operation did not succeed.

So, the questions:

  1. Does OpenClipboard() actually work?

  2. What is the argument for OpenClipboard() for? The rest of the API does not need a handle to any window, so why does OpenClipboard()? In other words, the Clipboard is supposed to be shared between PROCESSES, not WINDOWS - but I don't see a way to lock it for my current process.

  3. I can call OpenClipboard(IntPtr.Zero), which MSDN says:

    If this parameter is NULL, the open clipboard is associated with the current task.

    What is 'task' supposed to mean?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
John T
  • 97
  • 1
  • 7
  • 3
    *If I randomly throw around API code and it doesn't work, it's Microsoft's fault*? There's a link to an example of properly using it on the [OpenClipboard page at MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/ms649016(v=vs.85).aspx#_win32_Copying_Information_to_the_Clipboard). Did you read it to at least get an idea of the proper way to do so? Yes, OpenClipboard actually works, it's used every day in every Windows application that uses the clipboard, and the documentation explains precisely how it's used. The parameter is the handle to the window that's opening it. – Ken White Apr 03 '17 at 22:26
  • And just FYI: The vast majority of the WinAPI uses an HWND. Because the framework hides that from you doesn't mean they're not in use. Buy Petzold's book. – Ken White Apr 03 '17 at 22:29
  • You will have to throw this away. Google "c# clipboard listener" to learn how to do it properly. – Hans Passant Apr 03 '17 at 22:52
  • @KenWhite - sorry if the code was originally rather bad. I've updated it, to show a simple example where I get the error. My issue is that I need to copy stuff into the clipboard, and a times, this seems to fail for seconds at a time (for instance, it works 10 seconds, and then for the next 30 seconds it does not). So, I tried to "capture" the clipboard, but that seems to fail too. – John T Apr 03 '17 at 23:13
  • @HansPassant. I have updated the code. I did look at SetClipboardViewer, but I don't think it will help, since I need to copy stuff into the clipboard (as opposed to reading from it) – John T Apr 03 '17 at 23:18
  • 1
    Read the documentation. It will tell you to match every call to OpenClipboard against one to CloseClipboard. How can you think that the library is broken without having read the documentation? – David Heffernan Apr 04 '17 at 05:02
  • @DavidHeffernan That is not the issue, thanks anyway. The issue is that if I'm using OpenClipboard(), I should use the rest of the Win32 API (SetClipboardData) – John T Apr 04 '17 at 10:38
  • 1
    Not calling `CloseClipboard` is a pretty big problem. One that would have been avoided had you read the documentation. Mixing .net clipboard class with raw Win32 API is also a problem. – David Heffernan Apr 04 '17 at 10:58

1 Answers1

0

Does OpenClipboard() actually work?

OpenClipboard() works, but definitely not in the way you showed. It is a raw Win32 API. Here is an example of using it to copy string to clipboard (C/C++).

What is the argument for OpenClipboard() for?

To be honest, I'm not sure about this. Usually we just pass NULL aka IntPtr.Zero and let it associate with the current task. I guess it retrieves the thread that created the specified window, and then associates it with the clipboard.

What is task? Well here is my understanding. Back in Win16 days, instead of 'Thread' or 'Process', they used the terminology 'Task'. There was a function to GetCurrentTask().

enter image description here

Then the function is replaced by GetCurrentProcess() and GetCurrentThread().

enter image description here

Since it makes more sense that only one thread can access a shared resource at one time, I would say that 'Task' actually means 'Thread'.

The rest of the API does not need a handle to any window, so why does OpenClipboard()?

If my assumption above is correct, that is, only one thread can access Clipboard at a time, then chances are, Windows will use the thread/window you specified with OpenClipboard() previously, until you call CloseClipboard() or the thread/window becomes invalid. That's why you don't need to specify the HWND all the time.

In other words, the Clipboard is supposed to be shared between PROCESSES, not WINDOWS - but I don't see a way to lock it for my current process.

It locks, though I'm not sure about C# P/Invoke. If you have access to Win32/C development toolkit, compile and run the following code:

#include <conio.h>
#include <Windows.h>

int main()
{
    OpenClipboard(GetForegroundWindow());
    _getch();
    return 0;
}

And see what happen if you use Clipboard in other program. :) Close the console window to restore.

Community
  • 1
  • 1
raymai97
  • 806
  • 7
  • 19
  • 1
    There is lots of mis-information here. If you are reading from the clipboard, you can provide an empty handle to OpenClipboard, but if you intend to write (ex, `SetClipboardData`) then you must open the clipboard with a handle to a window you own. Windows may raise a `WM_RENDERFORMAT` message when another application requests a format you've set with delayed rendering and you are required to respond to this. See the remarks for `SetClipboardData` for more information. You should not open the clipboard with a handle to the ForegroundWindow as these messages will be wrongly sent there instead. – caesay Mar 25 '21 at 12:01