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

win32 Function Question

gelarimer
Beginner
1,274 Views

I am attempting to get the disc free space available for a user with the following:

INTEGER(4) iret
INTEGER(8), TARGET :: iFB
INTEGER(8), POINTER :: pFB
TYPE(T_LARGE_INTEGER) iFreeBytes

pFB => iFB
iret = GetDiscFreeSpaceEX('H:'C, iFreeBytes,
NULL, NULL)
! because 8 bytes are contiguous in memory
pFB = LOC(iFreeBytes)

From Exporer I know thedisc has about 129GBs of free disc space, however, when I execute the code above iFB shows only about 5MBs of free space.

Is the use ofthe pointer pFB correct in the code above?

I also noticed that the sign bit was set for the LowPart whichalso appears to be a problem:
iFreeBytes%LowPart = -1525272576
iFreeBytes%HighPart = 3

Any comments would be appreciated. Thanks in advance.

0 Kudos
6 Replies
anthonyrichards
New Contributor III
1,274 Views

This version works. I use Compaq Visual Fortran 6.6C, but you should be able to see what changes to make for IVF. Note I cannot do 64-bit integer arithmetic, so I converted to REAL arithmetic and did the sums andI checked the values it gave me doing the sum indicated against values given by Explorer and they were identical. Note the double back-slash needeed for the folder C-string and I had to use GetDisKFreeSpace with a 'K' in DisK rather than a 'C'.

program freespace
use kernel32
use dfwin
implicit none
REAL(8) Callerbytes, Threadbytes, Totalbytes, Factor
INTEGER(4) iret
TYPE(T_LARGE_INTEGER) iCallerBytes, iThreadBytes, iTotalBytes
character(10) Folder
folder='C:'C
iret = GetDiskFreeSpaceEx(folder, iCallerBytes, iThreadBytes, iTotalBytes)
print *,' IF LOWPART is >0, Total bytes = 2**32 x HIGHPART + LOWPART'
print *,' IF LOWPART is <0, Total bytes = 2**32 x (HIGHPART+1) + LOWPART'
print *
print *,' HIGHPART LOWPART'
print *,'bytes free to Caller = ',iCallerbytes%highpart,' ', icallerbytes%lowpart
print *,'bytes free to Thread = ',iThreadbytes%highpart,' ', iThreadbytes%lowpart
print *,'bytes free Total = ',iTotalbytes%highpart, ' ',iTotalbytes%lowpart
factor=2.0d+00**32
if(icallerbytes%lowpart<0) then
Callerbytes=factor*(dble(iCallerbytes%highpart+1))+dble(icallerbytes%lowpart)
else
Callerbytes=factor*(dble(iCallerbytes%highpart))+dble(icallerbytes%lowpart)
endif
if(ithreadbytes%lowpart<0) then
threadbytes=factor*(dble(ithreadbytes%highpart+1))+dble(ithreadbytes%lowpart)
else
threadbytes=factor*(dble(ithreadbytes%highpart))+dble(ithreadbytes%lowpart)
endif
if(itotalbytes%lowpart<0) then
totalbytes=factor*(dble(itotalbytes%highpart+1))+dble(itotalbytes%lowpart)
else
totalbytes=factor*(dble(itotalbytes%highpart))+dble(itotalbytes%lowpart)
endif
print *,'bytes free to Caller = ',Callerbytes
print *,'bytes free to Thread = ',Threadbytes
print *,'bytes free Total = ',Totalbytes
end program freespace
OUTPUT FOLLOWS:
 IF LOWPART is >0, Total bytes = 2**32 x HIGHPART + LOWPART
IF LOWPART is <0, Total bytes = 2**32 x (HIGHPART+1) + LOWPART
 HIGHPART LOWPART
bytes free to Caller = 5 1557180416
bytes free to Thread = 9 -1000779776
bytes free Total =&nbs p; 5 1557180416
bytes free to Caller = 23032016896.0000
bytes free to Thread = 41948893184.0000
bytes free Total = 23032016896.0000
Press any key to continue
0 Kudos
gelarimer
Beginner
1,274 Views
ThanksAnthony.May have questions afterI study yourcode.
0 Kudos
joerg_kuthe
Novice
1,274 Views

Here is an sample program which might be easier to use. I simply copied the INTERFACE from KERNEL32.f90 and changed those ULONGLONG args into INTEGER*8. So you don't have to considerthose sign bits.

Joerg Kuthe
www.qtsoftware.de

PROGRAM

T_GetDiskFreeSpaceEx

USE IFWINTY

USE KERNEL32

IMPLICIT NONE

INTEGER :: iRet

INTEGER(8) lpFreeBytesAvailableToCaller ! PULARGE_INTEGER lpFreeBytesAvailableToCaller

INTEGER(8) lpTotalNumberOfBytes ! PULARGE_INTEGER lpTotalNumberOfBytes

INTEGER(8) lpTotalNumberOfFreeBytes ! PULARGE_INTEGER lpTotalNumberOfFreeBytes

CHARACTER(*), PARAMETER :: szDir = 'C:'C

INTERFACE

FUNCTION qtGetDiskFreeSpaceEx( lpDirectoryName, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes)

use ifwinty

integer(BOOL) :: qtGetDiskFreeSpaceEx ! BOOL

!DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'GetDiskFreeSpaceExA' :: qtGetDiskFreeSpaceEx

!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: lpDirectoryName

CHARACTER*(*) lpDirectoryName

!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: lpFreeBytesAvailableToCaller

INTEGER(8) lpFreeBytesAvailableToCaller ! PULARGE_INTEGER lpFreeBytesAvailableToCaller

!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: lpTotalNumberOfBytes

INTEGER(8) lpTotalNumberOfBytes ! PULARGE_INTEGER lpTotalNumberOfBytes

!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: lpTotalNumberOfFreeBytes

INTEGER(8) lpTotalNumberOfFreeBytes ! PULARGE_INTEGER lpTotalNumberOfFreeBytes

END FUNCTION

END INTERFACE

iRet = qtGetDiskFreeSpaceEx( szDir, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, &

lpTotalNumberOfFreeBytes )

IF ( iRet /= 0 ) THEN

WRITE(*,6000) szDir(1:3)

6000 FORMAT('Size of Directory "', A '"')

CALL CS_PrintResult( 'Free Bytes Available To Caller', lpFreeBytesAvailableToCaller )

CALL CS_PrintResult( 'Total Number Of Bytes', lpTotalNumberOfBytes )

CALL CS_PrintResult( 'Total Number Of Free Bytes', lpTotalNumberOfFreeBytes )

ELSE

PRINT*,'GetDiskFreeSpaceEx() failed; error = ', GetLastError()

END IF

CONTAINS

SUBROUTINE CS_PrintResult( cText, i8MemVal )

CHARACTER(*), INTENT(IN) :: cText

INTEGER(8), INTENT(IN) :: i8MemVal

WRITE(*,6000) TRIM(cText), i8MemVal, i8MemVal / (1024.*1024.)

6000 FORMAT(A, ' = ', I0, ' (= ', F0.3, ' MB)')

END SUBROUTINE CS_PrintResult

END

PROGRAM

0 Kudos
gelarimer
Beginner
1,274 Views

Thanks for both replies. I was stumped for a little while about the math used inanthonyrichardsexample code, but after a littlebinary math realized that Fortran displays the two's compliment +1 of the binary when the sign bit is set.A little binary math demonstrated thatadding 1 to theHighPart and multiplying by factorand then adding the negative LowPart actuallyproduces the correct result.

In the second example,I realize that the HighPart and LowPart of the structure Large_Integer (filled in by the Win32 fn.) are contiguous in memory, and thatSTDCALL means that actual values are returned in the Win32 function arg list.However, not clear on how returning actual values for a C structure works in an arg list. Sincecode works fine, I assume that the arg or returned values for theC structure will always be just 8 contiguous Bytes. Is there anyrisk that manipulating the INTERFACE in this way may cause unexpected problems?

0 Kudos
joerg_kuthe
Novice
1,274 Views

All arguments in the

FUNCTION qtGetDiskFreeSpaceEx( lpDirectoryName, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes)

are returned by REFERENCE (STDCALL passes arguments by VALUE, so you have to change the interface). This means, not the value itself is returned but the starting address of memory where the values of

lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes

are found. The type information then specifies how many bytes have to be considered to obtain thevalue.So you can handle any size of argument.

I don't see a risk in the kind of manipulation that I have made because I simply gave those 8-bytes being addressed just another type of the same memory sizeas expected(INTEGER(8)).
It is your decision how you want your compiler to handle those arguments. So you choose what suits your needs best.

Joerg Kuthe

www.qtsoftware.de

0 Kudos
gelarimer
Beginner
1,274 Views

Thanks forthe explanation about how memory was treated.

I was fixated on the ATTRIBUTES STDCALL for qtGetDiskFreeSpaceEX(),but now seethat the ATTRIBUTES REFERENCEyou gave to the arguments overrides pass by value.

Trying to learnabout INTERFACE Blocks, and your example helped quite a bit.

0 Kudos
Reply