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

Use Fortran DLL in C++

bjdesa
New Contributor I
1,983 Views

I want to use a DLL file that I created in Fortran using ifort in a C++ program I don't know how to do it on the C++ side so far I have

subroutine func01( a ) bind(C,name="func01")
!DEC$ ATTRIBUTES DLLEXPORT :: func01
implicit none
character(len=1), dimension(90) , intent(in) :: a
character(len=30), dimension(3) :: b
integer*4 :: count,i,j

count=1
do j=1,3
b(J)=''
do I=1,30
b(J)=trim(b(J))//a(count)
count=count+1
enddo
enddo

print *
print *, "char length = ", len(b(1)), len(b(2)), len(b(3))
print *, "raw a(1) : [", b(1), "]"
print *, "raw a(2) : [", b(2), "]"
print *, "raw a(3) : [", b(3), "]"
print *, "trim     : [", trim(b(1)), "] [", trim(b(2)), "]  [", trim(b(3)), "]"
end
 

and on the c++ side I have been able to gather the following code

 

      str[0] = "moon"; str[1] = "mercury"; str[2] = "jupiter";

      for( int k = 0; k < numstr; k++ ) {
          memset( a, ' ', lenmax );  // fill space
          str.copy( a, lenmax );  // copy at most lenmax char (no \0 attached)
      }

  //    func01( a[0], lenmax );
  //    func01( a[1], lenmax ); // pass from mercury


    HINSTANCE hDLL = LoadLibrary("foo.dll");

    if (hDLL == NULL)
    {
        std::cout << "Failed to load library.\n";
    }

    else
    {
        lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "func01");

 

        FreeLibrary(hDLL);
    }

        lpfnDllFunc1( a[0], lenmax );
  //    std::cin.get();

    return 0;
  }

When I compile the program and run it it crashes. I am sure that I am making some errors on the C++ side of thing.

0 Kudos
1 Solution
bjdesa
New Contributor I
1,983 Views

I found the solution myself. The following code works properly the trouble I was having was have with was how the Fortran DLL was being compiled I used MSV 2008 environment to compile the dll now everything works okay. 

  #include <iostream>

  #include <Windows.h>

  typedef void(*LPFNDLLFUNC1)(char *c, const int len);

  int main()
  {
      LPFNDLLFUNC1 lpfnDllFunc1;    // Function pointer

      const int lenmax = 30, numstr = 3; // changed char length to 30 to fit in the terminal
      char a[ numstr ][ lenmax ];
      std::string str[ numstr ];

      str[0] = "moon"; str[1] = "mercury"; str[2] = "jupiter";

      for( int k = 0; k < numstr; k++ ) {
          memset( a, ' ', lenmax );  // fill space
          str.copy( a, lenmax );  // copy at most lenmax char (no \0 attached)
      }

    HINSTANCE hDLL = LoadLibrary("DLL1.dll");

    if (hDLL == NULL)
    {
        std::cout << "Failed to load library.\n";
    }

    else
    {
        lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "func01");

        lpfnDllFunc1( a[0], lenmax );

    }

    FreeLibrary(hDLL);
    return 0;
  }

View solution in original post

0 Kudos
5 Replies
IanH
Honored Contributor III
1,983 Views

As explained in the comments on your post on StackOverflow, you are calling FreeLibrary before you reference the function.  That FreeLibrary call may unload the DLL from memory - the Fortran procedure will no longer be available to call.  Move the FreeLibrary call to after the reference to the Fortran procedure.

You should also check the return values from the GetProcAddress call to make sure that the DLL contains the procedure with the expected name.

The Fortran subroutine takes a single argument.  Your C++ code passes two arguments.

0 Kudos
bjdesa
New Contributor I
1,983 Views

HINSTANCE hDLL = LoadLibrary("source1.dll");

if (hDLL == NULL)

{

std::cout << "Failed to load library.\n";

}

else

{

lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "func01");

 

}

//lpfnDllFunc1( a[0], lenmax );

FreeLibrary(hDLL);

// std::cin.get();

I fixed that with the above but I am getting a "Failed to load library." i.e. the library does not load.

0 Kudos
bjdesa
New Contributor I
1,983 Views

I am using the following to build my files

ifort /nologo /iface:stdcall /libs:dll /threads /c source1.f90

link /NOLOGO /SUBSYSTEM:WINDOWS /manifest /dll /out:source1.dll source1.obj
   Creating library source1.lib and object source1.exp

cl /EHsc main1.cpp

0 Kudos
TimP
Honored Contributor III
1,983 Views

Why are you specifying stdcall in just 1 place?  CL defaults to cdecl, same as ifort does.  One would expect a link error. Then you would add the .dll to your final build step.

As far as I know, the only current use for stdcall is in windows api calls, and the current ifort provides for that by allowing the corresponding attributes along with bind(c...).

0 Kudos
bjdesa
New Contributor I
1,984 Views

I found the solution myself. The following code works properly the trouble I was having was have with was how the Fortran DLL was being compiled I used MSV 2008 environment to compile the dll now everything works okay. 

  #include <iostream>

  #include <Windows.h>

  typedef void(*LPFNDLLFUNC1)(char *c, const int len);

  int main()
  {
      LPFNDLLFUNC1 lpfnDllFunc1;    // Function pointer

      const int lenmax = 30, numstr = 3; // changed char length to 30 to fit in the terminal
      char a[ numstr ][ lenmax ];
      std::string str[ numstr ];

      str[0] = "moon"; str[1] = "mercury"; str[2] = "jupiter";

      for( int k = 0; k < numstr; k++ ) {
          memset( a, ' ', lenmax );  // fill space
          str.copy( a, lenmax );  // copy at most lenmax char (no \0 attached)
      }

    HINSTANCE hDLL = LoadLibrary("DLL1.dll");

    if (hDLL == NULL)
    {
        std::cout << "Failed to load library.\n";
    }

    else
    {
        lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "func01");

        lpfnDllFunc1( a[0], lenmax );

    }

    FreeLibrary(hDLL);
    return 0;
  }

0 Kudos
Reply