Tracking down a AccessViolationException in WPF

2019-05-16 23:34发布

问题:

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
}

回答1:

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