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

Using Modules with DLL's

Ken_B_
Beginner
784 Views

Can anyone suggest how to go about this I have a dll project that is launched by an exe. I created this example project below where the dcalc array has values and passes the array to one dll. Then the next dll has the array defined in a module.

At the point where the Dll_2_mod is called the values in the array are wiped out. 

The end goal in the real project is a number of dll's will be adding to the dcalc array and I did not want to change arguments to pass the array because the project already has a module layout.

Sample code:

program Module_Pass_Array
Real,dimension(10) :: Dcalc
    Do I=1,10
      Dcalc(i) = real(i+1)
    Enddo
    Call dll_1(dcalc)
end program Module_Pass_Array
    
subroutine Dll_1(dcalc)
!DEC$ ATTRIBUTES DLLEXPORT::Dll_1
  Real, Dimension(10) :: Dcalc
  Call Dll_2_mod()
end subroutine Dll_1

Module Module_dcalc
!DEC$ ATTRIBUTES DLLEXPORT::Module_Decalc
Real, dimension(10) :: Dcalc
End Module 

subroutine Dll_2_mod
Use Module_dcalc
!DEC$ ATTRIBUTES DLLEXPORT::Dll_2_mod
 Write(*,'(A, F7.2)') 'Dcalc', dcalc(2)
end subroutine Dll_2_mod

 

Thanks in advance for any help. Ken

0 Kudos
4 Replies
IanH
Honored Contributor II
784 Views

As supplied, this doesn't have a lot to do with DLL's.  The Dcalc variable in Module_dcalc is unrelated to the Dcalc variable in the main program and the Dcalc variable in the Dll_1 subroutine (those two are linked by argument association).  The Dcalc variable in Module_dcalc never has a value set and so is undefined - there is nothing to "wipe out".

It might be worth providing more explanation about what it is you are trying to achieve.

0 Kudos
Ken_B_
Beginner
784 Views

Thanks for the comment.  I was trying to make the variable associated by argument the same as in the module. This was for the reason I had an existing exe that lauched the project using the argument array. Then The dll's using a module I hope can maybe point to the initial memory. Perhaps using some sort of pointer allows the array in the module the same values as the exe array? 

0 Kudos
IanH
Honored Contributor II
784 Views

You need some way to explicitly associate Dcalc within the module Module_dcalc with the Dcalc that is in the main program.  There are a couple of options, what's best depends on your specific situation.  My view is that if you need to pass information to and from a procedure, then you explicitly pass that information to and from the procedure using arguments, but if you wanted to make the module variable a pointer, you could do something like this:

program Module_Pass_Array
  Implicit None
  
  Integer :: i
  Real,dimension(10) :: Dcalc
  
  Interface
    Subroutine Dll_1(dcalc)
      Implicit None
      Real, Dimension(10), Target :: Dcalc
    End Subroutine Dll_1
  End Interface
  
  Do i=1,10
    Dcalc(i) = real(i+1)
  Enddo
  Call dll_1(dcalc)
end program Module_Pass_Array

subroutine Dll_1(dcalc)
  Use Module_dcalc, Only: AssociateDcalc
  !DEC$ ATTRIBUTES DLLEXPORT::Dll_1
  Real, Dimension(10), Target :: Dcalc
  Call AssociateDcalc(Dcalc)
  Call Dll_2_mod()
end subroutine Dll_1

!-------------------------------------------------------------------------------


Module Module_dcalc
  Implicit None
  Real, Pointer :: Dcalc(:)
Contains
  Subroutine AssociateDcalc(remote)
    !DEC$ ATTRIBUTES DLLEXPORT :: AssociateDcalc
    Real, Target :: remote(:)
    
    Dcalc => remote
  End Subroutine
End Module 

subroutine Dll_2_mod
  Use Module_dcalc
  Implicit None
  !DEC$ ATTRIBUTES DLLEXPORT::Dll_2_mod
  Write(*,'(A, F7.2)') 'Dcalc', dcalc(2)
end subroutine Dll_2_mod

Note that with the above code, the association between the Dcalc that is the module variable and the dcalc that is the argument to the Dll_1 procedure only lasts as long as the invocation of the Dll_1 procedure.  If you want the association to last longer than that, then you need to give the Dcalc in the main program the target attribute too.  The use of the target attribute on procedure arguments necessitates an explicit interface, hence the interface block.  This would be unnecessary if your procedures were declared within modules.

 

0 Kudos
Ken_B_
Beginner
784 Views

IanH, I was able to get that to work with one exception.

I had to add an export like below;  !DEC$ ATTRIBUTES DLLEXPORT :: Dcalc in the module.

Otherwise I would get a link error.

Module Module_dcalc
  Implicit None
  Real, Pointer :: Dcalc(:)
   !DEC$ ATTRIBUTES DLLEXPORT :: Dcalc
Contains
  Subroutine AssociateDcalc(remote)
    !DEC$ ATTRIBUTES DLLEXPORT :: AssociateDcalc
    Real, Target :: remote(:)
    
    Dcalc => remote
  End Subroutine
End Module 

Zip attached if anyone needs as a reference.

Thanks for your help IanH.

Ken

0 Kudos
Reply