Clipboard Monitoring Event Stops Triggering - c#

I have some software which manipulates text on the Windows clipboard. Specifically it will remove an underscore _ (and return characters) from the front of clipboard text, then check if the remaining text is a URL. If it is, the URL without the underscore is stored on the clipboard, otherwise the original text is left. To monitor the clipboard for changes, I am using code from the answer to this question, provided by DBKK. It works fine, but randomly stops working after an amount of time which can be anywhere between 5 mins and ~24 hours.
Below is the code which is called on the clipboard event trigger:
private void clipboardMonitor_ClipboardChanged(object sender, ClipboardAssist.ClipboardChangedEventArgs e)
{
lock(lockVar)
{
if (locked)
{
return;
}
else
{
locked = true;
//this.clipboardMonitor.ClipboardChanged -= new System.EventHandler<ClipboardAssist.ClipboardChangedEventArgs>(this.clipboardMonitor_ClipboardChanged);
count++;
label1.Text = count.ToString();
removeUnderscore();
//this.clipboardMonitor.ClipboardChanged += new System.EventHandler<ClipboardAssist.ClipboardChangedEventArgs>(this.clipboardMonitor_ClipboardChanged);
locked = false;
}
}
}
I have added various debugging code. Firstly the counter, which made me realise when I write back to the clipboard it triggers the event again. I added the two lines that unset then set the event, so modifying the clipboard doesn't call the event again while it is running. I also added code which would block the event from running if it hadn't finished the previous run (the if(lock) part). Eventually the event stops triggering (as can be seen by a counter not being incremented). It is definitely a problem with the event, I added removeUnderscore() to a button call and that still works fine when the event has stopped triggering.
My theory is that because of the weird way it can call its self, something is going wrong and not adding the event again. I seem unable to lock the the function using a lock object or the boolean value. Any ideas on what might be going wrong?
Edit:
I created another program with the same even which only counts clipboard changes. It appears to run fine indefinitely, so the problem is definitely caused by the event calling it's self. I need a robust way to suspend the even while it is executing.

Related

Outlook 2013 Form Region and the Delete Key

So, I've finally had to deal with this annoying issue. It seems that it's a known "bug" and there doesn't seem to be a great work-around. I was wondering what seems to be the best work around for this.
A little bit of info. In my form region I have a Winform control and a WPF control. The user can't do certain key combinations on the Winform control (Ctrl-A to select all, Delete key deletes email instead of highlighted text), but everything works fine on the WPF control.
I've tried adding the Winform control to the WPF control using a WindowsFormHost, but that made it worse as it wouldn't register the backspace key after that. I tried capturing the delete event for the email, but I can't get the .BeforeDelete to trigger. Same for the Explorer.BeforeItemCut event. Currently I'm trying to capture the WndProc event to re-direct the key events, but it seems like there should be a better/easier way.
Not sure how to continue from here. Any help in direction is welcomed. Below is my how I'm trying to capture email delete event.
Outlook.MailItem _selEmail;
// This does get triggered
private void Explorer_SelectionChange()
{
var actExplorer = this.Application.ActiveExplorer();
if(this.Application.ActiveExplorer().Selection.Count > 0)
{
var selObject = actExplorer.Selection[1];
if(selObject is Outlook.MailItem)
{
_selEmail = selObject as Outlook.MailItem;
_selEmail.BeforeEmailDelete -=
new Outlook.ItemEvents_10_BeforeDeleteEventHandler(Email_BeforeDelete);
_selEmail.BeforeEmailDelete +=
new Outlook.ItemEvents_10_BeforeDeleteEventHandler(Email_BeforeDelete);
}
}
}
// Haven't gotten this to trigger. The Console.Write("") is there
// only for a breakpoint;
private void Email_BeforeDelete(object sender, ref bool cancel)
{
Console.WriteLine("");
}
First of all, I'd suggest breaking the chain of property and method calls and declare each property or method call on a separate line of code. Thus, you will be able to release underlying COM objects inplace. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. You can read more about that in the Systematically Releasing Objects article in MSDN.
Try to turn off the Single key reading using the space bar option in Outlook which allows you to move quickly through your messages in the Reading Pane. The space bar scrolls the current item. At the end of the item, it jumps to the next unread item in your message list.
Finally, using WPF controls on Outlook forms produce a well-known issue. Outlook has a habit of swallowing various keys and not sending them along to your code or form region. The spacebar, tab, backspace keys are among those affected when the keys are pressed in the reading pane. You can find a similar forum thread.

In Idle cannot access RichTextControl or IME will not work

When reading some RichTextControl properties inside Application.Idle some IME won't work.
Given this simple code:
_richTextControl = new RichTextControl();
Application.Idle += delegate(object sender, EventArgs e) {
btnCopy.Enabled = _richTextControl.SelectionLength > 0;
btnPaste.Enabled = _richTextControl.CanPaste();
};
It'll work fine with most IME I tried but, at least, for Chinese (Traditional, Taiwan) with Microsoft Chinese Traditional Array (6.0) and Chinese Traditional DaYi (6.0) it'll prevent IME to work properly (I tried only with Windows 7, in English and Taiwanese). You can start typing but when Idle code is executed (reading SelectionLength property and invoking CanPaste() method, here I wrote them both but each one is enough to reproduce this) it'll stop working (you type but pop-up window is closed immediately and nothing is sent to RichTextControl).
I checked MSDN about EM_GETSELTEXT and EM_CANPASTE but it says nothing about this issue. I also tried to replace SelectionLength property manually sending EM_GETSELTEXT with SendMessage() but it doesn't change this odd behavior (however I checked WordPad - which uses rich editor - and it works properly even if (AFAIK) MFC commands use idle time to update UI status).
Of course I can move some code into SelectionChanged event and update UI both from Idle and from SelectionChanged (and it'll work) or I may update some flags in SelectionChanged and change UI in Idle but this will break existing code and it'll force a big change in UI library (all commands have not knowledge of Idle or SelectionChanged, they simply return true in a CanExecute() method when their target control allows their execution). If nothing else is viable then I may derive a class from RichTextControl to make these methods/properties callable in Idle (using flags updated elsewhere) but (to avoid a big refactoring) I would know if it's a knows issue, a bug related to IME itself or if there is something else I missed.

AccessViolationException when interacting with RichTextBox

I'm aware there is a bug with .Net 2.0 with LCG which generates AccessViolationException when certain IEnumerable<> and similar objects are used; and that there is a hotfix.
I have a project in .Net 4.0 using WinForms running on Windows 7 x64. I have a very simple form - nothing but a form and a RichTextBox docked to take up the whole client size.
From a background thread, I periodically call an update method on my form that does something similar to the following:
public static void Log(string text)
{
Invoke((MethodInvoker)(() => {
lock(richTextBox) {
richTextBox.Text += text;
}
}));
}
I do actually have both the inside of the invoke and the outside in a try/catch (Yes, I know this is horrible!) and I'm doing some additional things like putting the caret to the end and scrolling to it. I'm also using StringBuilder but this is all beside the point:
Rarely, but inevitably, while debugging, my IDE detects an AccessViolationException somewhere in the code that's updating the text box. It's sometimes in the bit that updates the text, it's sometimes at the bit that makes the selection, and it's sometimes at the bit that scrolls to the caret. If I press F5 to continue, I usually don't see the problem for some time and the application continues as before.
There is nothing fancy happening with this text box. There is no race condition (first of all because I have a lock), but also because there is simply nothing in my code that would try and write to the text box at the same time as something else is trying to.
Any idea why this may be happening? I'm sorry, I don't know what other information I can put here, as I'm not even sure why this is happening in the first place.
Not sure what the rest of your code is doing but I reckon the problem is with lock(richTextBox). If the GUI thread is doing something with the RichTextBox, the lock will not work Or if you are accessing this RichTextBox in some other thread.

C# How To: Trying to call button twice in same class?

Did some searches here & on the 'net and haven't found a good answer yet. What I'm trying to do is call a button twice within the same class in C#.
Here's my scenario -
I have a form with a button that says "Go". When I click it the 1st time, it runs through some 'for' loops (non-stop) to display a color range. At the same time I set the button1.Text properties to "Stop". I would like to be able to click the button a 2nd time and when that happens I would like the program to stop. Basically a stop-and-go button. I know how to do it with 2 button events, but would like to utilize 1 button.
Right now the only way to end the program is the X button on the form.
I've tried different things and haven't had much luck so far so wanted to ask the gurus here how to do it.
BTW, this is a modification of a Head First Labs C# book exercise.
Thanks!
~Allen
You would need to use Multithreading (launch the process intensive code asynchronously in a separate thread), for instance, using the BackgroundWorker object in .NET 2+. This would be necessary because your UI will not respond to the user's click until the loop running in the Start method is completed. It is quite irrelevant if you use the same button or another one to toggle the process, because the processor is busy processing the loop.
The BackgroundWorker has a property called WorkerSupportsCancellation which needs to be true in this scenario. When the user clicks Stop you would invoke the CancelAsync method of the BackgroundWorker.
See MSDN for a good example. Also DreamInCode has a good tutorial which seems quite similar to your requirement.
Why not create two buttons, hide one when the other is visible? That should be a lot of easier to handle.
Or you can add a bool field to indicate which operation branch to execute.
One simple solution would be to add a boolean member to your form that is, e.g., true when the button says "Go" and false when the button says "Stop".
Then, in your button's event handler, check that boolean value. If the value is true, then start your operation and set the value to false when you change the button's text to say "stop". Vice-versa for the other case. :)
There are other techniques that I might prefer if this were production code, perhaps including considering the design of the form more carefully, but as this is clearly a learning exercise I believe that a simple boolean flag indicating the current state of the form is just what you're looking for.
Note that I would strongly discourage you from checking the value of the button text to determine what state the object is in. Whenever possible, as a general rule of good design, you want your visual state to be "decoupled" from your underlying object's state. That is to say, your visual widgets can depend on your underlying objects, but your underlying objects should not depend on your visual widgets. If you tested the text of the button, your underlying logic would depend on your visual state and that would violate this general rule.
If your problem is related to the fact that you can't cancel the operation while it's being performed, you'll want to look into using a BackgroundWorker to perform your long-running activity.
Another option would be to check the current text on your button to determine what to do:
void btnStartStop_Click(Object sender, EventArgs e)
{
if (btnStartStop.Text == "Go")
{
btnStartStop.Text = "Stop";
// Go code here
}
else
{
btnStartStop.Text = "Go";
// Stop code here
}
}
Are you getting your second button click event? Put a breakpoint in your click handler and run your code. When you click the second time, do you ever hit your breakpoint?
If your loop is running continuously, and it is in your button click handler, then your loop is running in the UI thread. You probably don't get to "see" the second button click until after the loop is completed. In addition to the branch code that you see above, try either inserting a DoEvents in your loop processing (this is a place where your loop will temporarly give up control so that messages can be processed). Or, (better) have a look at the backgroundworker class -- do most of your processing in a different thread, so that you UI can remain responsive to button clicks.
Cerebrus is right about using the Background Worker thread. However if you are doing a WPF app then it won't be able to update the UI directly. To get around this you can call Dispatcher.BeginInvoke on the main control/window.
Given code like:
Private Delegate Sub UpdateUIDelegate(<arguments>)
Private Sub CallUpdateUI(<arguments>)
control.Dispatcher.BeginInvoke(Windows.Threading.DispatcherPriority.Background, New UpdateUIDelegate(AddressOf UpdateUI), <arguments>)
End Sub
Private Sub UpdateUI(<arguments>)
'update the UI
End Sub
You can call CallUpdateUI from the Background Worker thread and it will get the main thread to perform UpdateUI.
You could set the Tag property on the button to a boolean indicating whether the next action should be "Stop" or "Go", and reset it each time you click the button. It's an Object property, though, so you'll have to cast it to bool when you read it.

How to determine whether a C# control is being unloaded?

In my C# Windows Forms application, I have a user control that contains other controls and does its own logic. One of them is a delayed call (Timer-invoked) that does certain things after the user has finished a keyboard input (live filter text). It accesses the other controls for this, one of them is that text input control. This method is invoked 500 ms after the last input event.
Now I have a problem when the delayed call is running while the application is terminating. When I enter some text, then wait about 500 ms (it seems to work every time) and then press Alt+F4 to close the window, the application throws a NullReferenceException while trying to access the text input control. This doesn't happen when I close the window immediately after the last input or a second or more after.
It seems that the control is being disposed or something and its methods cannot access the child controls anymore. So, when the control is being put in that state (by whomever and whatever that state exaclty is), those timer need to be stopped first so that the controls can be safely disposed.
I have already tried to stop the timer in the OnHandleDestroyed method (overridden) and at the beginning of the Designer-generated Dispose method. Nothing helped.
This procedure works fine in regular Forms when stopping the timers in the overridden OnFormClosed method, before calling base.OnFormClosed(). I just cannot find a suitable event in a user control.
Try this in your UserControl:
bool isDisposed;
protected override void Dispose(bool disposeManaged)
{
if(!isDisposed)
{
if(disposeManaged)
{
//Dispose your timer here
}
isDisposed = true;
}
}
Another possibility is that one of your UI classes doesn't do its cleanup. Eg. it registers itself for an event but doesn't deregister when it's manually disposed. It is never collected by the GC and when the event is fired for the next time, it tries to access some members that were set to null during the Dispose(...) call before.
Another possibility is that you have a more complex race condition within your code but it's hard to say from here.

Categories

Resources