I'm using CEF4Delphi and trying get a determinated html input
element of a page to after set a value to the same using the code below, but happens that the method TElementNameVisitor.visit(const document: ICefDomDocument);
never is executed.
How i can solve this?
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;
This code is creating the DOM visitor in the browser process but the DOM visitor functions are called in the render process as you can see in the CEF3 code comments
This would work if you use the "single process" mode but that mode is unsupported by CEF3, it causes errors and you should use that mode for debugging purposes only.
You need to use several processes. Use the DOMVisitor demo as a template for your app and read all the code comments in that demo too.
The DOM visitor has to be created in the render process. In order to do that, you send a process message from the browser process to the render process and then you create the TCefDomVisitorOwn subclass inside the event that receives the process message.
The DOMVisitor demo uses the GlobalCEFApp.OnProcessMessageReceived event to receive the messages in the render process and it creates a TCefFastDomVisitor2 inside that event.
The TCefFastDomVisitor2 constructor has a procedure parameter called "proc" that is executed when the TCefDomVisitorOwn.visit event is triggered.
Inside those procedures you can search nodes in the DOM and then send the results back to the browser process calling browser.SendProcessMessage(PID_BROWSER, msg)
The browser will receive those messages in the TChromium.OnProcessMessageReceived event.
As you know, Delphi can only debug one process. If you need to debug the code executed in the render process you would need to :