Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi-使用Wininet下载文件?_Delphi_Download_Wininet - Fatal编程技术网

Delphi-使用Wininet下载文件?

Delphi-使用Wininet下载文件?,delphi,download,wininet,Delphi,Download,Wininet,注: 这段代码是在DelphiXe2中编写的 我正在尝试不使用UrlMon.dll下载文件 我只想使用wininet。这就是我到目前为止的想法: uses Windows, Wininet; procedure DownloadFile(URL:String;Path:String); Var InetHandle:Pointer; URLHandle:Pointer; FileHandle:Cardinal; ReadNext:Cardinal; DownloadBuff

注: 这段代码是在DelphiXe2中编写的

我正在尝试不使用UrlMon.dll下载文件

我只想使用wininet。这就是我到目前为止的想法:

uses Windows, Wininet;

procedure DownloadFile(URL:String;Path:String);
Var
  InetHandle:Pointer;
  URLHandle:Pointer;
  FileHandle:Cardinal;
  ReadNext:Cardinal;
  DownloadBuffer:Pointer;
  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);
  Repeat
    InternetReadFile(URLHandle,DownloadBuffer,1024,ReadNext);
    WriteFile(FileHandle,DownloadBuffer,ReadNext,BytesWritten,0);
  Until ReadNext = 0;
  CloseHandle(FileHandle);
  InternetCloseHandle(URLHandle);
  InternetCloseHandle(InetHandle);
end;

我认为问题在于我的循环和“ReadNext”。当执行此代码时,它将以正确的路径创建文件,但代码完成,文件为0字节。

我对您的例程进行了一些改进,它为我完成了以下工作:

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);
  if not Assigned(InetHandle) then RaiseLastOSError;
  try
    URLHandle := InternetOpenUrl(InetHandle, PWideChar(URL), 0, 0, 0, 0);
    if not Assigned(URLHandle) then RaiseLastOSError;
    try
      FileHandle := CreateFile(PWideChar(Path), GENERIC_WRITE, FILE_SHARE_WRITE, 0,
        CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
      if FileHandle = INVALID_HANDLE_VALUE then RaiseLastOSError;
      try
        DownloadBuffer := @Buffer;
        repeat
          if (not InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead) 
             or (not WriteFile(FileHandle, DownloadBuffer^, BytesRead, BytesWritten, 0)) then
            RaiseLastOSError;
        until BytesRead = 0;
      finally
        CloseHandle(FileHandle);
      end;
    finally
      InternetCloseHandle(URLHandle);
    end;
  finally
    InternetCloseHandle(InetHandle);
  end;
end;
例如,一个电话:

  DownloadFile
    ('https://dl.dropbox.com/u/21226165/XE3StylesDemo/StylesDemoSrcXE2.7z',
    '.\StylesDemoXE2.7z');
工作起来很有魅力

我所做的改变是:

  • 提供缓冲区
  • 检查调用WriteFile的结果,如果结果为false或写入的字节数与读取的字节数不同,则引发异常
  • 更改了变量名
  • 命名常数
  • [编辑后]正确的功能结果检查
  • [编辑后]使用try/finally块进行资源泄漏保护

编辑感谢TLama提高了对最后两点的认识。

我对你的例行程序做了一些改进,它为我做了一些工作:

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);
  if not Assigned(InetHandle) then RaiseLastOSError;
  try
    URLHandle := InternetOpenUrl(InetHandle, PWideChar(URL), 0, 0, 0, 0);
    if not Assigned(URLHandle) then RaiseLastOSError;
    try
      FileHandle := CreateFile(PWideChar(Path), GENERIC_WRITE, FILE_SHARE_WRITE, 0,
        CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
      if FileHandle = INVALID_HANDLE_VALUE then RaiseLastOSError;
      try
        DownloadBuffer := @Buffer;
        repeat
          if (not InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead) 
             or (not WriteFile(FileHandle, DownloadBuffer^, BytesRead, BytesWritten, 0)) then
            RaiseLastOSError;
        until BytesRead = 0;
      finally
        CloseHandle(FileHandle);
      end;
    finally
      InternetCloseHandle(URLHandle);
    end;
  finally
    InternetCloseHandle(InetHandle);
  end;
end;
例如,一个电话:

  DownloadFile
    ('https://dl.dropbox.com/u/21226165/XE3StylesDemo/StylesDemoSrcXE2.7z',
    '.\StylesDemoXE2.7z');
工作起来很有魅力

我所做的改变是:

  • 提供缓冲区
  • 检查调用WriteFile的结果,如果结果为false或写入的字节数与读取的字节数不同,则引发异常
  • 更改了变量名
  • 命名常数
  • [编辑后]正确的功能结果检查
  • [编辑后]使用try/finally块进行资源泄漏保护

编辑感谢特拉玛提出关于最后两点的建议。

首先,这是错误的

InetHandle := InternetOpen(PChar(URL), 0, 0, 0, 0);
需要

InetHandle := InternetOpen(PChar(USERANGENT), 0, 0, 0, 0);
这里缺了一个)

(not InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead) ")"

首先,这是错误的

InetHandle := InternetOpen(PChar(URL), 0, 0, 0, 0);
需要

InetHandle := InternetOpen(PChar(USERANGENT), 0, 0, 0, 0);
这里缺了一个)

(not InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead) ")"


ReadNext<1024时必须停止。顺便说一句,该变量的更好名称是BytesRead。未更改任何内容。我甚至在InternetReadFile显示ReadNext变量或“ByteRead”后显示一个消息框,它显示0。请注意WinInet已过时!!!!!!!!!!您可能需要使用WinHTTP:而且您的缓冲区可能太小。当ReadNext<1024时,您必须停止。顺便说一句,该变量的更好名称是BytesRead。未更改任何内容。我甚至在InternetReadFile显示ReadNext变量或“ByteRead”后显示一个消息框,它显示0。请注意WinInet已过时!!!!!!!!!!您可能需要使用WinHTTP:而且您的缓冲区可能太小。您能解释一下如何在delphi 7应用程序中执行相同的代码吗?在Delphi7中,这段代码可以编译,但不能正确下载文件。它似乎一次又一次地添加同一行“byte sequence”…实际上,我将所有“PWideChar”编辑为“PChar”,还尝试了“PAnsiChar”Josh,您必须匹配Windows API。在2009年之前的Delphi中,它是Ansi,因此必须使用PChar或PAnsiChar。在Delphi 2009+中,它是unicode,因此您可以使用PWideChar或PChar作为等价物。最安全的方法是总是用PChar来做演员。如果你能检查一下我的最新问题:我已经试过PChar和PAnsiChar了。两者都失败。@jachguate,您应该使用
try..finally
块关闭打开的句柄。始终使用适当的变量类型。无需在
WriteFile
处检查
bytesWritedbytesRead
,如果不同,则函数将失败。并且,正如参考中所述,您应该调用
InternetReadFile
,直到它返回True,并且直到
lpdwNumberOfBytesRead
为0。请看一下评论。您能解释一下如何在Delphi7应用程序中执行相同的代码吗?在Delphi7中,这段代码可以编译,但不能正确下载文件。它似乎一次又一次地添加同一行“byte sequence”…实际上,我将所有“PWideChar”编辑为“PChar”,还尝试了“PAnsiChar”Josh,您必须匹配Windows API。在2009年之前的Delphi中,它是Ansi,因此必须使用PChar或PAnsiChar。在Delphi 2009+中,它是unicode,因此您可以使用PWideChar或PChar作为等价物。最安全的方法是总是用PChar来做演员。如果你能检查一下我的最新问题:我已经试过PChar和PAnsiChar了。两者都失败。@jachguate,您应该使用
try..finally
块关闭打开的句柄。始终使用适当的变量类型。无需在
WriteFile
处检查
bytesWritedbytesRead
,如果不同,则函数将失败。并且,正如参考中所述,您应该调用
InternetReadFile
,直到它返回True,并且直到
lpdwNumberOfBytesRead
为0。看一看评论。不明白,我为这段代码写了两个错误,我得到了-1:)))不错的答案不明白,我为这段代码写了两个错误,我得到了-1:))不错的答案