Modifying clipboard contents on clipboard change - c#

I'm doing this in C#, but, I guess, it isn't language specific problem...
I've got some sample code on how to detect when the contents of the clipboard changes. Now I want to modify the text that just got copied (strip some tags) and replace clipboard text with fixed one.
But if I SetDataObject() when I detect the clipboard contents have changed, that will generate the the message that Clipboard contents have changed again. In theory, i guess, it sounds like an infinite loop (in practice for some reason it's not).
What's the strategy to do this modification once, and sent the message down the clipboard monitoring chain?
P.S. As a test I'm doing following, but what happens is Clipboard.SetDataObject.. line gets called twice. I don't understand why, I'd expect it do this infinitely.
case Win32.Msgs.WM_DRAWCLIPBOARD:
String clipboardText = GetClipboardText();
if (!String.IsNullOrEmpty(clipboardText))
{
Clipboard.SetDataObject("test( " + clipboardText + " )!");
}
Win32.User32.SendMessage(_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);

Unfortunately, any time you set the Clipboard's data with Clipboard.SetDataObject, you'll "redraw" the clipboard, since you're changing its contents.
The best way to handle this situation is to make your routine check the clipboard contents, and only set it if you actually change the clipboard text.
In your case, you say you're stripping out some tags. Just check the clipboardText string before and after your routine, and if the string is unchanged, don't set it again.
This way, the first time, it'll strip the tags out, then reset. Then fire again, see there are no changes, and not reset the clipboard data.

To prevent the recursion, you should only actually set the clipboard text if there were tags to strip.
To explain the behavior, I would guess that WM_DRAWCLIPBOARD isn't sent recursively, meaning that if the clipboard is changed during a WM_DRAWCLIPBOARD notification, it won't be sent again.

Actually there is a much better way to avoid infinite loop which works even in cases when you are not modifying clipboard content and consequently you cannot compare if you changed it or not.
When you detect WM_DRAWCLIPBOARD message call GetClipboardOwner which will return handle to the window which modified the handle. Once you have the handle you can get the process which owns the window. If the process is different from your process then process the clipboard, otherwise the clipboard was changed by you so ignore it.

Related

Microsoft.Office.Interop.Word.Document - are COM calls to this object async or sync?

I am attempting to extract RTF code out of a word instance that my .NET C# application launches. The code that performs this is:
Clipboard.Clear();
//document is of type Microsoft.Office.Interop.Word.Document
document.Application.Activate();
document.Select();
document.Content.Copy();
if (Clipboard.ContainsData(DataFormats.Text) &&
Clipboard.ContainsData(DataFormats.Rtf))
{
DocumentContent = Clipboard.GetText(TextDataFormat.Rtf);
}
Clipboard.Clear();
What is periodically happening is that when the call is made to Clipboard.GetText it is returning String.Empty. So I was wondering if it is possible that the COM call to the Content.Copy has not finished yet. The reason I suspect this is because if I put a break point on DocumnetContent=... and it comes back as String.Empty I can just move the debugger back one line and call the GetText line again and this time it will contain the text. Similarly if it comes back with String.Empty I can go into notepad and hit control+V and it will paste the copied text that I expect to be on the clipboard.
I must stress that this behavior is not consistent. I can't reproduce it at will but if I perform the action enough (usually 1 out of 20 will trigger this behavior) I'll eventually get it.
Thank you for your help and please let me know of any clarifications needed.

Copy and paste with C#

I know this is asked many times before but it s not what i look for, to make copy paste in c# we use;
//Copy
Clipboard.SetDataObject("String to copy");
//Paste
IDataObject iData = Clipboard.GetDataObject();
I only want to use copy, after using:
Clipboard.SetDataObject("String to copy");
when i close the program, then when i right click and paste on a txt file nothing happens!
So Clipboard class seems doesnt help, so i need another solution.
Clipboard.SetDataObject("String to copy", true);
That boolean value at the end specifies whether the string should remain in the clipboard after the application closes, and is set to false as default.
You want to use second overload of SetDataObject(object, bool).
When bool is set to true, data will remain after application is closed.
Did you try to use Clipboard.SetText(your_String)?
This works for me.

Problem with C# multiline textbox memory usage

I am using a multiline text box in C# to just log some trace information. I simply use AppendText("text-goes-here\r\n") as I need to add lines.
I've let this program run for a few days (with a lot of active trace) and I noticed it was using a lot of memory. Long story short, it appears that even with the maxlength value to something very small (256) the content of the text box just keeps expanding.
I thought it worked like a FIFO (throwing away the oldest text that exceeds the maxlength size). It doesn't, it just keeps increasing in size. This is apparently the cause of my memory waste. Anybody know what I'm doing wrong?
Added a few hours after initial question...
Ok, I tried the suggested code below. To quickly test it, I simply added a timer to my app and from that timer tick I now call a method that does essentially the same thing as the code below. The tick rate is high so that I can observe the memory usage of the process and quickly determine if there is a leak. There wasn't. That was good; however, I put this in my application and memory usage did not change (still leaking). That sure seems to imply that I have a leak somwehere else :-( however, if I simply add a return at the top of that method, the usage drops back to stable. Any thoughts on this? The timer-tick-invoked code did not accumulate memory but my real code (same method) does. The difference is that I'm calling the method from a variety of different places in the real code. Can the context of the call affect this somehow? (note, if it isn't already obvious, I'm not a .NET expert by any means)...
TextBox will allow you to append text regardless of MaxLength value - it's only used to control user entry. You can create a method that will be adding new text after verifying that maxlength is not reached, and if it is, just remove x lines from the beginning.
You could use a simple function to append text:
int maxLength = 256;
private void AppendText(string text)
{
textBox1.AppendText(text);
if(textBox1.Text.Length > maxLength)
textBox1.Text = textBox1.Text.Substring(textBox1.Text.Length - maxLength);
}

C# Clipboard Help

I am copying the contents of an Excel file onto the Clipboard within a program I have written. I can then use that data in memory rather than 'chatting' constantly with Excel.
When I have finished with the data, I cal a cleanup method that calls Clipboard.Clear() first and then closes all Excel sheets/workbooks/apps, etc.
The problem is, even though I clear the Clipboard prior to closing the Excel sheets, I get a pop up window still saying there is substantial amount of data on the clipboard. Anybody know why?
Thanks,
Darren.
Not sure why that happens, but have you tried setting _Application.DisplayAlerts = false; (MSDN) before you close the sheets to see if that prevents the warning message?
You could try setting the Excel CutCopyMode property to cancel the current copy information:
Application.CutCopyMode = false;
Another thought is to set the clipboard to String.Empty so the amount of data copied is small enough that it bypasses the warning popup. This may have to be done from the Excel sheet, not the regular clipboard (i.e., copy a cell from the active sheet in Excel).
Perhaps you could use
Application.CutCopyMode = false;
http://msdn.microsoft.com/en-us/library/ff839532.aspx
Well at the end, try copying an empty string in clipboard and leave it, then Excel may not give any warning. But use Excel API to copy empty string in clipboard.

Writing huge amounts of text to a textbox

I am writing a log of lots and lots of formatted text to a textbox in a .net windows form app.
It is slow once the data gets over a few megs. Since I am appending the string has to be reallocated every time right? I only need to set the value to the text box once, but in my code I am doing line+=data tens of thousands of times.
Is there a faster way to do this? Maybe a different control? Is there a linked list string type I can use?
StringBuilder will not help if the text box is added to incrementally, like log output for example.
But, if the above is true and if your updates are frequent enough it may behoove you to cache some number of updates and then append them in one step (rather than appending constantly). That would save you many string reallocations... and then StringBuilder would be helpful.
Notes:
Create a class-scoped StringBuilder member (_sb)
Start a timer (or use a counter)
Append text updates to _sb
When timer ticks or certain counter reached reset and append to
text box
restart process from #1
No one has mentioned virtualization yet, which is really the only way to provide predictable performance for massive volumes of data. Even using a StringBuilder and converting it to a string every half a second will be very slow once the log gets large enough.
With data virtualization, you would only hold the necessary data in memory (i.e. what the user can see, and perhaps a little more on either side) whilst the rest would be stored on disk. Old data would "roll out" of memory as new data comes in to replace it.
In order to make the TextBox appear as though it has a lot of data in it, you would tell it that it does. As the user scrolls around, you would replace the data in the buffer with the relevant data from the underlying source (using random file access). So your UI would be monitoring a file, not listening for logging events.
Of course, this is all a lot more work than simply using a StringBuilder, but I thought it worth mentioning just in case.
Build your String together with a StringBuilder, then convert it to a String using toString(), and assign this to the textbox.
I have found that setting the textbox's WordWrap property to false greatly improves performance, as long as you're ok with having to scroll to the right to see all of your text. In my case, I wanted to paste a 20-50 MB file into a MultiLine textbox to do some processing on it. That took several minutes with WordWrap on, and just several seconds with WordWrap off.

Categories

Resources