4

I have this intermittent and incosistent problem which has been driving me crazy for a long time: In a program of mine, GetClipboardData(CF_TEXT) succeeds 90% (or so) of the time, but every once in a while it returns NULL.

This is despite the fact that OpenClipboard() always succeeds (and return value checked) before calling GetClipboardData(CF_TEXT).

Please note that the 90% success ratio is for the same exact page! (i.e. I know there is a CF_TEXT content there)

Note: When it fails, I immediately call GetLastError() but all it returns is: "The operation completed successfully".

The code in question is as simple as:

if (::OpenClipboard(hwndW))
{
  HANDLE handleClip = ::GetClipboardData(CF_TEXT);
  if (handleClip == NULL)
    dw = GetLastError()
}

What could possibly inject the wrong GetLastError() code into this?

Any idea what could prompt such inconsistent behavior?

Is it possible that some other process is locking the clipboard? If so, how do I take it back?

How do I troubleshoot or debug something like this?

Android Eve
  • 14,864
  • 26
  • 71
  • 96
  • OpenClipboard() doesn't tell you anything. What does EnumClipboardFormats() tell you? – Hans Passant Jan 19 '11 at 21:02
  • 1
    How do you know the content is still on the clipboard? – Jeff Yates Jan 19 '11 at 22:53
  • @Jeff That's a good question. I "know" it's there because if I try again (same exact page) it will succeed. This is not really very "scientific" but when GetLastError() returns "The operation completed successfully", what else do I have in my toolkit? I am going to try Hans's suggestion to call EnumClipboardFormats(), but even if it tells me that CF_TEXT exists (or doesn't exist), it doesn't tell me *why* it is so inconsistent. – Android Eve Jan 19 '11 at 22:58
  • I've been working on a similar (re-occurring) issue of mine, having read this thread months ago to run across it again today. In my case, I don't mind a last error of success -- I get it whenever the last thing I copied to the clipboard was the empty string, after having already emptied the clipboard. No content, not a failure, just nothing to return, error success. But, my problem now was a "null string copy" returning a stale last error of "cannot find file". GetClipboardData wasn't setting error success on a null handle! Now I SetLastError(0) before my calls. – Charles J. Daniels Nov 15 '14 at 10:11

2 Answers2

3

Are you using WebRoot SecureAnywhere? It's Identity Shield feature automatically empties the clipboard if a non-allowed application (basically anything that wasn't pre-approved) attempts to retrieve text from the clipboard that was placed onto the clipboard by a protected application (includes many browsers and email clients by default). When this happens, GetClipboardData(CF_TEXT) will return NULL even if a previous call to IsClipboardFormatAvailable(CF_TEXT) returned true.

Jan Goyvaerts
  • 21,379
  • 7
  • 60
  • 72
  • This just cost me an afternoon trying to figure out what was wrong with my program. The user was running WebRoot and this exactly matched my issue and solution. – Mark Elder Jan 14 '14 at 16:46
  • We could not figure out what was clearing out the CF_TEXT portion of the clipboard for one of our users in our software. This was it! Thanks for saving us a bunch of time. – Warren Markon Jan 14 '14 at 17:39
2

I did a Google search and found someone else with a similar problem (scroll down to find the particular response) that turned out to be due to re-entrancy. Do you call EmptyClipboard() anywhere and then react to changes? Perhaps you have a re-entrancy problem.

Update after code snippet provided
In the code you posted, the condition is wrong before calling GetLastError. You're only calling it when you get a non-NULL result, rather than when you get a NULL result. If you fix that, you should get a better answer from GetLastError. This MSDN article should help in deciphering what the result of GetLastError actually means.

Update after corrected code snippet
My guess is that you're facing a race condition with some other application accessing the clipboard. I would recommend checking to see if you have any other tools running that might do this.

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
  • @Jeff Sorry for failing to mention that of course I called GetLastError(). This is what it returns: **"The operation completed successfully"**. I am totally puzzled by this. – Android Eve Jan 19 '11 at 22:50
  • @Android Eve: I've modified my answer based on additional information. – Jeff Yates Jan 19 '11 at 22:58
  • @Jeff +1 for this link. Knowing my program, I think you are onto something... No, I don't call EmptyClipboard(), but I do call CloseClipboard() -- isn't this even better? Besides, even if I forget to call an empty/close function, why does GetLastError() return "successfully"? – Android Eve Jan 19 '11 at 23:04
  • Android Eve: Unfortunately, GetLastError returns the last error set by the last call to SetLastError on the current thread, not the last error you necessarily want to see. There's a chance that if you have a re-entrant problem, it is returning the last error of some other API call besides GetClipboardData. Also, it could be that the last error wasn't set by the call. – Jeff Yates Jan 19 '11 at 23:05
  • @Jeff: How would you define "re-entrancy problem" in this context? – Android Eve Jan 19 '11 at 23:15
  • Usually, re-entrancy occurs in Windows programs when a message is processed and during that processing, it causes the message loop to pump so that a second message is handled before the first one's handling was finished. There are various ways this can happen. – Jeff Yates Jan 19 '11 at 23:18
  • @Jeff: I just posted the exact code snippet in question. How can message loop pump anything into this? Note: this is a single-thread application and the code isn't even in a DLL. – Android Eve Jan 19 '11 at 23:24
  • @Android Eve: The problem you have there is that it should be if (handle == NULL) GetLastError... You have the wrong check in the condition. – Jeff Yates Jan 19 '11 at 23:30
  • @Jeff: Sorry, that was a typo in the post (I did this very hastily). It's corrected now. The problem and questions remain. (would've been too easy if that '!=' was the problem :). Also, it goes without saying that I verify that hwndW is not NULL before calling OpenClipboard(). – Android Eve Jan 19 '11 at 23:59
  • Update: This is weird. I only added a call to CountClipboardFormats() before OpenClipboard() and the problem seems to have disappeared. I am sure it will come back to haunt me. (and then, how do I troubleshoot a crazy problem like this?) – Android Eve Jan 20 '11 at 00:33
  • @Android Eve: Everything you describe leads me to think this is a Heisenbug. Do you have any clipboard tools installed on your machine? Might be that another application is accessing the clipboard periodically and you encountering some kind of race condition. – Jeff Yates Jan 20 '11 at 02:47
  • Mystery never been solved but I am accepting this answer until a better answer comes along. – Android Eve Mar 03 '11 at 00:18
  • The link to the "similar problem" does not show the expected content, anymore. – Akito Apr 29 '21 at 23:12
  • @AndroidEve No idea how it worked, but your proposed workaround helps a bunch, indeed. Calling `CountClipboardFormats()` before `OpenClipboard()` makes the whole thing work for whatever reason. With this workaround enabled, I copied text a couple of hundred times to my clipboard and it failed only a single time, as opposed to roughly every third copy before applying this workaround. Thank you. I hope there will be a real solution to this at some point. – Akito Apr 29 '21 at 23:46