GetDiskFreeSpace returns wrong total clusters under XP

Posted on 2004-11-10
Last Modified: 2013-12-03
I have some code that was working under Windows 2000 but returns bizarre results under XP (SP1).

GetDiskFreeSpace on a diskette drive returns 805,306,368 (0x30000000) for TotalNumberOfClusters.  GetDiskFreeSpaceEx returns 1,407,374,883,553,280 (0x0005000000000000) for TotalNumberOfBytes.

The above was using "A:\\" as the volume name.  However I tried "C:\\", "X:\\" (where X drive is not present) and even "?:\\" and I always get the same result from GetDiskFreeSpace and GetDiskFreeSpaceEx (which do not return 0 for error).  SectorsPerCluster always returns 4096 and BytePerSector is always 512.  I doubt these values are the same for A: and C:.

And why does GetDiskFreeSpace on "?:\\" not even return an error.

I searched help and the web on this problem but could not find a mention of it.

I realise that I can use IOCTL_DISK_GET_LENGTH_INFO, but what is wrong with GetDiskFreeSpace under XP?!?
Question by:aphillips
    LVL 17

    Expert Comment

    I'm using GetDiskFreeSpace under xp.
    Works OK. Could You please give the code?
    LVL 48

    Expert Comment

    Just For Knowlege

    Here is code you should try

    Public Declare Function GetDiskFreeSpace Lib "kernel32" _
       Alias "GetDiskFreeSpaceA" _
      (ByVal lpRootPathName As String, _
       lpSectorsPerCluster As Long, _
       lpBytesPerSector As Long, _
       lpNumberOfFreeClusters As Long, _
       lpTtoalNumberOfClusters As Long) As Long
    Public Declare Function GetDiskFreeSpaceEx Lib "kernel32" _
       Alias "GetDiskFreeSpaceExA" _
       (ByVal lpRootPathName As String, _
       lpFreeBytesAvailableToCaller As Currency, _
       lpTotalNumberOfBytes As Currency, _
       lpTotalNumberOfFreeBytes As Currency) As Long

    debug.Print " Disk size:", Format$(GetDiskSpace(sDrive), "###,###,###,###,##0")
      debug.Print " Total free:", Format$(GetDiskSpaceFree(sDrive), "###,###,###,###,##0")
      debug.Print " Bytes free:", Format$(GetDiskBytesAvailable(sDrive), "###,###,###,###,##0")
      debug.Print " Disk used :", Format$(GetDiskSpaceUsed(sDrive), "###,###,###,###,##0")
    LVL 3

    Author Comment

    > I'm using GetDiskFreeSpace under xp.

    The code with the problem was built with VC7 (ie Visual Studio.Net) and run under XP SP1.

    I tried exactly the same code at home but built with VC6 and run under XP (not SP1) and it works fine.  In that case I get SectorsPerCluster = 1, BytesPerSector = 512 and correct values for number of clusters.

    > Could You please give the code?

    // Disk volume - file name of form <\\.\D:>
    _TCHAR vol[4] = _T("?:\\");
    vol[0] = 'A';  // or 'C' or 'X' or '?'
    DWORD SectorsPerCluster;
    DWORD BytesPerSector;
    DWORD NumberOfFreeClusters;
    DWORD TotalNumberOfClusters;

    if (!::GetDiskFreeSpace(vol,
            // never gets here, even for drive 'X' or '?'
            return FALSE;
    m_SectorSize = BytesPerSector;

    ULARGE_INTEGER total_bytes;
    m_Length = total_bytes.QuadPart;  // m_Length is an __int64
    LVL 3

    Author Comment

    Stepping into the assembler the C++ generated code pushes the parameters and calls __imp__GetDiskFreeSpaceA@20 (72AC6Ch).  Stepping into that I see this:

    0157D4A0  push        ebp  
    0157D4A1  mov         ebp,esp
    0157D4A3  mov         eax,dword ptr [ebp+18h]
    0157D4A6  push        eax  
    0157D4A7  mov         ecx,dword ptr [ebp+14h]
    0157D4AA  push        ecx  
    0157D4AB  mov         edx,dword ptr [ebp+10h]
    0157D4AE  push        edx  
    0157D4AF  mov         eax,dword ptr [ebp+0Ch]
    0157D4B2  push        eax  
    0157D4B3  call        0157D440
    0157D4B8  mov         eax,1
    0157D4BD  pop         ebp  
    0157D4BE  ret         14h  

    There is something wrong here as the return value (EAX) is always 1.  I know that GetDiskFreeSpace should sometimes return 0.

    This also ignores the 1st parameter (volume name string) which explains why I get the same result what ever I pass in the string.

    Do you think something has hooked or intercepted the call?  I am not sure where this code is from.
    LVL 3

    Author Comment

    I worked out the problem.  I noticed that something seemed to have hooked GetDiskFreeSpace and when I stepped into it I noticed that the code was in "appvcore.dll" in the call stack.  Using TaskInfo I worked out that appvcore.dll was in C:\WINDOWS\AppPatch and part of "Windows Application Verifier".

    About 6 months ago I was asked to test a Microsoft tool called AppVerifier which was supposed to tell you about all the things your software was doing wrong.  I tried it a few times and got nothing useful out of it.  (It produced masses of warnings and errors all of which turned out to be what was wanted or benign.)

    Anyway, I did not realise that once you have added a program into AppVerifier to be checked it somehow hooks the Application even when AppVerifier (appverif.exe) itself is not even running.  So the software has been running under App Verifier all that time (and creating huge log files).

    Obviously there is something wrong with how AppVerifier hooks GetDiskFreeSpace and GetDiskFreeSpaceEx.  After I removed the application from AppVerifier's list it now works fine.
    LVL 3

    Author Comment

    Some final notes:

    1. App Verifier is apparently interccepting and changing the values returned by GetDiskFreeSpace and GetDiskFreeSpaceEx in order to detect bugs caused by disk sizes greater greater than 32 bits.  For GetDiskFreeSpace: multiplying number of free clusters or total clusters by cluster size would give a number that overflows 32 bits and has zero in the lower 32 bits.  For GetDiskFreeSpaceEx: using the lower 32 bits of the sizes returned from give disk sizes and free spaces of zero.

    I guess the intent is that programs that check free disk space but only use 32 bit values will report errors like "you have 0 bytes free".

    However, here are a few problems with the strategy:

     a) Floppy drives should be excluded since they are never going to be > 2 Gbytes.
     b) Ignoring passed drive letters is extremely confusing.  GetDiskFreeSpace should return the same errors that it normally does.
     c) Why return 0x0005000000000000 (GetDiskFreeSpaceEx)? 0x000000010000000 would be a more obvious value.
     d) It might detect bugs to return these values for free space but I can't see any reason to return these values for total disk space (and causes nasty side-effects as in my case).
     e) The total size returned by GetDiskFreeSpaceEx is inconsistent with that from IOCTL_DISK_GET_LENGTH_INFO.
     e) I don't see the need for GetDiskFreeSpaceEx.  If someone explicitly use GetDiskFreeSpaceEx (rather than GetDiskFreeSpace) they are obviously aware of large disk sizes so why would they ignore the full 64 bit size?

    2. IOCTL_DISK_GET_LENGTH_INFO (which I mentioned in the original post) does not work for floppies.


    Accepted Solution

    PAQed with points refunded (250)

    Community Support Moderator
    LVL 3

    Author Comment

    Sorry, I solved this myself, and thought I asked for a refund.  I also didn't see any emails informing of posts in this topic (may have been lost in SPAM).
    LVL 3

    Author Comment

    Yes, I did see that I got the refund, thanks.

    However, I was just trying to explain/apologise.

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    How your wiki can always stay up-to-date

    Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
    - Increase transparency
    - Onboard new hires faster
    - Access from mobile/offline

    zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
    A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
    This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA.…
    Hi everyone! This is Experts Exchange customer support.  This quick video will show you how to change your primary email address.  If you have any questions, then please Write a Comment below!

    759 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    13 Experts available now in Live!

    Get 1:1 Help Now