![]() |
Wininet asynchronous download
Greetings fellows!
Ich arbeite mit Lazarus und habe ein Problem mit asynchronous download und Wininet. HUrl ist immer nil, egal welche flags InternetOpenUrl gesetzt.
Delphi-Quellcode:
Ich habe noch eine method ohne asynchronous mode.
uses WinInet;
procedure StatusCallback(hInet: HINTERNET; dwContext: DWORD_PTR; dwInternetStatus: DWORD; lpvStatusInformation: Pointer; dwStatusInformationLength: DWORD); stdcall; begin // end; function DownloadAsync(const Url, FileName: string; var Progress: Single): Boolean; const BufferSize = 1024 * 5; var hOpen, hUrl: HINTERNET; buffStruct: INTERNET_BUFFERS; bRead: LongBool; begin result := false; hOpen := InternetOpen(PChar('Test'), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, INTERNET_FLAG_ASYNC) ; try InternetSetStatusCallback(hOpen, INTERNET_STATUS_CALLBACK(@StatusCallback)); hUrl := InternetOpenUrl(hOpen, PChar(Url), nil, 0, INTERNET_FLAG_DONT_CACHE, 0) ; try repeat bRead := InternetReadFileEx(hUrl, @buffStruct, WININET_API_FLAG_ASYNC, 0); if not bRead then ShowMessage(SysErrorMessage(GetLastError)) until buffStruct.dwBufferLength = 0; result := true; finally InternetCloseHandle(hUrl); end; finally InternetCloseHandle(hOpen); end; end; Das funktioniert aber das Progress wird im main thread nicht aktualisiert.
Delphi-Quellcode:
Funktioniert INTERNET_FLAG_ASYNC nicht mehr oder mach ich etwas falsch?
function Download(const Url, FileName: string; var Progress: Single): Boolean;
const BUFFER_SIZE = 1024 * 5; var hOpen, hUrl: HINTERNET; buff: array[0..BUFFER_SIZE - 1] of Char; buffLen: DWORD; currentBytes, totalBytes: DWORD; f: File; begin result := false; buffLen := SizeOf(buff); ZeroMemory(@buff, buffLen); currentBytes := 0; totalBytes := 0; hOpen := InternetOpen(PChar('Test'), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ; try hUrl := InternetOpenUrl(hOpen, PChar(Url), nil, 0, INTERNET_FLAG_DONT_CACHE, 0) ; try HttpQueryInfo(hUrl, HTTP_QUERY_CONTENT_LENGTH, @buff, buffLen, totalBytes); totalBytes := StrToInt(string(buff)); AssignFile(f, FileName); Rewrite(f, 1); repeat InternetReadFile(hUrl, @buff, SizeOf(buff), buffLen); currentBytes := currentBytes + buffLen; Progress := currentBytes / totalBytes; BlockWrite(f, buff, buffLen); until buffLen = 0; CloseFile(f) ; result := true; finally InternetCloseHandle(hUrl); end; finally InternetCloseHandle(hOpen); end; end; |
AW: Wininet asynchronous download
Zitat:
|
AW: Wininet asynchronous download
Delphi-Quellcode:
function DownloadAsync(const Url, FileName: string; var Progress: Single): Boolean;
const BufferSize = 1024 * 5; var hOpen, hUrl: HINTERNET; buffStruct: INTERNET_BUFFERS; bRead: LongBool; e, eBuffLen: DWORD; eBuff: array[0..254] of Char; begin result := false; hOpen := InternetOpen(PChar('Test'), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, INTERNET_FLAG_ASYNC) ; try InternetSetStatusCallback(hOpen, INTERNET_STATUS_CALLBACK(@StatusCallback)); hUrl := InternetOpenUrl(hOpen, PChar(Url), nil, 0, INTERNET_FLAG_DONT_CACHE, 0) ; try repeat bRead := InternetReadFileEx(hUrl, @buffStruct, WININET_API_FLAG_ASYNC, 0); if not bRead then begin ShowMessage(SysErrorMessage(GetLastError)); // returns invalid handle ebufflen := SizeOf(eBuff); ZeroMemory(@eBuff, ebufflen); if InternetGetLastResponseInfo(e, @eBuff[0], ebuffLen) then ShowMessageFmt('%d, %d, %s', [e, eBuffLen, eBuff]); // returns 0, 0, '' end; until buffStruct.dwBufferLength = 0; result := true; finally InternetCloseHandle(hUrl); end; finally InternetCloseHandle(hOpen); end; end; |
AW: Wininet asynchronous download
|
AW: Wininet asynchronous download
Schonmal auf die vollkommen abwägige Idee gekommen, die API zu fragen, was sie hat, also dir Rückgaben zu prüfen?
![]() oder
Delphi-Quellcode:
SysErrorMessage(GetLastError)
Delphi-Quellcode:
Und natürlich auch für hOpen.
if hUrl = 0 then
RaiseLastOSError; // oder RaiseLastWin32Error, falls FreePascal das Andere nicht kennt |
AW: Wininet asynchronous download
Wenn ich es ja nicht gesagt hätte... :roll:
|
AW: Wininet asynchronous download
Du mußt lauter schreiben auf die Tastatur hämmern, sonst hört dich niemand.
Sowas, wie die COM-Library, muß man hierfür nicht initialisieren? ![]() |
AW: Wininet asynchronous download
Zitat:
|
AW: Wininet asynchronous download
Zitat:
|
AW: Wininet asynchronous download
Ich habe ein Beispiel gefunden und übersetzt
![]()
Delphi-Quellcode:
Funktioniert, aber während Download ist Programm frozen, bis Download fertig ist.
// < TAsyncInet >
uses WinInet, StrUtils; type TAsyncInet = class; PINET_CONTEXT = ^INET_CONTEXT; INET_CONTEXT = record Obj: TAsyncInet; Context: DWORD; end; TRequestType = ( _GET, _POST ); TAsyncInet = class const CONTEXT_CONNECT = 0; CONTEXT_REQUESTHANDLE = 1; private FhConnectEvent: THandle; FhRequestOpenEvent: THandle; FhRequestCompleteEvent: THandle; FhOpen: HINTERNET; FhConnect: HINTERNET; FhRequest: HINTERNET; FContext: INET_CONTEXT; protected public constructor Create; reintroduce; destructor Destroy; override; function Connect(UserAgent, Host: string; Timeout: DWORD = 20000): Boolean; function SendRequest(RequestType: TRequestType; Url, RequestData, Referrer: string; Timeout: DWORD = 20000): Boolean; function ReadData(Buffer: Pointer; Size: DWORD; Timeout: DWORD = 20000): DWORD; procedure Disconnect; end; constructor TAsyncInet.Create; begin inherited; FhConnectEvent := CreateEvent(nil, false, false, nil); FhRequestOpenEvent := CreateEvent(nil, false, false, nil); FhRequestCompleteEvent := CreateEvent(nil, false, false, nil); FhOpen := nil; FhConnect := nil; FhRequest := nil; FContext.Obj := nil; FContext.Context := 0; end; destructor TAsyncInet.Destroy; begin if FhConnectEvent > 0 then CloseHandle(FhConnectEvent); if FhRequestOpenEvent > 0 then CloseHandle(FhRequestOpenEvent); if FhRequestCompleteEvent > 0 then CloseHandle(FhRequestCompleteEvent); Disconnect; inherited; end; procedure StatusCallback(hInet: HINTERNET; dwContext: DWORD_PTR; dwInternetStatus: DWORD; lpvStatusInformation: Pointer; dwStatusInformationLength: DWORD); stdcall; var pContext: PINET_CONTEXT; pConnectResult, pRequestResult: PINTERNET_ASYNC_RESULT; begin pContext := PINET_CONTEXT(dwContext); case pContext^.Context of TAsyncInet.CONTEXT_CONNECT: begin if dwInternetStatus = INTERNET_STATUS_HANDLE_CREATED then begin pConnectResult := PINTERNET_ASYNC_RESULT(lpvStatusInformation); pContext^.Obj.FhConnect := HINTERNET(pConnectResult^.dwResult); SetEvent(pContext^.Obj.FhConnectEvent); end; end; TAsyncInet.CONTEXT_REQUESTHANDLE: begin case dwInternetStatus of INTERNET_STATUS_HANDLE_CREATED: begin pRequestResult := PINTERNET_ASYNC_RESULT(lpvStatusInformation); pContext^.Obj.FhRequest := HINTERNET(pRequestResult^.dwResult); SetEvent(pContext^.Obj.FhRequestOpenEvent); end; INTERNET_STATUS_REQUEST_COMPLETE: begin SetEvent(pContext^.Obj.FhRequestCompleteEvent); end; end; end; end; end; function TAsyncInet.Connect(UserAgent, Host: string; Timeout: DWORD): Boolean; begin result := false; Disconnect; ResetEvent(FhConnectEvent); ResetEvent(FhRequestOpenEvent); ResetEvent(FhRequestCompleteEvent); FhOpen := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, INTERNET_FLAG_ASYNC); if FhOpen = nil then exit; if Boolean(InternetSetStatusCallback(FhOpen, INTERNET_STATUS_CALLBACK(@StatusCallback))) then exit; FContext.Context := TAsyncInet.CONTEXT_CONNECT; FContext.Obj := self; FhConnect := InternetConnect(FhOpen, PChar(Host), INTERNET_DEFAULT_PORT, nil, nil, INTERNET_SERVICE_HTTP, INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_DONT_CACHE, DWORD(@FContext)); if FhConnect = nil then begin if GetLastError = ERROR_IO_PENDING then begin if Boolean(WaitForSingleObject(FhConnectEvent, Timeout)) then exit; end; exit; end; if FhConnect = nil then exit; result := true; end; function TAsyncInet.SendRequest(RequestType: TRequestType; Url: string; RequestData, Referrer: string; Timeout: DWORD): Boolean; var verb: string; requested: Boolean; header: string; begin result := false; requested := false; FContext.Context := TAsyncInet.CONTEXT_REQUESTHANDLE; FContext.Obj := self; if RequestType = _GET then verb := 'GET' else if RequestType = _POST then verb := 'POST'; FhRequest := HttpOpenRequest(FhConnect, PChar(verb), PChar(Url), nil, PChar(Referrer), nil, INTERNET_FLAG_RELOAD or INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_DONT_CACHE, DWORD(@FContext)); if FhRequest = nil then begin if GetLastError = ERROR_IO_PENDING then begin if Boolean(WaitForSingleObject(FhRequestOpenEvent, Timeout)) then exit; end; end; if FhRequest = nil then exit; if RequestType = _GET then requested := HttpSendRequest(FhRequest, nil, 0, PChar(RequestData), Length(RequestData)) else if RequestType = _POST then begin header := 'Content-Type: application/x-www-form-urlencoded'; requested := HttpSendRequest(FhRequest, PChar(header), Length(header), PChar(RequestData), Length(RequestData)); end; if not requested then begin if GetLastError = ERROR_IO_PENDING then begin if WaitForSingleObject(FhRequestCompleteEvent, Timeout) = WAIT_TIMEOUT then begin Disconnect; exit; end; end; end; result := true; end; function TAsyncInet.ReadData(Buffer: Pointer; Size: DWORD; Timeout: DWORD): DWORD; var inetBuffers: INTERNET_BUFFERS; begin result := 0; ZeroMemory(@inetBuffers, SizeOf(INTERNET_BUFFERS)); inetBuffers.dwStructSize := SizeOf(INTERNET_BUFFERS); inetBuffers.lpvBuffer := Buffer; inetBuffers.dwBufferLength := Size - 1; FContext.Context := TAsyncInet.CONTEXT_REQUESTHANDLE; FContext.Obj := self; if not InternetReadFileEx(FhRequest, inetBuffers, 0, DWORD(@FContext)) then begin if GetLastError = ERROR_IO_PENDING then begin if WaitForSingleObject(FhRequestCompleteEvent, Timeout) = WAIT_TIMEOUT then exit; end; end; result := inetBuffers.dwBufferLength; end; procedure TAsyncInet.Disconnect; begin InternetCloseHandle(FhOpen); InternetCloseHandle(FhConnect); InternetCloseHandle(FhRequest); FhOpen := nil; FhConnect := nil; FhRequest := nil; end; // < /TAsyncInet > procedure ExtractUrlTo(const Url: string; var Host, Path: string); var posLeft, posRight: Integer; begin posLeft := Pos('//www.', Url) + 6; if posLeft = 6 then begin posLeft := Pos('//', Url) + 2; if posLeft = 2 then begin posLeft := Pos('www.', Url) + 4; if posLeft = 4 then posLeft := 1; end; end; posRight := StrUtils.PosEx('/', Url, posLeft); if posRight > 0 then Path := Copy(Url, posRight, Length(Url) - posRight + 1) else begin posRight := Length(Url) + 1; Path := '/'; end; Host := Copy(Url, posLeft, posRight - posLeft); end; function DownloadAsync(const Url, FileName): Boolean; const BUFFER_SIZE = 1024 * 4; var inet: TAsyncInet; host, path: string; buff: array[0..BUFFER_SIZE - 1] of Byte; currentBytes: DWORD; f: File; begin result := false; inet := TAsyncInet.Create; try ZeroMemory(@buff[0], BUFFER_SIZE); ExtractUrlTo(Url, host, path); if inet.Connect('Test', host) then if inet.SendRequest(_GET, path, '', '') then begin AssignFile(f, FileName); Rewrite(f, 1); repeat currentBytes := inet.ReadData(@buff, BUFFER_SIZE); buff[currentBytes] := 0; BlockWrite(f, buff, currentBytes); until currentBytes = 0; CloseFile(f); result := true; end; finally inet.Free; end; end; // Call var url, filename: string; begin url := 'http://212.183.159.230/50MB.zip'; filename := 'example.zip'; DownloadAsync(url, filename); ShowMessage('Finished!'); end; Das sollte bei Async nicht passieren, oder? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:17 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz