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

Pass Allocatble Arrays to DLL Subroutine via Modules

Arash_Z_
Beginner
783 Views

Hi,

I am trying to use a derived type structure in a dll subroutine using modules. Here is my main program:

Program Main
    
!dec$ attributes dllimport::_DERIVEDTYPECONSTRCT
    
use PARAM

   real a,b
   integer c

    a=2.0
    b=3.0
    c=6

    allocate (MyArray(1))
    call DERIVEDTYPECONSTRCT (1,a,b,c)!
    
     deallocate (MyArray)
end

the module "Param" is defined as below:

    MODULE PARAM
    
    type Derived_type
    real length   
    real width  
    integer measurmentflag
  
    end type Derived_type
    
    type(Derived_type), allocatable :: MyArray(:)
          
    END MODULE

The derived type "MyArray" is declared in the modules and is allocated in the Main program. I want to use is it a subroutine which is defined in a dll project.The subroutine DERIVEDTYPECONSTRCT is built as a dll:

subroutine derivedtypeConstrct (i,x,y,z)!
    
    
!dec$ attributes dllexport::derivedtypeConstrct
!DEC$ ATTRIBUTES STDCALL,ALIAS:"derivedtypeConstrct" :: derivedtypeConstrct
!DEC$ ATTRIBUTES REFERENCE  :: i,x,y,z 
      
use PARAM
    integer i
    real x
    real y
    integer z

    MyArray(i)%length=x
    MyArray(i)%width=y
    MyArray(i)%measurmentflag=z
 
end

The problem is that when the code enters subroutine derivedtypeConstrct, the array "MyArray" becomes undefined although I have "use PARAM". The code works fine if "MyArray" is not allocatable or if subroutine derivedtypeConstrct is not a dll. I am trying to use the dll later in visual basic where MyArray will be a structure (I am not if it will work though).

Thanks for your helps.

Arash

 

0 Kudos
1 Solution
Steven_L_Intel1
Employee
783 Views

There's more than one problem here.

Regarding the array, simply putting the array definition in a module doesn't share it between a DLL and an executable. You have two different copies of MyArray in the program. What you need to do is add:

!DEC$ ATTRIBUTES DLLEXPORT :: MyArray

in the module. When you build the executable, make sure that you don't compile the module again - reference the compiled .mod built by the DLL project (if you make the DLL project a dependent of the executable, this will happen automatically) and link to the export library of the DLL project (to get the object file from the module.) The DLLEXPORT in the module turns into a DLLIMPORT when you "use" it. The DLL project will get an informational message from the linker about a "locally defined" symbol for MyArray, which you can ignore.

Next, you have incorrectly declared the subroutine in the main program. One doesn't put name decoration (the leading underscore) on the ATTRIBUTES line, and you have a mismatch on calling conventions (and name - I am not sure how this even linked.) You need to replace the ATTRIBUTES line you have in the main program with:

!dec$ attributes dllimport::derivedtypeConstrct
!DEC$ ATTRIBUTES STDCALL,ALIAS:"derivedtypeConstrct" :: derivedtypeConstrct

Last, you need to make sure that the main program and the DLL both link against the DLL form of the run-time libraries. This is now the default (it wasn't in earlier versions), so it may not be an issue, but check the setting of Fortran > Libraries > Use Runtime Library in both projects to make sure they both name the same DLL library type.

View solution in original post

0 Kudos
11 Replies
Steven_L_Intel1
Employee
784 Views

There's more than one problem here.

Regarding the array, simply putting the array definition in a module doesn't share it between a DLL and an executable. You have two different copies of MyArray in the program. What you need to do is add:

!DEC$ ATTRIBUTES DLLEXPORT :: MyArray

in the module. When you build the executable, make sure that you don't compile the module again - reference the compiled .mod built by the DLL project (if you make the DLL project a dependent of the executable, this will happen automatically) and link to the export library of the DLL project (to get the object file from the module.) The DLLEXPORT in the module turns into a DLLIMPORT when you "use" it. The DLL project will get an informational message from the linker about a "locally defined" symbol for MyArray, which you can ignore.

Next, you have incorrectly declared the subroutine in the main program. One doesn't put name decoration (the leading underscore) on the ATTRIBUTES line, and you have a mismatch on calling conventions (and name - I am not sure how this even linked.) You need to replace the ATTRIBUTES line you have in the main program with:

!dec$ attributes dllimport::derivedtypeConstrct
!DEC$ ATTRIBUTES STDCALL,ALIAS:"derivedtypeConstrct" :: derivedtypeConstrct

Last, you need to make sure that the main program and the DLL both link against the DLL form of the run-time libraries. This is now the default (it wasn't in earlier versions), so it may not be an issue, but check the setting of Fortran > Libraries > Use Runtime Library in both projects to make sure they both name the same DLL library type.

0 Kudos
Arash_Z_
Beginner
783 Views

Thanks for the reply Steve. In my Dll project I added the export statement for MyArray:

    MODULE PARAM
    
!DEC$ ATTRIBUTES DLLEXPORT :: MyArray
    
    type Derived_type
    real length   
    real width  
    integer measurmentflag
  
    end type Derived_type
    
    type(Derived_type), allocatable :: MyArray(:)
          
    END MODULE

and added import statement for MyArray into subroutine derivedtypeConstrct:

subroutine derivedtypeConstrct (i,x,y,z)!
    
use PARAM    

!dec$ attributes dllexport::derivedtypeConstrct
!DEC$ ATTRIBUTES STDCALL,ALIAS:"derivedtypeConstrct" :: derivedtypeConstrct
!DEC$ ATTRIBUTES REFERENCE  :: i,x,y,z 
      
!DEC$ ATTRIBUTES dllimport :: MyArray
    

    integer i
    real x
    real y
    integer z

    MyArray(i)%length=x
    MyArray(i)%width=y
    MyArray(i)%measurmentflag=z
 
end
    

However, when I compile the dll project I get the following error:

error #6401: The attributes of this name conflict with those made accessible by a USE statement.   [MYARRAY]

Thanks.

0 Kudos
Steven_L_Intel1
Employee
783 Views

I didn't say to put in a DLLIMPORT directive for MyArray. Take that out.

Did you also make the necessary changes to the main program?

0 Kudos
Arash_Z_
Beginner
783 Views

I removed the DLLIMPORT to MyArray. I made the changes to the main file. everything works fine now if I also remove "!DEC$ ATTRIBUTES REFERENCE :: i,x,y,z" from the subroutine. Do I need the statement?

I want to use the dll in a visual basic code and define a "structure" for MyArray. However, I guess since I don't have "MyArray" in the arguments of the subroutine it won't work.

Thanks,

Arash

 

0 Kudos
Steven_L_Intel1
Employee
783 Views

For the ATTRIBUTES REFERENCE line, it has to be in both the subroutine and the main program or neither. (As long as you added the ATTRIBUTES STDCALL with the correct name, along with ALIAS, to the main program.)

For use from VB I recommend keeping REFERENCE in there. You're not going to be able to use MyArray with VB. You may want to look at the two VB examples we provide in  MixedLanguage.zip under Samples.

0 Kudos
Arash_Z_
Beginner
783 Views

What will be the reference attribute in the main file then?

0 Kudos
Steven_L_Intel1
Employee
783 Views

See my reply #2 above, where I gave you the lines to be used there. Make sure that you keep the REFERENCE attribute in the subroutine.

0 Kudos
Arash_Z_
Beginner
783 Views

Thank you very much for all the helps Steve.

Arash

0 Kudos
Arash_Z_
Beginner
783 Views

Steve, one last issue. I am compiling using visual studio community 2015. When I call the dll in VB I get the error Unable to find an entry point  in DLL. I checked the dll with dependency walker and it cannot find these:

API-MS-WIN-CORE-KERNEL32-PRIVATE-L1-1-1.DLL
API-MS-WIN-CORE-PRIVATEPROFILE-L1-1-1.DLL
API-MS-WIN-SERVICE-PRIVATE-L1-1-1.DLL

However, the dll works fine in VB if I compile with visual studio 2010 shell (which I have installed on another machine). Do I need any special treatment in Community?

Thanks,

Arash

0 Kudos
Steven_L_Intel1
Employee
783 Views

Are you running this on a different PC than where you built it? If so, download and install (on the target system) the Visual C++ 2015 Redistributables from https://www.microsoft.com/en-us/download/details.aspx?id=48145 You will probably want vc_redist.x86.exe

0 Kudos
Arash_Z_
Beginner
783 Views

Thanks a lot Steve. That solved the issue.

0 Kudos
Reply