Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29235 Discussions

Problems passing Array of Strings between CVF dll and IVF exe

thomas_boehme
New Contributor II
779 Views

We are facing the following problem:

We want to replace a legacy dll previously compiled with CVF with a new version compiled with Intel Fortran. This dll will be called by both new Intel compiled code as well as from legacy CVF code, which we cannot recompile.

Therefore, we want to make the dll with an external interface that is backward compatible with CVF. This generally works fine by specifying

!DEC$ ATTRIBUTESDLLEXPORT,MIXED_STR_LEN_ARG,REFERENCE,STDCALL,ALIAS : 'abc' :: abc
for the new dll routines.

However, this does not seem to work for arrays of strings. The interface for arrays of string in IVF and CVF seem to be handled different.

Below is a sample code to illustrate the problem.

When both executable and dll are compiled with CVF, things work fine, the output is 'abcdefghi'.

When both are compiled by IVF, also both works fine.

When the executable is compiled by CVF and the dll with Intel, it does not work as expected. The output is abcbcdcde. It also doesn't work when the executable is compiled by IVF and the dll with CVF.

It seems likethere is an offset problem here.It seems like the interface for string arrays was changed between CVF and IVF. Is there any way to ensure backward compatability for string arrays?

Any help on this issue would be greatly appreciated. As said before, we cannot change the interface, as there are existing legacy applications compiled with CVF that we cannot recompile.

Btw, this issue is the same for IVF 11.0.61 or IVF 10.1.025.

best regards,

Thomas Boehme

Sample Code:

!===========================================================

! PassingStringArray_prg.f90

program PassingStringArray_prg

USE PassingStringArray_dll

implicit none

! Variables

CHARACTER(LEN=3), DIMENSION(3) :: strarr

! Body

STRARR(1) = 'abc'

STRARR(2) = 'def'

STRARR(3) = 'ghi'

CALL PassingStringArray(strarr)

end program PassingStringArray_prg

!===========================================

! PassingStringArray_dll.f90

MODULE PassingStringArray_dll

CONTAINS

subroutine PassingStringArray(aStringArray)

!DEC$ ATTRIBUTES DLLEXPORT,MIXED_STR_LEN_ARG,REFERENCE,STDCALL,ALIAS : 'PassingStringArray' :: PassingStringArray

implicit none

! Variables

CHARACTER(LEN=*), INTENT(IN) :: aStringArray(:)

! Body

write(*,*) aStringArray

end subroutine PassingStringArray

END MODULE PassingStringArray_dll

0 Kudos
1 Solution
Jugoslav_Dujic
Valued Contributor II
779 Views
Quoting - thomas_boehme

It seems likethere is an offset problem here.It seems like the interface for string arrays was changed between CVF and IVF. Is there any way to ensure backward compatability for string arrays?

CHARACTER(LEN=*), INTENT(IN) :: aStringArray(:)

! Body

You're on partially right track. However, it is not string array interface that was changed, but all assumed-shape (and POINTER and ALLOCATABLE) arrays: Intel has one field more in the array descriptor than CVF.

That being said, I don't have an elegant solution. An obvious workaround of changing aStringArray into assumed-size or explicit-shape array doesn't satisfy your "no interface change" condition.

View solution in original post

0 Kudos
4 Replies
Jugoslav_Dujic
Valued Contributor II
780 Views
Quoting - thomas_boehme

It seems likethere is an offset problem here.It seems like the interface for string arrays was changed between CVF and IVF. Is there any way to ensure backward compatability for string arrays?

CHARACTER(LEN=*), INTENT(IN) :: aStringArray(:)

! Body

You're on partially right track. However, it is not string array interface that was changed, but all assumed-shape (and POINTER and ALLOCATABLE) arrays: Intel has one field more in the array descriptor than CVF.

That being said, I don't have an elegant solution. An obvious workaround of changing aStringArray into assumed-size or explicit-shape array doesn't satisfy your "no interface change" condition.

0 Kudos
g_f_thomas
Beginner
779 Views
Quoting - thomas_boehme

We are facing the following problem:

We want to replace a legacy dll previously compiled with CVF with a new version compiled with Intel Fortran. This dll will be called by both new Intel compiled code as well as from legacy CVF code, which we cannot recompile.

Therefore, we want to make the dll with an external interface that is backward compatible with CVF. This generally works fine by specifying

!DEC$ ATTRIBUTESDLLEXPORT,MIXED_STR_LEN_ARG,REFERENCE,STDCALL,ALIAS : 'abc' :: abc
for the new dll routines.

However, this does not seem to work for arrays of strings. The interface for arrays of string in IVF and CVF seem to be handled different.

Below is a sample code to illustrate the problem.

When both executable and dll are compiled with CVF, things work fine, the output is 'abcdefghi'.

When both are compiled by IVF, also both works fine.

When the executable is compiled by CVF and the dll with Intel, it does not work as expected. The output is abcbcdcde. It also doesn't work when the executable is compiled by IVF and the dll with CVF.

It seems likethere is an offset problem here.It seems like the interface for string arrays was changed between CVF and IVF. Is there any way to ensure backward compatability for string arrays?

Any help on this issue would be greatly appreciated. As said before, we cannot change the interface, as there are existing legacy applications compiled with CVF that we cannot recompile.

Btw, this issue is the same for IVF 11.0.61 or IVF 10.1.025.

best regards,

Thomas Boehme

Sample Code:

!===========================================================

! PassingStringArray_prg.f90

program PassingStringArray_prg

USE PassingStringArray_dll

implicit none

! Variables

CHARACTER(LEN=3), DIMENSION(3) :: strarr

! Body

STRARR(1) = 'abc'

STRARR(2) = 'def'

STRARR(3) = 'ghi'

CALL PassingStringArray(strarr)

end program PassingStringArray_prg

!===========================================

! PassingStringArray_dll.f90

MODULE PassingStringArray_dll

CONTAINS

subroutine PassingStringArray(aStringArray)

!DEC$ ATTRIBUTES DLLEXPORT,MIXED_STR_LEN_ARG,REFERENCE,STDCALL,ALIAS : 'PassingStringArray' :: PassingStringArray

implicit none

! Variables

CHARACTER(LEN=*), INTENT(IN) :: aStringArray(:)

! Body

write(*,*) aStringArray

end subroutine PassingStringArray

END MODULE PassingStringArray_dll

You could usecopymemory

http://msdn.microsoft.com/en-us/library/aa366535(VS.85).aspx

Gerry

0 Kudos
forall
Beginner
779 Views
Quoting - Jugoslav Dujic

You're on partially right track. However, it is not string array interface that was changed, but all assumed-shape (and POINTER and ALLOCATABLE) arrays: Intel has one field more in the array descriptor than CVF.

That being said, I don't have an elegant solution. An obvious workaround of changing aStringArray into assumed-size or explicit-shape array doesn't satisfy your "no interface change" condition.


A hopefully simpler question: How do I get a scalar assumed-length string trough the interface between IVF EXE and CVF Fortran DLL?

Currently I cannot get them get through regardless of the various combinations of !IDEC I use, except when the subroutine has a single string as argument.

In general I get a string of wrong length which then causes a stack error. Sometimes (if the string is last in the argument list) its length is ok but there is a stack error on exit from sub.

interface
subroutine str(hv,name,stat)
!DEC$ ATTRIBUTES DLLIMPORT, C:: str
! !DEC$ ATTRIBUTES DLLIMPORT, REFERENCE :: str
implicit none
integer,intent(in)::hv
character(*):: name
integer::stat
end subroutine str
endinterface
...
character(20)::name
! Start procedure here
!
name="1234567";hv=1; status=0
call str(hv,name,status)
write(*,*)hv,status,name
...

subroutine str(hv,name,stat)
!DEC$ ATTRIBUTES DLLEXPORT, C :: str ! runs with wrong results
! !DEC$ ATTRIBUTES DLLEXPORT, REFERENCE :: str ! stack overflow or bizarre results
implicit none
integer,intent(in)::hv
character(*):: name
integer::stat
integer::L
L=len(name) ! gives wrong results
write(*,*)"L=",L,name
stat=L+hv
name="ok"
end subroutine str

The problem goes away when string is the only argument.

Steve mentioned about string lengths being passed after all args under IVF and after each individual string in CVF. Though here even switching to string being last doesnt help.

I tried adding MIXED_STR_LEN_ARG or NOMIXED_STR_LEN_ARG but does not seem to help - when used in conjuction with REFERENCE it actually gives the correct L but still stack overflow, whereas with C it just gives wrong results...

Is it some extra IDEC setting I am missing?

---------------------------
Also regarding copymem post just above: Gerry (or anybody else) - Could you please elaborate on this? I am not seeing how could this solve the problem of extra fields in the array descriptor..
0 Kudos
Steven_L_Intel1
Employee
779 Views
First, you have no array descriptors here, so that is not an issue.

Adding MIXED_STR_LEN_ARG on the IVF side (in your interface block) should take care of the problem.
0 Kudos
Reply