MJW Posted July 7, 2021 Share Posted July 7, 2021 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. Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted July 7, 2021 Share Posted July 7, 2021 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 1 Quote (September 25th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
MJW Posted July 7, 2021 Author Share Posted July 7, 2021 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.) Quote Link to comment Share on other sites More sharing options...
Rick Brewster Posted July 7, 2021 Share Posted July 7, 2021 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 IClipboardService, IClipboardTransaction, 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 } } 2 Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
null54 Posted July 8, 2021 Share Posted July 8, 2021 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. 3 Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC | Paint 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 More sharing options...
MJW Posted July 8, 2021 Author Share Posted July 8, 2021 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); } Quote Link to comment Share on other sites More sharing options...
null54 Posted July 8, 2021 Share Posted July 8, 2021 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. Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC | Paint 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 More sharing options...
MJW Posted July 8, 2021 Author Share Posted July 8, 2021 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? Quote Link to comment Share on other sites More sharing options...
null54 Posted July 8, 2021 Share Posted July 8, 2021 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). 1 Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC | Paint 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 More sharing options...
MJW Posted July 8, 2021 Author Share Posted July 8, 2021 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.