1 (edited by JohnWasilewski 2014-09-23 09:34:34)

Topic: Malfunction when running good executable outside SF

Strange behaviour:

My project uses DISLIN.
I can build it normally with SF.

I can run the executable from within SF.
Everything works.  This includes the following GUI functions, created with DISLIN:
- A program window.
- Pull-down menus.
- One of the menus is or opening a data file.
- A lot of other stuff.

All this works, including using the pull-down menu to display a file-opening dialog box and to open the selected data file.

When I come out of SF and execute the executable by double clicking the icon, it seems to run normally, including displaying the program window I have coded using DISLIN, and including using the pull-down menu to display the file-opening dialog box but, when I navigate to a file, select it and click open, my program triggers an error-trap I have encoded, to say that it is unable to open the data file.

This happens every time.  I can not see anything in my options settings which could cause it.

I will continue investigating but I'm wondering whether anything could accidentally have found its way into SF's new improved file location handling which makes it lose track of where things are when a program is executed outside SF. 
Almost certainly its a bug in my own code, however, and I'll report back when I find it.
---
John

Re: Malfunction when running good executable outside SF

Looking more closely, I see that my call to a DISLIN function merely chooses a filename and pathname.
The code which then fails is this:

:
:
C     INPUT FILE
C     Attempt to open existing file
C     -----------------------------
      OPEN(UNIT=LUI,
     +     FILE=TRIM(InF),
     +     STATUS='OLD',
     +     ERR=50,
     +     IOSTAT=IOCODE)
:
:
:
:
C     Failed to open an input file
C     ----------------------------
50    IF(.NOT.EXISTS(TRIM(InF))) THEN
          ErrPrmt='File '//TRIM(InF)//' not found.'
          CALL PERROR(ErrPrmt)
      ELSE
          ErrPrmt='Unable to open file '//TRIM(InF)//'.'
          CALL PERROR(ErrPrmt)
      END IF
      GO TO 90
:
:
:
C     Error recovery
C     --------------
90    IF(F%I%OPEN) THEN
          CALL ClearAllData
          CLOSE(LUI)
          LUISET     = .FALSE.
          F%I%OPEN   = .FALSE.
          F%I%LU     =  0
      END IF

      IF(F%O%OPEN) THEN
          CLOSE(LUO)
          LUISET     = .FALSE.
          F%I%OPEN   = .FALSE.
          F%I%LU     =  0
      END IF

      YN=1
      CALL DWGBUT
     +  ('ERROR: '//TRIM(ErrPrmt)//'|'//
     +  'IOSTAT error code '//TRIM(ADJUSTL(I2CHAR(IOCODE,iDum)))//'.|'//
     +   'Retry opening an input file?|'//
     +   '  - YES to do so|'//
     +   '  - NO to cancel',YN)
:
:
:

The error message my program then generates is:

ERROR: unable to open file {my filename}
IOSTAT error code 9.
Retry opening an input file?
  -YES to do so
  -NO  to cancel

I haven't yet found what GFortran's IOSTAT error code 9 means.
---
John

3 (edited by JohnWasilewski 2014-09-23 11:38:03)

Re: Malfunction when running good executable outside SF

I've slightly modified the file opening and error handling statements, to produce more information.

The relevant code fragments now read:

:
:
C     INPUT FILE
C     Attempt to open existing file
C     -----------------------------
      OPEN(UNIT=LUI,
     +     FILE=TRIM(InF),
     +     STATUS='OLD',
     +     ERR=50,
     +     IOSTAT=IOCODE,
     +     IOMSG=IOMSG)
:
:
:
:
C     Failed to open an input file
C     ----------------------------
50    IF(.NOT.EXISTS(TRIM(InF))) THEN
          ErrPrmt='File '//TRIM(InF)//' not found.'
          CALL PERROR(ErrPrmt)
      ELSE
          ErrPrmt='Unable to open file '//TRIM(InF)//'.'
          CALL PERROR(ErrPrmt)
      END IF
      GO TO 90
:
:
:
C     Error recovery
C     --------------
90    IF(F%I%OPEN) THEN
          CALL ClearAllData
          CLOSE(LUI)
          LUISET     = .FALSE.
          F%I%OPEN   = .FALSE.
          F%I%LU     =  0
      END IF

      IF(F%O%OPEN) THEN
          CLOSE(LUO)
          LUISET     = .FALSE.
          F%I%OPEN   = .FALSE.
          F%I%LU     =  0
      END IF

      YN=1
      CALL DWGBUT
     +  ('ERROR: '//TRIM(ErrPrmt)//'|'//
     +  'IOSTAT error code '//TRIM(ADJUSTL(I2CHAR(IOCODE,iDum)))//'.|'//
     +   TRIM(IOMSG)//'.||'//
     +   'Retry opening an input file?|'//
     +   '  - YES to do so|'//
     +   '  - NO to cancel',YN)
:
:
:

The error message my program now generates is:

      ERROR: unable to open file {my filename}
      IOSTAT error code 9.
      Error closing file in OPEN statement.

      Retry opening an input file?
       -YES to do so
       -NO  to cancel



Just to be clear, when I run this code from inside SF, this error does not occur.
It only happens when I run the program from Win Doze but double-clicking the icon.
--
John

Re: Malfunction when running good executable outside SF

John,

It would be useful to see full path names that the system is trying to open.  Simply Fortran always executes targets in the project directory (or a directory relative to the project directory based on Launch Options).  When you double click an executable in Windows, it should start in the executable's directory.  However, if you click a shortcut to an executable, it might not start in the executable directory (it's configurable).

I'm just wondering what path information DISLIN is actually providing via its file dialog.  It could be a relative directory, but relative to what?  Which function in DISLIN are you using to request a file dialog?  I'm wondering if maybe DISLIN is providing some odd relative path that your executable isn't handling properly.  I'm not implying it's a bug in your code, more that DISLIN is perhaps behaving in an unexpected manner.

Jeff Armstrong
Approximatrix, LLC

Re: Malfunction when running good executable outside SF

PATHNAMES

Executable
   C:\Users\jwasilewski\DEV\Fortran\InStruct\Instruct64.SF.exe
   
Data files (a couple of examples)
   C:\Users\jwasilewski\DEV\Fortran\InStruct\Tests\Hastings.ins
   C:\Users\jwasilewski\DEV\Fortran\InStruct\Tests\Pw0.ins

Launch options
   I hadn't noticed that new options facility.
   Looking at it, I see I have everything blank except the greyed out bit.


THE EXECUTABLE OR A SHORTCUT TO IT?
I have been getting the same aberrant behaviour both when I double click a link and when I double click the executable's own icon.


COMMENT
From my code which I posted on this, it looks to me as if problem doesn't lie within DISLIN, because the error message arises from an attempted FORTRAN file OPEN statement, not from the call just made a line or two earlier to a DISLIN finction to open a file requester dialog and return a pathname.


MORE INFO
I've just tried something.  I copied the data file I've been trying to open into teh same directory as the compiled executable.
ie pathname, 
      C:\Users\jwasilewski\DEV\Fortran\InStruct\Hastings.ins

When I run it from Windows, outside SF, it returns the strange file-opening error code 9 and GFortran 2003 errmsg, "Error closing file in OPEN statement.".  When I run the executable from within SF, it successfully opens the data file.

Just so very peculiar!
---
John

Re: Malfunction when running good executable outside SF

John,

My question is what path does your Fortran code see exactly after DISLIN provides it with a path to the file.  The "problem" I was hypothesizing with DISLIN was actually more related to what exactly its function is returning.  I was questioning whether it was providing an absolute or relative path.

The IOSTAT value of 9 probably refers to the C equivalent EBADF, which Microsoft describes as a "Bad File Number."  In this case, though, the term "file number" is entirely unrelated to Fortran's "unit number," so you shouldn't go investigating your choice of unit number in this case.  I'll have to do some more digging on my end.

Jeff Armstrong
Approximatrix, LLC

7 (edited by JohnWasilewski 2014-09-23 23:19:18)

Re: Malfunction when running good executable outside SF

Here's the full code of my subprogram, SUBROUTINE FOPEN, followed by the full code of another subroutine it calls, SUBROUTINE GETFILENAME, and that of a utility subprogram, SUBROUTINE PARSEPATH, the purpose of which will be obvious.

What happens is that, at statement label 10, FOPEN calls GETFILENAME, WHICH USES DISLIN to display a filename requester dialog, which reads the filename the user enters into the dialog, and returns the file pathname via GETFILENAME back to FOPEN.

Immediately after statement label 10, FOPEN then stores the input filename in string variable InF (only for readability), and then uses InF as the filename in the statement,

      OPEN(UNIT=LUI,
     +     FILE=TRIM(InF),
     +     STATUS='OLD',
     +     ERR=50,
     +     IOSTAT=IOCODE,
     +     IOMSG=IOMSG)


       SUBROUTINE FOpen
C     ----------------
C     jw / 25-07-12  1st draft started
C     jw / 25-08-12  last rev.

C     In any un-saved data then prompt to call FSave or FSaveAS if reqd.

C     CALL ClearAllData
C     CALL GetFileName

C     Open the named INPUT file as a READ file on LUI at:
C     TRIM(F%Path)//TRIM(F%Name)//'.'//TRIM(F%I%Ext).
C     CALL ReadInput(LU)
C     Close LUI

C     Call the function CHANGED() to obtain a new ChkSUM

C     Open the new OUTPUT file as a WRITE file on LUO at:
C     TRIM(F%Path)//TRIM(F%Name)//'.rtf' .
C     Leave LUO open.
C     RETURN

      USE Dislin
      USE LUnits
      USE Files
      USE Params
      USE WinSTUFF
      USE Titles

      CHARACTER*132 InF, OuF, BkF
      CHARACTER*160 ErrPrmt
      CHARACTER DateToday*9, IOMSG*120, I2CHAR*16
      LOGICAL EXISTS, IsOPEN, DELETABLE, SavedIfWanted, CHANGED
      INTEGER YN

C     If any un-saved data then prompt to call FSave or FSaveAS as reqd.
      IF(F%Named.AND.CHANGED()) THEN
          CALL SWGWTH(-54)
          ISel=3
          CALL DWGlis
     +   ('You still have unSAVEd data.  SAVE it or lose it.',
     +    'Save|Save-AS|Continue without SAVing|Go back|Quit', ISel)
          IF(ISel.EQ.1) THEN
              CALL fSave
          ELSE IF(ISel.EQ.2) THEN
              CALL fSaveAs
          ELSE IF(ISel.EQ.3)  THEN
              CONTINUE
          ELSE IF(ISel.EQ.4)  THEN
              RETURN
          ELSE
              CALL CloseALL ! (ISel.EQ.4)
          END IF
      END IF
      CALL CloseALL
      CALL ClearAllData
      UDat = DateToday()

      NMATS = 0
      NMTYP = 0
      NNODE = 0
      NMEMB = 0
      NPRES = 0
      NSPRI = 0
      NLCAS = 0

      IPAGE  = 0
      ILINE  = 0

      IF(F%I%OPEN) THEN
          CLOSE(LUI)
          LUISET     = .FALSE.
          F%I%OPEN   = .FALSE.
          F%I%LU     =  0
      END IF

      CALL LUinit

10    CALL GetFileName(.TRUE.)
C         InF = TRIM(F%NAME)//'.'//TRIM(F%I%EXT)
          InF = TRIM(F%Path)//TRIM(F%Name)//'.'//TRIM(F%I%Ext)
          Li = LEN_TRIM(InF)
C     BAK FILE
          BkF = TRIM(F%NAME)//'.'//'bak'
          Lb = LEN_TRIM(BkF)
C     OUTPUT FILE
          OuF = TRIM(F%NAME)//'.rtf'
          Lo = LEN_TRIM(OuF)

C     INPUT FILE
C     Attempt to open existing file
C     -----------------------------
      OPEN(UNIT=LUI,
     +     FILE=TRIM(InF),
     +     STATUS='OLD',
     +     ERR=50,
     +     IOSTAT=IOCODE,
     +     IOMSG=IOMSG)

C     File-open succeeded
C     -------------------
C     No ERR, set file-opened flag, read the file and close it
      F%Named    = .TRUE.
      F%I%EXISTS = .TRUE.
      LUISET     = .TRUE.
      F%I%OPEN   = .TRUE.
      F%I%LU     =  LUI

C     Attempt to create and open an empty Output file
C     -----------------------------------------------
      IF(.NOT.EXISTS(TRIM(F%NAME)//'.rtf')
     +   .OR. SavedIfWanted(LU,TRIM(F%NAME)//'.rtf'))
     +    OPEN(UNIT=LUO,
     +         FILE=TRIM(F%NAME)//'.rtf',
     +         STATUS='NEW',
     +         ERR=51,
     +         IOSTAT=IOCODE)

C     File-open succeeded
C     -------------------
C     No ERR, so say so and set the file-opened flag
      LUOSET=.TRUE.
      F%Named    = .TRUE.
      F%O%EXISTS = .TRUE.
      F%O%OPEN   = .TRUE.
      F%O%LU     =  LUO


C     Succesfully opened both an input file
C     and the corresponding output file
C     -------------------------------------
C     Read the input data and close the input file
C     Then initialise the output file
C
      CALL SCRmsg('Reading input data from file '//TRIM(InF)//'.',
     +             .FALSE.)

C     -------------------
      CALL ReadINput(LUI)
C     -------------------

      CLOSE(LUI, STATUS='KEEP',ERR=60,IOSTAT=IOCODE)
      LUISET     = .FALSE.
      F%I%OPEN   = .FALSE.
      F%I%LU     =  0
      CALL SCRmsg('Output file ready for results: '//
     +TRIM(F%NAME)//'.rtf',.FALSE.)

C     All done successfully
C     ---------------------
      MORE = .TRUE.
      CALL SENDOK
      RETURN


C     Failed to open an input file
C     ----------------------------
50    IF(.NOT.EXISTS(TRIM(InF))) THEN
          ErrPrmt='File '//TRIM(InF)//' not found.'
          CALL PERROR(ErrPrmt)
      ELSE
          ErrPrmt='Unable to open file '//TRIM(InF)//'.'
          CALL PERROR(ErrPrmt)
      END IF
      GO TO 90

C     Failed to open an output file
C     -----------------------------
51    ErrPrmt='Unable to open file '//TRIM(OuF)//'.'
      GO TO 90

C     Failed to close the input file
C     ----------------------------
60    ErrPrmt='Unable to close file '//TRIM(InF)//'.'
      CALL PERROR(ErrPrmt)
C     GO TO 90

C     Error recovery
C     --------------
90    IF(F%I%OPEN) THEN
          CALL ClearAllData
          CLOSE(LUI)
          LUISET     = .FALSE.
          F%I%OPEN   = .FALSE.
          F%I%LU     =  0
      END IF

      IF(F%O%OPEN) THEN
          CLOSE(LUO)
          LUISET     = .FALSE.
          F%I%OPEN   = .FALSE.
          F%I%LU     =  0
      END IF

      YN=1
      CALL DWGBUT
     +  ('ERROR: '//TRIM(ErrPrmt)//'|'//
     +  'IOSTAT error code '//TRIM(ADJUSTL(I2CHAR(IOCODE,iDum)))//'.|'//
     +   TRIM(IOMSG)//'.||'//
     +   'Retry opening an input file?|'//
     +   '  - YES to do so|'//
     +   '  - NO to cancel',YN)
         IF(YN.EQ.0) THEN
             RETURN
         ELSE
             GO TO 10
         END IF
      RETURN
      END
 


       SUBROUTINE GetFileName(ChangePath)
C     ----------------------------------
C     jw / 25-07-12  1st draft started
C     jw / 15-02-14  last rev.

C     On returning from this subroutine:

C     The INPUT file pathname should be stored in
C     TRIM(F%Path)//TRIM(F%Name)//'.'//TRIM(F%I%Ext).

C     F%I%Exists should indicate whether the INPUT file already exists.
C     F%I%OPEN should indicate whether it is already open.

C     F%bakExists should indicate whether the a BAK file already exists.
C     (It should not be open).

C     F%O%Exists should indicate whether the OUTPUT file already exists.
C     F%O%OPEN should indicate whether it is already open.

      USE Dislin
      USE Files
      LOGICAL EXISTS, ChangePath

C     IF(F%Named) RETURN

C     Input filename not yet known
      F%Path = REPEAT(' ',128)
      F%Name = REPEAT(' ',96)
      F%I%Exists = .FALSE.
      F%I%OPEN = .FALSE.
      F%BAKexists = .FALSE.
      F%BAKdeletable = .FALSE.

      CALL SWGOPT('STANDARD','DIALOG') !Use STANDARD file dialog boxes

C     Prompt user for a data input Path\filename.ext
      F%Path = ' '
10    CALL DWGfil('Structure DATA filename',F%Path,'*.*')
      CALL SWGOPT('TOP','DIALOG') !Keep all other dialog boxes on top

C     Was a file actually selected or named by the user?
      IF(LEN(F%Path).EQ.0) THEN
C         No.
          CALL BailOut('No input file provided.$', 'OPTIONS', 'YES')
          RETURN
      END IF

      F%Named = .TRUE.

      CALL ParsePath(F%PATH,F%Name,F%I%Ext)
      IF(LEN_TRIM(F%I%Ext).EQ.0) F%I%Ext='ins'
      F%O%Ext = 'rtf'

C     Set the current directory to that of the chosen file
      IF(ChangePath) CALL CHDIR(F%Path,iDone)

C     INPUT FILE

C     Does the named INPUT file already exist?
      F%I%Exists=EXISTS(TRIM(F%Path)//TRIM(F%Name)//'.'//TRIM(F%I%Ext))
      IF(F%I%Exists) THEN
C         Yes, it exists
C         Is it OPEN?
          INQUIRE
     +    (FILE=TRIM(F%Path)//TRIM(F%Name)//'.'//TRIM(F%I%Ext),
     +    OPENED=F%I%OPEN)
C         Is there a 'bak' file?
          F%BAKexists = EXISTS(TRIM(F%Path)//TRIM(F%Name)//'.bak')
      END IF

C     OUTPUT FILE

      F%O%Exists = EXISTS(TRIM(F%Path)//TRIM(F%Name)//'.rtf')
      IF(F%I%Exists) THEN
C         Yes, it exists
C         Is it OPEN?
          INQUIRE
     +    (FILE=TRIM(F%Path)//TRIM(F%Name)//'.rtf',
     +    OPENED=F%O%OPEN)
      END IF

      RETURN
      END

 

       SUBROUTINE ParsePath(PATH,NAME,EXT)
C     -----------------------------------

C     Parse PATHname into PATH (no filename), NAME and EXT

      CHARACTER PATH*128, NAME*32, EXT*6

      iLen=LEN(Trim(AdjustL(PATH)))
      iBsl=INDEX(PATH,'\',.TRUE.)
      iDot=INDEX(PATH,'.',.TRUE.)

      IF(iDot.GT.iBsl) THEN
         LenEXT=iLen-iDot
         EXT(1:LenEXT) = PATH(iDot+1:iLen)
      ELSE
         iDot=iLEN+1
         LenEXT=0
         EXT=REPEAT(' ',12)
      END IF

      LenNAM=iDot-iBsl
      NAME(1:LenNAM) = PATH(iBsl+1:iDot-1)
      PATH=TRIM(PATH(1:iBsl)//REPEAT(' ',LenNAM+LenEXT+1))

C     NAME=TRIM(NAME)//'.'//TRIM(EXT)
      
      RETURN
      END 

The error I have reported is being thrown by FOPEN, using my error trap code.

Originally, I had the FOPEN assign only the filename, not the whole pathname, to string variable InF, using the statement you see commented out in my code, namely,
          InF = TRIM(F%NAME)//'.'//TRIM(F%I%EXT)

This was the position until a few minutes ago.  I had found that Windows was handling the path for me (I guess by remembering the path that was last used when DISLIN obtained a filename from a dialog box.  All I had to do in the OPEN statement was give the filename, not the complete path.  My error trap code quotes the filename it is having trouble with, and it had been correctly received from DISLIN.  The filename was just, 'Hastings.ins'. 

This was working perfectly well, as long as I ran the executable from inside SF.

I have now amended the code of FOPEN to substitute this assignment for the one referred to above:
          InF = TRIM(F%Path)//TRIM(F%Name)//'.'//TRIM(F%I%Ext)

On re-testing the program, I have found EXACTLY THE SAME FLAWED BEHAVIOUR as before.
It all works when run from inside SF, but when the executable is run directly from Windows, it gives this error message (I hope you can see my screenshot):

http://i.imgur.com/hvg1aGd.png
----
John

Re: Malfunction when running good executable outside SF

I've found an older version of my executable file, which I compiled on 10-08-2014, at a slightly earlier stage of my recent project development work.
I assume I must then have been using SF 1.15, but I can't be sure.
Perhaps SF also had older versions of GFortran and maybe DISLIN, though I am fairly confident that this problem has nothing at all to do with DISLIN.

I have also added quite a lot to my project since then, though I'm fairly sure I haven't touched the filehandling routines.
Alas, I haven't yet had time to learn sufficiently and start using properly any versioning software; I've just started dabbling with it but nothing more than that.

The 10-08-2014 executable runs perfectly well, both from inside SF and from the Windows executable when double clicking hte icon, and it opens the program's data input file without any problem.
---
John

Re: Malfunction when running good executable outside SF

If your previous version was from August 10th, it would have used version 2.14 or earlier, which is indeed a different version of the compiler, although only a micro-difference (GNU Fortran 4.9.1 versus 4.9.0). Based on changes, there shouldn't have been anything done to the OPEN statement.

I'm still trying to figure out why you're having the problem based on your code, but I don't have an explanation yet.  I'm still looking into it.

Jeff Armstrong
Approximatrix, LLC

Re: Malfunction when running good executable outside SF

I hope you have received the project files I sent last night in case you'd care to take a look.
---
John.

Re: Malfunction when running good executable outside SF

John,

I did receive them, but I haven't had a chance yet to look at them.  Today was rather busy with some billing system changes (doesn't affect current users).  I will definitely get to it tomorrow, though.

Jeff Armstrong
Approximatrix, LLC

Re: Malfunction when running good executable outside SF

Note to everyone:

Jeffrey Armstring is a genius.
I am posting a copy below this of his email to me.
As always, with correct diagnosis and solution, naturally.
---
J.



John,

I think I've figured out your issue.  I believe it's related to your unit numbers defined in mLUNITS.for.  You've hardcoded the input and output files to use units 5 and 6 respectively.  Normally these are actually standard input (keyboard) and standard output (screen).  While most Fortran compilers don't have a problem with reassigning them to files, Simply Fortran's compiler does have a problem.

Quite frankly, I'm surprised your program runs at all because reassigning these units for a lot of Fortran examples with Simply Fortran crashes the program immediately.  Yours seems to keep working, which is good.

I changed mLUNITS.for to use units 105 and 106 rather than 5 and 6 for input and output files.  When I run your program from its executable directly, it now works fine.

I think the reason it was running under Simply Fortran before was that Simply Fortran continued to provide it with standard input and output handles so that text could be output if you so wished.  When run from its executable, though, it would fail because Windows would see that it was a Windows GUI program and not provide it with the standard handles.  Even though you were reassigning those unit numbers, Windows and your Fortran program (through the Fortran runtime library) were still associating those two units with the standard handles somehow.  When it couldn't find the handles to standard input, it said that your file open operation failed.

This behavior is a bug, so you didn't actually code anything wrong.  However, it's usually best to avoid unit numbers under 20 or so unless you really want to access the devices they historically represent.  I'm surprised it worked in the previous version of the compiler, too.

Let me know if all of the above makes sense.   Sorry for the delay in my response!

-Jeff


--
Jeffrey Armstrong
jeffrey.armstrong@approximatrix.com 
Approximatrix, LLC - http://approximatrix.com/

Re: Malfunction when running good executable outside SF

John,

Glad to hear things are working now!

Jeff Armstrong
Approximatrix, LLC