Невозможно уничтожить компонент THTTPReqResp в потоке - PullRequest
7 голосов
/ 16 января 2012

У меня проблемы с использованием SOAP в XE / XE2 из потока. (Я не тестировал его с более старой версией Delphis.) Простой код, работающий в основном потоке, вылетает, уничтожая экземпляр THTTPReqResp с Invalid pointer operation.

Это полная программа. Форма содержит только одну кнопку, которая вызывает событие btnTestClick:

unit Unit79;

interface

uses
  SysUtils, Forms, Classes, Controls, StdCtrls, ComObj,
  ActiveX, InvokeRegistry, SOAPHTTPTrans, Rio, SOAPHTTPClient;

type
  TForm79 = class(TForm)
    btnTest: TButton;
    procedure btnTestClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form79: TForm79;

implementation

{$R *.dfm}

procedure TForm79.btnTestClick(Sender: TObject);
begin
  TThread.CreateAnonymousThread(
    procedure
    var
      FHTTPReqResp: THTTPReqResp;
      FHTTPRIO: THTTPRIO;
    begin
      if CoInitializeEx(NIL, COINIT_MULTITHREADED or COINIT_SPEED_OVER_MEMORY) = S_OK then try
        FHTTPReqResp := THTTPReqResp.Create(nil);
        with FHTTPReqResp do begin
          Name := 'HTTPReqResp1';
          UseUTF8InHeader := True;
          InvokeOptions := [soIgnoreInvalidCerts, soAutoCheckAccessPointViaUDDI];
          WebNodeOptions := [];
        end;
        FHTTPRIO := THTTPRIO.Create(nil);
        with FHTTPRIO do begin
          Name := 'HTTPRIO1';
          HTTPWebNode := FHTTPReqResp;
        end;
        //
        FreeAndNil(FHTTPRIO);
        FreeAndNil(FHTTPReqResp); //<-- crashes here
      finally CoUninitialize; end;
    end
  ).Start;
end;

end.

Исключение возникает в TObject.FreeInstance при вызове _FreeMem.

procedure TObject.FreeInstance;
begin
  CleanupInstance;
  _FreeMem(Self);
end;

Стек вызовов, приводящий к этой проблеме,

:75bab9bc KERNELBASE.RaiseException + 0x58 System.TObject.FreeInstance
System.ErrorAt(2,$4052E1) System.Error(reInvalidPtr)
System.TObject.FreeInstance System._ClassDestroy(???)
Soap.SOAPHTTPTrans.THTTPReqResp.Destroy System.TObject.Free
frmMain.TMainForm.btnTestClick$4934$ActRec.$0$Body
System.Classes.TAnonymousThread.Execute
System.Classes.ThreadProc($F83530) System.ThreadWrapper($F51050)
:76a4339a kernel32.BaseThreadInitThunk + 0x12 :77b59ef2
ntdll.RtlInitializeExceptionChain + 0x63 :77b59ec5
ntdll.RtlInitializeExceptionChain + 0x36

Я абсолютно не знаю, что происходит, почему вообще вызывается _ClassDestroy и почему происходит сбой кода :( Может кто-нибудь, пожалуйста, а) объясните, что я делаю неправильно, и б) исправьте мой код?

1 Ответ

8 голосов
/ 17 января 2012

«Недопустимая операция с указателем» означает, что вы освобождаете что-то, что не соответствует допустимой памяти. Иногда это может указывать на повреждение стека или кучи, но более вероятно, что вы освобождаете что-то, что уже было освобождено.

Не удивительно, что _ClassDestroy называется. FHTTPReqResp не является нулевым, поэтому, когда FreeAndNil вызывает Free, Free вызывает Destroy.

Может показаться, что ваш THTTPRIO объект получает право собственности на THTTPReqResp, который вы ему даете. Если это так, то решение простое: не освобождайте его сами.

...