gusucode.com > 一个视频压缩并通过网络来传送的源代码 > 一个视频压缩并通过网络来传送的源代码/断点续传和多线程VC源码/code/THttpGetThread.cpp

    //---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "THttpGetThread.h"
#pragma package(smart_init)
#pragma link "wininet.lib"
//---------------------------------------------------------------------------
int GetFileSize(const AnsiString &FileName)
{
    int FileSize=0;
    HANDLE hFile=CreateFile(FileName.c_str(),
                    GENERIC_READ,
                    FILE_SHARE_READ,
                    NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    NULL);
    if(hFile!=INVALID_HANDLE_VALUE)
    {
        FileSize=GetFileSize(hFile,NULL);
        CloseHandle(hFile);
    }
    return FileSize;
}
//---------------------------------------------------------------------------

__fastcall THttpGetThread::THttpGetThread(TObject *Owner): TThread(true)
{
    FreeOnTerminate = True;   // 自动删除
    FRepeatCount=5;

    FIndex=0;
    FOwner=Owner;

    FFromBreakpoint=false;
    FSuccess=false;
    FConnected=false;
    iFileHandle=-1;
    FFileSize=-2;
    dwStart=0;
    dwTotal=0;
}
//---------------------------------------------------------------------------
void __fastcall THttpGetThread::Execute()
{
    for(int i=0;i<FRepeatCount;i++)
    {
        StartHttpGet();
        GetWebFileSize();
        SetFilePointer();
        DoHttpGet();
        EndHttpGet();
        if(FSuccess)break;
    }
    // 调用完成事件
    if(FSuccess)DoOnComplete();
    else DoOnError();
}
//---------------------------------------------------------------------------
// 从URL中提取主机名称和下载文件路径
void THttpGetThread::ParseURL(void)
{
    AnsiString URL=FURL;
    int i=URL.Pos("http://");
    if(i>0)
    {
        URL.Delete(1, 7);
    }
    i=URL.Pos("/");
    FHostName = URL.SubString(1, i-1);
    FDownPath = URL.SubString(i, URL.Length());
}
//---------------------------------------------------------------------------
// 打开Internet句柄,初使化下载环境
void THttpGetThread::StartHttpGet(void)
{
    if(FConnected)return;
    ParseURL();
    try
    {
        // 1.建立会话
        FhSession = InternetOpen("http-get-demo",
                    INTERNET_OPEN_TYPE_PRECONFIG,
                    NULL,NULL,
                    0);         // 同步方式
        if( FhSession==NULL)throw(Exception("Error:InterOpen"));
        DoOnStatusText("ok:InterOpen");
        // 2.建立连接
        FhConnect=InternetConnect(FhSession,
                    FHostName.c_str(),
                    INTERNET_DEFAULT_HTTP_PORT,
                    NULL,NULL,
                    INTERNET_SERVICE_HTTP, 0, 0);
        if(FhConnect==NULL)throw(Exception("Error:InternetConnect"));
        DoOnStatusText("ok:InternetConnect");
        // 3.初使化下载请求
        const char *FAcceptTypes = "*/*";
        FhRequest = HttpOpenRequest(FhConnect,
                    "GET",
                    FDownPath.c_str(),
                    "HTTP/1.0",
                    NULL,
                    &FAcceptTypes,
                    INTERNET_FLAG_RELOAD,
                    0);
        if( FhRequest==NULL)throw(Exception("Error:HttpOpenRequest"));
        DoOnStatusText("ok:HttpOpenRequest");
        // 4.发送下载请求
        HttpSendRequest(FhRequest, NULL, 0, NULL, 0);
        DoOnStatusText("ok:HttpSendRequest");
        FConnected=true;
    }catch(Exception &exception)
    {
        EndHttpGet();
        DoOnStatusText(exception.Message);
    }
}
//---------------------------------------------------------------------------
int __fastcall THttpGetThread::GetWebFileSize(void)
{
    if(FFileSize>-2)return FFileSize;
    FFileSize=-1;
    if(FConnected==false)StartHttpGet();
    if(FConnected==false)return FFileSize;
    try
    {
        // 取得文件的大小
        DWORD BufLen=HTTPGET_BUFFER_MAX;
        DWORD dwIndex=0;
        bool RetQueryInfo=HttpQueryInfo(FhRequest,
                    HTTP_QUERY_CONTENT_LENGTH,
                    Buffer, &BufLen,
                    &dwIndex);
        if( RetQueryInfo==false) throw(Exception("Error:HttpQueryInfo"));
        DoOnStatusText("ok:HttpQueryInfo");
        FFileSize=StrToInt(Buffer); // 文件大小
        DoOnGetFileSize(FFileSize);
    }catch(Exception &exception)
    {
        DoOnStatusText(exception.Message);
    }
    return FFileSize;
}
//---------------------------------------------------------------------------
bool __fastcall THttpGetThread::SetFilePointer(void)
{
    int Size=GetWebFileSize();
    if(Size<0)return false;
    if(dwStart==0)return true;
    try
    {
        // 调整文件指针
        bool ReadReturn=InternetSetFilePointer(FhRequest,
                    dwStart,NULL,FILE_BEGIN,0);
        if( ReadReturn==false) throw(Exception("Error:InternetSetFilePointer"));
        DoOnStatusText("ok:InternetSetFilePointer");
        return true;
    }catch(Exception &exception)
    {
        DoOnStatusText(exception.Message);
    }
    return false;
}
//---------------------------------------------------------------------------
// 打开输出文件,以保存下载的数据
DWORD THttpGetThread::OpenOutFile(void)
{
    try
    {
        // 打开输出文件,准备保存下载的数据
        if(FileExists(FOutFileName))
        {
            if(FFromBreakpoint) // 使用断点续传
            {
                DWORD dwCount=GetFileSize(FOutFileName);
                if(dwCount>0)
                {
                    iFileHandle=FileOpen(FOutFileName,fmOpenWrite);
                    FileSeek(iFileHandle,0,2);   // 移动文件指针到末尾
                    if(iFileHandle==-1) throw(Exception("Error:FileCreate"));
                    DoOnStatusText("ok:OpenFile");
                    return dwCount;
                }
            }
            DeleteFile(FOutFileName);
        }
        iFileHandle=FileCreate(FOutFileName);
        if(iFileHandle==-1) throw(Exception("Error:FileCreate"));
        DoOnStatusText("ok:CreateFile");
    }catch(Exception &exception)
    {
        DoOnStatusText(exception.Message);
    }
    return 0;
}
//---------------------------------------------------------------------------
// 执行下载过程
void THttpGetThread::DoHttpGet(void)
{
    if(FConnected==false)return;
    DWORD dwCount=OpenOutFile();
    if(dwCount>0)   // 调整文件指针
    {
        dwStart = dwStart + dwCount;
        if(!SetFilePointer())   // 服务器不支持操作
        {
            // 清除输出文件
            FileSeek(iFileHandle,0,0);   // 移动文件指针到头部
        }
    }
    try
    {
        // 发出下载事件
        DoOnStatusText("StartGet:InternetReadFile");
        // 读取数据
        DWORD dwRequest;    // 请求下载的字节数
        DWORD dwRead;       // 实际读出的字节数
        dwRequest=HTTPGET_BUFFER_MAX;
        while(true)
        {
            Application->ProcessMessages();
            // 修正需要下载的字节数,使得dwRequest + dwCount<dwTotal
            if(dwTotal>0)     // dwTotal<=0表示下载到文件结束
            {
                if(dwRequest+dwCount>dwTotal)
                    dwRequest=dwTotal-dwCount;
            }
            bool ReadReturn = InternetReadFile(FhRequest,
                    (LPVOID)Buffer,
                    dwRequest,
                    &dwRead);
            if(!ReadReturn)break;
            if(dwRead==0)break;
            // 保存数据
            Buffer[dwRead]='\0';
            FileWrite(iFileHandle, Buffer, dwRead);
            dwCount = dwCount + dwRead;
            // 发出下载进程事件
            DoOnProgress(dwCount);
            if(dwTotal>0)     // Count<=0表示下载到文件结束
            {
                if(dwCount>=dwTotal)break;
            }
        }
    }catch(Exception &exception)
    {
        DoOnStatusText(exception.Message);
    }
    FileClose(iFileHandle);

    DoOnStatusText("End:InternetReadFile");
    if(dwCount==dwTotal)FSuccess=true;
}
//---------------------------------------------------------------------------
// 关闭Internet句柄
void THttpGetThread::EndHttpGet(void)
{
    if(FConnected)
    {
        DoOnStatusText("Closing:InternetConnect");
        try
        {
            InternetCloseHandle(FhRequest);
            InternetCloseHandle(FhConnect);
            InternetCloseHandle(FhSession);
        }catch(...){}
        FhSession=NULL;
        FhConnect=NULL;
        FhRequest=NULL;
        FConnected=false;
        DoOnStatusText("Closed:InternetConnect");
    }
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void THttpGetThread::DoOnGetFileSize(int Size)
{
    if(FOnGetFileSize)
        FOnGetFileSize(FOwner,Size);
}
//---------------------------------------------------------------------------
void THttpGetThread::DoOnProgress(int Position)
{
    if(FOnProgress)
        FOnProgress(FOwner,Position,dwTotal,FIndex);
}
//---------------------------------------------------------------------------
void THttpGetThread::DoOnStatusText(AnsiString Text)
{
    if(FOnStatusText)
        FOnStatusText(FOwner,Text,FIndex);
}
//---------------------------------------------------------------------------
void THttpGetThread::DoOnComplete(void)
{
    if(FOnComplete)
        FOnComplete(FOwner,FIndex);
}
//---------------------------------------------------------------------------
void THttpGetThread::DoOnError(void)
{
    if(FOnError)
        FOnError(FOwner,FIndex);
}
//---------------------------------------------------------------------------