首页 > 解决方案 > 从 IWinHttpRequest 返回的二进制数据已更改,无法将 Variant 转换为字节数组

问题描述

在我的安装过程结束时的设置场景中,每个客户端都从服务器下载应用程序密钥。该文件由约 64 个随机字节组成,二进制,非编码。它应该存储在安装目录的配置文件中。

CurStepChanged设置由 Inno Setup 处理,它在事件期间调用密钥生成过程。创建OLE WinHttp.WinHttpRequest.5.1,发送包含客户端数据的 POST 请求,并应接收二进制响应。使用 提取响应WinHttpReq.ResponseText并将其存储到文件中SaveStringToFile

但是,生成的文件与从服务器发送的文件不同。例如在服务器端记录的数据:

5a7868256a890e25735f431351f023c143f0cc397e6ec01e8a81806564eaa9f4fc8a005d9035c18fa32f95daaeff34955f3f6e4bfc5051bd33a522cc2aaddac8f29a1031dcb23728250c4f0a73db6a5bcc64e1ddef71a6

被接收为

5a7868256a3f0e25735f4313513f23c1433f49397e6e411e3f813f656465a9f4fc3f005d9035c13f4c2f3fdaae79343f5f3f6e4bfc505131335922492aadda456f3f1031dc323728250c4f0a73556a5b4964e1dd6971a6

(例如第 6 个字节不同)。没有这样的问题是数据不包含非ASCII数据。

我的第一个想法是,在某些时候将二进制数据编码/解码为文本会修改一些字节。我想用IWinHttpRequest::ResponseBody二进制版本而不是文本版本来访问数据。传递此属性会导致目标文件填充?字符而不是数据。仅保留 ascii 字符。

我也尝试转换ResponseBody为 pascal 字节数组,但收到Type Mismatch错误。VarTypeforResponseBody返回 dec 8209,它映射到and arraybyte但分配ResponseBodyarray of byte会导致上述错误。

在 Inno Setup 中将二进制 HTTP 结果存储到文件的正确方法是什么?

标签: inno-setupolepascalscriptwinhttprequest

解决方案


你没有向我们展示你的代码,所以很难说你可能有什么问题。

虽然我猜你已经直接通过WinHttpReq.ResponseText(wide string) 到SaveStringToFile(which takes AnsiString)。这涉及到隐式 UTF-16 到 ANSI 编码的转换,这会导致某些字符的丢失或转换。

这工作得很好,在Inno Setup 的Unicode版本(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.Streamclass


推荐阅读