Двоичные данные, возвращаемые IWinHttpRequest, изменены, невозможно преобразовать Variant в массив байтов.

В моем сценарии установки в конце процесса установки каждый клиент загружает ключ приложения с сервера. Файл состоит из ~64 случайных байтов, двоичных, незакодированных. Он должен храниться в файле конфигурации в каталоге установки.

Настройка выполняется с помощью Inno Setup, который вызывает процедуру генерации ключа во время события CurStepChanged. Создается OLE WinHttp.WinHttpRequest.5.1, отправляется POST-запрос, содержащий данные клиента, и должен быть получен бинарный ответ. Ответ извлекается с помощью WinHttpReq.ResponseText и сохраняется в файл с помощью SaveStringToFile.

Однако полученный файл отличается от файла, отправленного с сервера. Например, данные, зарегистрированные на стороне сервера:

5a7868256a890e25735f431351f023c143f0cc397e6ec01e8a81806564eaa9f4fc8a005d9035c18fa32f95daaeff34955f3f6e4bfc5051bd33a522cc2aaddac8f29a1031dcb23728250c4f0a73db6a5bcc64e1ddef71a6

принимается как

5a7868256a3f0e25735f4313513f23c1433f49397e6e411e3f813f656465a9f4fc3f005d9035c13f4c2f3fdaae79343f5f3f6e4bfc505131335922492aadda456f3f1031dc323728250c4f0a73556a5b4964e1dd6971a6

(например, 6-й байт отличается). Таких проблем нет, если данные не содержат данные, отличные от ascii.

Моя первая идея заключалась в том, что в какой-то момент кодирование/декодирование двоичных данных в текст изменяет некоторые байты. Я хотел использовать IWinHttpRequest::ResponseBody для доступа к данным в двоичной версии вместо текстовой. Передача этого свойства приводит к заполнению целевого файла ? символами вместо данных. Сохранились только символы ascii.

Я также пытался преобразовать массив байтов ResponseBody в паскаль, но получил ошибку Type Mismatch. VarType для ResponseBody возвращает dec 8209, что соответствует array и byte, но присвоение ResponseBody array of byte приводит к указанной выше ошибке.

Как правильно сохранить двоичный результат HTTP в файл в Inno Setup?


person peku33    schedule 09.10.2018    source источник


Ответы (1)


Вы не показали нам свой код, поэтому сложно сказать, какая у вас может быть проблема.

Хотя я предполагаю, что вы передали WinHttpReq.ResponseText (широкий string) непосредственно в SaveStringToFile (который занимает AnsiString). Это включает в себя неявное преобразование кодировки UTF-16 в ANSI, что приводит к потере или преобразованию некоторых символов.

Это отлично работает в Unicode версии Inno Setup (единственная версия Inno Setup 6):

var
  WinHttpReq: Variant;
  S: string;
  I: Integer;
  Data: AnsiString;
begin
  WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  WinHttpReq.Open('GET', 'https://www.example.com/key.dat', False);
  WinHttpReq.Send('');
  if WinHttpReq.Status <> 200 then
  begin
    Log('HTTP Error: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
  end
    else
  begin
    S := WinHttpReq.ResponseText;
    SetLength(Data, Length(S));
    for I := 1 to Length(S) do
    begin
      Data[I] := S[I];
    end;

    SaveStringToFile(ExpandConstant('{app}\key.dat'), Data, False);
  end;
end;

Код может быть неэффективным для загрузки больших двоичных файлов. А вот для 64 байт вполне нормально. Для больших файлов, возможно, можно использовать класс ADODB.Stream.

person Martin Prikryl    schedule 10.10.2018