Matlab:如何从外部API调查已编译的M代码进度? [英] Matlab: How to survey compiled m-code progression from external API?
问题描述
我的问题非常特定于matlab编译器和运行时的奥秘.因为只有熟悉matlab运行时API的人才能回答,所以我缩短了很多细节.请让我知道我是否应该更详细.
My question is extremely specific to the arcanes of the matlab compiler and runtime. As only people familiar with matlab runtime API may answer, I shortened much details. Please let me know if I should be more verbose.
使用matlab编译器&运行时,我可以从C#程序中调用用m代码编写的函数.假设致电:
Using the matlab compiler & runtime I can call a function written in m-code from a C# program. Let's say calling:
function [result] = foo(n)
%[
result = 0;
for k = 1:n,
pause(1.0); % simulate long processing
result = result + 42;
end
%]
with(在C#代码中某些dllimport的后面):
with (somewhere behind some dllimports in the C# code):
mclFeval(IntPtr inst, string name, IntPtr[] plhs, IntPtr[] prhs)
到目前为止,很好,我对此没有任何问题(即初始化运行时,加载".cft"文件,使用.Net类型来回编组MxArray等)
So far, so good, I have no issue with this (i.e intializing the runtime, loading the '.cft' file, marshalling back and forth MxArray with .Net types, etc...)
我想使用一些cancel
和progress
回调调查foo
函数的进度:
I would like to survey the progression of my foo
function using some cancel
and progress
callbacks:
function [result] = foo(n, cancelCB, progressCB)
%[
if (nargin < 3), progressCB = @(ratio, msg) disp(sprintf('Ratio = %f, Msg = %s', ratio, msg)); end
if (nargin < 2), cancelCB = @() disp('Checking cancel...'); end
result = 0;
for k = 1:n,
if (~isempty(cancelCB)),
cancelCB(); % Up to the callback to raise some error('cancel');
end;
if (~isempty(progressCB)),
progressCB(k/n, sprintf('Processing (%i/%i)', k, n));
end
pause(1.0); % simulate long processing
result = result + 42;
end
%]
但是我当然希望这些回调在C#代码中,而不是在m-one中.
But of course I would like these callbacks to be in the C# code, not within the m-one.
-
查看"mclmcr.h"头文件,看来这些功能可能有所帮助:
Looking at 'mclmcr.h' header file, it looks like these functions may be of help:
extern mxArray* mclCreateSimpleFunctionHandle(mxFunctionPtr fcn);
extern bool mclRegisterExternalFunction(HMCRINSTANCE inst, const char* varname, mxFunctionPtr fcn);
不幸的是,这些完全没有文档记录,我发现没有可以模仿的用例来理解它们的工作原理.
Unfortunatly these are fully undocumented and I found no use case I could mimic to understand how they work.
我还考虑过用C#创建一个COM可见对象并将其作为参数传递给Matlab代码:
I've also thought about creating a COM visible object in C# and pass it as a parameter to the matlab code:
// Somewhere within C# code:
var survey = new ComSurvey();
survey.SetCancelCallback = () => { if (/**/) throw new OperationCancelException(); };
survey.SetProgressCallback = (ratio, msg) => { /* do something */ };
function [result] = foo(n, survey)
%[
if (nargin < 2), survey = []; end
result = 0;
for k = 1:n,
if (~isempty(survey)),
survey.CheckCancel(); % up to the COM object to raise exception
survey.SetProgress(k/n, sprintf('Processing... %i/%i', k, n));
end
pause(1.0); % simulate long processing
result = result + 42;
end
%]
我对创建数字和结构数组的函数非常熟悉,并且知道如何使用它们:
I'm very familiar with functions to create numeric and structure arrays and know how to use them:
extern mxArray *mxCreateNumericArray(...)
extern mxArray *mxCreateStructArray(...)
无论如何,我不知道如何将COM对象打包到MxArrays中?
Anyhow, how COM objects are packaged to MxArrays, I don't know?
进一步调查
第1天
即使仍然不稳定,我还是成功让matlab回调到我的C#代码中,看来mclCreateSimpleFunctionHandle
是前进的方向.
Even if still unstable, I succeeded to have matlab to callback into my C# code and it seems that mclCreateSimpleFunctionHandle
is the direction to go.
注意:以下代码仅供参考.它可能不适合您自己的情况.稍后,我将提供更简单的代码(即,一旦我获得稳定的解决方案).
-
看
mxFunctionPtr
的签名,我创建了两个这样的代表:
Looking to the signature of the
mxFunctionPtr
, I created two delegates like this:
// Mimic low level signature for a Matlab function pointer
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
delegate void MCRInteropDelegate(int nlhs, IntPtr[] plhs, int nrhs, IntPtr[] prhs);
和
// Same signature (but far more elegant from .NET perspective)
delegate void MCRDelegate(MxArray[] varargouts, MxArray[] varargins);
我也这样链接到运行时:
I also linked to the runtime like this:
[DllImport("mclmcrrt74.dll", EntryPoint = "mclCreateSimpleFunctionHandle", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
static extern IntPtr _mclCreateSimpleFunctionHandle(MCRInteropDelegate fctn);
假定MxArray
是我的.NET类,仅封装了mxArray*
句柄,然后我将这样的委托编组:
Assuming MxArray
is a .NET class of mine that simply encapsulate for mxArray*
handles, I then marshaled my delegates like this:
// Create MxArray from corresponding .NET delegate
static MxArray CreateFromDelegate(MCRDelegate del)
{
// Package high level delegate signature to a 'dllimport' signature
MCRInteropDelegate interopDel = (nlhs, plhs, nrhs, prhs) =>
{
int k = 0;
var varargouts = new MxArray[nlhs];
var varargins = new MxArray[nrhs];
// (nrhs, prhs) => MxArray[] varargins
Array.ForEach(varargins, x => new MxArray(prhs[k++], false)); // false = is to indicate that MxArray must not be disposed on .NET side
// Call delegate
del(varargouts, varargins); // Todo: varargouts created by the delegate must be destroyed by matlab, not by .NET !!
// MxArray[] varargouts => (nlhs, plhs)
k = 0;
Array.ForEach(plhs, x => varargouts[k++].getPointer());
};
// Create the 1x1 array of 'function pointer' type
return new MxArray(MCRInterop.mclCreateSimpleFunctionHandle(interopDel));
}
最后,假设module
是MCRModule
的一个实例(同样是一类我的类,用于将hInst*
封装在低级mclFeval
API中),我能够调用foo
函数并让它像这样输入我的.NET cancel
委托:
Finally, assuming module
is an instance of MCRModule
(again, a class of mine to encapsulate hInst*
in low level mclFeval
API), I was able to call foo
function and have it to enter my .NET cancel
delegate like this:
// Create cancel callback in .NET
MCRDelegate cancel = (varargouts, varargins) =>
{
if ((varargouts != null) && (varargouts.Length != 0) { throw new ArgumentException("'cancel' callback called with too many output arguments"); }
if ((varargins != null) && (varargins.Length != 0) { throw new ArgumentException("'cancel' callback called with too many input arguments"); }
if (...mustCancel...) { throw new OperationCanceledException(); }
}
// Enter the m-code
// NB: Below function automatically converts its parameters to MxArray
// and then call low level mclFeval with correct 'mxArray*' handles
module.Evaluate("foo", (double)10, cancel);
此.NET代码工作正常,并且foo
确实正确地回调了cancel
委托.
This .NET code worked fine, and foo
really made callback to the cancel
delegate properly.
唯一的问题是它非常不稳定.我的猜测是,我使用了太多的匿名函数,并且其中一些可能为时过早……
Only problem, is that it is quite unstable. My guess is that I used too many anonymous functions, and probably some of them are disposed too early ...
将尝试在接下来的几天内提供稳定的解决方案(希望能提供更简单的代码,以便在您自己的环境中进行读取和复制粘贴,以便立即进行测试).
Will try to provide with stable solution within the next few days (hopefully with simpler code to read and copy-paste in your own context for immediate testing).
如果您认为我使用mclCreateSimpleFunctionHandle
走错了方向,请告诉我.
Please let me know if you think I'm going the wrong direction with mclCreateSimpleFunctionHandle
.
推荐答案
知道了
mclCreateSimpleFunctionHandle
实际上是调用正确的API函数,以创建一个数组变量(在matlab方面),该数组变量持有一个函数指针(在外部).现在,我可以编译m代码以回调到我的C#代码中,以进行取消和升级.
mclCreateSimpleFunctionHandle
was effectively the right API function to call at in order to create an array variable (on matlab's side) holding for a function pointer (on external's side). I'm now able to have compiled m-code to call back into my C# code for cancellation and progression purposes.
在此处
这篇关于Matlab:如何从外部API调查已编译的M代码进度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!