- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I want to use Fortran dll in C#, in function "wrapper_integrate", forth argument "intsteps" is an optional argument.
My fortran code:
module integration implicit none contains function Integrate(func, a,b, intsteps) result(integral) interface real function func(x) real, intent(in) :: x end function func end interface real :: integral, a, b integer :: intsteps intent(in) :: a, b, intsteps optional :: intsteps real :: x, dx integer :: i,n integer, parameter :: rk = kind(x) n = 1000 if (present(intsteps)) n = intsteps dx = (b-a)/n integral = 0.0_rk do i = 1,n x = a + (1.0_rk * i - 0.5_rk) * dx integral = integral + func(x) end do integral = integral * dx end function end module integration function wrapper_integrate(func, a, b, intsteps) result(integral) bind(C, name='wrapper_integrate') !DEC$ ATTRIBUTES DLLEXPORT :: wrapper_integrate use iso_c_binding use Integration implicit none interface function func(x) bind(C) use, intrinsic :: iso_c_binding implicit none real(c_float), intent(in) :: x real(c_float) :: func end function func end interface real(c_float), intent(in),value :: a,b integer(c_int), intent(in), optional :: intsteps real(c_float) :: integral real :: local_a, local_b integer :: local_intsteps local_a = a local_b = b if (present(intsteps)) then local_intsteps = intsteps integral = Integrate(local_func, a, b, local_intsteps) else integral = Integrate(local_func, a, b) end if contains function local_func(x) real, intent(in) :: x real :: local_func real(c_float) :: local_x local_x = x local_func = func(local_x) end function local_func end function wrapper_integrate
My C# code in VS2013:
using System; using System.Runtime.InteropServices; namespace Console_use_integrate{ class Program { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate float ActionRefInt(ref float n); public ActionRefInt callbackHandler; public Program() { callbackHandler = new ActionRefInt(square); } public float square(ref float n) { return n*n; } static void Main(string[] args) { Program myProg2 = new Program(); float a = 1f; float b = 3f; int step = null; float result; Console.WriteLine("Interval from {0} to {1} ", a, b); result = integrate_Dll(myProg2.callbackHandler, a, b,ref step); Console.WriteLine("integration result is {0}",result); Console.ReadKey(); } [DllImport(@"integrate_Dll.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "wrapper_integrate")] public static extern float integrate_Dll([MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack, float a, float b,ref int c); } }
Can I pass "null" if I don't want to use argument "step" which is corresponding to optional argument "intsteps" in Fortran dll?
Thanks!
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You would have to pass null by value. I am not a C# expert but I think what you have is wrong in a couple of ways. You initialize step as an int with null, which simply is zero. You then pass step by reference, which passes the address of an int with zero. Fortran doesn't consider this an omitted argument.
I think the simplest approach is to pass null instead of step - I believe that will work.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
C# treats int as a value type which is not nullable, so the C# code in the original post at line 31 of " int step = null" should not compile:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/value-types
My recommended approach is to simply be consistent with Microsoft's own approach in .NET and overload the external unmanaged procedure with additional signatures as necessary to handle the optional parameters with overloads making use of IntPtr from the System namespace; invocations then pass in the constant System.IntPtr.Zero to denote the absent argument:
[DllImport(@"integrate_Dll.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "wrapper_integrate")] public static extern float integrate_Dll([MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack, float a, float b, ref int c); [DllImport(@"integrate_Dll.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "wrapper_integrate")] public static extern float integrate_Dll([MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack, float a, float b, System.IntPtr c); .. result = integrate_Dll(myProg2.callbackHandler, a, b, System.IntPtr.Zero) ..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
>>You initialize step as an int with null, which simply is zero.
In C# every variable is a reference (reference to reference type as well as reference to value type). Initializing an int as null will generate an error if an attempt to use the variable other than to test for null reference.
The item referenced (for int) for all intents and purposes is a struct. It is unclear as to if the data object of the struct for int is identical as int, or if it contains a type code as well as the int value. (implementation issue). Some searching on msdn might provide this information.
I suggest writing a C wrapper function, that you call from C#, that in turn calls Fortran with the address of the optional argument.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FF's suggestion is more elegant (C# is creating the wrapper functions in the declarations).
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I want to migrate from VB.Net to C#.These are my codes:
Module1.vb file:
Module Module1 REM Use ByVal to pass strings unless the called routine expects BSTR structures Public Declare Auto Sub electrostatica3D Lib "FCALL.DLL" _ (ByVal DBL_IN() As Double, ByVal STR_IN As String, ByVal DBL_OUT() As Double) End Module
fcall.f90 fortran file:
subroutine electrostatica3D(DBL_IN, STRING_IN, DBL_OUT) use malla_3DP1 use electros3D use external_electros3D use derivados3D use resolucion_sistema_lineal implicit none ! Specify that DLL_ROUT is exported to a DLL ! and that the external name is 'DLL_ROUT' !DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: electrostatica3D !DEC$ ATTRIBUTES ALIAS:'electrostatica3D' :: electrostatica3D REAL(8), INTENT(IN) :: DBL_IN(0:3) CHARACTER(10), INTENT(IN) :: STRING_IN !DEC$ ATTRIBUTES REFERENCE :: STRING_IN ! When VB passes in a "ByVal String", it passes the address ! of a NUL-terminated string, similar to what C would do, ! and no separate length. The REFERENCE attribute tells ! Fortran not to expect a length. In order to use a function ! such as INDEX, we need to supply some maximum length to Fortran ! which should be at least as long as the longest expected string. REAL(8), INTENT(OUT) :: DBL_OUT(4) REAL(8) STRVAL INTEGER IOS, STRLEN integer :: info double precision :: suma integer :: i STRLEN = INDEX(STRING_IN, CHAR(0)) - 1 ! Convert STRING_IN to a double. If we get an error, we'll ! supply 1.0 as a default READ (STRING_IN(1:STRLEN), *, IOSTAT=IOS) STRVAL IF (IOS /= 0) STRVAL = 1.0 DBL_OUT = STRVAL * DBL_IN call arint3D () return end
Form1.vb file:
Public Class Form1 Inherits System.Windows.Forms.Form Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim DBL_IN(4) As Double Dim DBL_OUT(4) As Double Dim MULTIPLIER As String ' Note that in VB, arrays are zero-based. DBL_IN(0) = 1.0 DBL_IN(1) = 2.0 DBL_IN(2) = 3.0 DBL_IN(3) = 4.0 MULTIPLIER = "2.0" Call electrostatica3D(DBL_IN, MULTIPLIER, DBL_OUT) TextBox1.Text = DBL_OUT(0) TextBox2.Text = DBL_OUT(1) TextBox3.Text = DBL_OUT(2) TextBox4.Text = DBL_OUT(3) End Sub
use C# code as :
using System; using System.Runtime.InteropServices; namespace Console_use_integrate{ class Program { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate float ActionRefInt(ref float n); public ActionRefInt callbackHandler; public Program() { callbackHandler = new ActionRefInt(square); } public float square(ref float n) { return n*n; } static void Main(string[] args) { Program myProg2 = new Program(); float a = 1f; float b = 3f; int step = null; float result; Console.WriteLine("Interval from {0} to {1} ", a, b); result = integrate_Dll(myProg2.callbackHandler, a, b, System.IntPtr.Zero) Console.WriteLine("integration result is {0}",result); Console.ReadKey(); } [DllImport(@"FCALL.DLL", CallingConvention = CallingConvention.Cdecl, EntryPoint = "electrostatica3D")] public static extern float electrostatica3D([MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack, float a, float b, ref int c); [DllImport(@"FCALL.DLL", CallingConvention = CallingConvention.Cdecl, EntryPoint = "electrostatica3D")] public static extern float electrostatica3D([MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack, float a, float b, System.IntPtr c); } }
and changing
float a, float b, System.IntPtr c
to something like below but in C# format
ByVal DBL_IN() As Double, ByVal STR_IN As String, ByVal DBL_OUT() As Double
and a little modification maybe needed.
so what should I do?
I found a link maybe it's useful Converting FORTRAN code to C# https://www.codeproject.com/Questions/491373/ConvertingplusFORTRANpluscodeplustoplusCRegards

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page