Delphi - XE2 code to Delphi7 needed. Using wininet

2019-08-12 20:23发布

问题:

Note: I only want to use wininet, not urlmon-urldownloadtofile.

Well, I have the following code which works perfectly in XE2 to download a file:

procedure DownloadFile(URL: string; Path: string);
const
  BLOCK_SIZE = 1024;
var
  InetHandle: Pointer;
  URLHandle: Pointer;
  FileHandle: Cardinal;
  BytesRead: Cardinal;
  DownloadBuffer: Pointer;
  Buffer: array [1 .. BLOCK_SIZE] of byte;
  BytesWritten: Cardinal;
begin
  InetHandle := InternetOpen(PWideChar(URL), 0, 0, 0, 0);
  URLHandle := InternetOpenUrl(InetHandle, PWideChar(URL), 0, 0, 0, 0);
  FileHandle := CreateFile(PWideChar(Path), GENERIC_WRITE, FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
  DownloadBuffer := @Buffer;
  repeat
    InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead);
    if not WriteFile(FileHandle, DownloadBuffer, BytesRead, BytesWritten, 0) or
  (BytesWritten <> BytesRead) then
      RaiseLastOSError;
  until BytesRead < BLOCK_SIZE;
  CloseHandle(FileHandle);
  InternetCloseHandle(URLHandle);
  InternetCloseHandle(InetHandle);
end;

The above code's credits go to jachguate. He edited my code to correct it, and I thank him for that.

Now, this code only works correctly under Delphi XE2. I try to use it under Delphi 7 and it is not working correctly. It seems to store the same "line" or "byte sequence" to the file over and over a few times.

The following are the two reformations of the above code I have attemted to use in Delphi 7 - neither of which worked properly.

procedure DownloadFile(URL: string; Path: string);
const
  BLOCK_SIZE = 1024;
var
  InetHandle: Pointer;
  URLHandle: Pointer;
  FileHandle: Cardinal;
  BytesRead: Cardinal;
  DownloadBuffer: Pointer;
  Buffer: array [1 .. BLOCK_SIZE] of byte;
  BytesWritten: Cardinal;
begin
  InetHandle := InternetOpen(PChar(URL), 0, 0, 0, 0);
  URLHandle := InternetOpenUrl(InetHandle, PChar(URL), 0, 0, 0, 0);
  FileHandle := CreateFile(PChar(Path), GENERIC_WRITE, FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
  DownloadBuffer := @Buffer;
  repeat
    InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead);
    if not WriteFile(FileHandle, DownloadBuffer, BytesRead, BytesWritten, 0) or
  (BytesWritten <> BytesRead) then
      RaiseLastOSError;
  until BytesRead < BLOCK_SIZE;
  CloseHandle(FileHandle);
  InternetCloseHandle(URLHandle);
  InternetCloseHandle(InetHandle);
end;

procedure DownloadFile(URL: string; Path: string);
const
  BLOCK_SIZE = 1024;
var
  InetHandle: Pointer;
  URLHandle: Pointer;
  FileHandle: Cardinal;
  BytesRead: Cardinal;
  DownloadBuffer: Pointer;
  Buffer: array [1 .. BLOCK_SIZE] of byte;
  BytesWritten: Cardinal;
begin
  InetHandle := InternetOpen(PAnsiChar(URL), 0, 0, 0, 0);
  URLHandle := InternetOpenUrl(InetHandle, PAnsiChar(URL), 0, 0, 0, 0);
  FileHandle := CreateFile(PAnsiChar(Path), GENERIC_WRITE, FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
  DownloadBuffer := @Buffer;
  repeat
    InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead);
    if not WriteFile(FileHandle, DownloadBuffer, BytesRead, BytesWritten, 0) or
  (BytesWritten <> BytesRead) then
      RaiseLastOSError;
  until BytesRead < BLOCK_SIZE;
  CloseHandle(FileHandle);
  InternetCloseHandle(URLHandle);
  InternetCloseHandle(InetHandle);
end;

Only thing edited was the data type conversions. Example one "PChar" was used, and example two "PAnsiChar" was used.

回答1:

You are getting garbage in the file because you need dereference the pointer DownloadBuffer using the ^ char, so to fix your method just replace this code

WriteFile(FileHandle, DownloadBuffer, BytesRead, BytesWritten, 0)

by this

WriteFile(FileHandle, DownloadBuffer^, BytesRead, BytesWritten, 0)

btw, remember add try..finally blocks to your function to ensure release the handles when a exception occurs.