Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29285 Discussions

vb2005 main with IVF dll - passing window ID

Al_Worth
Beginner
812 Views
I've made some old Fortran console code into an IVF 11 dll and call it from a vb2005 GUI. I commented out all the fortran console writes to make it work. Now I'd like to open a modeless window in vb and re-enable the console writes in the dll, but have them write to the modeless window. At my present level of understanding I assume that I need to somehow tie the modeless window to the LU for the fortran writes.

I'm not sure how to do this or just exactly what to do, so any suggestions would be very welcome.

Thanks.
0 Kudos
8 Replies
Steven_L_Intel1
Employee
812 Views
I don't think there's a way to have this work. The Fortran writes want a console window, not a regular bitmap window. The way I'd do this is somehow have the Fortran code call back into VB with the text to write (you can use internal writes to format strings). I've never done VB callbacks but I think it's possible. I'm sure others would know.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
812 Views
Quoting - Al Worth
At my present level of understanding I assume that I need to somehow tie the modeless window to the LU for the fortran writes.

I'm not sure how to do this or just exactly what to do, so any suggestions would be very welcome.


Sort of, yeah, but there are two principal catches:

1) Have in mind that one process can do only one thing at a time: do the calculation OR refresh the GUI windows, but not both. While your dll runs, everything else in the application is blocked. If your calculation takes more than a few seconds, it will be noticable. Thus, if you want an UI window to be updated during the calculation, you need to launch the calculation in a separate thread, or manage to call ProcessMessages from time to time. (Or instead make a separate exe rather than a dll out of your Fortran code).

2) When you solve obstacle 1, you can use pipes or callbacks to "redirect" the output to a modeless window.

But first things first: how long does your calculation take?
0 Kudos
Al_Worth
Beginner
812 Views
Quoting - Jugoslav Dujic

Sort of, yeah, but there are two principal catches:

1) Have in mind that one process can do only one thing at a time: do the calculation OR refresh the GUI windows, but not both. While your dll runs, everything else in the application is blocked. If your calculation takes more than a few seconds, it will be noticable. Thus, if you want an UI window to be updated during the calculation, you need to launch the calculation in a separate thread, or manage to call ProcessMessages from time to time. (Or instead make a separate exe rather than a dll out of your Fortran code).

2) When you solve obstacle 1, you can use pipes or callbacks to "redirect" the output to a modeless window.

But first things first: how long does your calculation take?

A legitimate question; it's amazing how much we assume when we post a question.

In my case, it's not a concern. It's iteratively solving for up to 50 points to a max of 100 iterations each. It reports the number of iterations and other info after each point is finished. Even if it doesn't converge, a point finishes in about 2 seconds on my 2.6 GHz machine.

My initial thought was to open a form in Vb that has a multi-line textbox. The textbox has a method toobtain it's Hwnd, but I'm not sure whether this is in any wayuseful to Fortran to set up a LU.

I'm also open to any other approaches, but in any case sample code would be gratefully accepted.
0 Kudos
Steven_L_Intel1
Employee
812 Views
Sounds as if you really want some sort of progress bar or box. Either the Fortran or VB code can open the window for such a thing and the Fortran code can update it as the computations progress. A progress bar would probably be easiest.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
812 Views
Quoting - Al Worth

A legitimate question; it's amazing how much we assume when we post a question.

In my case, it's not a concern. It's iteratively solving for up to 50 points to a max of 100 iterations each. It reports the number of iterations and other info after each point is finished. Even if it doesn't converge, a point finishes in about 2 seconds on my 2.6 GHz machine.

My initial thought was to open a form in Vb that has a multi-line textbox. The textbox has a method toobtain it's Hwnd, but I'm not sure whether this is in any wayuseful to Fortran to set up a LU.

I'm also open to any other approaches, but in any case sample code would be gratefully accepted.

Um, "reports the number of iterations..." -- where? If it only WRITEs it to console, it's not good enough. It must call (an equivalent of) DoEvents so that the UI windows are updated. So, the options there are:

1) Return control (for example, through a callback) to VB, to update text/progress/whatever and call DoEvents
2) Launch calculation in a separate thread.

I have an example where the Fortran "dll" uses WRITE(*,*) to write its output into a pipe, and the calling application overtakes that info and prints it into an edit box. The good thing about it is that Fortran source remains unchanged, and the calling application takes care about output redirecting. However, if the processing takes too long, you need a separate thread to avoid blocking of the user interface.
0 Kudos
Al_Worth
Beginner
812 Views
You are helping me focus my thoughts a bit better. I think I could (based on the calculation timings I've seen):

1. Just dump the writes into a single character variable and wait until the dll finishes to print it in an edit box. Easy; would probably work OK; I'm already doing something similar. Not quite what I had in mind, though.

2. Dump each individual line into a line buffer, then call a managed code routine (vb) to show the line in the edit box. Is this a "callback"? (I think this is a C term?In any case I don't know precisely what it means.) This would probably work pretty much as I had in mind, even without a separate thread. Calling the managed code from the Fortran dll would be a new thing for me, but I'm sure I could get it figured out.

3. Run the calculations in a separate thread as you suggest. This would probably require a bit more "learning" than the ultimate goal justifies, but I'd sure be a lot smarter if I ever got it working.

4. Open a window from Fortran. This is a non-starter since I want the window to have a life after Fortran.

It seems that my original thought of just passing the managed window/editbox to the Fortran dll as a device so it could be opened as an LU and written to directly from the Fortran subroutine isn't possible? That's a shame.

BTW - on your "write where?" question: with the writes commented out, there simply are none, of course. If I uncomment them, then the output appears quite nicely in the Visual Studio "output" area. If I get around to running it as release code outside the VS environment, I'll either need to provide a place for it to be written or skip it altogether. Thus the initial post.

Thanks for getting me thinking. If you have some skeleton code for approach 3, I'd like to see it to use as a road map for reading through the IVF docs. Also: I take it that a pipe would be essential for the multi-thread approach, but otherwise just a memory buffer would do (as I mention in approaches 1 & 2) ?

0 Kudos
Jugoslav_Dujic
Valued Contributor II
812 Views
Quoting - Al Worth
You are helping me focus my thoughts a bit better. I think I could (based on the calculation timings I've seen):

1. Just dump the writes into a single character variable and wait until the dll finishes to print it in an edit box. Easy; would probably work OK; I'm already doing something similar. Not quite what I had in mind, though.

2. Dump each individual line into a line buffer, then call a managed code routine (vb) to show the line in the edit box. Is this a "callback"? (I think this is a C term?In any case I don't know precisely what it means.) This would probably work pretty much as I had in mind, even without a separate thread. Calling the managed code from the Fortran dll would be a new thing for me, but I'm sure I could get it figured out.

3. Run the calculations in a separate thread as you suggest. This would probably require a bit more "learning" than the ultimate goal justifies, but I'd sure be a lot smarter if I ever got it working.

4. Open a window from Fortran. This is a non-starter since I want the window to have a life after Fortran.

It seems that my original thought of just passing the managed window/editbox to the Fortran dll as a device so it could be opened as an LU and written to directly from the Fortran subroutine isn't possible? That's a shame.

BTW - on your "write where?" question: with the writes commented out, there simply are none, of course. If I uncomment them, then the output appears quite nicely in the Visual Studio "output" area. If I get around to running it as release code outside the VS environment, I'll either need to provide a place for it to be written or skip it altogether. Thus the initial post.

Thanks for getting me thinking. If you have some skeleton code for approach 3, I'd like to see it to use as a road map for reading through the IVF docs. Also: I take it that a pipe would be essential for the multi-thread approach, but otherwise just a memory buffer would do (as I mention in approaches 1 & 2) ?


Pipe has the advantage that you don't need to change Fortran code: if you take care to redirect standard output into the pipe, WRITE(*) will automagically end up there and you can read it on the other end. I believe Visual Studio uses the same technique: if you're curious, you can check it yourself by checking if GetFileType(GetStdHandle(STD_OUTPUT_HANDLE).eq.FILE_TYPE_PIPE).

Here's the code I assembled. CreateThread call is commented out; you can try it yourself (but you need some synchronization as well using WaitForSingleObject or MsgWaitForMultipleObjects, because you probably want to know when it's finished). The code is all Fortran (I can post full solution if you like), so you need to replicate the functionality in VB (in which I'm not too proficient, especially VB.NET). For sake of brevity, DllExec is a "dummy dll routine", which just does something lentghy (sleepqq).

The key API calls are CreatePipe, SetStdHandle, PeekNamedPipe, and ReadFile. (Note that ReadFile blocks if there are less remaining bytes in the Pipe than requested, so you should generally check with PeekNamedPipe). As it currently stands, it duplicates functionality of your approach (1) (in a more elegant way, I guess).

The approach 2) -- callback -- would also work. I'm not sure about calling managed code from Fortran either, and I'm not even positive if it's possible. The good thing about it is that it's probably the only way to reliably implement a progress bar (which you may or may not need).

3) is fairly simple in terms of elegance. It's not too complicated, but it does involve some learning curve, I suppose. But let's take it one step at a time.

[cpp]module DllPipes

use ifwin

integer(HANDLE):: hPipeRead, hPipeWrite
!==============================================================
contains
!==============================================================
function WinMain( hInstance, hPrevInstance, lpszCmdLine, nCmdShow )
!DEC$ATTRIBUTES STDCALL, DECORATE, ALIAS: "WinMain":: WinMain
use iflogm

implicit none

integer(SINT) :: WinMain
integer(HANDLE) hInstance
integer(HANDLE) hPrevInstance
integer(LPWSTR) lpszCmdLine
integer(SINT)   nCmdShow

type(dialog):: gdlg
logical::        lret
integer::        iret
 
 include 'resource.fd'
 
lret = CreatePipe(LOC(hPipeRead), LOC(hPipeWrite), NULL, 0)
!Redirect the standard output to write end of the pipe.
!Since stdout is not used for GUI apps, only WRITE(*) will go here:
iret = SetStdHandle(STD_OUTPUT_HANDLE, hPipeWrite)
 
lret = DlgInit(IDD_DllPipes_DIALOG, gdlg)
lret = DlgSetSub(gdlg, ID_RUN, OnRun)

lret = DlgModal(gdlg)
call DlgUnInit(gdlg)

lret = CloseHandle(hPipeRead)
lret = CloseHandle(hPipeWrite)

WinMain=0

end function WinMain
!==============================================================
subroutine OnRun(dlg, id, ievent)
use ifwin
use iflogm
implicit none

type(dialog):: dlg
integer::      id, ievent
integer::      iret, ilen, nBytes, idThread
character, allocatable :: stext(:)
 include 'resource.fd'

call DllExec(0)
!Try the thread approach
!iret=CreateThread(NULL, 0, LOC(DllExec), 42, 0, 0)

!Check what is written in the meantime:
iret = PeekNamedPipe(hPipeRead, NULL, 0, 0, LOC(nBytes), 0)
allocate(stext(nBytes+1))
!Read what was written:
iret = ReadFile(hPipeRead, LOC(stext), size(sText)-1, LOC(nBytes), NULL)
sText(nBytes+1:nBytes+1) = char(0)

!Dump whole text to the edit box:
iret = DlgSendCtrlMessage(dlg, IDC_EDIT1, WM_SETTEXT, 0, LOC(sText))

!append text to the edit box:
!ilen = DlgSendCtrlMessage(dlg, IDC_EDIT1, WM_GETTEXTLENGTH, 0, 0)
!iret = DlgSendCtrlMessage(dlg, IDC_EDIT1, EM_SETSEL, ilen-1, ilen-1)
!iret = DlgSendCtrlMessage(dlg, IDC_EDIT1, EM_REPLACESEL, false, LOC(sText))

end subroutine 
!==============================================================
subroutine DllExec(iret)
!Thread func must be STDCALL with one argument
!DEC$ATTRIBUTES STDCALL:: DllExec

use ifport, only: sleepqq

do i=1,100
   !dummy sleep just for 
   call sleepqq(10)
   write(*,*) "Iteration No. ", i
end do

end subroutine DllExec
!==============================================================
end module [/cpp]

0 Kudos
Al_Worth
Beginner
812 Views
Thanks. You've given me a great start. Now to go off and ponder and try a few things....

0 Kudos
Reply