【问题标题】:StringStream.DataString Access Violation errorStringStream.DataString 访问冲突错误
【发布时间】:2021-10-05 23:53:31
【问题描述】:

我正在使用 StringStream 读取发送到 chromedriver 的命令的结果。

问题是返回的结果弄乱了内存地址,它给了我一个访问冲突错误。

我尝试了多种不同的方法来捕获异常,但程序停止工作。当我使用断点时,我看到 DataString 具有请求的值,但是当它尝试将其放入变量中时,它会终止程序。

这是我正在使用的代码:

function TDelphiCommand.ExecutePost(port: WORD; const URL, Data: string): string;
var
Header      : TStringStream;
pSession    : HINTERNET;
pConnection : HINTERNET;
pRequest    : HINTERNET;
flags       : DWord;
AcceptType: array[0..1] of PChar;// = ('*/*', nil);
sStream: TStringStream;
Buffer: array[0..255] of Byte;
aBufferSize: Cardinal;
b1: Boolean;
AData: TMemoryStream;
sUrl: string;
aMem: PByte;
begin
Result := '';
pSession := InternetOpen('Mozila/5.0', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

if Assigned(pSession) then
try
    pConnection := InternetConnect(pSession, '127.0.0.1', port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);

    if Assigned(pConnection) then
    try
    AcceptType[0] := 'application/json';
    AcceptType[1] := nil;
    sUrl := Copy(URL, Pos(IntToStr(port), URL)+Length(IntToStr(port))+1, Length(URL));
    pRequest := HTTPOpenRequest(pConnection, 'POST', PChar(sUrl), 'HTTP/1.1', nil, @AcceptType[0], INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_ASYNC or INTERNET_FLAG_MAKE_PERSISTENT, 0);

    if Assigned(pRequest) then
    try
        Header := TStringStream.Create('');
        try
        with Header do
        begin
            WriteString('Accept: text/html, application/json, application/xhtml+xml, image/jxr, */*' + sLineBreak);
            WriteString('Accept-Encoding: gzip, deflate' + sLineBreak);
            WriteString('Accept-Language: en-US, en; q=0.5' + sLineBreak);
                                    //text/html
            WriteString('Content-Type: application/json; charset=UTF-8' + sLineBreak);
            WriteString('Connection: keep-alive'+ SlineBreak);
            WriteString('Host: 127.0.0.1' + sLineBreak);
            WriteString('User-Agent: Mozilla/5.0'+ sLineBreak);
        end;
        HttpAddRequestHeaders(pRequest, PChar(Header.DataString), Length(Header.DataString), HTTP_ADDREQ_FLAG_ADD);

        AData := TMemoryStream.Create;
        try
            AData.Write(TEncoding.UTF8.GetBytes(Data), Length(Data));
            b1 := HTTPSendRequest(pRequest, nil, 0, AData.Memory, AData.Size);
            if b1 then
            begin
            sStream := TStringStream.Create('');
            try
                try
                sStream.Position := 0;
                while InternetReadFile(pRequest, @Buffer[0], SizeOf(Buffer), aBufferSize) and (aBufferSize <> 0) do
                    sStream.Write(Buffer[0], aBufferSize);

                Result := sStream.Datastring;//UTF8ToString(RawByteString(sStream.Datastring));
                except
                sStream.Free;
                end;
            finally
                sStream.Free;
            end;
            end;
        finally
            AData.Free;
        end;
        finally
        Header.Free;
        end;
    finally
        InternetCloseHandle(pRequest);
    end;
    finally
    InternetCloseHandle(pConnection);
    end;
finally
    InternetCloseHandle(pSession);
end;
end;

这是我尝试过的其他方法之一,这个也给出了同样的错误:

function TDelphiCommand.ExecutePost(const URL, Data: string): string;
type
PMemArray = ^TMemArray;
TMemArray = array [0..0] of byte;
var
RespStream: TMemoryStream;
ResBytes: TBytes;
aPointer: PMemArray;
PostStream: TStringStream;
S: string;
begin
Result := '{"value":""}';
PostStream := TStringStream.Create(Data, TEncoding.UTF8);
RespStream := TMemoryStream.Create;
try
    PostStream.WriteString(Data);
    PostStream.Position := 0;
    RespStream.Size := 0;
    RespStream.Position := 0;
    InitHeader;
    Fhttp.Request.ContentLength := PostStream.Size;
    try
//        Fhttp.Post(URL, PostStream, aResponseStream);
    Fhttp.Post(URL, PostStream, RespStream);
    RespStream.Seek(0, soFromBeginning);
    aPointer := HeapAlloc(GetProcessHeap, 0, Fhttp.Response.ContentLength);
    RespStream.Read(aPointer^, Fhttp.Response.ContentLength);
    SetLength(ResBytes, Fhttp.Response.ContentLength);
    RespStream.Read(aPointer, Fhttp.Response.ContentLength);
//  VirtualProtect(@NOP_Proc, FSizeOfNOP_Proc, PAGE_EXECUTE_READWRITE, @c1);
        if PByte(ResBytes)^ > 0 then
        Result := TEncoding.UTF8.GetString(ResBytes);

    Debug_Log(Result);
    except
    Debug_Log('ExecuteGet POST: ' + Result);
//      Result := 'Disconnected!';
    FreeAndNil(PostStream);
        FreeAndNil(PostStream);
    FreeAndNil(RespStream);
        FreeAndNil(RespStream);
    end;
finally
    if Assigned(PostStream) then
    FreeAndNil(PostStream);
    if Assigned(RespStream) then
    FreeAndNil(RespStream);
end;
end;

【问题讨论】:

  • 你的 AV 在哪一行?当您尝试分配给结果时?顺便提一下 - 在源代码的第一个变体中 - 您将尝试双重释放 sStream 以防出现异常,只是一个旁注。
  • 你说的AV是什么意思?这是设置结果的行:Result := sStream.Datastring; 当它因访问冲突而中断时,DataString 有一个值,但结果为空,
  • 用 UTF8 字节创建一个字节数组然后将其写入内存流以传递指向字节的指针也有点奇怪。只需创建字节数组,就有指向字节的指针。这里有太多无关的代码,我无法深入挖掘。
  • 我不是质疑你是否需要使用UTF8,我只是指出你做错了。
  • @Gimmly 在您的 Indy 代码中,您将 Data 写入 TStringStream 两次。并双重释放流。但更重要的是,Post() 之后的所有代码都是错误的,太过分了,而且没有必要。 Post() 有一个返回字符串的重载,如果服务器声称数据使用 UTF-8,它将为您处理 UTF-8 解码:Result := Fhttp.Post(URL, PostStream);

标签: delphi


【解决方案1】:

我使用 TButton 和 TMemo 在一个小的 VCL-App 中重新创建了您的第一个代码,并像这样调用函数:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Text := ExecutePost(80, 'HTTPS://google.com', 'MyData');
end;

而且它运行良好,无一例外。只是一些注意事项:

  • 我不理解 sURL 并丢弃了变量,使用 HTTPOpenRequest 的 URL
  • 删除了 flags 和 aMem 的声明,因为你不使用它们
  • 正如 Miroslav 所写,我当然删除了 sStream.Free 的替身。尝试 .. 除了没有必要。 Free sStream 两次导致异常!!

所以我在备忘录中收到了来自 google.com 的回复。

function TForm1.ExecutePost(port: WORD; const URL, Data: string): string;
var
  Header: TStringStream;
  pSession: HINTERNET;
  pConnection: HINTERNET;
  pRequest: HINTERNET;
  AcceptType: array [0 .. 1] of PChar; // = ('*/*', nil);
  sStream: TStringStream;
  Buffer: array [0 .. 255] of Byte;
  aBufferSize: Cardinal;
  b1: Boolean;
  AData: TMemoryStream;
begin
  Result := '';
  pSession := InternetOpen('Mozila/5.0', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

  if Assigned(pSession) then
    try
      pConnection := InternetConnect(pSession, '127.0.0.1', port, nil, nil,
        INTERNET_SERVICE_HTTP, 0, 0);

      if Assigned(pConnection) then
        try
          AcceptType[0] := 'application/json';
          AcceptType[1] := nil;

          pRequest := HTTPOpenRequest(pConnection, 'POST', PChar(Url),
            'HTTP/1.1', nil, @AcceptType[0], INTERNET_FLAG_KEEP_CONNECTION or
            INTERNET_FLAG_ASYNC or INTERNET_FLAG_MAKE_PERSISTENT, 0);

          if Assigned(pRequest) then
            try
              Header := TStringStream.Create('');
              try
                with Header do
                begin
                  WriteString('Accept: text/html, application/json, '
                    +'application/xhtml+xml, image/jxr, */*'+ sLineBreak);
                  WriteString('Accept-Encoding: gzip, deflate' + sLineBreak);
                  WriteString('Accept-Language: en-US, en; q=0.5' + sLineBreak);
                  // text/html
                  WriteString('Content-Type: application/json; charset=UTF-8' +
                    sLineBreak);
                  WriteString('Connection: keep-alive' + sLineBreak);
                  WriteString('Host: 127.0.0.1' + sLineBreak);
                  WriteString('User-Agent: Mozilla/5.0' + sLineBreak);
                end;
                HttpAddRequestHeaders(pRequest, PChar(Header.DataString),
                  Length(Header.DataString), HTTP_ADDREQ_FLAG_ADD);

                AData := TMemoryStream.Create;
                try
                  AData.Write(TEncoding.UTF8.GetBytes(Data), Length(Data));
                  b1 := HTTPSendRequest(pRequest, nil, 0, AData.Memory,
                    AData.Size);
                  if b1 then
                  begin
                    sStream := TStringStream.Create('');
                    try
                      sStream.Position := 0;
                      while InternetReadFile(pRequest, @Buffer[0],
                        SizeOf(Buffer), aBufferSize) and (aBufferSize <> 0) do
                        sStream.Write(Buffer[0], aBufferSize);

                      Result := sStream.DataString;
                      // UTF8ToString(RawByteString(sStream.Datastring));
                    finally
                      sStream.Free;
                    end;
                  end;
                finally
                  AData.Free;
                end;
              finally
                Header.Free;
              end;
            finally
              InternetCloseHandle(pRequest);
            end;
        finally
          InternetCloseHandle(pConnection);
        end;
    finally
      InternetCloseHandle(pSession);
    end;
end;

【讨论】:

  • 这段代码重复了原帖中的一些错误
猜你喜欢
  • 1970-01-01
  • 2018-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多