- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
I'm not sure how to do this or just exactly what to do, so any suggestions would be very welcome.
Thanks.
Link Copied
8 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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) ?
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) ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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) ?
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]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks. You've given me a great start. Now to go off and ponder and try a few things....

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