динамические массивы и wininet в delphi? - PullRequest
2 голосов
/ 12 июля 2010

Я использую 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 установить его длину, но произошло 2 вещи.

1) Я до сих пор не знаю размер индексных данных, которые вернет сервер, поэтому я не могу правильно установить, скажем, 100000.

2) Я не могу использовать (как сейчас) CopyMemory, передавая Low (indexdata), чтобы скопировать indexdata в простую строковую переменную, чтобы я мог использовать данные.

Как мне справиться с этим в Delphi? Я могу сделать это в C, но я не могу сделать это в Delphi.

Код приветствуется

спасибо!

Ответы [ 3 ]

3 голосов
/ 12 июля 2010

Вы знаете, что char - это символ Unicode со времен Delphi 2009, но символ ANSI до Delphi 2009. Точно так же в Delphi 2009 string - это UnicodeString , а не AnsiString.

Итак, когда вы пишете SetLength(text, Reserved), вы устанавливаете количество символов в text на Reserved. Но количество байтов будет 2*Reserved.

Другими словами, в Delphi 2009+ один char - это не один byte, а два байта.

Вы можете вернуть старое поведение, заменив все char на AnsiChar и все string на AnsiString.

Обновление

Поскольку вы не опубликовали весь свой код, я не могу точно сказать, в чем проблема. Тем не менее, вам может быть интересно прочитать мой пример использования InternetReadFile в Delphi. Смотрите мой ответ на этот вопрос . Это полностью рабочий пример того, как читать текстовые файлы из Интернета, используя Delphi и InternetReadFile.

Для вашего удобства я также вставляю свой код ниже:

Для чтения данных из Интернета используйте функцию InternetReadFile. Я использую следующий код для чтения небольшого (однострочного) текстового файла из Интернета:

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')
1 голос
/ 12 июля 2010

Функции Windows, которые возвращают буфер неизвестного размера, обычно возвращают требуемый размер буфера, если передан слишком маленький буфер. Таким образом, вам не нужно заранее определять размер буфера, достаточно большой, чтобы вместить самые большие данные - пропустите небольшой буфер (даже нулевой длины), и функция вернет размер буфера. Затем вы можете изменить размер буфера и снова передать его функции для чтения данных - посмотрите, например, объяснение HttpQueryInfo () в MSDN. Для обработки буфера неизвестного размера в 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;
1 голос
/ 12 июля 2010

Вместо CopyMemory попробуйте использовать процедуру Move, например, так:

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

(Да, без символов @.) Это должно решить проблему # 2.Что касается проблемы # 1, это между вами и сервером.У вас должен быть какой-то способ узнать, какова верхняя граница размера, который он будет возвращать, и сделать ваш буфер как минимум настолько большим.Вы должны либо найти это в документации, либо сначала вызвать другой API, который даст вам размер входящих данных.

Также установите некоторую проверку, чтобы, если он возвращает что-то большее, чем ваш буферСразу возникает исключение.Если ваш буфер переполнен, вы должны предположить, что ваша программа находится под атакой и реагировать соответственно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...