Wireless Communication Library Support Forum

Frameworks => Bluetooth Framework => Topic started by: zach.green on June 01, 2015, 08:47:25 PM

Title: System.AccessViolationException was unhandled
Post by: zach.green on June 01, 2015, 08:47:25 PM
I am receiving the following error when my application closes:

System.AccessViolationException was unhandled
Message: An unhandled exception of type 'System.AccessViolationException' occurred in wcl.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

This error seems very similar to this issue, but I can't tell from this topic what the resolution is: http://forum.btframework.com/index.php/topic,1923.msg6660.html#msg6660.

On creation of my app, I initialize my adapter like so:

       
        public WclAdapter()
        {
            _wclApi = new wclAPI();
            _wclApi.Load();

            _wclBluetoothDiscovery = new wclBluetoothDiscovery();
            _wclBluetoothDiscovery.OnDiscoveryStarted += wclBluetoothDiscovery_OnDiscoveryStarted;
            _wclBluetoothDiscovery.OnDiscoveryComplete += async (sender, args) => await wclBluetoothDiscovery_OnDiscoveryComplete(sender, args);
            _wclBluetoothDiscovery.OnDeviceFound += async (sender, args) => await wclBluetoothDiscover_OnDeviceFound(sender, args);
            _wclBluetoothDiscovery.OnDeviceLost += async (sender, args) => await wclBluetoothDiscover_OnDeviceLost(sender, args);
        }


On exit, I call the following:

        public void Shutdown()
        {
            _isShuttingDown = true;

            _wclApi.Unload();

            _wclBluetoothDiscovery.Dispose();
            _wclApi.Dispose();
        }


Any ideas to what would cause this error? I am using version 6.14.3.0.

Thanks.
Zach Green
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 01, 2015, 09:47:58 PM
Hello,

You can not use async await with WCL events.
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 01, 2015, 09:49:43 PM
Removing async/await has no affect on the problem.
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 01, 2015, 10:01:36 PM
Is it possible this is related to me trying to use this in a WPF application? Is the library supported in WPF?
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 01, 2015, 10:02:37 PM
Removing async/await has no affect on the problem.

Would be great to see event handlers code. Problem may be there.
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 01, 2015, 10:04:19 PM
Is it possible this is related to me trying to use this in a WPF application? Is the library supported in WPF?

In fact we have never tested it but I do not see any reason why it can not. I think WCL should work with WPF
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 01, 2015, 10:12:33 PM
Seems strange that these event handlers would affect an error thrown when I close the app. Below is most of the life cycle from constructor and events. The scancallback basically just saves some info to the db, and then calls connect if the device was previously connected.



        public WclAdapter()
        {
            _wclApi = new wclAPI();
            _wclApi.Load();

            _wclBluetoothDiscovery = new wclBluetoothDiscovery();
            _wclBluetoothDiscovery.OnDiscoveryStarted += wclBluetoothDiscovery_OnDiscoveryStarted;
            _wclBluetoothDiscovery.OnDiscoveryComplete += wclBluetoothDiscovery_OnDiscoveryComplete;
            _wclBluetoothDiscovery.OnDeviceFound += wclBluetoothDiscover_OnDeviceFound;
            _wclBluetoothDiscovery.OnDeviceLost += wclBluetoothDiscover_OnDeviceLost;
        }

        public void Connect(string address, int messageSize, Action onConnected, Action<byte[]> onMessage, Action<BluetoothError> onError)
        {
            //fire connecting event
            if (Connecting != null)
            {
                Connecting(this, new DeviceStatusEventArgs { Address = address });
            }


            //try to clear client if it exists already
            if (_clients.ContainsKey(address))
            {
                wclClient client;
                if (!_clients.TryRemove(address, out client))
                {
                    if (Error != null)
                    {
                        Error(this, new DeviceStatusEventArgs { Address = address, Message = "Unable to clear old bluetooth client." });
                    }
                }
            }

            //setup call backs
            var bc = new wclClient();
            if (!_clients.TryAdd(address, bc))
            {
                if (Error != null)
                {
                    Error(this, new DeviceStatusEventArgs { Address = address, Message = "Unable to save new bluetooth client." });
                }
            }

            bc.OnDisconnect += (sender, args) =>
            {
                if (Disconnected != null && !_isShuttingDown)
                {
                    Disconnected(this, new DeviceStatusEventArgs { Address = address });
                }
            };

            bc.OnData += (sender, args) =>
            {
                //buffer data till full message received
                foreach (var b in args.Data)
                {
                    _buffer.Add(b);
                    if (b != Convert.ToByte('\n') || _buffer.Count != messageSize)
                    {
                        continue;
                    }

                    onMessage(_buffer.ToArray());
                    _buffer.Clear();
                }
            };

            bc.OnConnect += (sender, args) =>
            {
                //if it didn't complete, bounce it back to disconnect
                if (args.Error != wclErrors.WCL_E_SUCCESS)
                {
                    if (Error != null)
                    {
                        Error(this, new DeviceStatusEventArgs { Address = address, Message = wclErrors.wclGetErrorMessage(args.Error) });
                    }

                    bc.Disconnect();
                    return;
                }

                //fire connected event
                if (Connected != null)
                {
                    Connected(this, new DeviceStatusEventArgs { Address = address });
                }
            };

            //start connection
            var radio = GetSelectedRadio(_wclBluetoothDiscovery);
            if (radio != null)
            {
                bc.BluetoothParams.Address = string.Format("({0})", address);
                bc.BluetoothParams.Radio = radio;
                bc.BluetoothParams.Service = wclUUIDs.SerialPortServiceClass_UUID;
                bc.Transport = wclTransport.trBluetooth;
                bc.ConnectTimeout = 30000; //ms
                var errorCode = bc.Connect();
               
                //if it didn't complete, bounce it back to disconnect
                if (errorCode != wclErrors.WCL_E_SUCCESS)
                {
                    if (Error != null)
                    {
                        Error(this, new DeviceStatusEventArgs { Address = address, Message = wclErrors.wclGetErrorMessage(errorCode) });
                    }

                    bc.Disconnect();
                }
            }
        }

        public void StartScan(IScanCallback scanCallback, bool toggleRadios = true)
        {
            WriteDiagnosticEntryAction("Beginning scan of devices");
            IsScanning = true;
            if (ScanStarted != null)
            {
                ScanStarted(this, EventArgs.Empty);
            }

            ScanCallback = scanCallback;

            var radio = GetSelectedRadio(_wclBluetoothDiscovery);
            if (radio != null)
            {
                var errorCode = _wclBluetoothDiscovery.Discovery(radio);

                if (errorCode != wclErrors.WCL_E_SUCCESS)
                {
                    if (ScanError != null)
                    {
                        ScanError(this, new ScanErrorEventArgs { Message = wclErrors.wclGetErrorMessage(errorCode) });
                    }
                }
            }
        }

        private wclBluetoothRadio GetSelectedRadio(wclBluetoothDiscovery discovery)
        {
            wclBluetoothRadio radio = null;
            var radios = new wclBluetoothRadios();
            if (discovery.EnumRadios(radios) == wclErrors.WCL_E_SUCCESS && radios.Count > 0)
            {
                radio = new wclBluetoothRadio();
                radio.Assign(radios[0]);
            }
            if (radio == null)
            {
                if (Error != null)
                {
                    Error(this, new DeviceStatusEventArgs { Address = null, Message = "No Bluetooth API was found." });
                }
            }
            return radio;
        }

        private void wclBluetoothDiscovery_OnDiscoveryComplete(object sender, wclBluetoothDiscoveryCompleteEventArgs e)
        {
            if (ScanCallback != null)
            {
                var count = e.Devices.Count;
                var devices = new List<WclDevice>((int)count);
                for (var i = 0U; i < count; i++)
                {
                    string name = null;
                    e.Devices.GetName(e.Radio, ref name);
                    devices.Add(new WclDevice(name, e.Devices.Address.Replace("(", string.Empty).Replace(")", string.Empty), 0, new byte[] { }));
                }

                foreach (var device in devices)
                {
                    ScanCallback.Callback(device);
                }
            }

            WriteDiagnosticEntryAction("Completed scan of devices");
            IsScanning = false;
            if (ScanCompleted != null)
            {
                ScanCompleted(this, EventArgs.Empty);
            }
        }

        private void wclBluetoothDiscovery_OnDiscoveryStarted(object sender, wclBluetoothDiscoveryStartedEventArgs e)
        {
            IsScanning = true;
            if (ScanStarted != null)
            {
                ScanStarted(this, EventArgs.Empty);
            }
        }

        private void wclBluetoothDiscover_OnDeviceLost(object sender, wclBluetoothDiscoveryDeviceEventArgs args)
        {
            WriteDiagnosticEntryAction(string.Format("Device Lost, {0}", args.Device.Address));
        }

        private void wclBluetoothDiscover_OnDeviceFound(object sender, wclBluetoothDiscoveryDeviceEventArgs args)
        {
            WriteDiagnosticEntryAction(string.Format("Device Found, {0}", args.Device.Address));
        }
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 01, 2015, 10:20:43 PM
Possible problem is here

var count = e.Devices.Count;

in OnDiscoveryComplete event handler.

If discovering is active when you close your application e.devices is NULL.

Also

e.Devices.GetName(e.Radio, ref name);

should look like

e.Devices.GetName(e.Radio, ref name);
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 01, 2015, 10:29:39 PM
Added a check for null on e.Devices; no change.

I noticed your demo apps all fire the Trial warning on close of the app, but mine doesn't. I am not sure if that is a result of the error, or if the error is occurring when the library is trying to open the warning.
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 01, 2015, 10:31:20 PM
Also, I don't see a difference in the two lines of your comment:

Also

e.Devices.GetName(e.Radio, ref name);

should look like

e.Devices.GetName(e.Radio, ref name);


Thanks for all of your help.
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 01, 2015, 10:33:32 PM
Added a check for null on e.Devices; no change.

I noticed your demo apps all fire the Trial warning on close of the app, but mine doesn't. I am not sure if that is a result of the error, or if the error is occurring when the library is trying to open the warning.

Send me your code to mike@btframework.com. I'll find the bug. The problem that when you call wclAPI.Unload it shows dialog and closes all connections/terminates all operations/destroys object. So the problem appears in one of event handler. It is hard to find the bug without all the code.
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 01, 2015, 10:34:21 PM
Also, I don't see a difference in the two lines of your comment:

Also

e.Devices.GetName(e.Radio, ref name);

should look like

e.Devices.GetName(e.Radio, ref name);


Thanks for all of your help.

I think that is a forum problem :) Should be Devices [ i ] but forum deleted [ i ] in your and in my code (I think).
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 01, 2015, 10:38:03 PM
Yes it did. The index into the array is in my code.

Sending all the code isn't real simple. This is a Xamarin project in which I have an iOS, Android, and WPF UI for a single PCL implementation. The project also uses MVVMCross to handle cross platform implementation features. For example, I am testing out your library as our WPF implementation for Bluetooth. Without a Xamarin license, I don't know that you can open project. I'll have to see if I can create a project tomorrow that shows the issue without the Xamarin integration.
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 01, 2015, 10:47:27 PM
May be then just a part which uses WCL? At least I can review it. The problem may apper when you call wclAPI.Unload. This method terminates all active WCL operations and after that call WCL objects become invalid. Also some events may fire (such us OnDiscoveryComplete, OnConnect, OnDisconnect). After that application terminates and GC disposes object. That may cause AV. I already saw such issue in other projects so problem can be in just one code line.

But all that happens after Trial Dialog appeared.

The other possible problem is your wrapper. If you do not dispose your wrapper when your application closes it will be disposed by GC. But application already closed/partially disposed and wclAPI.Unload cause the AV by reasons I described above.
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 02, 2015, 01:39:34 PM
Ok. I am guessing it is probably something in the order of operations. I'll try to track down if I am leaving something open. The full source of my WclAdapter is attached. This is where all of the WCL code resides.

[attachment deleted by admin]
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 02, 2015, 02:06:11 PM
Hello,

All the code looks absolutely correct (at first look). I will try to write test app around your Adapter and reproduce the issue. I will keep you updated.
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 02, 2015, 04:00:15 PM
I was able to extract as little of the code as possible to create a similar project with the same error. The app doesn't do much, but if you run the app and then try to close app, you should get the error.

Thanks again for all of your help.
Zach

[attachment deleted by admin]
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 02, 2015, 04:10:31 PM
WclAdapter.Shutdown has never called, so wclAPI.Unload has never called. That causes AV
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 02, 2015, 04:11:35 PM
Found the problem using the simplified project. Just a dumb mistake. I had an extra instance of the WclAdapter that isn't used and it wasn't being closed out.


Line 17 in WclAdapter: protected static WclAdapter Instance = new WclAdapter();

Deleted the line, and no more error.


Edit: Shutdown is being called in the simplified project from MainWindow's closing event. My original Zip was missing that, but I updated it.
Title: Re: System.AccessViolationException was unhandled
Post by: zach.green on June 02, 2015, 04:14:24 PM
Thanks again for all of your help. Great service.
Title: Re: System.AccessViolationException was unhandled
Post by: Mike Petrichenko on June 02, 2015, 04:18:08 PM
Yes, just found that too. Any way, great that now all works as expected.

You are very welcome.