Jump to content

Clipboard.ContainsText question


Recommended Posts

I was experimenting with some things related to the Copy Selection feature and wrote a test plugin to read the selection from the clipboard. Before trying to read the selection, I called Clipboard.ContainsText() to verify there was text on the clipboard.  Even when there was a selection on the clipboard, it returned "false". Since I could retrieve the text just fine by calling Services.GetService<IClipboardService>().TryGetText(), it isn't important that Clipboard.ContainsText() work the way I expect it to work, but I'm still curious as to why it didn't, and whether I'm making some mistake it how I'm using it.

 

The call is simply:

        public bool ClipboardContainsText()
        {
            return Clipboard.ContainsText();
        }

 

Called by:

        public bool GetClipboardText()
        {
            //if (!ClipboardContainsText())	// Commented out, since it doesn't seem to work.
            //   return false;

            // If we tried and succeded, don't try again. Use the text we got.
            if (clipboardText != null)
                return true;
            else if (triedToGetCbText)  // Don't retry if we failed once.
                return false;

            triedToGetCbText = true;
            clipboardText = Services.GetService<IClipboardService>().TryGetText();
            if (clipboardText == null)
                return false;
              
            return true;
        }

 

I used Clipboard.ContainsImage() in a plugin, and it worked exactly as I expected it to.

Link to comment
Share on other sites

The Clipboard stuff in WinForms needs to be run in a STA thread; which paint.net Effects do not run in.

 

This returned true when run in CodeLab:

Thread t = new Thread(() =>
{
    bool foo = System.Windows.Forms.Clipboard.ContainsText();
    Debug.WriteLine(foo);
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();

 

 

You could also try the Clipboard methods that are part of WPF. I don't know if they have the same thread requirements.

(PresentationCore.dll is not referenced in CodeLab, so I could not quickly try it myself)

https://docs.microsoft.com/en-us/dotnet/api/system.windows.clipboard.containstext?view=netframework-4.7

  • Upvote 1
Link to comment
Share on other sites

41 minutes ago, toe_head2001 said:

The Clipboard stuff in WinForms needs to be run in a STA thread; which paint.net Effects do not run in.

 

That's strange, because as far as I can tell, Clipboard.ContainsImage seems to work correctly. I used it in a plugin to disable some controls when there was no image on the clipboard. I believe I tested it fairly well, and it always seemed to correctly identify when there was and wasn't an image on the clipboard. (Though perhaps I didn't test it as thoroughly as I should have, because at that time I had no reason to doubt that a few successful tries with different types of clipboard data was all I'd need.)

Link to comment
Share on other sites

8 hours ago, toe_head2001 said:

The Clipboard stuff in WinForms needs to be run in a STA thread; which paint.net Effects do not run in.

 

Plugins don't need to worry about this -- the IClipboardService manages this for them by creating a new STA thread and routing requests through it. (see internal classes: ClipboardServiceForEffects, MarshaledClipboardTransaction)

 

Do not use the WinForms Clipboard class directly. The reason this is failing is because you're asking WinForms' Clipboard class if there's text, and it does require the STA dance, so it says no. Only request clipboard data through the IClipboardServiceIClipboardTransaction, and their extension methods. You can use IClipboardTransaction::IsNativeDataPresent(ClipboardNativeFormats.Text) to test for text. There should probably be another extension method to make that simpler, but there currently isn't. You first need to open a transaction with the IClipboardService

 

Something like this,

 

IClipboardService clipboard = this.Services.GetService<IClipboardService>();
using (IClipboardTransaction clipTx = clipboard.Open())
{
    if (clipTx.IsNativeDataPresent(ClipboardNativeDataFormats.Text))
    {
        // you have text, so get it with clipTx.TryGetText(), which should not return null at this point
    }
}

 

  • Like 2

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

8 hours ago, Rick Brewster said:

There should probably be another extension method to make that simpler, but there currently isn't.

 

I submitted a PR that adds ContainsText and ContainsImage extension methods.

  • Like 3

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

Here are the routines I wrote based on Rick's code. It appears to work for text (I haven't tested it yet for images).

 

It seems to be ClipboardNativeFormats rather than ClipboardNativeDateFormats. I assume Bitmap is the correct format to test for images.

 

       public bool ClipboardContainsFormat(uint format)
       {
            bool clipboardContainsFormat;
            IClipboardService clipboard = this.Services.GetService<IClipboardService>();
            using (IClipboardTransaction clipTx = clipboard.Open())
            {
                clipboardContainsFormat = clipTx.IsNativeDataPresent(format);
            }
            return clipboardContainsFormat;
        }

        public bool ClipboardContainsImage()
        {
            return ClipboardContainsFormat(ClipboardNativeFormats.Bitmap);
        }

        public bool ClipboardContainsText()
        {
            return ClipboardContainsFormat(ClipboardNativeFormats.Text);
        }

 

Link to comment
Share on other sites

1 hour ago, MJW said:

I assume Bitmap is the correct format to test for images.

 

That is the correct format, but there are cases where it would produce a false negative.

For example, Paint.NET will not place a Bitmap on the clipboard if the image data is larger than 4 GB.

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

15 minutes ago, null54 said:

That is the correct format, but there are cases where it would produce a false negative.

For example, Paint.NET will not place a Bitmap on the clipboard if the image data is larger than 4 GB.

 

I'm not sure what that means in regard to a plugin that's trying to determine if it can use the data on the clipboard (which is the only thing I would care about). Also, Bitmap seems to be the only one that makes sense for images, so if it doesn't work, what would?

Link to comment
Share on other sites

2 hours ago, MJW said:

I'm not sure what that means in regard to a plugin that's trying to determine if it can use the data on the clipboard

 

I was trying to say that there are situations where your code would return false, even if there is an image on the clipboard that TryGetSurface can read.

 

2 hours ago, MJW said:

Also, Bitmap seems to be the only one that makes sense for images, so if it doesn't work, what would?

 

The ContainsImage extension method I submitted to Rick uses the same logic as TryGetSurface when checking for an image on the clipboard.

Hopefully it will be included in the next alpha build of 4.2.17.

 

The Paint.NET clipboard code handles more image formats than just a Windows Bitmap (file path, PNG, etc).

  • Like 1

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

6 hours ago, null54 said:

I was trying to say that there are situations where your code would return false, even if there is an image on the clipboard that TryGetSurface can read.

 

Thanks. I'll hold off releasing any plugin that uses it before the update.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...