2

WinInet を使用して、サーバーの 1 つに接続して情報を取得しています。私は以下を使用しています:

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

今までは 2 つのバイト配列で十分でした。状況は変わりました。サーバーは、5000 より大きくても小さくてもよい情報を返すことができるようになりました。さらに悪いことに、InternetReadFile では、infoBuffer で可変サイズを返すことができます。

そのため、indexdata と infobuffer をバイト配列として宣言し、SetLength を使用してその長さを設定しようとしましたが、2 つのことが起こりました。

1) サーバーが返す indexdata のサイズがまだわからないため、たとえば 100000 に適切に設定することはできません。

2) データを使用できるように、Low(indexdata) を渡す CopyMemory を使用して indexdata を単純な文字列変数にコピーすることはできません。

Delphi でこれを処理するにはどうすればよいですか? C ではできますが、Delphi では適切に実行できないようです。

コードは高く評価されています

ありがとう!

4

3 に答える 3

3

charDelphi 2009 以降はUnicode 文字ですが、Delphi 2009 より前は ANSI 文字であることがわかります。同様に、Delphi 2009 では、 astringUnicodeStringではなくAnsiString.

したがって、書くときSetLength(text, Reserved)は文字数を に設定しtextますReserved。ただし、バイト数は になります2*Reserved

つまり、Delphi 2009 以降では、1charは 1byteではなく 2 バイトです。

charallとAnsiCharallstringをに置き換えることで、古い動作に戻すことができますAnsiString

アップデート

コード全体を投稿していないため、何が問題なのかはわかりません。とはいえ、Delphi での InternetReadFile の私の使用例を読むと興味深いかもしれません。この質問に対する私の回答を参照してください。これは、Delphi とInternetReadFile.

ご参考までに、私のコードも以下に貼り付けます。

インターネットからデータを読み取るには、InternetReadFile関数を使用します。次のコードを使用して、インターネットから小さな (1 行の) テキスト ファイルを読み取ります。

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

未知のサイズのバッファーを返す Windows 関数は、通常、小さすぎるバッファーが渡された場合に必要なサイズのバッファーを返します。この方法では、最大のデータを保持するのに十分な大きさのバッファーを事前にサイズ設定する必要はありません。小さなバッファー (長さが 0 の場合でも) を渡すと、関数はバッファーの大きさを返します。次に、バッファーのサイズを変更し、データを読み取る関数に再度渡すことができます-たとえば、MSDN の HttpQueryInfo() の説明を確認してください。Delphi で未知のサイズのバッファを処理するには、2 つの方法があります。

  • 動的配列と SetLength() を使用する
  • C で行う場合と非常によく似た方法で、GetMem() と FreeMem() を使用して動的に割り当てられたバッファーを使用します。

例えば:

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 に答える
1

CopyMemory の代わりに、次のように Move ルーチンを使用してみてください。

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

(はい、@ 記号はありません。) これで問題 2 は解決するはずです。問題#1に関しては、それはあなたとサーバーの間です。返されるサイズの上限を知る方法が必要であり、バッファを少なくともその大きさにする必要があります。ドキュメントでこれを見つけるか、受信データのサイズを取得する別の API を最初に呼び出す必要があります。

また、そこにチェックを入れて、バッファよりも大きなものを返す場合、すぐに例外を発生させます。バッファがオーバーランした場合、プログラムが攻撃を受けていると想定し、それに応じて対応する必要があります。

于 2010-07-12T16:51:42.267 に答える