How to catch TargetInvo​cationExce​ption raised from .Net BackgroundWorker in Matlab?

5 views (last 30 days)
I am writing a small application in Matlab using GUIDE. This application calls on a .Net library. The library connects to a serial device. Using a `BackgroundWorker`, the library polls the port for new data, and raises an `IncomingData` event whenever a new packet is received. (I know this because I used a decompiler to view the guts of the library.)
The problem is that the SDK I'm using didn't i implement the `RunWorkerCompleted` method properly It does not check to see if an exception occurred via the `e.Errors` property before accessing the `e.Result` property. This causes a TargetInvocationException to be thrown. This exception is going unhandled and causes Matlab to crash with the following event in the Windows event log. The inner exception is not serialized to the event log, so I don't know what's actually causing the failure.
Application: MATLAB.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Reflection.TargetInvocationException
Stack:
at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
at System.ComponentModel.RunWorkerCompletedEventArgs.get_Result()
at TargetInvocationIssueMVCE.BlackBox._backgroundWorker_RunWorkerCompleted(System.Object, System.ComponentModel.RunWorkerCompletedEventArgs)
at System.ComponentModel.BackgroundWorker.OnRunWorkerCompleted(System.ComponentModel.RunWorkerCompletedEventArgs)
at System.ComponentModel.BackgroundWorker.AsyncOperationCompleted(System.Object)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
I was able to replicate the behavior of the library that I'm using with the following C# class library. You can think of this `BlackBox` example below as the library that I cannot change.
using System;
using System.ComponentModel;
namespace TargetInvocationIssueMVCE
{
public class BlackBox
{
private BackgroundWorker _backgroundWorker;
public event EventHandler<EventArgs> IncomingData;
public void Connect()
{
_backgroundWorker = new BackgroundWorker()
{
WorkerSupportsCancellation = true
};
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
_backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted;
_backgroundWorker.RunWorkerAsync();
}
private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// BlackBox should check e.Errors first, but doesn't,
// so throws a TargetInvocationException that I can't seem to catch, so it crashes Matlab.
Console.Write(e.Result == null ? "Failure" : "Success");
}
private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
throw new InvalidOperationException("I could be any exception.");
// the real worker is supposed to raise IncomingData here.
}
}
}
I'm calling this library in a Matlab GUIDE GUI like this.
% --- Executes just before Figure1 is made visible.
function Figure1_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to Figure1 (see VARARGIN)
% load the library
NET.addAssembly('C:\path\to\TargetInvocationIssueMVCE.dll');
blackbox = TargetInvocationIssueMVCE.BlackBox();
handles.blackbox = blackbox;
addlistener(blackbox, 'IncomingData', @OnIncomingData);
% store the SerialConnection to use through out the form
handles.connection = connection;
% Choose default command line output for Figure1
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% ... some other irrelevant callbacks
% --- button click callback starts .Net BackgroundWorker process
function btnConnect_Callback(hObject, eventdata, handles)
try
handles.blackbox.Connect();
set(hObject, 'String', 'Disconnect');
catch ex
warning(ex.message);
set(hObject, 'Value', 1);
end
% --- Callback to process incoming data packets
function OnIncomingData(source, arg)
% It doesn't matter what I put here, the exception is raised before
% I ever get a packet event and Matlab crashes.
msgbox('Received Packet');
---
In .Net, if I really had to, I could set up a catch in my `static void Main()` method so that I could inspect the inner exception.
try
{
Application.Run(new Form1());
}
catch (TargetInvocationException exception)
{
System.Windows.Forms.MessageBox.Show(exception.InnerException.ToString());
}
I tried the same in Matlab by creating a Script to run the Figure, but it still did not catch the issue. It seems to somehow bypass the catch below. Matlab still crashes with the same event log that I get if I just double click `Figure1` to run it.
try
Figure1
catch ex
warning(ex.message)
end
So, I really don't know where to go from here. I know this is an XY problem. I don't really need to be able to catch this exception, but I *do*** need to be able to inspect the inner exception and I don't what else I can do to get a look at it.
---
Callbacks of all kinds are executed in the context of the base
workspace, not in the context of the routine that set the Callback
function. You can only "catch" the exceptions of statements you call
directly, not of functions automatically executed on your behalf
through a callback.
If this is true, it would explain why I can't catch the exception when creating the figure from a script. Am I screwed? Does this mean I can't catch this exception?

Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!