views:

588

answers:

1

I've written a WPF application that uses many Frame controls to view camera feeds. When deployed, it crashes pretty randomly (anywhere from 2 hours to 16+ hours), and I see these in the event log, consecutively:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.Run() at System.Windows.Application.RunDispatcher(Object ignore) at System.Windows.Application.RunInternal(Window window) at System.Windows.Application.Run(Window window) at System.Windows.Application.Run() at Status_Station_client.MainClass.Main()

Faulting application status station client.exe, version 1.0.0.0, stamp 4ad0faa5, faulting module msvfw32.dll, version 5.1.2600.2180, stamp 41109753, debug? 0, fault address 0x00002642.

Any ideas on how to track this down? The web pages do contain ActiveX controls, so a first guess is there's a problem there.

I haven't been able to trace this in Debug mode. Another thing I have thought of trying is swallowing the exception from the navigation call, but am unsure if this is a wise thing to do:

try
{
    if (Frame1 != null)
        Frame1.Source = new Uri(uriWithResolution);
}
catch (AccessViolationException ex)
{
    // log message
}

EDIT: Here's some more source code, I'm stumped as to where the error is (i.e. where the exception is being thrown)

MatrixView.cs:

public partial class MatrixView : Window
{
    System.Timers.Timer timer;
    int pageNumber = 0;
    IEnumerable<List<CameraInfo>> _cameraList;
    GlobalSettings _globalSettings;
    Screen _screen;

    public MatrixView(List<CameraInfo> cameras, int pageFlipInterval, int camerasPerPage, GlobalSettings globalSettings, Screen screen)
    {
        InitializeComponent();
        _globalSettings = globalSettings;
        _screen = screen;
        _cameraList = Partition<CameraInfo>(cameras, camerasPerPage);

        this.Dispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(Dispatcher_UnhandledException);

        displayCameras();

        timer = new System.Timers.Timer(pageFlipInterval * 1000); // interval (in seconds) * 1000 ms / s
        timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
        timer.Enabled = true;

        this.KeyUp += new System.Windows.Input.KeyEventHandler(MatrixView_KeyUp);

        if (globalSettings.FullScreenOnLoad)
        {
            this.WindowStyle = WindowStyle.None;
        }
    }

    void MatrixView_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (this.WindowStyle == WindowStyle.None)
        {
            if (e.Key == Key.F11 || e.Key == Key.Escape)
            {
                this.WindowStyle = WindowStyle.SingleBorderWindow;

            }
        }
        else
        {
            if (e.Key == Key.F11)
            {
                this.WindowStyle = WindowStyle.None;
            }
        }
        this.WindowState = WindowState.Maximized;

    }

    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new ThreadStart(delegate()
        {
            displayCameras();

        }));

    }

    void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        EventLog.WriteEntry("Matrix Monitor", string.Format("Unhandled exception from Matrix Dispatcher\r\nMessage: {0}\r\nSource: {1}\r\nInnerException: {2}\r\nStack Trace: {3}\r\nFull String: {4}", e.Exception.Message, e.Exception.Source, e.Exception.InnerException, e.Exception.StackTrace, e.Exception.ToString()));
        e.Handled = true;
    }

    private void displayCameras()
    {
        foreach (var child in uniformGrid1.Children)
        {
            FrameTimer c = child as FrameTimer;
            if (c != null)
            {
                c.Dispose();
                c = null;
            }
        }
        GC.Collect();
        GC.WaitForPendingFinalizers();

        uniformGrid1.Children.Clear();
        List<CameraInfo> camerasInPage = _cameraList.ElementAt(pageNumber);
        int numCameras = camerasInPage.Count;

        int sqrtOfCameras = (int) Math.Sqrt(numCameras);
        double height = _screen.Bounds.Height / sqrtOfCameras;
        double width = _screen.Bounds.Width / sqrtOfCameras;
        foreach (CameraInfo camera in camerasInPage)
        {
            uniformGrid1.Children.Add(new FrameTimer(camera, _globalSettings, height, width));
        }
        pageNumber++;
        if (pageNumber >= _cameraList.Count<List<CameraInfo>>())
        {
            pageNumber = 0;
        }



    }
    public static IEnumerable<List<T>> Partition<T>(IList<T> source, int size)
    {
        int remainder = source.Count % size == 0 ? 0 : 1;
        for (int i = 0; i < (source.Count / size) + remainder; i++)        
            yield return new List<T>(source.Skip(size * i).Take(size)); 
    }
}

FrameTimer.cs:

public partial class FrameTimer : UserControl, IDisposable
{

    System.Timers.Timer timer;
    string _uri;
    string _noImageUrl;
    bool? _successState = null;
    GlobalSettings _globalSettings;
    CameraInfo _camera;
    Ping ping;
    double _height;
    double _width;

    public FrameTimer(CameraInfo camera, GlobalSettings globalSettings, double height, double width)
    {
        InitializeComponent();

        _noImageUrl = AppDomain.CurrentDomain.BaseDirectory + "noImage.jpg";
        _globalSettings = globalSettings;
        _camera = camera;
        _height = height;
        _width = width;

        _uri = string.Format("http://{0}:{1}/LiveView.aspx?camera={2}", globalSettings.ServerIPAddress, globalSettings.ServerPort, camera.camName);
        this.Dispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(Dispatcher_UnhandledException);

        setUrl();

        timer = new System.Timers.Timer(_globalSettings.PingInterval * 1000); 
        timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
        timer.Enabled = true;

    }

    void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        EventLog.WriteEntry("Matrix Monitor", string.Format("Unhandled exception from Frame Dispatcher\r\nMessage: {0}\r\nSource: {1}\r\nInnerException: {2}\r\nStack Trace: {3}\r\nFull String: {4}", e.Exception.Message, e.Exception.Source, e.Exception.InnerException, e.Exception.StackTrace, e.Exception.ToString()));
        e.Handled = true;
    } 


    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        this.Dispatcher.BeginInvoke(DispatcherPriority.Send, new ThreadStart(delegate()
            {
                setUrl();
            }));
    }

    private void setUrl()
    {
        ping = new Ping();
        ping.PingCompleted += new PingCompletedEventHandler(ping_PingCompleted);
        videoChecks checks = new videoChecks();

        string ipAddressToUse = checks.isIPInternal(_camera.camIP) ? _camera.camIP : _camera.camExtIP;
        ping.SendAsync(ipAddressToUse, 1000, null);
    }

    void ping_PingCompleted(object sender, PingCompletedEventArgs e)
    {
        try
        {
            if (e.Reply.Status == IPStatus.Success)
            {
                if (_successState == null || _successState == false)
                {
                    _successState = true;
                    string uriWithResolution = string.Format("{0}&res={1}x{2}&header=0", _uri, (int)_width, (int)_height);

                    if (Frame1 != null)
                        Frame1.Source = new Uri(uriWithResolution);
                }
            }
            else
            {
                if (_successState == null || _successState == true)
                {
                    _successState = false;
                    Image1.Source = new BitmapImage(new Uri(_noImageUrl));
                }
            }
        }
        catch (ObjectDisposedException ex)
        {
            Dispose();
        }
        finally
        {
            ((IDisposable)sender).Dispose();
        }

    }

    #region IDisposable Members

    public void Dispose()
    {
        if (timer != null)
        {
            timer.Elapsed -= new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.Enabled = false;
            timer.Dispose();
            timer = null;
        }

        Frame1.Source = null;

        if (ping != null)
        {
            ping.PingCompleted -= new PingCompletedEventHandler(ping_PingCompleted);
            ((IDisposable)ping).Dispose();
            ping = null;
        }
    }

    #endregion
}
+2  A: 

If you look at the faulting module at the bottom your stacktrace, you will see msvfw32.dll. This is not a DLL used by WPF, so I assume it's coming from some active-x within a web page you are loading. I'm even more convinced of that due to your code implying something dealing with cameras/video and msvfw32 deals with video (its very old too!!). It's showing up in the Dispatcher loop because the Dispatcher also handles a Win32 message loop, that is ultimately used by the alleged activex.

Also, try checking for the exception here, maybe you can set the argument Handled=true

Jeremiah Morrill
@Jeremiah Yeah, I think the culprit is in the ActiveX control as well. I have Dispatcher.UnhandledException in the main class, the matrixview class, and the frametimer class. The main class is the one that appears to catch it, I think I may have forgotten to set Handled=true there, wonder if that would work :)I'm a little confused about how the Dispatcher works. Does one thread handle the Dispatcher for all the objects created on the same thread? And the Win32 message loop is on that same thread as well?
David Hodgson
The WPF Dispatcher handles both the managed queue of "work" and processes the win32 message loop. Win32 messages and .NET delegates are interleaved when processed based on priorities. The reason it even handles the Win32 message pump is for handling low level things (ie dragging the WPF window, getting mouse info from the os, etc) and also driving any Win32 components (such as an activex).
Jeremiah Morrill
@Jeremiah I was mistaken, the app.DispatcherUnhandledException doesn't catch it; only the AppDomain.CurrentDomain.UnhandledException event sees it.
David Hodgson
You may have to startup your application's Dispatcher yourself. Shouldn't be too hard. You just have to remove your StartUri property from your App.xaml and override OnStartup in App.xaml.cs. Inside there, try creating your window, do a .Show, then do a Dispatcher.Run, all within a try/catch block. If it throws an error, try rerunning the Dispatcher.Run
Jeremiah Morrill