2013-01-22 21 views
8

我想枚舉使用下面的代碼(在XE2下)的DOM節點。枚舉TChromium中的DOM節點

我從這裏給出的答案中借用了大部分內容,但由於某種原因它沒有做任何事情。

IOW,ProcessDOM()不會被調用。

而且,我在我的智慧結束。

有人可以告訴我我在做什麼錯在這裏。

在此先感謝。

procedure ProcessNode(ANode: ICefDomNode); 
var 
    Node1: ICefDomNode; 
begin 
    if Assigned(ANode) then begin 
    Node1 := ANode.FirstChild; 
    while Assigned(Node1) do begin 
     {Do stuff with node} 
     ProcessNode(Node1); 
     Node1 := Node1.NextSibling; 
    end; 
    end; 
end; 

procedure ProcessDOM(const ADocument: ICefDomDocument); 
begin 
    ProcessNode(ADocument.Body); 
end; 

procedure TMainForm.Chrome1LoadEnd(Sender: TObject; const ABrowser: ICefABrowser; const AFrame: ICefAFrame; AStatus: Integer); 
begin 
    if Assigned(AFrame) then AFrame.VisitDomProc(ProcessDOM); 
end; 
+0

據我所知,有一個版本的Chromium在DOM訪問根本不起作用。你使用什麼版本? – TLama

+0

我正在使用'Delphi Chromium Embedded 3'最新的SVN。你知道哪個版本可以工作嗎? – Adem

+0

嗯,它似乎沒有在當前的Chromium 3快照中工作(當然我已經從這裏修復了'ICefABrowser'和'ICefAFrame'錯字)。你的代碼恕我直言應該工作,但沒有。 DOM訪問在舊的Chromium的某些舊版本中運行良好(不是v3),並且據我記憶,舊的Chromium的新快照也破壞了。我會建議提交一個錯誤(如果沒有的話)或聯繫作者。恐怕我無法幫助你更多。 – TLama

回答

1

我有同樣的問題,我用它的dcef3演示guiclient。隨着以下它的作品。

type TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn) 
     protected 
     function OnProcessMessageReceived(const browser: ICefBrowser; 
      sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean; 
      override; 
     end; 

    Chromium1.browser.SendProcessMessage(PID_RENDERER,TCefProcessMessageRef.New('visitdom')); 

    function TCustomRenderProcessHandler.OnProcessMessageReceived(
     const browser: ICefBrowser; sourceProcess: TCefProcessId; 
     const message: ICefProcessMessage): Boolean; 
    begin if (message.Name = 'visitdom') then begin browser.MainFrame.VisitDomProc(
     procedure(const doc: ICefDomDocument) begin 
    ProcessNode(Doc.Body); 
       end) 
      end); 
      Result := True; 
     end; end; 

    initialization 
     CefRenderProcessHandler := TCustomRenderProcessHandler.Create; 
0

您需要向處理程序添加一個過程。 過程ProcessNode(ANode:ICefDomNode);

閱讀:1

+0

這個答案沒有意義。它鏈接到這個問題,爲什麼它需要一個額外的程序?你能解釋更多嗎? –

0

由於這blog指出的,主要的困難在訪問一個渲染頁面的DOM是,你只能在同一進程作爲該頁面的關聯呈現這樣做。

您無法從瀏覽器線程訪問dom,您必須在渲染器線程中執行此操作。

首先,從轉發瀏覽器進程的消息(如visitdom)在渲染過程

procedure TMainForm.crmLoadEnd(Sender: TObject; const browser: ICefBrowser; 
    const frame: ICefFrame; httpStatusCode: Integer); 
var 
    msg : ICefProcessMessage; 
begin 
    if IsMain(browser, frame) then 
    FLoading := False; 

    msg := TCefProcessMessageRef.New('visitdom'); 
    browser.SendProcessMessage(PID_RENDERER, msg); 
end; 

二,創建TCustomRenderProcessHandler來處理消息,將結果發送回瀏覽器PROCESSS。

function TCustomRenderProcessHandler.OnProcessMessageReceived(
    const browser: ICefBrowser; sourceProcess: TCefProcessId; 
    const message: ICefProcessMessage): Boolean; 
begin 
    Result := False; 
    if (message.Name = 'visitdom') then 
    begin 
     browser.MainFrame.VisitDomProc(
     procedure(const doc: ICefDomDocument) 
      function ProcessNode(ANode: ICefDomNode) : String; 
      var 
      Node: ICefDomNode; 
      begin 
      Result := 'Not Found'; 
      if Assigned(ANode) then 
      begin 
       Node := ANode.FirstChild; 
       while Assigned(Node) do 
       begin 
       if Node.ElementTagName='DIV' then 
       begin 
        if Node.GetElementAttribute('class')='tv-panels' then 
        begin 
        Result := 'Found'; 
        Exit; 
        end; 
       end; 
       ProcessNode(Node); 
       Node := Node.NextSibling; 
       end; 
      end; 
      end; 
     var msg : ICefProcessMessage; 
     begin 
      msg := TCefProcessMessageRef.New('visitdom'); 
      msg.ArgumentList.SetString(0, processNode(doc.Body)); 
      browser.SendProcessMessage(PID_BROWSER, msg); 
     end); 
     Result := True; 
    end; 
end; 

第三,在瀏覽器進程中,創建一個處理程序來處理從渲染進程發送回來的消息。

procedure TMainForm.crmProcessMessageReceived(Sender: TObject; 
    const browser: ICefBrowser; sourceProcess: TCefProcessId; 
    const message: ICefProcessMessage; out Result: Boolean); 
begin 
    Result := False; 
    if (message.Name = 'visitdom') then 
    begin 
    StatusBar.SimpleText := message.ArgumentList.GetString(0); 
    Result := True; 
    end; 
end; 

在調試時要小心,在渲染過程中放置​​一個斷點將無法工作。它永遠不會到達那裏。