I have some very specialized C file-reading functions that I would like to use in my CVF Windows program. Several of these functions require that I pass the handle of the open file. How do I get the file handle in CVF?
链接已复制
12 回复数
A general rule of thumb when working with I/O is that you mustn't mix libraries when working with files; that is, you can use Fortran's OPEN...WRITE/READ...CLOSE, or C's fopen...fprintf/fscanf...fclose, or Win32 CreateFile...WriteFile/ReadFile...CloseHandle -- but you shouldn't mix the methods, at least not simultaneously on the same file.
So, if I got you right that the C file expects a Win32-based handle, you can open it in Fortran with CreateFile (see SDK documentation), which returns its handle. If it expects another library-based handle (such as standard C RTL fopen), you'll have to create C wrapper functions and link them with the rest or fortran sources.
So, if I got you right that the C file expects a Win32-based handle, you can open it in Fortran with CreateFile (see SDK documentation), which returns its handle. If it expects another library-based handle (such as standard C RTL fopen), you'll have to create C wrapper functions and link them with the rest or fortran sources.
The advice on not mixing libraries opened my eyes! I certainly was going to try something along that line when using my C functions. And so I have bit the bullet, translated the C to Fortran. At present I am using open/read, but would prefer to use the CreateFile family because SetFilePointer would be most useful for this project. If time allows....
Thanks for the advice.
Thanks for the advice.
Here are some routines which implement handle-based file i/o in F90,
using the Win32 API functions. Not true Fortran, not portable, but
IMHO a whole lot more versatile than the the limited i/o capabilities
of Fortran, since one can transfer a specified byte count to/from a
specified offset position in a file, without any need for records or
any other form of internal formatting. (If the posted/rec'd versions
of the code are illegible, email me at [email protected] & I'll be
glad to send the code directly).
!=======================================================================
! Files/disk access routines
!=======================================================================
MODULE filesubs
USE kernel32 ! Win32 API interfaces
CONTAINS
FUNCTION file_exists (fname) RESULT (size)
IMPLICIT NONE
TYPE(T_WIN32_FIND_DATA) :: fdata
CHARACTER(LEN=*),INTENT(IN) :: fname ! full pathname to file
INTEGER :: size
IF (FindFirstFile(fname,fdata) /= INVALID_HANDLE_VALUE) THEN
size = fdata%nFileSizeLow
ELSE
size = -1
ENDIF
END FUNCTION file_exists
FUNCTION open_the_file (fullpath, rwmode) RESULT (ihandl)
IMPLICIT NONE
INTEGER :: access,ihandl
CHARACTER(LEN=*),INTENT(IN) :: fullpath,rwmode
! old-style Fortran file open
IF (rwmode == 'F') THEN
IF (file_exists(fullpath) > 0) THEN
OPEN (ihandl,FILE=fullpath,STATUS='OLD')
ELSE
OPEN (ihandl,FILE=fullpath,STATUS='NEW')
END IF
RETURN
! Win32 file opens
ELSE IF (rwmode == 'R') THEN
access = GENERIC_READ
ELSE
access = IOR(GENERIC_READ,GENERIC_WRITE)
END IF
ihandl = CreateFile (fullpath, &
access, &
FILE_SHARE_READ, &
NULL_SECURITY_ATTRIBUTES, &
OPEN_ALWAYS, &
FILE_ATTRIBUTE_NORMAL, &
NULL )
END FUNCTION open_the_file
SUBROUTINE full_path (root,subdir,fnam,extn,pathname)
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: root,subdir,fnam,extn
CHARACTER(LEN=*),INTENT(OUT) :: pathname
CHARACTER(LEN=1),PARAMETER :: slash = '', dot = '.'
WRITE (pathname,'(8A)') root(1:LEN_TRIM(root)), &
slash, &
subdir(1:LEN_TRIM(subdir)), &
slash, &
fnam(1:LEN_TRIM(fnam)), &
dot, &
extn(1:MIN0(3,LEN_TRIM(extn))), &
CHAR(0)
END SUBROUTINE full_path
SUBROUTINE rw_file (rwmode,ihandl,nbytes,offset,loc_pointer)
IMPLICIT NONE
CHARACTER(LEN=1),INTENT(IN) :: rwmode
INTEGER,INTENT(IN) :: ihandl,nbytes,offset
INTEGER,INTENT(IN) :: loc_pointer
INTEGER :: nact
LOGICAL :: rslt
! position pointer if offset is provided
IF (offset > 0) rslt = SetFilePointer (ihandl,offset,NULL,FILE_BEGIN)
IF (rwmode == 'R') THEN
rslt = ReadFile (ihandl, & ! file handle
loc_pointer, & ! address of data
nbytes, & ! byte count to read
LOC(nact),
using the Win32 API functions. Not true Fortran, not portable, but
IMHO a whole lot more versatile than the the limited i/o capabilities
of Fortran, since one can transfer a specified byte count to/from a
specified offset position in a file, without any need for records or
any other form of internal formatting. (If the posted/rec'd versions
of the code are illegible, email me at [email protected] & I'll be
glad to send the code directly).
!=======================================================================
! Files/disk access routines
!=======================================================================
MODULE filesubs
USE kernel32 ! Win32 API interfaces
CONTAINS
FUNCTION file_exists (fname) RESULT (size)
IMPLICIT NONE
TYPE(T_WIN32_FIND_DATA) :: fdata
CHARACTER(LEN=*),INTENT(IN) :: fname ! full pathname to file
INTEGER :: size
IF (FindFirstFile(fname,fdata) /= INVALID_HANDLE_VALUE) THEN
size = fdata%nFileSizeLow
ELSE
size = -1
ENDIF
END FUNCTION file_exists
FUNCTION open_the_file (fullpath, rwmode) RESULT (ihandl)
IMPLICIT NONE
INTEGER :: access,ihandl
CHARACTER(LEN=*),INTENT(IN) :: fullpath,rwmode
! old-style Fortran file open
IF (rwmode == 'F') THEN
IF (file_exists(fullpath) > 0) THEN
OPEN (ihandl,FILE=fullpath,STATUS='OLD')
ELSE
OPEN (ihandl,FILE=fullpath,STATUS='NEW')
END IF
RETURN
! Win32 file opens
ELSE IF (rwmode == 'R') THEN
access = GENERIC_READ
ELSE
access = IOR(GENERIC_READ,GENERIC_WRITE)
END IF
ihandl = CreateFile (fullpath, &
access, &
FILE_SHARE_READ, &
NULL_SECURITY_ATTRIBUTES, &
OPEN_ALWAYS, &
FILE_ATTRIBUTE_NORMAL, &
NULL )
END FUNCTION open_the_file
SUBROUTINE full_path (root,subdir,fnam,extn,pathname)
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: root,subdir,fnam,extn
CHARACTER(LEN=*),INTENT(OUT) :: pathname
CHARACTER(LEN=1),PARAMETER :: slash = '', dot = '.'
WRITE (pathname,'(8A)') root(1:LEN_TRIM(root)), &
slash, &
subdir(1:LEN_TRIM(subdir)), &
slash, &
fnam(1:LEN_TRIM(fnam)), &
dot, &
extn(1:MIN0(3,LEN_TRIM(extn))), &
CHAR(0)
END SUBROUTINE full_path
SUBROUTINE rw_file (rwmode,ihandl,nbytes,offset,loc_pointer)
IMPLICIT NONE
CHARACTER(LEN=1),INTENT(IN) :: rwmode
INTEGER,INTENT(IN) :: ihandl,nbytes,offset
INTEGER,INTENT(IN) :: loc_pointer
INTEGER :: nact
LOGICAL :: rslt
! position pointer if offset is provided
IF (offset > 0) rslt = SetFilePointer (ihandl,offset,NULL,FILE_BEGIN)
IF (rwmode == 'R') THEN
rslt = ReadFile (ihandl, & ! file handle
loc_pointer, & ! address of data
nbytes, & ! byte count to read
LOC(nact),
These look like excellent routines. I had already tried to implement the WinAPI functions on my own, because I need byte transfer, and need to be able to position the file for input/output. However, I quit after a few hours because I couldn't solve one of the compilation problems. I am going to try these out right away.
Having problems with the defined parameters for CreateFile (in Paul's module). Same problems that I had when I tried to do it myself. I am running CVF 6.1A, compiling a quickwin pgm, and get the following error message for link:
Linking...
Filesubs.obj : error LNK2001: unresolved external symbol _DFWINTY_mp_NULL_SECURITY_ATTRIBUTES
Filesubs.obj : error LNK2001: unresolved external symbol _DFWINTY_mp_NULL_OVERLAPPED
What module do I need to include? Why aren't these defined in dfwinty?
Linking...
Filesubs.obj : error LNK2001: unresolved external symbol _DFWINTY_mp_NULL_SECURITY_ATTRIBUTES
Filesubs.obj : error LNK2001: unresolved external symbol _DFWINTY_mp_NULL_OVERLAPPED
What module do I need to include? Why aren't these defined in dfwinty?
Linking via Visual Fortran IDE.
(Is it important that I also have a version of Microsoft Visual Studio 6.0 on my hard drive? Is there cross-talk here?) Anyway, I added dfwin.lib to the link libraries and now all is fine. Thanks everyone.
(Is it important that I also have a version of Microsoft Visual Studio 6.0 on my hard drive? Is there cross-talk here?) Anyway, I added dfwin.lib to the link libraries and now all is fine. Thanks everyone.