- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I have a VB.Net application calling Fortran dll's and I needed to migrate to x64. I use VS2019 and IVF V19. It crashes in the Fortran call where I need a returned string. I changed the string length parameter to a Long in following sample. Also tried ISO binding, but it crashes when entering the DLL. Sample VB.Net source frmTis.vb:
Declare Sub CMPNMS Lib "TISdlld_x64.dll" (ByVal IND As Integer, ByRef str As String, ByVal lang As Long)
Dim i As Integer
Dim BigLen As Long
Dim cmpnam as String
i = 1
cmpnam = "------"
BigLen = Len(cmpnam)
Call CMPNMS(i, cmpnam, BigLen) ' Call Fortran procedure cmpnam to return string 1, but crashes.
Sample Fortran file Tis.for:
subroutine CMPNMS (COUNT, NAME, LNG) bind(C)
!DEC$ ATTRIBUTES DLLEXPORT::CMPNMS
use, intrinsic :: ISO_C_BINDING
character(1,C_CHAR),target ::NAME(*)
integer(C_INT32_T),value::COUNT ! 4-byte integer
integer(C_SIZE_T),value::LNG ! 8-byte Long
character(LNG,C_CHAR), pointer :: fptr
type(C_PTR) cptr
integer*8 LNG
cptr = C_LOC(NAME(1))
call C_F_POINTER(cptr,fptr)
print *, fptr ! content of string of caller
NAME = 'NewStr' ! return a new string; always 6 char
LNG = LEN(NAME)
return
The Fortran calling convention was in x86 STDCALL, now default
String Length Argument passing is After Individual String Argument.
It gives runtime AccessViolationException at CMPNMS(Int32 IND, String& str, Int64 lang)
Any help is appreciated. Kind regards, Harry.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Immediately I am unable to spend the time to read through your code and point you to any changes. But I had this simple example for a colleague who previously had a similar question. Perhaps you can try out this simple case and see if you can reproduce what is shown below If yes, that might point you as to how to proceed with your code?
Fortran "library" code:
module Fdll_m
use, intrinsic :: iso_c_binding, only : c_char, c_size_t, c_loc, c_f_pointer
contains
subroutine Fstr(str, lenstr) bind(C, name="Fstr")
!DEC$ ATTRIBUTES DLLEXPORT::Fstr
! Argument list
character(kind=c_char,len=1), intent(in), target :: str(*)
integer(c_size_t), intent(in), value :: lenstr
! Elided are any checks for the lenstr value
block
character(kind=c_char,len=lenstr), pointer :: pstr
call c_f_pointer( cptr=c_loc(str), fptr=pstr )
pstr = c_char_"Hello World!"
pstr => null()
end block
return
end subroutine
end module
Visual Basic calling program in .NET:
Imports System.IO
Imports System.Text
Imports System.Runtime.InteropServices
Namespace Fortran
Public Class Fdll
<DllImport("Fdll.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Shared Sub Fstr (A As StringBuilder, lenA As UIntPtr)
end Sub
End Class
NotInheritable Class Test
Private Sub New()
End Sub
Public Shared Sub Main()
Dim s As StringBuilder
' Write header
Console.WriteLine("*** Test Fortran Interop using VB ***" + vbLf)
Try
s = New StringBuilder(12)
Fdll.Fstr(s, s.Capacity)
Console.WriteLine("s = " + s.ToString())
Catch ex As Exception
Console.WriteLine(ex.Message)
Finally
Console.WriteLine("Press any key to continue..")
Console.ReadKey()
End Try
End Sub
End Class
End Namespace
Program execution using Intel Fortran:
C:\Temp>ifort /dll /libs:static Fdll.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.3.0 Build 20210609_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.
Microsoft (R) Incremental Linker Version 14.29.30038.1
Copyright (C) Microsoft Corporation. All rights reserved.
-out:Fdll.dll
-dll
-implib:Fdll.lib
Fdll.obj
Creating library Fdll.lib and object Fdll.exp
C:\Temp>vbc -platform:x64 test.vb
Microsoft (R) Visual Basic Compiler version 3.10.0-4.21318.11 (7ceb6331)
Copyright (C) Microsoft Corporation. All rights reserved.
C:\Temp>test.exe
*** Test Fortran Interop using VB ***
s = Hello World!
Press any key to continue..
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Immediately I am unable to spend the time to read through your code and point you to any changes. But I had this simple example for a colleague who previously had a similar question. Perhaps you can try out this simple case and see if you can reproduce what is shown below If yes, that might point you as to how to proceed with your code?
Fortran "library" code:
module Fdll_m
use, intrinsic :: iso_c_binding, only : c_char, c_size_t, c_loc, c_f_pointer
contains
subroutine Fstr(str, lenstr) bind(C, name="Fstr")
!DEC$ ATTRIBUTES DLLEXPORT::Fstr
! Argument list
character(kind=c_char,len=1), intent(in), target :: str(*)
integer(c_size_t), intent(in), value :: lenstr
! Elided are any checks for the lenstr value
block
character(kind=c_char,len=lenstr), pointer :: pstr
call c_f_pointer( cptr=c_loc(str), fptr=pstr )
pstr = c_char_"Hello World!"
pstr => null()
end block
return
end subroutine
end module
Visual Basic calling program in .NET:
Imports System.IO
Imports System.Text
Imports System.Runtime.InteropServices
Namespace Fortran
Public Class Fdll
<DllImport("Fdll.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Shared Sub Fstr (A As StringBuilder, lenA As UIntPtr)
end Sub
End Class
NotInheritable Class Test
Private Sub New()
End Sub
Public Shared Sub Main()
Dim s As StringBuilder
' Write header
Console.WriteLine("*** Test Fortran Interop using VB ***" + vbLf)
Try
s = New StringBuilder(12)
Fdll.Fstr(s, s.Capacity)
Console.WriteLine("s = " + s.ToString())
Catch ex As Exception
Console.WriteLine(ex.Message)
Finally
Console.WriteLine("Press any key to continue..")
Console.ReadKey()
End Try
End Sub
End Class
End Namespace
Program execution using Intel Fortran:
C:\Temp>ifort /dll /libs:static Fdll.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.3.0 Build 20210609_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.
Microsoft (R) Incremental Linker Version 14.29.30038.1
Copyright (C) Microsoft Corporation. All rights reserved.
-out:Fdll.dll
-dll
-implib:Fdll.lib
Fdll.obj
Creating library Fdll.lib and object Fdll.exp
C:\Temp>vbc -platform:x64 test.vb
Microsoft (R) Visual Basic Compiler version 3.10.0-4.21318.11 (7ceb6331)
Copyright (C) Microsoft Corporation. All rights reserved.
C:\Temp>test.exe
*** Test Fortran Interop using VB ***
s = Hello World!
Press any key to continue..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks so much for your reply FortranFan. I'm in the process of converting the include files (14) and sources to Fortan-90. The compiler does not seem to like the line: integer(C_INT32_T),value:: COUNT ! 4-byte integer. It complains that the parameter must be a compile-time constant. I will keep you up-to-date with the result.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It appears that the constant is satisfied by extending the USE clause.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks a lot FortranFan and JimDempseyAtTheCove for the solution to the problem. I cannot emphasize enough how valuable your replies are.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@HarryWelten , glad you were able to solve your problem.
A question if you are willing to share your feedback: do you plan to do further work on the Fortran side and if so, will you be considering modern Fortran (starting with free-form source and so much more)?
Or is it the case for you of needing to do continue with .for files as in "Tis.for" (that are usually FORTRAN 77 style fixed form source) and doing minimal to no changes in some existing codebase?
By the way, I had reused the Fortran code I had posted in this thread toward another recent thread that involved part of a namesake i.e., Visual Basic for Applications as opposed to Visual Basic .NET though there are major differences between the two platforms. It appears that user too was able to solve the problem, so for me it is good to see Fortran "libraries" remaining in use with different solutions, especially on Windows:
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi FortranFan,
I need to continue with the .for files because there is minimal time to upgrade this; the objective of the current project is to migrate to the 64-bit platform only. Thanks again!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I built this example that you gave, modified it slightly, run the x64 debug mode and that also crashes entering into the Fortran routine.
The VB part:
<DllImport("TISdlld_x64.dll", CallingConvention:=CallingConvention.Cdecl)>
Public Sub CMPNMS(ByVal IND As Integer, ByRef str As String, ByVal lang As Long)
End Sub
Dim i As Integer
Dim BigLen As Long
Dim cmpnam as String
i = 1
cmpnam = "------"
BigLen = Len(cmpnam)
Call CMPNMS(i, cmpnam, BigLen) ' Call Fortran procedure cmpnam to return string 1, but crashes.
Sample Fortran file Tis.for:
subroutine CMPNMS (COUNT, NAME, LNG) bind(C)
!DEC$ ATTRIBUTES DLLEXPORT::CMPNMS
use, intrinsic :: ISO_C_BINDING
character(1,C_CHAR),target ::NAME(*)
integer(C_INT32_T),value::COUNT ! 4-byte integer
integer(C_SIZE_T),value::LNG ! 8-byte Long
character(LNG,C_CHAR), pointer :: fptr
type(C_PTR) cptr
integer*8 LNG
cptr = C_LOC(NAME(1))
call C_F_POINTER(cptr,fptr)
print *, fptr ! content of string of caller
NAME = 'NewStr' ! return a new string; always 6 char
LNG = LEN(NAME)
return
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Look at FortranFan's post on 4/1. His VB argument specification for the string was to pass
A As StringBuilder
Yours is passing
ByRef str As String
"String" is a container (containing several member variables one of which is the base address of the buffer for the string) whereas StringBuilder returns what amounts to the address of a null terminated string (IOW the string itself as opposed to the address of container).
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim, thanks for your remark. I assumed it was a detail, but assumption is the mother of all f*. I will try it soon. Regards, Harry.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page