unit UJSExec; interface uses MSHTML, ShDocVw; type TJSExec = class(TObject) private fWB: TWebBrowser; function GetDocWindow: IHTMLWindow2; function GetElementById(const ID: string): IHTMLElement; function GetRetValContainer: IHTMLElement; function CreateRetValContainer: IHTMLElement; public constructor Create(const WB: TWebBrowser); procedure RunJSProc(const Fn: string); function RunJSFn(const Fn: string): string; end; implementation uses SysUtils; const // unique id that should clash with anything in the doc cRetValElemId = 'id58A3A2A46539468A943D00FDD6A4FF08'; { TJSExec } constructor TJSExec.Create(const WB: TWebBrowser); begin inherited Create; fWB := WB; end; function TJSExec.CreateRetValContainer: IHTMLElement; var Doc: IHTMLDocument2; begin if not Supports(fWB.Document, IHTMLDocument2, Doc) then raise Exception.Create('Invalid document'); Result := Doc.createElement('input'); Result.id := cRetValElemId; Result.setAttribute('name', cRetValElemId, 0); Result.setAttribute('type', 'hidden', 0); Result.setAttribute('value', '', 0); end; function TJSExec.GetDocWindow: IHTMLWindow2; var Doc: IHTMLDocument2; begin if not Supports(fWB.Document, IHTMLDocument2, Doc) then raise Exception.Create('Invalid document'); Result := Doc.parentWindow; if not Assigned(Result) then raise Exception.Create('No document window'); end; function TJSExec.GetElementById(const ID: string): IHTMLElement; var Doc: IHTMLDocument3; begin if not Supports(fWB.Document, IHTMLDocument3, Doc) then raise Exception.Create('Invalid document'); Result := Doc.getElementById(ID); end; function TJSExec.GetRetValContainer: IHTMLElement; var NewNode: IHTMLDOMNode; BodyNode: IHTMLDOMNode; Doc: IHTMLDocument2; begin Result := GetElementById(cRetValElemId); if not Assigned(Result) then begin if not Supports(fWB.Document, IHTMLDocument2, Doc) then raise Exception.Create('Invalid document'); if not Supports(Doc.body, IHTMLDOMNode, BodyNode) then raise Exception.Create('Invalid body node'); Result := CreateRetValContainer; if not Supports(Result, IHTMLDOMNode, NewNode) then raise Exception.Create('Invalid new node'); BodyNode.appendChild(NewNode); end; end; function TJSExec.RunJSFn(const Fn: string): string; var EmbedFn: string; WrapperFn: string; HiddenElem: IHTMLElement; const WrapperFnTplt = 'eval("' + 'id = document.getElementById(''' + cRetValElemId + '''); ' + 'id.value = %s;' + '")'; begin EmbedFn := StringReplace(Fn, '"', '\"', [rfReplaceAll]); EmbedFn := StringReplace(EmbedFn, '''', '\''', [rfReplaceAll]); HiddenElem := GetRetValContainer; WrapperFn := Format(WrapperFnTplt, [EmbedFn]); RunJSProc(WrapperFn); Result := HiddenElem.getAttribute('value', 0); end; procedure TJSExec.RunJSProc(const Fn: string); var Wdw: IHTMLWindow2; begin try Wdw := GetDocWindow; Wdw.execScript(Fn, 'JavaScript'); // execute function except // swallow exception to prevent JS error dialog end; end; end.