Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28469 Discussions

CHDIR does not set the directory before open

reidar
New User
755 Views

In an application I am opening different files residing in different folders. To perform the assignment, I try to force Windows to display the correct folder. in the way that if I want to open an .INP file, the FileOpen dialog should list the content of the INP directory aso. However, the FileOpen  dialog box lists the file content of the most recent directory.  In the example below, the files in the "InputDir"  should be listed and this happens. But next, when I  will open a PLT file (not shown here), the dialog box list the files in the InputDir, and vice versa...

What could be done to fix the problem ?

 

 

! get open file dialog box

Ofn%Flags = null

szfilter = &

"TVC input files(*.INP)"C//"*.INP"C// &

"Simulation input files(*.SIN)"C//"*.SIN"C//""C

Ofn%LPSTRINITIALDIR = loc(trim(InputDir)//Char(0))

iret = CHDIR(InputDir)

iret = InitializeOpen()

bret = GETOPENFILENAME(Ofn)

bret=.true.

! check to see if the OK button has been pressed

if(bret == 0) then ! check for error

call COMDLGER(ierror)

0 Kudos
9 Replies
JVanB
Valued Contributor II
755 Views

I consider the line

Ofn%LPSTRINITIALDIR = loc(trim(InputDir)//Char(0))

to be especially problematic. You are taking the address of an expression and storing it in the OFN structure. By the time the very next statement executes, this address will already be invalid. I would declare a helper variable

CHARACTER(LEN(InputDir)+1), TARGET :: InputDir1

then you could copy the data to there and append the trailing NUL that C requires

InputDir1 = TRIM(InputDir) // Char(0)

Ofn%LPSTRINITIALDIR = loc(InputDir1)

let us know if this helps.

 

0 Kudos
mecej4
Honored Contributor III
755 Views

You have set szfilter to the file selection mask, but I do not see where you used it in the file open dialog to limit the file names returned.

0 Kudos
Paul_Curtis
Valued Contributor I
755 Views

RepeatOffender's reply is probably the key to your problem.  Here is a more complete code sample which works as expected to set the path for file reading/writing:

LOGICAL FUNCTION DlgFileIO (rw_mode, hwndParent, filter, fullpath, ncfn, extn, ncextn, path)
    IMPLICIT NONE
    CHARACTER(LEN=1), INTENT(IN)		   :: rw_mode
    INTEGER(HANDLE),  INTENT(IN)		   :: hwndParent
    CHARACTER(LEN=*), INTENT(IN)		   :: filter
	CHARACTER(LEN=*), INTENT(IN)		   :: extn
	CHARACTER(LEN=*), INTENT(INOUT)		   :: fullpath
	INTEGER,		  INTENT(INOUT)		   :: ncfn, ncextn
	CHARACTER(LEN=*), INTENT(INOUT)		   :: path
	INTEGER								   :: rval

    TYPE(T_OPENFILENAME)				   :: ofn
    
    ofn%lStructSize		  = SIZEOF(ofn)
    ofn%hwndOwner		  = hwndParent
    ofn%hInstance         = ghInstance
    ofn%lpstrFilter		  = LOC(filter)
    ofn%nFilterIndex	  = 0				! force use of 1st filter entry,
	ofn%lpstrCustomFilter = 0				! restricts to single file type

    ofn%lpstrFile		  = LOC(fullpath)
    ofn%nMaxFile		  = LEN(fullpath)
	ofn%lpstrInitialDir	  = LOC(path)
	ofn%lpstrDefExt		  = LOC(extn)
    ofn%nMaxCustFilter    = 0
    ofn%nMaxFileTitle     = 0
    ofn%lpstrTitle        = loc(""C)
    ofn%lpfnHook          = NULL
    ofn%lpTemplateName    = NULL

	IF (rw_mode == 'R') THEN
		ofn%Flags = MOR(OFN_HIDEREADONLY,  OFN_PATHMUSTEXIST,	&
				        OFN_FILEMUSTEXIST, OFN_SHAREAWARE		)
        DlgFileIO = GetOpenFileName (ofn)

	ELSE
		ofn%Flags = MOR(OFN_HIDEREADONLY,  OFN_CREATEPROMPT,		&
						OFN_PATHMUSTEXIST, OFN_OVERWRITEPROMPT)
		IF (dataprime) ofn%Flags = IOR(ofn%Flags, OFN_NONETWORKBUTTON)
        DlgFileIO = GetSaveFileName (ofn)
	END IF
	ncfn   = ofn%nFileOffset + 1
	ncextn = ofn%nFileExtension + 1
	
END FUNCTION DlgFileIO

 

 


 

0 Kudos
reidar
New User
755 Views

RepeatOffender.: I tested your proposal but it didn't change anything. Be aware that I always reset  the Ofn%LPSTRINITIALDIR  parameter  before execution of iret = InitializeOpen() : bret = GETOPENFILENAME(Ofn)

mecef4:  The filter only limit the types of file to be displayed in the dialogue..

Paul:  The function you suggest looks nice. I tried to compile it, but the IVF compiles does not accept the "MOR" function. I also noticed that some parameter  TYPE(T_OPENFILENAME) declarations was not accepted by Intel® Fortran Compiler 14.0 - Sp1. A clarification along with an example of application would be helpful..

Cheers

 

 

 

0 Kudos
JVanB
Valued Contributor II
755 Views

Since Paul's code effectively incorporates my proposal and is much more complete, I suggest you add

USE IFWIN, ONLY: T_OPENFILENAME

before his IMPLICIT NONE statement and replace

MOR(a,b,c,d)

with

IANY([a,b,c,d])

which I wish Paul would do throughout his code base because everyone seems to have trouble with that usage.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
755 Views

One other issue with interoperable filenames is the C/Windows side expects (requires) null terminated strings. While it is relatively easy to remember this and tack on a null character to TRIM'd variable, it is just as easy to overlook that TRIM does not trim out NULL characters. You must account for this when concatenating partial path//name//type that may contain embedded NULL character.

Jim Dempsey

0 Kudos
reidar
New User
755 Views

I did as suggested in post #6, and the code looks like shown below, logfila is Attached..

LOGICAL FUNCTION DlgFileIO (rw_mode, hwndParent, filter, fullpath, ncfn, extn, ncextn, path)

USE IFWIN, ONLY: T_OPENFILENAME

IMPLICIT NONE

CHARACTER(LEN=1), INTENT(IN) :: rw_mode

INTEGER(HANDLE), INTENT(IN) :: hwndParent

CHARACTER(LEN=*), INTENT(IN) :: filter

CHARACTER(LEN=*), INTENT(IN) :: extn

CHARACTER(LEN=*), INTENT(INOUT) :: fullpath

INTEGER, INTENT(INOUT) :: ncfn, ncextn

CHARACTER(LEN=*), INTENT(INOUT) :: path

INTEGER :: rval

logical dataprime ! by rjt

TYPE(T_OPENFILENAME) :: ofn

ofn%lStructSize = SIZEOF(ofn)

ofn%hwndOwner = hwndParent

ofn%hInstance = hInstance !ghInstance

ofn%lpstrFilter = LOC(filter)

ofn%nFilterIndex = 0 ! force use of 1st filter entry,

ofn%lpstrCustomFilter = 0 ! restricts to single file type

ofn%lpstrFile = LOC(fullpath)

ofn%nMaxFile = LEN(fullpath)

ofn%lpstrInitialDir = LOC(path)

ofn%lpstrDefExt = LOC(extn)

ofn%nMaxCustFilter = 0

ofn%nMaxFileTitle = 0

ofn%lpstrTitle = loc(""C)

ofn%lpfnHook = NULL

ofn%lpTemplateName = NULL

IF (rw_mode == 'R') THEN

ofn%Flags = IANY(OFN_HIDEREADONLY, OFN_PATHMUSTEXIST, &

OFN_FILEMUSTEXIST, OFN_SHAREAWARE )

DlgFileIO = GetOpenFileName (ofn)

ELSE

ofn%Flags = IANY(OFN_HIDEREADONLY, OFN_CREATEPROMPT, &

OFN_PATHMUSTEXIST, OFN_OVERWRITEPROMPT)

IF (dataprime) ofn%Flags = IOR(ofn%Flags, OFN_NONETWORKBUTTON)

DlgFileIO = GetSaveFileName (ofn)

END IF

ncfn = ofn%nFileOffset + 1

ncextn = ofn%nFileExtension + 1

END FUNCTION DlgFileIO

 

0 Kudos
JVanB
Valued Contributor II
755 Views

OK, that's progress. We seem to be down to 3 issues:

  1. Change USE IFWIN, ONLY: T_OPENFILENAME to USE IFWIN
  2. Change ofn%hinstance = hinstance to ofn%hinstance = 0_HANDLE
  3. Remember the array construtor syntax for IANY: IANY([a,b,c,d]) not IANY(a,b,c,d)

I didn't notice that so much stuff from IFWIN was being accessed, so just USE the whole module. Paul's code likely was in a module where hinstance was declared, but the docs for GetOpenFileName (Google GetOpenFileName MSDN) indicate that ofn%hinstance will be ignored for this value of ofn%Flags. IANY operates on one array, not several scalars.

 

0 Kudos
Paul_Curtis
Valued Contributor I
755 Views

You guys are so darn picky.  My code samples are obviously extracted from a much larger multimodule Windows program, which obviously USEs large parts of IFWIN and IFWINTY.  The point is to provide a quick guide which is actually useful for these sort of Windows methods using F90, all of which have been solved, somewhere, for decades.  And, my MOR() function is simply a concatenation of Multiple IORs to set a bunch of bitflags at once; worth abstracting into a function since this is done a lot in Win32 setups.

If your program is a native Win32 program (ie, not a console), here is where you get the global instance and module handle:

INTEGER FUNCTION WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
!DEC$ IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_WinMain@16' :: WinMain
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS : 'WinMain' :: WinMain
!DEC$ ENDIF

    !USE i f w i n
    USE globals   ! also USEs IFWIN components
	USE kernel32

    IMPLICIT NONE
    SAVE

    INTEGER(HANDLE), INTENT(IN)        :: hInstance
    INTEGER(HANDLE), INTENT(IN)        :: hPrevInstance
    INTEGER, INTENT(IN)                :: lpszCmdLine
    INTEGER, INTENT(IN)                :: nCmdShow

  
    ! intialize global instance; these are held in the Globals module
    ghInstance = hInstance
    ghModule   = GetModuleHandle(NULL)

 

0 Kudos
Reply