簡體   English   中英

Memory 泄漏使用帶有 TWebBrowser 的 IHTMLEventObj 處理程序

[英]Memory leak using IHTMLEventObj handlers with TWebBrowser

我正在使用 TWebBrowser 來顯示 WYSIWYG HTML 編輯器,並且我添加了一些處理程序來捕獲鍵盤和鼠標事件,因此我可以將此編輯器集成到我的應用程序流中。 此瀏覽器集成在自定義 TPanel 中,即 TPanelEditorHTML。

這就是我這樣做的方式,遵循這個答案中的一些提示:

  //Create the procedure type to assign the event
  THTMLProcEvent = procedure(Sender: TObject; Event: IHTMLEventObj) of object;

  //Create a  new class for manage the event from the twebbrowser
  THTMLBrowserEventLink = class(TInterfacedObject, IDispatch)
  private
    FOnEvent: THTMLProcEvent;
  private
    constructor Create(Handler: THTMLProcEvent);
    function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
    function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
    function GetIDsOfNames(const IID: TGUID; Names: Pointer;
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  public
    property OnEvent: THTMLProcEvent read FOnEvent write FOnEvent;
  end;

在我的 TWebBrowser 容器上,我有這個:

FOnKeyDownConnector:  IDispatch; 
FOnClickConnector:  IDispatch;
FOnKeyDownConnectorIFrame:  IDispatch;
FOnClickConnectorIFrame:  IDispatch;    

procedure BrowserIHTMLDocument2OnKeyDown(Sender: TObject; Event: IHTMLEventObj);
procedure BrowserIHTMLDocument2OnClick(Sender: TObject; Event: IHTMLEventObj); 
procedure IframeIHTMLDocument2OnKeyDown(Sender: TObject; Event: IHTMLEventObj);
procedure IframeIHTMLDocument2OnClick(Sender: TObject; Event: IHTMLEventObj);

BrowserIHTMLDocument2OnKeyDown 等是我將 HTML 編輯器數據集成到我的應用程序中的所有工作的程序

我在啟動時創建處理程序

constructor TPanelEditorHTML.Create(AOwner: TComponent);
begin
  inherited;
  // ...
  FNavegador := TGENBrowser.Create(self);
  FOnKeyDownConnector := THTMLBrowserEventLink.Create(BrowserIHTMLDocument2OnKeyDown);
  FOnClickConnector := THTMLBrowserEventLink.Create(BrowserIHTMLDocument2OnClick);
  FOnKeyDownConnectorIFrame := THTMLBrowserEventLink.Create(IFrameIHTMLDocument2OnKeyDown);
  FOnClickConnectorIFrame := THTMLBrowserEventLink.Create(IFrameIHTMLDocument2OnClick);
end;    

當我加載 HTML 編輯器時,我將此處理程序分配給 DOM 樹中的幾個元素:

procedure TPanelEditorHTML.AsignarManejadores;
var
  HTMLDocument2_A, HTMLDocument2_B: IHTMLDocument2;
begin
  HTMLDocument2_A := ExtraerIframeEditor;
  HTMLDocument2_B := (FNavegador.Document AS IHTMLDocument2);
  if (HTMLDocument2_A = nil) or (HTMLDocument2_B = nil) then
    Exit;

  if (FOnKeyDownConnectorIFrame <> nil) then
    HTMLDocument2_A.onkeydown := FOnKeyDownConnectorIFrame; 
  if (FOnClickConnectorIFrame <> nil) then
    HTMLDocument2_A.onclick := FOnClickConnectorIFrame; 

  if (FOnKeyDownConnector <> nil) then
    HTMLDocument2_B.onkeydown := FOnKeyDownConnector; 
  if (FOnClickConnector <> nil) then
    HTMLDocument2_B.onclick := FOnClickConnector;   
end;

當用戶結束編輯我刪除這個處理程序

procedure TPanelEditorHTML.DesconectarManejadores;
var
  HTMLDocument2      : IHTMLDocument2;
begin
  HTMLDocument2 := ExtraerIframeEditor;
  if (HTMLDocument2 <> nil) then
  begin
    HTMLDocument2.onkeydown := Unassigned; //assign the event handler
    HTMLDocument2.onclick := Unassigned; //assign the event handler
  end;

  HTMLDocument2:=(FNavegador.Document AS IHTMLDocument2);
  if (HTMLDocument2 <> nil) then
  begin
    HTMLDocument2.onkeydown := Unassigned; //assign the event handler
    HTMLDocument2.onclick := Unassigned; //assign the event handler
  end;
end;

我的問題出在 TPanelEditorHTML 析構函數上。 這會導致四個 THTMLBrowserEventLink 的 memory 泄漏。 如果我嘗試 FreeAndNil 處理程序,我會收到運行時錯誤。

destructor TPanelEditorHTML.Destroy;
begin
  FDataLink.Free;
  FOnKeyDownConnector := Unassigned;
  FOnClickConnector := Unassigned;
  FOnKeyDownConnectorIFrame := Unassigned;
  FOnClickConnectorIFrame := Unassigned;
  inherited;
end;

我發現這篇關於 memory 泄漏的文章,我試圖替換這兩種復制都無濟於事的方法。

我錯過了什么嗎?

正如@DalijaPrasnikar所說,THTMLEventLink.Create 中有一個多余的 _AddRef,我從這個答案中提出的解決方案中復制了它。

將 THTMLBrowserEventLink 的構造函數更改為:

constructor THTMLBrowserEventLink.Create(Handler: THTMLProcEvent);
begin
  inherited Create;
  FOnEvent := Handler;
end;

避免 memory 泄漏。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM