Click here to Skip to main content
16,021,687 members
Articles / Desktop Programming / MFC
Article

Bug in MFC's CFileFind::GetLength64()

Rate me:
Please Sign up or sign in to vote.
4.20/5 (4 votes)
1 Mar 20022 min read 80.2K   30   5
File size returned by CFileFind::GetLength64() is incorrect for files larger than 4Gb

Introduction

MFC provides the CFileFind class to encapsulate the ::FindFirstFile Win32 calls for searching the filesystem. The member function CFileFind::GetLength() returns the length in bytes of the current file, using a DWORD. Since a DWORD is 32bits long, the maximum file length this can cope with is 4 gigabytes.

The documentation states that for files larger than 4 gigabytes, there is the CFileFind::GetLength64() function that returns the size as an __int64.

However, in versions of MFC prior to the MFC7 that comes with Visual Studio.NET, this function does not return correct values for large files, due to a bug in the way the 64-bit arithmetic is done. The CFileFind::GetLength method in MFC7 now returns a ULONGLONG with the correct filesize, and the GetLength64() member function has been removed.

This is the offending code for earlier versions of MFC as used in Visual Studio 6.0 and earlier:

__int64 CFileFind::GetLength64() const
{
	ASSERT(m_hContext != NULL);
	ASSERT_VALID(this);

	if (m_pFoundInfo != NULL)
		return ((LPWIN32_FIND_DATA) m_pFoundInfo)->nFileSizeLow +
		(((LPWIN32_FIND_DATA) m_pFoundInfo)->nFileSizeHigh << 32);
	else
		return 0;
}

Whilst this appears fine at a glance, the problem lies in the shift operation for the high DWORD. It should have been cast to a 64-bit integer before the shift. As the code stands, it performs a 32-bit shift on a 32-bit value.

Whilst you may expect that to always be zero, in fact it gives the same value as before the shift. The compiler uses the x86 opcode shl, which shifts a 32-bit value a given number of places modulo 32.

Therefore the value returned for any file greater than 4 gigabytes is the value of the low 2 bytes added to the high 2 bytes, which is "more incorrect" than the value returned by GetLength().

Solution

The correct expression to get the filesize as a 64-bit integer from the WIN32_FIND_DATA structure pointed to by the m_pFoundInfo member is:

((LPWIN32_FIND_DATA)pFinder->m_pFoundInfo)->nFileSizeLow +
 ((unsigned __int64)((LPWIN32_FIND_DATA)pFinder->m_pFoundInfo)->nFileSizeHigh << 32);

However, this is a protected member, and altering MFC code is not an option, particularly if you are linking dynamically.

The solutions are:

  • Don't use CFileFind; only use the Win32 API functions ::FindFirstFile etc.
  • Create a derived class from CFileFind, implementing the GetLength64() member function correctly, and use this derived class instead of CFileFind.
  • Alter the Afx.h header file to make the m_pFoundInfo member public, so that you can perform the above calculation from the calling code, rather than calling GetLength64(). This is not recommended.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionI'm newbie and idiot to Programming Pin
Andrioindonesia16-Sep-06 22:39
Andrioindonesia16-Sep-06 22:39 
Generalquick-n-dirty fix Pin
30-May-02 8:19
suss30-May-02 8:19 
GeneralRe: quick-n-dirty fix Pin
Luca Piccarreta1-Feb-05 22:11
Luca Piccarreta1-Feb-05 22:11 
Very quick, very dirty...
you risk problems when the problem
get fixed (not in usual MS politics, though)
Luca.
QuestionMFC 7 ? Pin
Mario M.2-Mar-02 6:01
Mario M.2-Mar-02 6:01 
AnswerRe: MFC 7 ? Pin
Andy Hassall2-Mar-02 6:14
Andy Hassall2-Mar-02 6:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.