views:

283

answers:

2

Matlab provides a COM interface that supports remote execution of arbitrary functions (and code snippets). In particular, it has an Feval method that calls a given Matlab function. The third parameter to this method, pvarArgOut, has COM type VARIANT*, and appears in the Visual Studio F# editor as an argument of type:

pvarArgOut: byref<obj>

The following code calls interp1, which in Matlab returns a matrix (i.e. 2D double array) result, as is normal for most Matlab functions.

let matlab = new MLApp.MLAppClass()

let vector_to_array2d (v : vector) = Array2D.init v.Length 1 (fun i j -> v.[i])

let interp1 (xs : vector) (ys : vector) (xi : vector) =
    let yi : obj = new obj()
    matlab.Feval("interp1", 1, ref yi, vector_to_array2d xs, vector_to_array2d ys, vector_to_array2d xi)
    yi :?> float[,]

This code compiles fine, but when calling interp1, I get a COM exception:

A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
A first chance exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll
An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll

Additional information: Invalid callee. (Exception from HRESULT: 0x80020010 (DISP_E_BADCALLEE))

I get the same error whether initialize yi with a new obj, a new Array2D, or null.

How does F# translate VARIANT output arguments?

+1  A: 

The article F Sharp And MATLAB on StrangeLights.com describes using MATLAB from F# v1.1.5 and F# PowerPack.

The missing step is to create an interoperability dll using tlbimp eg

tlbimp "c:\Program Files\MATLAB\R2006a\bin\win32\mlapp.tlb"

then within F# import this dll with

'#r "Interop.MLApp.dll"'

Matt McDonnell
Thanks Matt; I'd seen the article - it's a good article, and it got me started, but it doesn't cover the use of Feval. I've already created the interoperability DLL and added it as a project reference, so that can't be it...
Matthew
Oops, sorry for thinking it was that simple. I've just had a quick look and reproduce the behavior but haven't got any closer to a solution.
Matt McDonnell
A: 

You don't want ref yi, you want

let mutable yi = new obj()
thatfunc(..., &yi, ...)

though I think that alone will not fix it. Perchance is there a C# sample of calling this particular API?

Brian
This works! - with a small modification to initialize yi to null rather than a new obj(). After the call, the yi variable contains an object array with the first element set to a 2-dimensional double array. Perfect. Thanks Brian!
Matthew
Hi Matthew, could you please add fully working example? Thanks in advance.
Oldrich Svec