Имя пользователя:
Пароль:
 

Показать сообщение отдельно

Аватара для Johny777

Ветеран


Сообщения: 649
Благодарности: 444

Профиль | Отправить PM | Цитировать


Tco 03, ну всё, с тебя ящик бухла:
написал полностью код закачки с нуля на основе тех же функций из Wininet.h/Wininet.pas
двойной прогресс как ты и хотел, ...
тот пример тут http://forum.oszone.net/post-2149513-443.html (гугл рулит), но это уже не важно!
справка по API:
читать дальше »
Код: Выделить весь код
function DownloadFiles
(
    const urlFiles: array of String;   // массив ссылок на закачку
    const dstFiles: array of string;   // массив путей сохраняемых файлов (каждый файл должен соответствовать соответствующей ссылке!)
    const SkipExistingFiles: Boolean;  // пропуск существующих файлов (True-да)
    const CallBack: _DOWNLOAD_CALLBACK // указатель на функцию обратного вызова или nil
): Boolean;
////////////////////////////////////////////////////////////////////////
type
    _DOWNLOAD_CALLBACK =
    function(
        const StatusMessage: Integer; // сообщение о статусе загрузки:
                                      //  DOWNLOAD_PREPARING,
                                      //  DOWNLOAD_IN_PROGRESS,
                                      //  DOWNLOAD_IN_PROGRESS_NEXT_FILE,
                                      //  DOWNLOAD_FINISHED.
        const dstFile: String; // путь к текущему файлу назначения
        const FileBytes: Extended; // размер текущего файла в байтах
        const FileBytesWritten: Extended; // кол-во загруженных, записанных в файл байт от его размера
        const TotalBytes: Extended; // размер всех файлов в байтах
        const TotalBytesWritten: Extended // кол-во загруженных, записанных байт от размера  всех файлов
     ): Boolean; // чтоб отменить загрузку нужно из вернуть False;
///////////////////////////////////////////////////////////////////////////////

// если функция DownloadFiles() вернула False, то можно узнать почему:
// function LastDownloadError(): Integer; возвращает следующие константы ошибок
const
    DOWNLOAD_ERROR_ABORTED_BY_USER = 2;
    DOWNLOAD_ERROR_COULD_NOT_DELETE_EXISTING_FILE = 4;
    DOWNLOAD_ERROR_DOWNLOAD_URL_IS_NOT_VALID_URL = 8;


сам код загрузки + демо
читать дальше »
Код: Выделить весь код
procedure IncEx(var Int: Extended; const Value: Extended);
begin
    Int := Int + Value;
end;
//////////////////////////////////////// download files ///////////////////////////////////////////////
type
    Pointer = Longint;
    HINTERNET = Pointer;
    
    _DOWNLOAD_CALLBACK =
    function(
        const StatusMessage: Integer; // сообщение о статусе загрузки
        const dstFile: String; // путь к текущему файлу назначения
        const FileBytes: Extended; // размер текущего файла в байтах
        const FileBytesWritten: Extended; // кол-во загруженных, записанных в файл байт от его размера
        const TotalBytes: Extended; // размер всех файлов в байтах
        const TotalBytesWritten: Extended // кол-во загруженных, записанных байт от размера  всех файлов
     ): Boolean; // чтоб отменить загрузку нужно из вернуть False;

const
    INTERNET_OPEN_TYPE_PRECONFIG        = 0;  { use registry configuration }
    HTTP_QUERY_CONTENT_LENGTH                   = 5;
    
    
#ifdef UNICODE
    #define A "W"
#else
    #define A "A"
#endif
function HttpQueryInfo(hRequest: HINTERNET; dwInfoLevel: DWORD;
  lpvBuffer: AnsiString; var lpdwBufferLength: DWORD;
  var lpdwReserved: DWORD): BOOL; external 'HttpQueryInfo{#A}@wininet.dll stdcall';
function InternetCloseHandle(hInet: HINTERNET): BOOL; external 'InternetCloseHandle@wininet.dll stdcall';
function InternetOpenUrl(hInet: HINTERNET; lpszUrl: String;
  lpszHeaders: String; dwHeadersLength: DWORD; dwFlags: DWORD;
  dwContext: DWORD): HINTERNET; external 'InternetOpenUrl{#A}@wininet.dll stdcall';
function InternetOpen(lpszAgent: String; dwAccessType: DWORD;
  lpszProxy, lpszProxyBypass: String; dwFlags: DWORD): HINTERNET; external 'InternetOpen{#A}@wininet.dll stdcall';
function InternetReadFile(hFile: HINTERNET; lpBuffer: AnsiString;
  dwNumberOfBytesToRead: DWORD; var lpdwNumberOfBytesRead: DWORD): BOOL; external 'InternetReadFile@wininet.dll stdcall';
  
///////////////////////////////////  handle Errors /////////////////////////////////
const
    DOWNLOAD_ERROR_ABORTED_BY_USER = 2;
    DOWNLOAD_ERROR_COULD_NOT_DELETE_EXISTING_FILE = 4;
    DOWNLOAD_ERROR_DOWNLOAD_URL_IS_NOT_VALID_URL = 8;
var
    downloadError: Integer;
    
function LastDownloadError(): Integer;
begin
    Result := downloadError;
end;
/////////////////////////////////////////////////////////////////////////////////////

const
    FILESIZE_BUFF_LEN = 30;
    UNDEF_FILE_SIZE = -1;
    
function InternetFileSize
(
    const hOpenedInet: HINTERNET; // in // with INTERNET_OPEN_TYPE_PRECONFIG flag
    const urlFile: String;    // in 
    var FileSize: Extended; // out
    var hOpenedFile: HINTERNET // out
): Boolean;
var
    Buff: AnsiString;
    dwBufLen, dwReserved: DWORD;
begin
    Result := False;
    FileSize := UNDEF_FILE_SIZE;

    SetLength(Buff, FILESIZE_BUFF_LEN);
    dwBufLen := DWORD(FILESIZE_BUFF_LEN);

    hOpenedFile := InternetOpenUrl( hOpenedInet, urlFile, '', 0, 0, 0 );
    if hOpenedFile = 0 then
    begin
        downloadError := DOWNLOAD_ERROR_DOWNLOAD_URL_IS_NOT_VALID_URL;
        Exit;
    end;

    if HttpQueryInfo( hOpenedFile, HTTP_QUERY_CONTENT_LENGTH, Buff, dwBufLen, dwReserved ) then
    begin
        FileSize := StrToFloat( Trim(Buff) );
        Result := True;
    end;
end;

function InternetFilesSizes
(
    const hOpenedInet: HINTERNET; // in // with INTERNET_OPEN_TYPE_PRECONFIG flag
    const urlFiles: array of String; // in
    const urlFilesCount: Integer; // in
    var TotalBytes: Extended;  // out
    var FileBytes: array of Extended;   // out
    var hOpenedFile: array of HINTERNET  // out
): Boolean;
var
    i, e: Integer;
begin
    Result := True;
    TotalBytes := 0;
    
    SetArrayLength(FileBytes, urlFilesCount);
    SetArrayLength(hOpenedFile, urlFilesCount);
    
    for i := 0 to urlFilesCount-1 do
    begin
        Result := Result and InternetFileSize(hOpenedInet, urlFiles[i], FileBytes[i], hOpenedFile[i]);
        if not Result then
        begin
            for e := 0 to i-1 do
              InternetCloseHandle(hOpenedFile[e]);
              
            Break;
        end;
        
        TotalBytes := TotalBytes + FileBytes[i];
    end;
end;



const
    MEGABYTE = 1024;
    READ_WRITE_FILE_BUFF_SIZE = MEGABYTE;
    
    // download messages
    DOWNLOAD_PREPARING = 2;
    DOWNLOAD_IN_PROGRESS = 4;
    DOWNLOAD_IN_PROGRESS_NEXT_FILE = 8;
    DOWNLOAD_FINISHED = 16;
    

function DownloadFiles
(
    const urlFiles: array of String;   // массив ссылок на закачку
    const dstFiles: array of string;   // массив путей сохраняемых файлов (каждый файл должен соответствовать соответствующей ссылке!)
    const SkipExistingFiles: Boolean;  // пропуск существующих файлов (True-да)
    const CallBack: _DOWNLOAD_CALLBACK // указатель на функцию обратного вызова или nil
): Boolean;
var
    i: Integer;
    
    TotalBytes, TotalBytesWritten: Extended;
    FileBytes: array of Extended;
    FileBytesWritten: Extended;
    
    hOpenedFile: array of HINTERNET;
    hOpenedInet: HINTERNET;
    
    urlFilesCount: Integer;
    
    dstFileStream: TFileStream;
    dwNumberOfBytesRead: DWORD;
    Buff: AnsiString;
    
    AbortedWhileWriting: Boolean;
begin
    Result := False;
    AbortedWhileWriting := False;
    
    
    hOpenedInet := InternetOpen('', INTERNET_OPEN_TYPE_PRECONFIG, '', '', 0);
    if hOpenedInet = 0 then Exit;
    try
        if CallBack <> nil then // callback
          if not CallBack(DOWNLOAD_PREPARING, '', UNDEF_FILE_SIZE, UNDEF_FILE_SIZE, UNDEF_FILE_SIZE, UNDEF_FILE_SIZE) then
            begin
                downloadError := DOWNLOAD_ERROR_ABORTED_BY_USER;
                Exit;
            end;  
    
        urlFilesCount := GetArrayLength(urlFiles);
        if not InternetFilesSizes(hOpenedInet, urlFiles, urlFilesCount, TotalBytes, FileBytes, hOpenedFile) then Exit;

        SetLength(Buff, READ_WRITE_FILE_BUFF_SIZE);
        
        if CallBack <> nil then TotalBytesWritten := 0; // callback
        
        for i := 0 to urlFilesCount-1 do // download
        begin
            
            if CallBack <> nil then // callback
            begin
                FileBytesWritten := 0;
                
                if not CallBack
                (
                    DOWNLOAD_IN_PROGRESS_NEXT_FILE,
                    dstFiles[i],
                    FileBytes[i],
                    UNDEF_FILE_SIZE,
                    TotalBytes,
                    TotalBytesWritten
                ) then
                begin
                    downloadError := DOWNLOAD_ERROR_ABORTED_BY_USER;
                    Exit;
                end;
            end;
            
            if FileExists(dstFiles[i]) then 
              if SkipExistingFiles then Continue
              else
              if not DeleteFile(dstFiles[i]) then
              begin
                  downloadError := DOWNLOAD_ERROR_COULD_NOT_DELETE_EXISTING_FILE;
                  Exit;
              end;

        
            dstFileStream := TFileStream.Create(dstFiles[i], fmCreate);
            try
                repeat

                    InternetReadFile(hOpenedFile[i], Buff, READ_WRITE_FILE_BUFF_SIZE, dwNumberOfBytesRead);
                    dstFileStream.Write(Buff, dwNumberOfBytesRead);
                    
                    if CallBack <> nil then // callback
                    begin
                        IncEx( TotalBytesWritten, Integer(dwNumberOfBytesRead) );
                        IncEx( FileBytesWritten, Integer(dwNumberOfBytesRead) );
                        
                        if not CallBack
                        (
                            DOWNLOAD_IN_PROGRESS,
                            dstFiles[i],
                            FileBytes[i],
                            FileBytesWritten,
                            TotalBytes,
                            TotalBytesWritten
                        ) then
                        begin
                            downloadError := DOWNLOAD_ERROR_ABORTED_BY_USER;
                            AbortedWhileWriting := True;
                            Exit;
                        end;
                    end;
                    
                until (dwNumberOfBytesRead = 0);
            finally
                InternetCloseHandle(hOpenedFile[i]);
                dstFileStream.Free;
                
                if AbortedWhileWriting then DeleteFile(dstFiles[i]);
            end;
            
        end;
        
        Result := True;
        if CallBack <> nil then // callback
          CallBack(DOWNLOAD_FINISHED, '', UNDEF_FILE_SIZE, UNDEF_FILE_SIZE, UNDEF_FILE_SIZE, UNDEF_FILE_SIZE);  
            
    finally
        InternetCloseHandle(hOpenedInet);
    end;
end;


///////////////////////////////////////////////////////////// demo ///////////////////////////////////////////////////////////////////////

var
    FilePrpgressBar, TotalProgressBar: TNewProgressBar;
    FileStatic: TNewStaticText;
    

function _DownloadCallBack(
    const StatusMessage: Integer;
    const dstFile: String;
    const FileBytes: Extended;
    const FileBytesWritten: Extended;
    const TotalBytes: Extended;
    const TotalBytesWritten: Extended
): Boolean;
begin
    case StatusMessage of
        DOWNLOAD_PREPARING: FileStatic.Caption := 'Preparing download...';
    
        DOWNLOAD_IN_PROGRESS:
        begin
            TotalProgressBar.Position := Round( (TotalProgressBar.Max*TotalBytesWritten) / TotalBytes );
            FilePrpgressBar.Position := Round( (FilePrpgressBar.Max*FileBytesWritten) / FileBytes );
        end;
        
        DOWNLOAD_IN_PROGRESS_NEXT_FILE:
        begin
            WizardForm.Caption := WizardForm.Caption + ' :) ';
            FileStatic.Caption := dstFile;
        end;
    
        DOWNLOAD_FINISHED: MsgBox('Download Finished!', mbInformation, MB_OK);
    end;
    
    Application.ProcessMessages;
    
    Result := not Application.Terminated;
end;
    

procedure DownloadBtnClick(Sender: TObject);
begin
    DownloadFiles
      ( ['http://mse.dlservice.microsoft.com/download/7/6/0/760B9188-4468-4FAD-909E-4D16FE49AF47/ruRU/x86/mseinstall.exe',
         '',
         'http://mse.dlservice.microsoft.com/download/7/6/0/760B9188-4468-4FAD-909E-4D16FE49AF47/ruRU/x86/mseinstall.exe',
         'http://mse.dlservice.microsoft.com/download/7/6/0/760B9188-4468-4FAD-909E-4D16FE49AF47/ruRU/x86/mseinstall.exe'
        ]
       ,['C:\test1.exe',
         'C:\test2.exe',
         'C:\test3.exe',
         'C:\test4.exe'
        ],
        False,
        @_DownloadCallBack
    );
end;
    

procedure InitializeWizard();
begin
    with WizardForm do
    begin
        OuterNotebook.Hide;

        WizardForm.Caption := '';
        
        TotalProgressBar := TNewProgressBar.Create(WizardForm);
        with TotalProgressBar do
        begin
            Parent := WizardForm;
            SetBounds(10,10,WizardForm.ClientWidth-20,25);
            Max := 1000;
        end;
        
        FilePrpgressBar := TNewProgressBar.Create(WizardForm);
        with FilePrpgressBar do
        begin
            Parent := WizardForm;
            SetBounds(10,40,WizardForm.ClientWidth-20,25);
        end;
        
        FileStatic := TNewStaticText.Create(WizardForm)
        with FileStatic do
        begin
            Parent := WizardForm;
            Left := 15;
            Top := 77;
        end;
        
        with TButton.Create(WizardForm) do
        begin
            Parent := WizardForm;
            SetBounds((WizardForm.ClientWidth-77) div 2, 270, 77, 25);
            Caption := 'Download';
            OnClick := @DownloadBtnClick;
        end;
    end;
    
    
    
end;


El Sanchez, ты тогда говорил:
Цитата El Sanchez:
P.S. Вообще-то пример в шапке устарел, заменю его как-нибудь. »
Теперь, думаю, нет необходимости
Предлагаю добавить код в шапку (с заменой, если сочтёшь нужным), тк он может многим пригодиться
PS:
только я так и не понял зачем нужен флаг в твоём коде InternetOpenUrl(... INTERNET_FLAG_NEED_FILE ), когда уже непосредственно получаешь указатель на файл для скачивания?
на MSDN сказано "Causes a temporary file to be created if the file cannot be cached". Не пойму я. Можешь пожалуйста объяснить:
"Создание временного файла, если он не может быть кэширован"?
Это сообщение посчитали полезным следующие участники:

Отправлено: 19:44, 05-12-2013 | #1618