0

Can anyone explain why the following code works on some Win7 PC's but on some I get a MissingMethodException and the Timer.Elapsed event is never called.

Private Sub _timer2_Elapsed(ByVal sender As Object, ByVal e As System.EventArgs) Handles _timer2.Elapsed
    _timer2.Enabled = False
    Dispatcher.Invoke(Sub()
                          HandleSingleKeyPress(-1)
                      End Sub)
End Sub

After some investigation I have found that the following code works much better:-

Public Delegate Sub InvokedSubDelegate()
Private Sub _timer2_Elapsed(ByVal sender As Object, ByVal e As System.EventArgs) Handles _timer2.Elapsed
    _timer2.Enabled = False
    Dispatcher.Invoke(New InvokedSubDelegate(Sub()
                                                 HandleSingleKeyPress(-1)
                                             End Sub))
End Sub

Not sure why the first approach works only sometimes but hope the solution can help someone else with similar problems.

Jerry

Jerry
  • 393
  • 4
  • 8

1 Answers1

2

It doesn't sound like you are close to identifying the true problem. There certainly is more than one in that snippet.

A MissingMethodException is a DLL Hell problem. In other words, you are running your code with an old version of the assembly, one that doesn't yet have the method you are trying to call. You avoid DLL Hell by paying lots of attention when you deploy the assemblies. And by religiously incrementing the [AssemblyVersion]. In the VB.NET IDE that's done with Project + Properties, Application tab, Assembly Information button. This does explain why the 2nd snippet doesn't seem to have this problem, you are just less likely to be running with that old version of the assembly.

This does end up rather poorly when you use the System.Timers.Timer class. It is a nasty class. In a highly uncharacteristic lapse of judgement, Microsoft decided to swallow all exceptions that are raised in the Elapsed event handler. Which explains why the timer appears to be stop working, it just won't do what you asked it to do when the exception aborts the code. Favor the System.Threading.Timer class, it doesn't swallow exceptions. Or always using try/catch inside the Elapsed handler, albeit that it is pretty hard to figure out what to do when you catch. Environment.Exit() is wise.

But most of all, you are just using the entirely wrong timer. There's no point in using an asynchronous one when you make it synchronous again by using Dispatcher.Begin/Invoke(). Simply use a DispatcherTimer instead. Gets you the exact same outcome, minus the nastiness and overhead. And the need to ask this question.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I used dispatcher.timer initially but I'm trying to detect a double click by measuring the click interval it was too course. I also tried the threading.timer after reading your comments in other posts. I still got the same exception. – Jerry Feb 18 '14 at 23:14
  • 1
    It makes no sense at all to use a System.Timers.Timer to measure click intervals. You of course use a mouse event, that tells you that the mouse was clicked. And an accurate interval timer to see how long it takes, Stopwatch. Pretty important that you state your goals in your question. – Hans Passant Feb 18 '14 at 23:18
  • My goal was to understand why wrapping the llambda function in a delegate makes a BIG difference but only on some systems. I accept I could use a StopWatch and avoid the use of Invoke but that just works around the problem. I dont think that this has anything to do with my use of Timers at all. I also have this code:- – Jerry Feb 19 '14 at 09:31
  • 1
    I specifically addressed that in the answer. Programmers tend to assume that a failure is explained by a single and directly identifiable cause. .NET certainly encourages this thinking. Gets to be hard to diagnose when there's a house of cards that topples over from removing one card and you only see the last card fall. Bad file => exception => no message => code doesn't work => change code => no bad file anymore => code starts working for no perceivable reason. The bad card in the middle here is System.Timers.Timer – Hans Passant Feb 19 '14 at 09:45