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

C# GUI to Fortran dll

lmckee
Beginner
1,257 Views
I'm new to .NET as I usually rely solely on fortran console programs however, I have a small project which requires a GUI ( C# in VS2003) to pass parameters (real numbers and character strings) to a fortran subroutine (IVF 9.0) and then to pass output back to the GUI. I mentioned a dll because based on what I could find that is how it's done but I'll use whatever works easiest. Please explain or direct me to an explicit example detailing the commands/options required to allow the Fortran to communicate back & forth with the C# GUI.
Thanks
L
0 Kudos
7 Replies
ipattielgc
Beginner
1,257 Views
I've done this with a CVF dll, interfaced to C#. What you need to do is follow the C# docs for how to access unmanaged and unsafe routines in external DLLs, like the Windows API. An example of C# calling a fortran routines that passcharacter arguments, 2d arrayby reference, and a 1d Fortran pointer: Enjoy! Ian.

StringBuilder cname =

new StringBuilder(32);

cname.Append(' ',cname.Capacity);

CsDllIntWrap.CSDLLCNAME( cname, cname.Length );

int isymcur=99;int isymtmp=0;int ndim=0;int ierr=0;

int[,] isize = new int[2,2];

StringBuilder cerr =

new StringBuilder(1024);

cerr.Append(' ',cerr.Capacity);

int[] iary = {1,2,3,4};

ra1_forptr ia =

new ra1_forptr();

ia.baseaddr=0;

CsDllIntWrap.FORPTR(

ref ia);

Console.WriteLine(ia.baseaddr);

Console.WriteLine(ia.elsize);

Console.WriteLine(ia.offset);

Console.WriteLine(ia.bdefined);

Console.WriteLine(ia.rank);

Console.WriteLine(ia.extent1);

Console.WriteLine(ia.stride1);

Console.WriteLine(ia.lbound1);

Console.ReadLine();

int ival;

UInt32 iadr;

unsafe

{

int* ip;

iadr=ia.baseaddr + ia.offset;

ip = (

int*)(ia.baseaddr + ia.offset); // point to first element

ival = *ip;

Console.WriteLine(iadr);

}

Console.WriteLine(ival);

Console.ReadLine();

CsDllIntWrap.CSDLLINT( cname, cname.Length

,

ref isymcur,ref isymtmp,ref ndim

,isize

,

ref ierr

,cerr, cerr.Length);

Console.WriteLine(isymcur);

Console.WriteLine(isize[0,0]);

Console.WriteLine(isize[1,1]);

Console.WriteLine(cerr);

Console.ReadLine();

}

}

[StructLayout(LayoutKind.Sequential)]

public struct ra1_forptr{

public UInt32 baseaddr;

public Int32 elsize;

public UInt32 offset;

public Int32 bdefined;

public Int32 rank;

public Int32 extent1;

public Int32 stride1;

public Int32 lbound1;

}

public class CsDllIntWrap

{

[DllImport("CSDLLINT.dll")]

public static extern void FORPTR(

ref ra1_forptr iary

);

[DllImport("CSDLLINT.dll")]

public static extern void CSDLLCNAME(StringBuilder cname, int len_cname );

[DllImport("CSDLLINT.dll")]

public static extern void CSDLLINT(StringBuilder cname, int len_cname

,

ref int isymcur, ref int isymtyp, ref int ndim

, [MarshalAs(UnmanagedType.LPArray)]

int[,] isize

,

ref int ierr

,StringBuilder cerr,

int len_cerr);

}

----------------- Fortran ------------------
! csdllint.f90
!
! FUNCTIONS/SUBROUTINES exported from CSDLLINT.dll:
! CSDLLINT - subroutine
!
subroutine FORPTR(iary)
!DEC$ ATTRIBUTES DLLEXPORT::FORPTR
save
integer,pointer :: iary(:)
integer, allocatable, target :: iary1(:)
allocate(iary1(4))
iary1=7
print*,'a1'
iary => iary1
print*,'a2'
return
end

subroutine CSDLLINT(cname,isymcur,isymtyp,ndim,isize,ierr,cerr)
! Expose subroutine CSDLLINT to users of this DLL
!
!DEC$ ATTRIBUTES DLLEXPORT::CSDLLINT
implicit none
character(len=*) :: cname
integer :: isymcur
integer :: isymtyp
integer :: ndim
integer :: isize(0:4)
integer :: ierr
character(len=*) :: cerr
character(len=32) :: cx
cx=cname//'-more'
cname=cx
isymcur=1
isymtyp=2
ndim=3
isize(:)=4
ierr=5
cerr='Just a test'
return
end subroutine CSDLLINT
subroutine CSDLLCNAME(cname)
!DEC$ ATTRIBUTES DLLEXPORT::CSDLLCNAME
implicit none
character(len=*) :: cname
character(len=32) :: cx
integer :: i
do i=1,32
print*,i,ichar(cname(i:i))
enddo
print*,cname
print*,len(cname),ichar(cname(30:30)),ichar(cname(31:31)),ichar(cname(32:32))
cx=cname(1:8)//'-more'
cname=cx

return
end subroutine CSDLLCNAME
0 Kudos
lmckee
Beginner
1,257 Views
Thanks for the help, unfortunately i still didn't succeed and i opted for a dialog approach in the end. the .NET solution will have to wait...
0 Kudos
anthonyrichards
New Contributor III
1,257 Views
You could also write a dialog-based GUI in FORTRAN using the INTEL or Compaq FORTRAN compiler
0 Kudos
lmckee
Beginner
1,257 Views
A dialog based GUI in f90 using IVF9.0 is the approach I'm using.

What is the best approach to output to the GUI several seperate lines? Can you get the editcontrol box (or whatever works) to display on seperate lines without creating a seperate box for each line? thanks.
0 Kudos
anthonyrichards
New Contributor III
1,257 Views
You mentioned above that you want the user to pass real numbers and character strings to your main program. This is straightforwardly done using edit boxes for the user to enter data and then adding a button to 'send' the data (i.e. a button torun the program that uses the data).
You have not detailed what you want to display as results of the computation: is it a list fo numbers and text, rather like a print-out on a console?
Is the user then expected to select (edit) portions and feed the results back?
0 Kudos
lmckee
Beginner
1,257 Views
The display of the results is the "print-out to a console" approach. something like :

Result x = X
result y = Y
....
...
..

The results to display could be longer than just "X & Y" if the user initially selected to calculate "A - Z". The results of the calculation are read-only to the user. The outputs from the calculation are reals and integers that are each converted to character strings for output to the GUI.
THANKS
0 Kudos
anthonyrichards
New Contributor III
1,257 Views
One possibility is to create a dialog containing a reasonable-size list box (which canbe selected to havea vertical scroll bar) and an EXIT button. This dialog is to be created and displayed when you want to display the contents ofa console log. Your main program saves your console printout in a console log file. When opened, your console display dialog reads the contents of the console log file and copies it into the list box. After examining it, you can close the box using the EXIT button. Here is some QuickWin code for it:
Code:
SUBROUTINE CONSOLEDISPLAY(CHECKED)
!*****************************************************************************
!*                                                                           *
!* CALBACK SUBROUTINE TO BRING UP A DIALOG BOX TO DISPLAY THE CONTENTS OF THE*
!* CONSOLE LOG FILE IN A LIST BOX                                            *
!*****************************************************************************

  USE DFLIB
  USE DFLOGM

  IMPLICIT NONE

  INCLUDE 'RESOURCE.FD'

  TYPE(DIALOG)DLG

  COMMON/CONSOLE/CONSOLEFILE
  CHARACTER($MAXPATH) CONSOLEFILE
  LOGICAL(KIND=4)RET
  INTEGER(KIND=4)IRET, I
  CHARACTER(LEN=130)CTEMP1
  LOGICAL(KIND=4)CHECKED

  CALL UNUSEDQQ(CHECKED)

!* INITIALIZE THE DIALOG BOX
  RET = DLGINIT(IDD_SHOWCONSOLE, DLG)
  RET = DLGSET(DLG, IDC_LIST_CONSOLE,250,DLG_NUMITEMS)
  OPEN(UNIT=200,FILE=CONSOLEFILE,STATUS='OLD', ERR=1000)
  I = 1
  DO WHILE (.NOT. EOF(200))
    READ(200,'(A130)')CTEMP1
	I = I+1
    RET = DLGSET(DLG, IDC_LIST_CONSOLE,CTEMP1,I)
! IF I EXCEEDS DLG_NUMITEMS, DLG_NUMITEMS IS AUTOMATICALLY INCREASED...
  END DO

!* BRING UP THE DIALOG BOX
  IRET = DLGMODAL(DLG)

!* EXIT BUTTON
  IF(IRET == IDC_CONSOLE_EXIT)THEN
    !* DESTROY AND RELEASE THE DIALOG RESOURCES
    CALL DLGUNINIT(DLG)
  ENDIF

  GO TO 999
1000 CONTINUE
  IRET = MESSAGEBOXQQ('ERROR OPENING CONSOLE LOG FILE'C,'ERROR'C,MB$ICONSTOP .OR. MB$OK)

999  CONTINUE
  REWIND(UNIT=200)
  CLOSE(UNIT=200)
  RETURN
END SUBROUTINE CONSOLEDISPLAY
0 Kudos
Reply