SafeArrayTypeMismatch when retrieving array from Fortran COM to VB.NET

SafeArrayTypeMismatch when retrieving array from Fortran COM to VB.NET

Hi,

We are trying to access a dynamic array in DVF COM server using Visual Basic.Net as follows. A VB.Net Executable calls a VB.Net DLL, which in turn calls a Property Get function in the Fortran COM Server to return the dynamic array (see Figure). This call is made via a .NET runtime callable wrapper (RCW) that was created by using the TLBIMP command.

VB.Net Executable
|
VB.Net DLL
|
Runtime Callable Wrapper (RCW)
|
Fortran COM Server

Our Fortran COM Server was developed using DVF 6.6B.

The DVF COM Server Wizard was used to add the COM Server methods and properties. Y1 is the property that is used to return the dynamically allocated array as a safearray. Note that an array is passed from COM to .NET as a safearray. As DVF COM Server Wizard can only output fixed length array in Property Get, we modified ITransform1.f90 (Transform1 is the name of our program) as shown below. Note that we manually filled in the safearray descriptor based on the size of the dynamic array in our COM server. (see code below)

We are able to correctly access the dynamic array via the Y1 property when the VB.Net DLL is NOT a ServicedComponent. However if the VB.Net IS a ServicedComponent (runs in Component Services as a COM Server) then we encounter a SafeArrayTypeMismatchException error when we attempt to access the dynamic array via theY1 property (Note that the Y1 property returns the safearray).

We do not know what caused the error after extensive search on the Internet. Could you give us some suggestion on what may have caused the problem and what we could try to resolve it. Thank you.

Lawrence

function $ITransform1_get_Y1( pInterface ,&
VALUE ) result (hresult)
!DEC$ ATTRIBUTES STDCALL :: $ITransform1_get_Y1
use CTransform1_Types
use dfcom
use dflib
implicit none
type (ITransform1_Ptr) pInterface
!dec$ attributes reference :: pInterface
integer(INT_PTR_KIND()), intent(out) :: VALUE
!DEC$ ATTRIBUTES reference :: VALUE
integer(LONG) hresult
integer i

REAL(8) f$VALUE(:)
VOLATILE f$VALUE
POINTER f$VALUE

integer(INT_PTR_KIND()) ptr$VALUE

integer(INT_PTR_KIND()) sa$VALUE
type(T_SAFEARRAY) sad$VALUE
pointer(ptrsad$VALUE, sad$VALUE)
type(T_SAFEARRAYBOUND) sab$VALUE(1)
pointer(ptrsab$VALUE, sab$VALUE)

type (FOR_DIMS_INFO) da$VALUE(1)

INTEGER(4) iLBound
INTEGER(4) iUBound
INTEGER(4) iElements

sa$VALUE = NULL

iLBound = 0
iUBound = UBound(pInterface % pInternalData % pInstanceData % Y1, DIM = 1) - &
LBound(pInterface % pInternalData % pInstanceData % Y1, DIM = 1)
iElements = (iUBound - iLBound) + 1

hresult = SafeArrayAllocDescriptor(1, sa$VALUE)
if (hresult < 0) goto 9999
ptrsad$VALUE = sa$VALUE

sad$VALUE % cbElements = 8
ptrsab$VALUE = loc(sad$VALUE % rgsabound(1))
sab$VALUE(1) % cElements = iElements
sab$VALUE(1) % lLbound = iLBound
hresult = SafeArrayAllocData(sa$VALUE)
if (hresult < 0) goto 9999
hresult = SafeArrayAccessData(sa$VALUE, ptr$VALUE)

if (hresult < 0) goto 9999

!Move the data from Y1 into the SafeArray
da$VALUE(1)%LowerBound = LBound(pInterface % pInternalData % pInstanceData % Y1, DIM = 1)
da$VALUE(1)%UpperBound = UBound(pInterface % pInternalData % pInstanceData % Y1, DIM = 1)
da$VALUE(1)%Stride = 1

call FOR_DESCRIPTOR_ASSIGN(f$VALUE, ptr$VALUE, SIZEOF(f$VALUE(iLBound)), &
IOR(FOR_DESCRIPTOR_ARRAY_DEFINED, IOR(FOR_DESCRIPTOR_ARRAY_NODEALLOC, FOR_DESCRIPTOR_ARRAY_CONTIGUOUS)), &
1, da$VALUE)

f$VALUE = pInterface % pInternalData % pInstanceData % Y1

if (hresult < 0) goto 9999
9999 continue ! Cleanup code

if (sa$VALUE /= NULL) i = SafeArrayUnaccessData(sa$VALUE)
VALUE = sa$VALUE
end function

4 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

At the risk of reminding you of something you might already know, VB .NET arrays are stored in row-major order whereas in VB .NYET they are stored in column-major order just as in Fortran.

HTH,
Gerry T.

"Nyet" as "No" in Russian or what? :-)

Jugoslav
www.xeffort.com

.NYET = NOT(.NET), ergo VB.NYET = VB6,5,4,...

HTH,
Gerry T.

Leave a Comment

Please sign in to add a comment. Not a member? Join today