GUIDE を使用して Matlab で小さなアプリケーションを作成しています。このアプリケーションは、.Net ライブラリを呼び出します。ライブラリはシリアル デバイスに接続します。を使用してBackgroundWorker
、ライブラリは新しいデータのポートをポーリングしIncomingData
、新しいパケットを受信するたびにイベントを発生させます。(これは、逆コンパイラを使用してライブラリの内部を表示したためです。)
問題は、私が使用している SDK がメソッドを適切に実装しRunWorkerCompleted
ていないことです。e.Errors
プロパティにアクセスする前に、プロパティを介して例外が発生したかどうかを確認しませんe.Result
。これにより、TargetInvocationExceptionがスローされます。この例外は処理されず、Matlab がクラッシュし、Windows イベント ログに次のイベントが記録されます。内部例外はイベント ログにシリアル化されないため、実際に何が原因でエラーが発生しているのかわかりません。
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()
私が使用しているライブラリの動作を、次の C# クラス ライブラリで再現できました。BlackBox
以下の例は、私が変更できないライブラリと考えることができます。
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.
}
}
}
このライブラリは、このような Matlab GUIDE GUI で呼び出しています。
% --- 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);
% 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');
.Net では、どうしても必要な場合は、static void Main()
メソッドに catch を設定して、内部例外を調べることができました。
try
{
Application.Run(new Form1());
}
catch (TargetInvocationException exception)
{
System.Windows.Forms.MessageBox.Show(exception.InnerException.ToString());
}
Figure を実行するスクリプトを作成して Matlab で同じことを試みましたが、それでも問題は解決しませんでした。どういうわけか以下のキャッチをバイパスしているようです。Figure1
Matlab は、ダブルクリックして実行した場合と同じイベント ログでクラッシュします。
try
Figure1
catch ex
warning(ex.message)
end
だから、ここからどこへ行けばいいのか本当にわかりません。これは XY 問題であることはわかっています。この例外をキャッチできる必要はありませんが、内部例外を検査できる必要があり、それを見るために他に何ができるかわかりません。
この興味深い情報を見つけました。
すべての種類のコールバックは、Callback 関数を設定するルーチンのコンテキストではなく、ベース ワークスペースのコンテキストで実行されます。コールバックを通じて自動的に実行される関数ではなく、直接呼び出すステートメントの例外のみを「キャッチ」できます。
これが本当なら、スクリプトから図を作成するときに例外をキャッチできない理由を説明できます。私はめちゃくちゃですか?これは、この例外をキャッチできないということですか?