Ветеран
Сообщения: 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". Не пойму я. Можешь пожалуйста объяснить:
"Создание временного файла, если он не может быть кэширован"?
|