- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have been trying to get returns from a a C sub, and seem to be going around in circles... I have tried IVF samples, suggestions from IVF forums and that I have similarly used before now, all to no avail. Any assistance/guidance would be appreciated.
The C routine:
Syntax
unsigned char *pBuffer,
int iOffset,
int iBytesToRead,
int *pBytesRead,
int iFlags
);
Parameters
- [out] pBuffer - pointer to the buffer that should receive the data read.
- [in] iOffset - the index of the first byte to read. Indices start at zero. If this value is negative, the function will treat it as if it were zero, and read from the start of the Data.
- [in] iBytesToRead - the number of bytes to read. If this value is negative, the function will return an error.
- [out, optional] pBytesRead - pointer to a variable that receives the number of bytes read.
- [in] iFlags - set this parameter to GET_Data_SIZE (1, or BIT0 set) to get the total size of the Data in the variable pointed to by pBytesRead. The buffer that pBuffer points to remains unmodified. Pass zero to perform a read with no special behaviour.
My Fortran module:
interface
function Data_READ(Ret_Str, Int1, Int2, Data_Bytes, Int3)
!DEC$ ATTRIBUTES STDCALL,DECORATE,ALIAS:"Data_Read" :: Data_READ
integer :: Data_READ
character*(*) :: Ret_Str
integer :: Int1, Int2, Data_Bytes, Int3
!DEC$ ATTRIBUTES REFERENCE :: Ret_Str, Int1, Int2, Data_Bytes, Int3
end function Data_READ
end interface
My Fortran routine:
use, intrinsic :: iso_c_binding, only: c_int
implicit none
character(len=50) :: Ret_Str
integer :: iRet
integer(C_int) :: iOut_1, iOut_2, Data_Bytes, iOut_3
iOut_1 = 0 ; iOut_2 = 50 ; iOut_3 = 0
iRet = Data_Read(Ret_Str, iOut_1, iOut_2, Data_Bytes, iOut_3)
The data in pbuffer (from the C sub) can be up to 512 bytes... I currently have 34 characters stored in the area that the C sub reads, and am trying to get those into my program.
I have other routines that read similarly read strings from C routines, but I cannot figure what I have done wrong or am missing (I know something is not right/missing, but not what nor where). At present the returns I get are 0 for iRet (0 indicates success), 0 for Data_Bytes, and Ret_Str is blank.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Your Fortran specifies Int1, Int2 and Int3 as pass by reference - when the C declaration says they are by value.
It is also possible that the calling conventions for the assumed length character string trip you up (this can change with compile options).
For what its worth, if I had to write a Fortran interface for this C function (guessing a little as to the behaviour beyond what your documentation provides and calling "bytes" INTEGER(C_SIGNED_CHAR)) I'd do it something like:
[fortran]
MODULE MakeCallingDataReadFromFortranEasy
IMPLICIT NONE
PRIVATE
PUBLIC :: GetTotalSizeOfData
PUBLIC :: ReadSomeData
PUBLIC :: ReadItAllAtOnce
INTERFACE
FUNCTION Data_Read(pBuffer, iOffset, iBytesToRead, pBytesRead, iFlags)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_PTR
IMPLICIT NONE
TYPE(C_PTR), INTENT(IN) :: pBuffer
INTEGER(C_INT), INTENT(IN) :: iOffset
INTEGER(C_INT), INTENT(IN) :: iBytesToRead
INTEGER(C_INT), INTENT(OUT) :: pBytesRead
!DEC$ ATTRIBUTES REFERENCE :: pBytesRead
INTEGER(C_INT), INTENT(IN) :: iFlags
INTEGER(C_INT) :: Data_Read
!DEC$ ATTRIBUTES STDCALL :: Data_Read
!DEC$ ATTRIBUTES ALIAS:'Data_Read' :: Data_Read
!DEC$ ATTRIBUTES DECORATE :: Data_Read
END FUNCTION Data_Read
END INTERFACE
CONTAINS
SUBROUTINE GetTotalSizeOfData(total_size, result)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_LOC, C_NULL_PTR
INTEGER(C_INT), INTENT(OUT) :: total_size
INTEGER(C_INT), INTENT(OUT) :: result
!****
! Assume that buffer
result = Data_Read( C_NULL_PTR, 0_C_INT, 0_C_INT, total_size, &
1_C_INT )
END SUBROUTINE GetTotalSizeOfData
SUBROUTINE ReadSomeData(data, offset, bytes_to_read, bytes_read, result)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_LOC, C_SIGNED_CHAR
INTEGER(C_SIGNED_CHAR), INTENT(OUT), TARGET :: data(*)
INTEGER(C_INT), INTENT(IN) :: offset
INTEGER(C_INT), INTENT(IN) :: bytes_to_read
INTEGER(C_INT), INTENT(OUT) :: bytes_read
INTEGER(C_INT), INTENT(OUT) :: result
!****
result = Data_Read( C_LOC(data), offset, bytes_to_read, bytes_read, &
0_C_INT )
END SUBROUTINE ReadSomeData
SUBROUTINE ReadItAllAtOnce(data, result)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_LOC, C_SIGNED_CHAR
INTEGER(C_SIGNED_CHAR), INTENT(OUT), ALLOCATABLE :: data(:)
INTEGER(C_INT), INTENT(OUT) :: result
!----
INTEGER(C_INT) :: total_size
INTEGER(C_INT) :: bytes_read
!****
CALL GetTotalSizeOfData(total_size, result)
IF (result /= 0) RETURN
ALLOCATE(data(total_size))
CALL ReadSomeData(data, 0_C_INT, total_size, bytes_read)
IF (result /= 0) RETURN
IF (total_size /= bytes_read) &
ERROR STOP 'Total size isn''t bytes_read!'
END SUBROUTINE ReadItAllAtOnce
END MODULE MakeCallingDataReadFromFortranEasy
[/fortran]
(But I wouldn't double space things...)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
ian has dropped your stdcall specification, with good reason.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Tim Prince wrote:
ian has dropped your stdcall specification, with good reason.
I agree, but I didn't mean to (and I don't think I did).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Many thanks Ian - I transposed parts of your suggested code into my module and routine, and it now works - I can return the read bytes and data area content exactly as I had hoped to.
I never would have got it myself as I have not found anything on how to address unsigned/signed characters to a buffer - many thanks again.

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