A Simple File Downloading Method with Progress Bar Updating
Many people have wondered how to download a file from the Internet while having a progress bar to track the download progress. In this example, I will demonstrate how to achieve this task. The article also covers how to get file complete percentage, bytes received, bytes left, and download speed (kb/sec).
The pictures below are snapshots off the downloadable example in this article. The code is fully commented for easy understanding and I will cover every aspect of the program in this article in detail so that coders can understand and implement this code on any program they want.

Note: The methods I used are probably not the fastest and most efficient out there, but that is the way I code. I hope that when you finish reading this article, you will be able to write such a thing yourself...so let's get started!
General Description
The program uses a worker thread to perform the file download; this is so that our main application won't be blocked and so that we could have a cancel download functionality inside the program. All the downloading is being done from inside the thread along with the on-screen updating; we will get into that in a minute.
Coding Time!
Note: The following code is just a general overview of how to perform these tasks. Look inside the program source code to see the actual implementation of the code below:
CInternetSession netSession;
CStdioFile *file;
file = netSession.OpenURL(char url,1,INTERNET_FLAG_TRANSFER_BINARY
| INTERNET_FLAG_RELOAD);
This function returns a pointer to a CStdioFile, which is currently the file we requested online. You now can process the file as it was on your local hard drive. I haven't tested writing into a file using this method but it probably will require the permission and access for the file write method on the specified server.
Reading from the File and Writing It to the Local Hard Drive
Reading from the file is quite easy; all we have to do is this:
file->Read(char buffer,int bytes to read);
CFile fl;
fl.Open("myfile",CFile::modeCreate | CFile::modeWrite
| CFile::typeBinary);
fl.Write(buffer,bytes read);
Progress Bar, Transfer Data, and More
To make our progress bar effective, we use the CProgressCtrl::SetRange32(); function. The parameters passed to the function are lower value and upper value; lower value is of course 0 and the upper value is the file size, which we determine by simply calling:
int x = file->SeekToEnd();
The ::SeekToEnd(); function returns the total bytes of the file, which is determined into a file size.
The updating of the progress bar is being made every time we read a chunk of the file. Our program uses chunks of 512 bytes, not to overload the connection. The progress is updated every time the program performs another file->Read(); function.
while(int bytesread = file->Read(charbuf,512))
{
currentbytes = currentbytes + bytesread;
CProgressCtrl::SetPos(currentbytes);
}
To calculate our bytes received, percentages, and download speed(kb/sec), use the following code.
int percent = currentbytes * 100 / x ( our file size integer
from above);
int kbreceived = currentbytes / 1024;
Calculating the download speed is a bit trickier. Before we go into the while loop, we create a COleDateTime object to get the current time and declare a variable (double) to store our seconds between the current time and the download start time.
COleDateTime dlStart = COleDateTime::GetCurrentTime(); double secs;
This function will get the time the download started. In the while loop, we declare a COleDateTimeSpan object to calculate the seconds between the download start and the current time.
COleDateTimeSpan dlElapsed = COleDateTime::GetCurrentTime()
- dlStart;
secs = dlElapsed.GetTotalSeconds();
Now "secs" holds the seconds between when we started downloading the file and now... dividing the seconds with the kbs received will result in the speed rate (kb/sec).
double kbsec = kbreceived / secs;
This is it, a general information on how to achive these tasks. The program also implements error handling by using the try and catch phrases to determine error messages and printing them out to the screen. Please refer to the source code for more information.
I hope this article helped you figure out everything you need to know about downloading a file from the Internet.

Comments
Memory Leak !!!
Posted by chgyver on 05/11/2004 04:28amIf I click "CANCEL" Button as downloading... This prog. create memory leak msg... And you can solve this problem... Modify, AfxEndThread(0) ==> return 0; In DownloadFile(LPVOID pParam) ------------------------------------ if(nTerminate == 1) // See if we got a Cancel requesst { netSession.Close(); fDestFile.Close(); // Close our destination file fTargFile->Close(); // Close remote file delete fTargFile; // Delete the CStdioFile object to prevent leaks fTargFile = NULL; pwnd->SetDlgItemText(IDC_STATUS,"Download cancelled by user"); // Set satus bar text // AfxEndThread(0); // End thread ==> MODIFY !!! return 0; // new code !!! }ReplyNeed a time out
Posted by Herve3D on 04/13/2004 05:52amSometimes during a file downloading, the program stay endlessly in this line : while(int bytesread = file->Read(charbuf,512)) I think we need to add a time out. Someone know a smart solution for this problem?
Replymemory exception
Posted by Legacy on 02/09/2004 12:00amOriginally posted by: Peter R.
"delete fTargFile;" is executed twice in ProgressExDlg.cpp, so you need to remove the second one.
delete fTargFile;
Replyif(nDownloaded == 1)
{
pwnd->SetDlgItemText(IDC_STATUS,"Download complete");
delete fTargFile;
}
Memory Exception
Posted by Legacy on 10/20/2003 12:00amOriginally posted by: Kapil Suri
whenever i try to run it
Replyit gives memory exceptiion error
waiting for any one rpz
kapil231@rediffmail.com
SeekToEnd didn't work
Posted by Legacy on 10/04/2003 12:00amOriginally posted by: Yae Chan
When i was using SeekToEnd fuction it doesn't work as i expected. Any, thank you.
ReplyException Error (The Memory Could not be Read)
Posted by Legacy on 09/27/2003 12:00amOriginally posted by: Sachin Mundhra
When i run the application it gives Unhandled Exception.
Sachin
Replyneed help in resuming
Posted by Legacy on 02/03/2003 12:00amOriginally posted by: jag
can anybody help me in how to resume a download.
thank u
Replyjag
File Size without using SeekToEnd
Posted by Legacy on 12/18/2002 12:00amOriginally posted by: Steve Scanlon
ReplyFalse Progress, Its Wrong
Posted by Legacy on 11/25/2002 12:00amOriginally posted by: Paul
The Open function does the download. That means that your app will wait for the Open function to return. Once it returns the whole file is in cache. So you can read the file as if its on your hard drive because it is on your had drive. So the read function reads a local copy. Your progress bar will time how quickly your PC copies the file from cache to your destination instead of how quickly the file is read. Think about it, how can you seek the end of the file if you haven't donwloaded it yet.
Try the code on a dialup modem. The status bar will sit idle for some time and then shoot across. The idle is the download. The shoot is the file copy. I think you have to overwrite the CInternetSession class to get a true progress.
Hope this clears up some misconceptions.
-
Reply
Replyasd
Posted by killbill7 on 01/06/2008 06:59pmDevide by zero bug
Posted by Legacy on 11/07/2002 12:00amOriginally posted by: BeomSeok, Lee
This code includes devide by zero bug.
(Line number about 202).
Original code:
pwnd->SetDlgItemText(IDC_KBSEC, KBsec);
Debugged code:
Replyif(secs != 0) // Add code
pwnd->SetDlgItemText(IDC_KBSEC, KBsec);
Loading, Please Wait ...