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

Progress Bar in C# written GUI

Ibrahim_A_
Novice
1,871 Views

Hello,

I have a C# based GUI that calls a FORTRAN-based dll. I would like to output a progress bar in the C#-GUI, but I'm not sure how that linkage would work. I know it can be done using the Dialog Box feature in Intel Visual Fortran with Microsoft Visual Studio, but that wouldn't show in my developed C#-GUI.
Any ideas or references?

Thanks, 

0 Kudos
1 Solution
Steve_Lionel
Honored Contributor III
1,871 Views

I have done very little with C#, but given that you are using a Fortran DLL what I recommend is that, in the call to the DLL, you include a pointer to a callback routine (in C#). The Fortran code would accept this as a TYPE(C_FUNPTR) and you would then use C_F_PROCPOINTER (both of these are defined in intrinsic module ISO_C_BINDING) to convert it to a Fortran procedure pointer. Then at the appropriate times in the Fortran code, call the C# routine through the procedure pointer to update the progress bar.

View solution in original post

0 Kudos
12 Replies
Steve_Lionel
Honored Contributor III
1,871 Views

Pass the Fortran DLL routine a pointer to a C-interoperable procedure that the Fortran DLL can call back periodically to update the progress bar. 

0 Kudos
Eugene_E_Intel
Employee
1,871 Views

Hello,

I would recommend leaving all the GUI work to C# code and implement some sort of callback mechanism for "% complete" from Fortran DLL to C#.  Mixing of different GUI implementations is possible (after all, they all end up being OS windows with window handles), but would be prone to lots of weird problems.

0 Kudos
Ibrahim_K_
New Contributor I
1,871 Views

I am not sure which API you are using (WPF vs Forms). If you are using WPF, you need to be very careful as WPF runs on a single thread. This means that you probably will need to create a new thread for your Fortran code  - unless you do not mind interrupting your calculations. If you search WPF related forums you will find lots of examples:

https://stackoverflow.com/questions/15327717/algorithm-progress-callback

The other issue you have to deal with is to pass a reference to your progress bar from C# to FORTRAN which is not so trivial as far as I know. 

You may like to look at creating DLLs wrapped in a managed C++ I posted yesterday. These problems become a little simpler.

i. konuk

0 Kudos
JohnNichols
Valued Contributor III
1,870 Views

Dear Ibrahim:

1. Do not waste your time.

2. Implement the update bar in Fortran -- it is not difficult

3. C# and Fortran are not designed to work together -- think the Iliad - C# is the Trojan Horse sent into the Fortran encampment and really just as welcome.

Although somewhere on this forum I posted a C# program that calls fortran.

0 Kudos
JAlexiou
New Contributor I
1,871 Views

Here is how I have done this using delegates:

C# Code

    publc static class Fortran
    {
        public delegate bool ProgressHandler(int i, int n);

        [DllImport("fortran.dll")]
        internal static extern void TEST(
            double[] in_values,
           ...
            ProgressHandler update);

    }


    public bool UpdateProgress(int i, int n) { /* Set progress bar here */  }

    public void CallFortran()
    {
        Fortran.TEST(
            in_values,
            ..
            UpdateProgress);
    }

and the corresponding Fortran code

    SUBROUTINE TEST( &
    in_values, &
    ...
    update)
    !DEC$ATTRIBUTES ALIAS:'TEST' :: TEST
    !DEC$ATTRIBUTES DLLEXPORT :: TEST
    !DEC$ATTRIBUTES VALUE :: n
    IMPLICIT NONE
    
!-----------------------------------------------------------------------
!     Specifications for passed arguments
!-----------------------------------------------------------------------
    INTEGER, intent(in) :: n
    REAL(8), intent(in) :: in_values(n) 
    
!-----------------------------------------------------------------------
!     Specifications for passed function pointers
!-----------------------------------------------------------------------
    interface
    FUNCTION update(i,n) result(ok)
    !DEC$ ATTRIBUTES VALUE :: i, n
    import
    integer, intent(in):: i, n
    LOGICAL :: ok
    END FUNCTION update
    END interface

 

The reason the handler returns a `bool`, is so that calls can support cancelation. The C# update function polls if the cancel button was pressed and Fortran checks the `ok` logical value returned from the callback.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,871 Views

Alternate suggestion have two entry points to the Fortran DLL. One to DoWork and the other to query progress. Then nstead of calling the Fortran function directly from C#, have C# spawn an additional C# thread that calls the Fortran DLL, then following the spawn of DoWork insert a loop that:

   

    startDoWorkThread(); 
    Done = false;
    while(!Done)
    {
       SleepForSomeShortTime();
       Done = QueryProgress(retProgress); // set Done when done, get progress in retProgress
        UpdateProgressBar(retProgress);
    }

The above is sketch code.

**** IIF the Fortran code itself is multi-threaded using OpenMP, then the worker thread you spawn from C# should be spawned only once and left around for re-use on subsequent calls into the DLL.

Jim Dempsey

0 Kudos
Paul_Curtis
Valued Contributor I
1,871 Views

Progress bars are really easy from Fortran, no need for any of the complexity.  If you have created a dialog with a progressbar element, all you need is to fetch the window handle for the progressbar.  Here is a sample proc function for a dialog which contains a progress bar,

INTEGER FUNCTION StartupProc (hwnd, msg, wParam, lParam) RESULT (res)
!DEC$ IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_StartupProc@16' :: StartupProc
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS : 'StartupProc' :: StartupProc
!DEC$ ENDIF
	USE DlgDate
	USE comctl32
	USE contwrap
    IMPLICIT NONE
    SAVE
    
    INTEGER(HANDLE),  INTENT(IN)   :: hwnd
    INTEGER(UINT),    INTENT(IN)   :: msg
    INTEGER(fWPARAM), INTENT(IN)   :: wParam
    INTEGER(fLPARAM), INTENT(IN)   :: lParam
									
    INTEGER							:: rval
    INTEGER(HANDLE), SAVE			:: hwndControl, hwprogressbar
    INTEGER							:: controlId
    INTEGER							:: code

	!	total delay of max_periods x period_delay, value in milliseconds	
	INTEGER, SAVE					:: period_count
	INTEGER, PARAMETER				:: period_delay = 200, max_periods = 50
									
    res = DefaultDialogProc (hwnd, msg, wParam, lParam)

    SELECT CASE (msg)

    CASE (WM_INITDIALOG)
		CALL InitCC (ICC_PROGRESS_CLASS)
		
		period_count = 0
		rval = SetTimer (hwnd, 1, period_delay, NULL)	! delay in milliseconds
		CALL CheckBoxSetSelected (hwnd, IDC_DATAENABLE, .TRUE.)
		CALL CheckBoxSetSelected (hwnd, IDC_FLASHCLEAR, .FALSE.)
		
		hwprogressbar = GetDlgItem (hwnd, IDC_STARTUP_PB)
		rval = SendMessage (hwprogressbar, PBM_SETRANGE, 0, MakeLong(INT2(0), INT2(max_periods)))
		rval = SendMessage (hwprogressbar, PBM_SETPOS,   0, 0)
		rval = SendMessage (hwprogressbar, PBM_SETSTEP,  1, 0)

and when you want to advance the progress bar, send it a message,

rval = SendMessage (hwprogressbar, PBM_STEPIT, 0, 0)

 

0 Kudos
Ibrahim_A_
Novice
1,871 Views

John Alexiou wrote:

Here is how I have done this using delegates:

C# Code

    publc static class Fortran
    {
        public delegate bool ProgressHandler(int i, int n);

        [DllImport("fortran.dll")]
        internal static extern void TEST(
            double[] in_values,
           ...
            ProgressHandler update);

    }


    public bool UpdateProgress(int i, int n) { /* Set progress bar here */  }

    public void CallFortran()
    {
        Fortran.TEST(
            in_values,
            ..
            UpdateProgress);
    }

and the corresponding Fortran code

    SUBROUTINE TEST( &
    in_values, &
    ...
    update)
    !DEC$ATTRIBUTES ALIAS:'TEST' :: TEST
    !DEC$ATTRIBUTES DLLEXPORT :: TEST
    !DEC$ATTRIBUTES VALUE :: n
    IMPLICIT NONE
    
!-----------------------------------------------------------------------
!     Specifications for passed arguments
!-----------------------------------------------------------------------
    INTEGER, intent(in) :: n
    REAL(8), intent(in) :: in_values(n) 
    
!-----------------------------------------------------------------------
!     Specifications for passed function pointers
!-----------------------------------------------------------------------
    interface
    FUNCTION update(i,n) result(ok)
    !DEC$ ATTRIBUTES VALUE :: i, n
    import
    integer, intent(in):: i, n
    LOGICAL :: ok
    END FUNCTION update
    END interface

 

The reason the handler returns a `bool`, is so that calls can support cancelation. The C# update function polls if the cancel button was pressed and Fortran checks the `ok` logical value returned from the callback.

Hi John,

In which part of the code are the iterations run and get updated?

Thanks

0 Kudos
Ibrahim_A_
Novice
1,871 Views

Steve Lionel (Ret.) wrote:

Pass the Fortran DLL routine a pointer to a C-interoperable procedure that the Fortran DLL can call back periodically to update the progress bar. 

 

Mr. Lionel,

The counter is running inside the fortran dll and the GUI is developed by a C# code. The GUI calls the fortran dll one time to run the iterations. I'd like to get the current iteration number from the fortran dll while it's running and pass it to the C# code. Can you provide more information about that?

Thanks,

0 Kudos
Steve_Lionel
Honored Contributor III
1,872 Views

I have done very little with C#, but given that you are using a Fortran DLL what I recommend is that, in the call to the DLL, you include a pointer to a callback routine (in C#). The Fortran code would accept this as a TYPE(C_FUNPTR) and you would then use C_F_PROCPOINTER (both of these are defined in intrinsic module ISO_C_BINDING) to convert it to a Fortran procedure pointer. Then at the appropriate times in the Fortran code, call the C# routine through the procedure pointer to update the progress bar.

0 Kudos
Michael_R_3
Beginner
1,871 Views

Ibraham,

Code for what Steve describes is shown here; I was the orginal poster albeit on another account: https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/391002 

Let me know if you have any problems getting this working and I will do my best to help.

 

Regards,

Michael 

0 Kudos
Ibrahim_A_
Novice
1,871 Views

Thank you Michael and Steve!

That helped a lot.

0 Kudos
Reply