delphi中的动态数组和wininet?

发布于 2024-09-09 06:35:29 字数 892 浏览 1 评论 0原文

我正在使用 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 中返回可变大小。

所以我尝试将索引数据和信息缓冲区声明为字节数组,然后使用 SetLength 设置其长度,但发生了两件事。

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

)我无法使用(就像现在一样)CopyMemory传递Low(indexdata)将索引数据复制到一个简单的字符串变量,这样我就可以使用数据。

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

感谢代码

I'm using WinInet to connect and retrieve information from one of our server. I'm using the following:

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);

The two array of bytes were enough up until now. Things changed. The server can return now information that can be bigger or smaller than 5000; worst yet, in InternetReadFile can return a variable size in the infoBuffer.

So i tried declaring the indexdata and infobuffer as array of byte and then using SetLength to set its length, but 2 things happened.

1) I still don't know the size of indexdata that the server will return so I cannot properly set it to, say, 100000.

2) I cannot use (as it is now) CopyMemory passing Low(indexdata) to copy indexdata to a simple string variable so I can use the data.

How do I handle this in Delphi? I can do it in C but I can't seem to be able to do it properly in Delphi.

Code is appreciated

thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

や三分注定 2024-09-16 06:35:29

您确实知道,自 Delphi 2009 以来,charUnicode 字符,但在 Delphi 2009 之前是 ANSI 字符。同样,在 Delphi 2009 中,string< /code> 是 UnicodeString,而不是 AnsiString

因此,当您编写 SetLength(text, Reserve) 时,您确实将 text 中的字符数设置为 Reserved。但字节数将为2*Reserved

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

您可以通过将所有 char 替换为 AnsiChar 并将所有 string 替换为 AnsiString 来恢复旧行为。

更新

由于您没有发布整个代码,我无法真正说出问题是什么。尽管如此,您可能会发现阅读我在 Delphi 中使用 InternetReadFile 的示例很有趣。请参阅我对这个问题的回答。这是一个完整的示例,说明如何使用 Delphi 和 InternetReadFile 从 Internet 读取文本文件。

为了方便起见,我还将我的代码粘贴在下面:

要从 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')

You do know that char is a Unicode character since Delphi 2009, but an ANSI character prior to Delphi 2009. In the same way, in Delphi 2009 a string is a UnicodeString, not an AnsiString.

So, when you write SetLength(text, Reserved) you do set the number of characters in text to Reserved. But the number of bytes will be 2*Reserved.

In other words, in Delphi 2009+, one char is not one byte, but two bytes.

You can get back the old behaviour by replacing all char with AnsiChar and all string with AnsiString.

Update

Since you did not post your entire code, I cannot really say what the problem is. Nevertheless, you might find it interesting to read my example usage of InternetReadFile in Delphi. See my answer to this question. It is a fully-working example of how to read a text file from the Internet using Delphi and InternetReadFile.

For your convinience, I paste my code below as well:

To read data from the Internet, use InternetReadFile function. I use the following code to read a small (one-line) text file from the 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;

Sample usage:

WebGetData('My UserAgent', 'www.rejbrand.se', '/MyDir/update/ver.txt')
眼藏柔 2024-09-16 06:35:29

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

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

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

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

Instead of CopyMemory, try using the Move routine, like so:

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

(Yes, without the @ symbols.) That should solve problem #2. As for problem #1, that's between you and the server. You need to have some way to know what the upper bound is on the size that it will return, and make your buffer at least that large. You should either be able to find this in the documentation, or call another API first that will give you the size of the incoming data.

Also put some check on there so that if it returns something larger than your buffer, it immediately raises an exception. If your buffer is overrun, you should assume that your program is under attack and react accordingly.

北渚 2024-09-16 06:35:29

返回未知大小的缓冲区的 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;

Windows functions that return a buffer of unknown size, usually return the require size of the buffer if a too small buffer is passed. This way you do not need to size in advance a buffer large enough to hold the largest data - pass a small buffer (even a zero length one), and the function will return how large the buffer should be. Then you can size your buffer and pass it again the the function to read data - check for example HttpQueryInfo() explanation in MSDN.
To handle buffer of an unknown size in Delphi, you have two ways.

  • Use dynamic arrays and SetLength()
  • Use dynamically allocated buffers using GetMem() and FreeMem(), very much alike you would do in C.

For example:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文