forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

WRITE called in a DLL results in an exception
Goto page 1, 2  Next
 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> General
View previous topic :: View next topic  
Author Message
BK



Joined: 07 May 2020
Posts: 14

PostPosted: Wed Jul 08, 2020 7:54 pm    Post subject: WRITE called in a DLL results in an exception Reply with quote

I'm using C++Builder 10.3 to build a GUI for legacy F77 FORTRAN analysis software. A Win32 DLL was built and loads OK. The DLL needs to write results to an external file. The usual WRITE statement with unit=num results in an External exception 80000003. WRITEFA@ can be used for one-line writes, but existing format statements that produce multi-line writes can't be included as arguments. Opening the external file using OPEN with a specific unit number seems to work OK, so it seems that WRITE doesn't have a good handle for the external file. Is there any way that WRITE can be used?
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Thu Jul 09, 2020 3:17 am    Post subject: Re: WRITE called in a DLL results in an exception Reply with quote

BK wrote:
... existing format statements that produce multi-line writes can't be included as arguments.


Format statements exist only in Fortran source code, and allow the statement label to be used for the format string. There is no way to pass a Fortran statement from your non-Fortran GUI code layer to the Fortran DLL*. You can, however, pass a properly constituted Format string as an actual argument, as long as the GUI code knows how to pass Fortran string arguments while adhering to the conventions of the Fortran compiler and runtime.

BK wrote:
Opening the external file using OPEN with a specific unit number seems to work OK, so it seems that WRITE doesn't have a good handle for the external file.

I do not see how the second statement follows from the first, and what you mean by "good handle". WRITE statements are converted to a series of calls to I/O routines in the Fortran RTL, and we rarely need to know the details of those calls.
-----
* Leaving out implementations that pass the Fortran code to the compiler, wait for the compilation and linking to complete, and transfer execution to the resulting EXE/DLL.


Last edited by mecej4 on Thu Jul 09, 2020 8:01 am; edited 1 time in total
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7916
Location: Salford, UK

PostPosted: Thu Jul 09, 2020 7:44 am    Post subject: Reply with quote

What UNIT numbers are you using for file output?
Back to top
View user's profile Send private message AIM Address
BK



Joined: 07 May 2020
Posts: 14

PostPosted: Thu Jul 09, 2020 8:28 pm    Post subject: Reply with quote

mecej4, the FORTRAN source includes several multi-line writes such as a header and a glossary. I wasn't talking abt passing a format statement from C++builder to the DLL. I was talking abt an inability to include in WRITEFA@ a format label or multiple format statement lines. But I have an idea for a work-around.

paullaidler, I was using unit=17 in WRITE. I later used OPENF@ to open the output file. This returns identifier SID which is used in WRITEFA@. In my inexperience, I interpret SID as a handle.
Back to top
View user's profile Send private message
BK



Joined: 07 May 2020
Posts: 14

PostPosted: Tue Jul 14, 2020 8:20 pm    Post subject: Reply with quote

Out of curiosity, I pulled my XP machine with an old FORTRAN compiler out of storage, and built the DLL with the same source code (taking out any F95 code). Running the DLL with C++Builder worked just fine, no problems.

Sad to say, I think Silverfrost is not ready for the big leagues.

BTW, when using an internal write, you have to know a priori the width of the value to write. For a one-digit integer, fmt='I1' works, fmt='I2' doesn't. Not too convenient when results are computed and you don't know what the width would be. And I didn't even try it with a floating-point number.

A very disappointed customer.
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Tue Jul 14, 2020 11:49 pm    Post subject: Re: Reply with quote

BK wrote:
... when using an internal write, you have to know a priori the width of the value to write. For a one-digit integer, fmt='I1' works, fmt='I2' doesn't. Not too convenient when results are computed and you don't know what the width would be.


You can use the I0 format. For example,

Code:
program inwrite
implicit none
integer ijk,i
character*11 str
!
ijk = 1
do i=1,5
   write(str,'(I0)')ijk
   print '(1x,I2,2x,A)',i,trim(str)//' $'
   ijk=ijk*10+1
end do
end program


gives

Code:
  1  1 $
  2  11 $
  3  111 $
  4  1111 $
  5  11111 $
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Wed Jul 15, 2020 12:18 am    Post subject: Multiple lines and writefa@ Reply with quote

You can build up a multi-line string in your code before writing that string using WRITEFA@, if you wish.

Code:
program inwrite
implicit none
integer ijk,i
integer*2 sid,ier
character*7 str
character*80 lines
!
ijk = 1
lines = ''
do i=1,5
   write(str,'(I0)')ijk
   if (i .gt. 1) lines = trim(lines) // char(10)
   lines = trim(lines) // str
   ijk=ijk*10+1
end do
call openw@('multi.txt',sid,ier)
call writefa@(lines,sid,ier)
call closef@(sid,ier)
end program


writes the file multi.txt, containing:

Code:
1
11
111
1111
11111
Back to top
View user's profile Send private message
BK



Joined: 07 May 2020
Posts: 14

PostPosted: Wed Jul 15, 2020 8:32 pm    Post subject: Reply with quote

mecej4, tnx for the hints, but it doesn't make sense for me to re-write hundreds of write statements that work perfectly fine when using a DLL created by an old FORTRAN compiler.

I'm hoping that my concerns abt DLL writes get passed on to the developers. I'm also hoping I get a notice abt an updated version of Silverfrost if and when they incorporate fixes.
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1885

PostPosted: Thu Jul 16, 2020 9:03 am    Post subject: Reply with quote

I am still in the dark regarding (i) what features, standard or non-standard, that you use in your code and are supported by your anonymous old compiler as well as FTN95 and (ii) the code that fails with the current version of FTN95.

If you can provide a demonstrator, please do; if the bug can be reproduced, we will be half-way to a solution. In the absence of actual code, little progress can be made.


Last edited by mecej4 on Thu Jul 16, 2020 10:49 am; edited 2 times in total
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7916
Location: Salford, UK

PostPosted: Thu Jul 16, 2020 9:55 am    Post subject: Reply with quote

This is just to endorse mecej4's comment.

Documentation is provided in ftn95.chm in under "Mixed language programming".

But we need some basic sample code from you in order to reproduce the failure - a main program in C calling a subprogram in Fortran with details of how they are linked.
Back to top
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7916
Location: Salford, UK

PostPosted: Thu Jul 16, 2020 10:33 am    Post subject: Reply with quote

BK

I have put together a sample based on your description and it works OK for me. So we need a very simple sample from you that illustrates the failure.

This is my C code:

Code:
extern "C" void SUB1(int* k);
int _tmain(int argc, _TCHAR* argv[])
{
  int k = 42;
  SUB1(&k);
  return 0;
}


and here is my Fortran code:

Code:
SUBROUTINE sub1(k)
  INTEGER k
  open(10,file="output.dat")
  write(10,*) k
  close(10)
END SUBROUTINE sub1
Back to top
View user's profile Send private message AIM Address
BK



Joined: 07 May 2020
Posts: 14

PostPosted: Fri Jul 17, 2020 6:54 pm    Post subject: Reply with quote

Here's the C++Builder code:
typedef void (__cdecl *MYPROC)();
HINSTANCE hndl;
MYPROC ProcAdd;
BOOL fFreeResult, fLinkSuccess = FALSE;
CurrDirec = GetCurrentDir();
hndl = LoadLibraryA("INPUTS.dll");
if (hndl != NULL)
{
ProcAdd = (MYPROC) GetProcAddress(hndl, "INPUTS");
if (NULL != ProcAdd)
{
fLinkSuccess = TRUE;
ShowMessage("link success");
(ProcAdd) ();
} else {
ShowMessage("could not get dll addr");
}
fFreeResult = FreeLibrary(hndl);
}

And here's the fortran:
F_STDCALL Subroutine INPUTS
CFTN95$OPTIONS(FIXED,STDCALL)
(misc comments)
ENTRY SALFSTARTUP
(the rest is F77 common blocks, local variables, & format statements.

The DLL was created using command-line slink since it didn't appear that link options did anything but create a default LibMain.

Here are the slink commands:
DLL
load c:\aa2\Inputs.obj
load c:\aa2\FixAnt.obj
load c:\aa2\GetLwr.obj
load c:\aa2\Stat1.obj
exportall
map c:\aa2\statmap.txt
file c:\aa2\INPUTS
Back to top
View user's profile Send private message
BK



Joined: 07 May 2020
Posts: 14

PostPosted: Fri Jul 17, 2020 7:03 pm    Post subject: Reply with quote

Forgot to mention that Sub INPUTS calls three other subroutines, all starting with "F_STDCALL Subroutine" and including "ENTRY SALFSTARTUP.", The on-line help wasn't clear on whether the other subroutines should include F_STDCALL and the ENTRY, so I put them in. But the issues occurred in INPUTS, not the others.
Back to top
View user's profile Send private message
BK



Joined: 07 May 2020
Posts: 14

PostPosted: Fri Jul 17, 2020 7:21 pm    Post subject: Reply with quote

After the F77 common blocks, local variables, & format statements, the fortran opens and reads a text file with integer arguments, input data file name, and output data file name. Both files are in the current working directory. I don't pass the file names because past experience shows that the file name strings get garbled.
The open is typical F77:
EXISTS = .FALSE.
INQUIRE(FILE='GUI_data.txt',EXIST=EXISTS)
IF (EXISTS) THEN
OPEN (UNIT=25,FILE='GUI_data.txt',STATUS='UNKNOWN',
& FORM='FORMATTED',ACCESS='SEQUENTIAL')
DO 5 JJ = 1,4
LINE = ' '
READ(25,1009) LINE
IF (JJ .EQ. 1) READ(LINE(1:1),fmt='(I1)') IGUI
IF (JJ .EQ. 2) READ(LINE(1:1),fmt='(I1)') IOUT
IF (JJ .EQ. 3) INPNAM = TRIM(LINE)
IF (JJ .EQ. 4) OUTNAM = TRIM(LINE)
5 CONTINUE

There's a similar section for opening the output data file on unit 17
A typical write (where iw is set to 17) is
write(iw,*) 'igui: ',igui
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7916
Location: Salford, UK

PostPosted: Sat Jul 18, 2020 8:34 am    Post subject: Reply with quote

BK

The first thing to note is that STDCALL is not a valid option in CFTN95$OPTIONS(FIXED,STDCALL). FTN95 does not fault this and at the moment I don't know if that is deliberate or just an oversight. But this makes no difference because you are attempting something like it with F_STDCALL.

The main concern relates to the matching of __cdel and F_STDCALL or STDCALL. The default calling convention for FTN95 is "__cdel" and presumably this is also the default for C++ Builder. In which case you should not use F_STDCALL or STDCALL in the Fortran code.

More to the point, I strongly recommend that you start with a simple test like the one that I outlined above - just a short main program with a very simple call to a Fortran routine. You will probably need to change from my _tmain() (which is for Microsoft C) to main() and it is OK to use LoadLibraryA and GetProcAddress for the dynamic linking but after that, keep it as simple as possible.

In short, my test demonstrates that you can do what you are aiming for, but you should first sort out the matching of the calling conventions (__stdcall versies __cdel).
Back to top
View user's profile Send private message AIM Address
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> General All times are GMT + 1 Hour
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group