Chromium Embedded: метод TCefDomVisitorOwn.visit () никогда не выполняется - PullRequest
0 голосов
/ 09 сентября 2018

Я использую CEF4Delphi и пытаюсь получить определенный html input элемент страницы, чтобы после установить значение на то же самое, используя код ниже, но бывает, что метод TElementNameVisitor.visit(const document: ICefDomDocument); никогда не выполняется.

Как я могу решить это?

uses
uCEFChromium, uCEFWindowParent,
  uCEFChromiumWindow, uCEFInterfaces, uCEFDomVisitor;

type
  TElementNameVisitor = class(TCefDomVisitorOwn)
  private
    FName: string;
  protected
    procedure visit(const document: ICefDomDocument); override;
  public
    constructor Create(const AName: string); reintroduce;
  end;

  type
  TForm2 = class(TForm)
    Chromium1: TChromium;
    CEFWindowParent1: TCEFWindowParent;
    procedure FormShow(Sender: TObject);
    procedure Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
      const frame: ICefFrame; httpStatusCode: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

constructor TElementNameVisitor.Create(const AName: string);
begin
  inherited Create;
  FName := AName;
end;

procedure ProcessElementsByName(const AFrame: ICefFrame; const AName: string);
var
  Visitor: TElementNameVisitor;
begin
  if Assigned(AFrame) then
  begin
    Visitor := TElementNameVisitor.Create(AName);
    AFrame.VisitDom(Visitor);
  end;
end;

procedure TElementNameVisitor.visit(const document: ICefDomDocument);

  procedure ProcessNode(ANode: ICefDomNode);
  var
    Node: ICefDomNode;
  begin
    if Assigned(ANode) then
    begin
      Node := ANode.FirstChild;
      while Assigned(Node) do
      begin
        if Node.GetElementAttribute('name') = FName then
        begin
          Node.SetElementAttribute('value', '-15.792253570362445');
          ShowMessage(Node.GetElementAttribute('value'));
        end;
        ProcessNode(Node);
        Node := Node.NextSibling;
      end;
    end;
  end;

begin
  ProcessNode(document.Body);
end;

procedure TForm2.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame; httpStatusCode: Integer);
var
  CefStringVisitor: ICefStringVisitor;
begin
  ProcessElementsByName(Chromium1.browser.MainFrame, 'latitude'); // "latitude" = name of field that i want set a value
end;

procedure TForm2.FormShow(Sender: TObject);
begin
  while not(Chromium1.CreateBrowser(CEFWindowParent1, '')) and
    (Chromium1.Initialized) do
  begin
    Sleep(100);
    Application.ProcessMessages;
  end;
  Application.MessageBox('CEFWindowParent1 created!', 'Success', MB_OK + MB_ICONINFORMATION);
  Chromium1.LoadURL('file:///' + ReplaceStr(ExtractFilePath(Application.ExeName) + 'gmaps.html', '\', '/'));
end;

1 Ответ

0 голосов
/ 10 сентября 2018

Этот код создает посетителя DOM в процессе браузера, но функции посетителя DOM вызываются в процессе рендеринга, как вы можете видеть в комментариях к коду CEF3

Это будет работать, если вы используете режим " single process ", но этот режим не поддерживается CEF3, он вызывает ошибки, и вы должны использовать этот режим только для целей отладки.

Вам нужно использовать несколько процессов. Используйте демоверсию DOMVisitor в качестве шаблона для своего приложения и прочитайте все комментарии кода в этой демоверсии.

Посетитель DOM должен быть создан в процессе рендеринга. Для этого вы отправляете сообщение процесса из процесса браузера процессу рендеринга, а затем создаете подкласс TCefDomVisitorOwn внутри события, которое получает сообщение процесса.

Демонстрация DOMVisitor использует событие GlobalCEFApp.OnProcessMessageReceived для получения сообщений в процессе рендеринга и создает TCefFastDomVisitor2 внутри этого события.

В конструкторе TCefFastDomVisitor2 есть параметр процедуры с именем «proc», который выполняется при запуске события TCefDomVisitorOwn.visit.

Внутри этих процедур вы можете искать узлы в DOM, а затем отправлять результаты обратно в процесс браузера, вызывающий browser.SendProcessMessage (PID_BROWSER, msg)

Браузер будет получать эти сообщения в событии TChromium.OnProcessMessageReceived.

Как вы знаете, Delphi может отлаживать только один процесс. Если вам нужно отладить код, выполненный в процессе рендеринга, вам необходимо:

  • Используйте режим «одного процесса», но помните, что вы не должны использовать этот режим в финальной версии.
  • Используйте параметр «Запуск без отладки ...» в Delphi и выберите процесс рендеринга.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...