2

我正在使用 WinInet 从我们的一台服务器连接和检索信息。我正在使用以下内容:

indexdata: array of byte[1..5000] of byte;
infoBuffer: array [0..5000] of char;
BufferSize: DWORD;
reserved:   DWORD;
text: string;

BufferSize := Length(infoBuffer);
res := HttpQueryInfo(hHttpRequest, HTTP_QUERY_RAW_HEADERS_CRLF, @infoBuffer, BufferSize, Reserved);

Reserved := 0;
InternetReadFile(hHttpRequest, @indexdata, sizeof(indexdata), Reserved);

SetLength(text, Reserved);
CopyMemory(@text[1], @indexdata[1], Reserved);

到目前为止,这两个字节数组已经足够了。事情发生了变化。服务器现在可以返回大于或小于5000的信息;最糟糕的是,在 InternetReadFile 中,可以在 infoBuffer 中返回可变大小。

所以我尝试将 indexdata 和 infobuffer 声明为字节数组,然后使用 SetLength 设置它的长度,但是发生了两件事。

1)我仍然不知道服务器将返回的 indexdata 的大小,因此我无法正确将其设置为 100000。

2)我不能使用(现在这样)CopyMemory 传递 Low(indexdata) 将 indexdata 复制到一个简单的字符串变量,所以我可以使用数据。

我如何在 Delphi 中处理这个问题?我可以在 C 中做到这一点,但我似乎无法在 Delphi 中正确地做到这一点。

代码表示赞赏

谢谢!

4

3 回答 3

3

您确实知道,自 Delphi 2009 以来这char是一个Unicode 字符,但在 Delphi 2009 之前是一个 ANSI 字符。同样,在 Delphi 2009 中,astring是 a UnicodeString,而不是AnsiString.

因此,当您编写时,SetLength(text, Reserved)您确实将字符数设置textReserved. 但字节数将是2*Reserved.

换句话说,在 Delphi 2009+ 中,一个char不是一个byte,而是两个字节。

您可以通过将 all 替换为 和 all 来char恢复AnsiCharstring行为AnsiString

更新

由于您没有发布整个代码,因此我无法真正说出问题所在。不过,您可能会发现阅读我在 Delphi 中使用 InternetReadFile 的示例会很有趣。请参阅我对这个问题的回答。它是如何使用 Delphi 和InternetReadFile.

为了您的方便,我也将我的代码粘贴在下面:

要从 Internet 读取数据,请使用InternetReadFile函数。我使用以下代码从 Internet 读取一个小的(单行)文本文件:

function WebGetData(const UserAgent: string; const Server: string; const Resource: string): string;
var
  hInet: HINTERNET;
  hURL: HINTERNET;
  Buffer: array[0..1023] of AnsiChar;
  i, BufferLen: cardinal;
begin
  result := '';
  hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    hURL := InternetOpenUrl(hInet, PChar('http://' + Server + Resource), nil, 0, 0, 0);
    try
      repeat
        InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen);
        if BufferLen = SizeOf(Buffer) then
          result := result + AnsiString(Buffer)
        else if BufferLen > 0 then
          for i := 0 to BufferLen - 1 do
            result := result + Buffer[i];
      until BufferLen = 0;
    finally
      InternetCloseHandle(hURL);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

示例用法:

WebGetData('My UserAgent', 'www.rejbrand.se', '/MyDir/update/ver.txt')
于 2010-07-12T16:50:42.440 回答
1

尝试使用 Move 例程,而不是 CopyMemory,如下所示:

Move(indexdata[1], text[1], reserved);

(是的,没有@ 符号。)这应该可以解决问题#2。至于问题#1,那是您和服务器之间的问题。您需要有一些方法来知道它将返回的大小的上限是多少,并使您的缓冲区至少有那么大。您应该能够在文档中找到它,或者首先调用另一个 API 来为您提供传入数据的大小。

还要在那里进行一些检查,以便如果它返回大于缓冲区的内容,它会立即引发异常。如果你的缓冲区溢出,你应该假设你的程序受到攻击并做出相应的反应。

于 2010-07-12T16:51:42.267 回答
1

返回未知大小的缓冲区的 Windows 函数,如果传递的缓冲区太小,通常会返回所需的缓冲区大小。这样,您无需预先设置足够大的缓冲区来容纳最大数据 - 传递一个小缓冲区(即使是零长度的缓冲区),该函数将返回缓冲区应该有多大。然后您可以调整缓冲区的大小并再次将其传递给读取数据的函数 - 检查例如 MSDN 中的 HttpQueryInfo() 说明。要在 Delphi 中处理未知大小的缓冲区,有两种方法。

  • 使用动态数组和 SetLength()
  • 使用 GetMem() 和 FreeMem() 使用动态分配的缓冲区,这与您在 C 中所做的非常相似。

例如:

var
  Buf: Pointer;
  BufSize: DWORD; 
  Rez: DWORD;
  ...
const
  InitialBufSize = 1024;

...
BufSize := InitialBufSize;
GetMem(Buf, BufSize);
try
  if not HttpQueryInfo(hRequest, dwInfoLevel, Buf, BufSize, lpdwIndex) then
  begin
    Rez := GetLastError;
    if Rez = ERROR_INSUFFICIENT_BUFFER then
    begin
      FreeMem(Buf, InitialBufSize);
      GetMem((Buf, BufSize);
      if not HttpQueryInfo(hRequest, dwInfoLevel, Buf, BufSize, lpdwIndex) then
        Rez := GetLastError
    end;
 ...
finally
  FreeMem(Buf, BufSize);
end;
于 2010-07-12T18:42:30.517 回答