Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner
9 Views

Progress Bar in C# written GUI

Jump to solution

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

Accepted Solutions
Highlighted
Black Belt
9 Views

I have done very little with

Jump to solution

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.

Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran

View solution in original post

0 Kudos
12 Replies
Highlighted
Black Belt
9 Views

Pass the Fortran DLL routine

Jump to solution

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. 

Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran
0 Kudos
Highlighted
Employee
9 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.

Eugene Epshteyn
0 Kudos
Highlighted
New Contributor I
9 Views

I am not sure which API you

Jump to solution

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
Highlighted
New Contributor I
9 Views

Dear Ibrahim:

Jump to solution

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
Highlighted
New Contributor I
9 Views

Here is how I have done this

Jump to solution

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.

John Alexiou
0 Kudos
Highlighted
9 Views

Alternate suggestion have two

Jump to solution

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
Highlighted
Valued Contributor I
9 Views

Progress bars are really easy

Jump to solution

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
Highlighted
Beginner
9 Views

Quote:John Alexiou wrote:

Jump to solution

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
Highlighted
Beginner
9 Views

Quote:Steve Lionel (Ret.)

Jump to solution

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
Highlighted
Black Belt
10 Views

I have done very little with

Jump to solution

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.

Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran

View solution in original post

0 Kudos
Highlighted
Beginner
9 Views

Ibraham,

Jump to solution

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
Highlighted
Beginner
9 Views

Thank you Michael and Steve!

Jump to solution

Thank you Michael and Steve!

That helped a lot.

0 Kudos