SOLVED What is my Clipboardowner for a script?

Hello;

I was just looking into the clipboard functions and found that the specialized function CopyBitmapToClipboard requires a CLIPBOARDOWNER.

I assume this has to do with delay-rendering of clipboard content and the WM_RENDERFORMAT message under Windows - no idea how the clipboard works under Mac... Wasn't actually aware that C4D uses that mechanism at all, but that's how it looks.

So, if I use CopyBitmapToClipboard in a script or plugin of my own, I wouldn't delay-render the bitmap, so I'd use neither the CLIPBOARDOWNER_BODYPAINT nor the CLIPBOARDOWNER_PICTUREVIEWER constants, which (I assume) would cause the clipboard to send WM_RENDERFORMAT to either window instead of my script. Of course, these are the only constants available, and the function description does not offer anything else.

When getting a bitmap from the system, GetC4DClipboardOwner returns 0, so I assume I can pass 0 safely too in calls to CopyBitmapToClipboard? Or am I overlooking some larger context here? As I am neither BodyPaint nor the PictureViewer, I would never want to use these constants anyway. But there is no speaking constant for 0, and CopyBitmapToClipboard makes it even a mandatory parameter?

Can I crash C4D by using one of the two CLIPBOARDOWNER constants in a script (while not implementing a delay-render to clipboard at all which C4D doesn't even offer)?

GetC4DClipboardOwner allows me to retrieve the clipboard owner, but under what circumstances would I want to know that? If this is only for the delayed retrieval of clipboard content, then this should work fully transparently (?)

(Edit: Does look better with less formatting now?)

Hello @cairyn,

Thank you for reaching out to us. I see you saw my post yesterday before I hid it. I was not implying that you should change the existing one, and more meant that you should try to reduce the complexity of presentation and content of future requests, as at least I often struggle with both of in your topics.

The reason I hid my posting was that I was a bit lazy yesterday and accidentally looked at the Linux implementation of the clipboard. So, for Windows, the backend implementation of GetC4DClipboardOwner() looks like this:

Int32 ClipBoard::GetC4DOwner() {
  if (!_GeClippboardWindow || _GeClippboardWindow != GetClipboardOwner()) return 0;
    return m_ownerid;
}

And this seems to be never to be able to get past the conditional expression in the first line, at least I never managed to do so. GetClipboardOwner() is a Windows function, and _GeClippboardWindow is a window handle (HWND) our clipboard is storing, the two simply never match up.

When writing a bitmap to the clipboard, and setting the owner identifier manually, the outcome is never what one would expect.

>>> bmp = c4d.bitmaps.BaseBitmap()
>>> c4d.CopyBitmapToClipboard(bmp, c4d.CLIPBOARDOWNER_PICTUREVIEWER)
>>> c4d.GetC4DClipboardOwner()
0
>>> c4d.CopyBitmapToClipboard(bmp, 12345678)
>>> c4d.GetC4DClipboardOwner()
0

The reason is that the field m_ownerid is never actually written when the backend function which is invoked by CopyBitmapToClipboard() is being called. The reason is again here that something with window handles is going wrong, causing m_ownerid always being 0.

So, to summarize:

  1. The ownerid argument of CopyBitmapToClipboard is effectively meaningless, as it is never being written to the backend field storing that information.
  2. There are in principle no restrictions to ownerid, you can write anything that fits into an Int32 there. The only functions that inside the clipboard rely on this field are the one's mentioned in this thread. It could of course be that the Picture Viewer or Bodypaint do some clever poking around in the backend, but this seems unlikely. To be absolutely sure, I would avoid writing the owner identifiers CLIPBOARDOWNER_BODYPAINT and CLIPBOARDOWNER_PICTUREVIEWER manually. But this is all very theoretical since writing m_ownerid does not work in the first place.

I am not sure yet how we will deal with this. It could for example be that the Windows API we are relying on has changed. It seems likely that we will simply make the argument ownerid and the concept of owners private, i.e., hide them in the C++ and Python docs, as this all is quite minor.

Thank you for pointing this out.

Cheers,
Ferdinand

Hmm, there seem to be recent changes in that functionality. When I try to copy a newly rendered image from the PictureViewer, the owner actually seems to be set fine in the R23.110:

>>> c4d.GetC4DClipboardOwner()
200000244

(I assume that Python cannot do anything that C++ would not support...)

On the other hand, your other code indeed returns 0 so maybe the functionality wasn't consistent in R23 anyway.

Thanks, I will go with an ownerid of 0 for now... as there are no callbacks targeting my script, it can't hurt anyway.

Hey @cairyn,

yeah, you are right. @m_adam already pointed this out too. I screwed up and overwrote my clipboard when I tried this out. I have edited my initial posting, to not confuse future readers.

GetC4DClipboardOwner works fine in regards to the Picture Viewer and Bodypaint, but the argument ownerid of CopyBitmapToClipboard is effectively meaningless in the public API, as it lacks the window handle context to actually cause the ownerid to be stored. The owner id will always be set to 0.

And to underline the answer to your major question: It seems very unlikely that you could crash Cinema 4D with writing a made-up owner id into the clipboard (in the case the function would work properly and actually store the id). It is hard to give here absolute answers, as there is a lot of code in our code base. In the context of the clipboard alone, crashing can be excluded, but there could be other parts of Cinema 4D which make assumptions based on the owner id. Which is why I would recommend not using the predefined ones (which is rather theoretical due to said limitations of CopyBitmapToClipboard).

Cheers,
Ferdinand