COM question

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

COM question

Pieter Emmelot-2
Hi Smalltalkers,
I'm trying to use Dolphin's COM interface to communicate with MATLAB. The
MATLAB Visual Basic examples look so simple, I though it was a piece of cake
but it turned out not to be not so easy. As far as I can see I have two
problems;
    A - I need to pass an empty SafeArray. In Visual Basic this is  "Dim A()
As Double" but in Dolphin? The closed I could get after some trail and error
is "SAFEARRAY length: -1 elementClass: elementClass: DOUBLE" (length: 0
isn't regarded as empty). To make this work I needed to modify
SAFEARRAY>>copy to handle this empty array. It seems to work for copying
data from Dolphin to MATLAB but I'm not sure about it.
    B - In the VB example the client code creates the array, passes it to
MATLAB which fills it with data. On inspection the result only contains
zero's. I suspect I should add an indirection (pointer) because now it looks
like the whole SAFEARRAY is copied by Dolphin before passing to MATLAB so
MATLAB writes in a copy of the array which I never get to see again. Is this
correct? If so how do I do this?

Thanks,
Pieter Emmelot


The VB example to copy a matrix to a SAFEARRAY looks like this:
    Option Base 1
    Dim MatLab As Object
    Dim MReal(2, 4) As Double
    Dim MImag() As Double
    Set MatLab = CreateObject("Matlab.Application")
    MatLab.Execute("a = [1 2 3 4; 5 6 7 8;]")
    Call MatLab.GetFullMatrix("a", "base", MReal, MImag)

The workspace code:
    matlab Execute: 'a = [1 2 3 4; 5 6 7 8;]'.
    pr := SAFEARRAY dimensions: #(2 4) elementClass: DOUBLE.
    pi := SAFEARRAY length: -1 elementClass: elementClass: DOUBLE.
    matlab GetFullMatrix: 'a' Workspace: 'base' pr: pr pi: pi
    pr elementAt: #(1 1) "Display it"

The IDL:
    void GetFullMatrix(
        [in] BSTR Name,
        [in] BSTR Workspace,
        [in, out] SAFEARRAY(double)* pr,
        [in, out] SAFEARRAY(double)* pi);

SAFEARRAY>>dimensions: anArray elementClass: elementClass
"Answer a multi dimensional safe array with elements of type elementClass.
The instance regards itself as the owner of the underlying safe array and
will free it on receipt of a #free message,
or upon finalization, unless previously sent a #detach message.
For example:
a := SAFEARRAY dimensions: #(2 3) elementClass: DOUBLE
is compatible with the Visual Basic declaration:
Option Base 1
Dim a(2, 3) As Double
"
| answer dimensions rgsabound |
dimensions := anArray size.
rgsabound := StructureArray length: dimensions elementClass: SAFEARRAYBOUND
.
1 to: dimensions do: [:i |
rgsabound at: i put: (SAFEARRAYBOUND new
cElements: (anArray at: i);
lLbound: 1)].
answer := OLEAutLibrary default
safeArrayCreateEx: elementClass vt
cDims: dimensions
rgsabound: rgsabound yourAddress
pvExtra: nil.
answer beFinalizable.
^answer


Reply | Threaded
Open this post in threaded view
|

Re: COM question

Blair McGlashan
Pieter

You wrote in message news:[hidden email]...
> Hi Smalltalkers,
> I'm trying to use Dolphin's COM interface to communicate with MATLAB. The
> MATLAB Visual Basic examples look so simple, I though it was a piece of
cake
> but it turned out not to be not so easy. As far as I can see I have two
> problems;
>     A - I need to pass an empty SafeArray. In Visual Basic this is  "Dim
A()
> As Double" but in Dolphin? The closed I could get after some trail and
error
> is "SAFEARRAY length: -1 elementClass: elementClass: DOUBLE" (length: 0
> isn't regarded as empty). To make this work I needed to modify
> SAFEARRAY>>copy to handle this empty array. It seems to work for copying
> data from Dolphin to MATLAB but I'm not sure about it.

No, that is not right. A length 0 SAFEARRAY is empty. A length of -1 is
invalid. If you pass a length of -1 then the call to
SafeArrayCreateVectorEx() API will fail, and you'll just end up with a null
SAFEARRAY (i.e. the same thing as executing 'SAFEARRAY newPointer').

>     B - In the VB example the client code creates the array, passes it to
> MATLAB which fills it with data. On inspection the result only contains
> zero's. I suspect I should add an indirection (pointer) because now it
looks
> like the whole SAFEARRAY is copied by Dolphin before passing to MATLAB so
> MATLAB writes in a copy of the array which I never get to see again. Is
this
> correct? If so how do I do this?

Make sure you are using interfaces generated from the typelib rather than
IDispatch #doesNotUnderstand: processing. The latter passes all parameters
wrapped as VARIANTs using a standard conversion to a VARIANT (#asVariant),
which will not work correctly for an in-out SAFEARRAY. If you really must
use IDispatch, then you will have to convert the SAFEARRAYs to VARIANTs
yourself so that they point at the original arrays and have the VT_BYREF
flagged OR'd into the 'vt' field.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: COM question

Pieter Emmelot-2
"Blair McGlashan" <[hidden email]> wrote in message
news:amvdhi$9f1fr$[hidden email]...
| >     B - In the VB example the client code creates the array, passes it
to
| > MATLAB which fills it with data. On inspection the result only contains
| > zero's. I suspect I should add an indirection (pointer) because now it
| looks
| > like the whole SAFEARRAY is copied by Dolphin before passing to MATLAB
so
| > MATLAB writes in a copy of the array which I never get to see again. Is
| this
| > correct? If so how do I do this?
|
| Make sure you are using interfaces generated from the typelib rather than
| IDispatch #doesNotUnderstand: processing.

I get an "Interface not registered" error when doing "matlab := IMLApp new".
Registering MLApp.tlb (see below) doesn't help. Since the VB code works I
continued with
IDispatch.

| The latter passes all parameters
| wrapped as VARIANTs using a standard conversion to a VARIANT (#asVariant),
| which will not work correctly for an in-out SAFEARRAY. If you really must
| use IDispatch, then you will have to convert the SAFEARRAYs to VARIANTs
| yourself so that they point at the original arrays and have the VT_BYREF
| flagged OR'd into the 'vt' field.

Ok, I created a subclass of SAFEARRAY called MLSAFEARRAY and redefined
#asVariant as:
    ^VARIANT new

        vt: self vt;

        ulVal: self asParameter;

        beByRef; "set VT_BYREF"

        yourself

Then I instantiated a MLSAFEARRAY
    o := MLSAFEARRAY length: 1 elementClass: DOUBLE
    o class == SAFEARRAY "true"
and got a SAFEARRAY object back!
I looks like the VM is wrapping safe array COM objects in instances of
SAFEARRAY class. For example
    o := OLEAutLibrary default safeArrayCreateVectorEx: 5 lLbound: 1
cElements: 1 pvExtra: nil

    o class == SAFEARRAY "true"

Does the VM automagically creates SAFEARRAY instances from pointers to
SafeArray COM objects?



Regards,

Pieter


Reply | Threaded
Open this post in threaded view
|

Re: COM question

Blair McGlashan
Pieter

You wrote in message news:[hidden email]...

> ...
> I looks like the VM is wrapping safe array COM objects in instances of
> SAFEARRAY class. For example
>     o := OLEAutLibrary default safeArrayCreateVectorEx: 5 lLbound: 1
> cElements: 1 pvExtra: nil
>
>     o class == SAFEARRAY "true"
>
> Does the VM automagically creates SAFEARRAY instances from pointers to
> SafeArray COM objects?
>

The VM is unaware of the SAFEARRAY class. The reason a SAFEARRAY instance is
required is because that is the way the external library call is declared
(see the return type of OLEAutLibrary>>safeArrayCreateVectorEx:).

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: COM question

Pieter Emmelot-2
"Blair McGlashan" <[hidden email]> wrote in message
news:an25au$af6sp$[hidden email]...
| Pieter
|
| You wrote in message news:[hidden email]...
| > ...
| > I looks like the VM is wrapping safe array COM objects in instances of
| > SAFEARRAY class. For example
| >     o := OLEAutLibrary default safeArrayCreateVectorEx: 5 lLbound: 1
| > cElements: 1 pvExtra: nil
| >
| >     o class == SAFEARRAY "true"
| >
| > Does the VM automagically creates SAFEARRAY instances from pointers to
| > SafeArray COM objects?
| >
|
| The VM is unaware of the SAFEARRAY class. The reason a SAFEARRAY instance
is
| required is because that is the way the external library call is declared
| (see the return type of OLEAutLibrary>>safeArrayCreateVectorEx:).

Ahhh, I get the picture, very nice!

Thanks,
Pieter