You may want to first have a web page loaded with some helper scripts populated in the <head> section. In that case, load your html doc first with something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 procedure TMyExample.LoadDoc(const pDocText:string); var vDocStream:TStringStream; begin vDocStream := TStringStream.Create(pDocText, TEncoding.UTF8); try vDocStream.Seek(0, TSeekOrigin.soBeginning); (fWB.Document as IPersistStreamInit).Load(TStreamAdapter.Create(vDocStream)); finally vDocStream.Free(); end; CurrentState := .. end;
Once you have your helper scripts loaded, you can simply call them repeatedly with the .ExecJS method. This sort of simple operation seems to work rather well, but it’s fairly slow when you start passing in lots of data back and forth.
One option is to create a custom ActiveX control and then load that into your document page and have Delphi and the ActiveX control communicate back and forth. That speeds things up, but the tooling starts getting more complicated. I’ll point that Delphi probably has the best ActiveX support available but it’s something rarely bragged about these days. ActiveX is very powerful with Delphi - if you have any interest, pick up the book “Delphi Programming with COM and ActiveX” which is only $11.99 (side note - why is the same book on Amazon also listed as ‘New’ for $1,012.90?) There’s another book “Essential Delphi 3 fast: Includes ActiveX Development” that can be picked up used for as low as $1.99 - or as New from $159 if you have money to burn.
One other project which deserves mention is the CEF4Delphi project being maintained by Salvador Díaz Fau who is doing an amazing job. If you are using TWebBrowser on Windows for browsing, you really should consider replacing it with CEF4Delphi. For this project, I wanted a single dll dependency for the ChakraCore library. I’m using CEF4Delphi in another project and it works great.
The bare minimum on ChakraCore that you need to know is that it requires a single active runtime environment per thread. There can be multiple execution contexts active per thread, but they are each tied to a single runtime environment. You typically have one runtime and one context, but the tooling is there to expand as needed (if you require concurrent multi-threaded code execution for example.) If you are using this library only in the main thread of your app, you’ll use a single runtime.
Ondrej has made this dead simple with a TChakraCoreRuntime and TChakraCoreContext classes. You first create a runtime, passing in any runtime attributes that you might need activated. You then create a context, passing in the associated runtime, for example:
1 2 FRuntime := TChakraCoreRuntime.Create([ccroDisableEval]); FContext := TChakraCoreContext.Create(FRuntime);
You can then execute script as needed, returning a JsValueRef result:
1 Result := FContext.RunScript(ScriptSource, ScriptName);
There are a slew of utility methods to work with JsValueRef objects such as JsNumberToInt(Value:JsValueRef):Integer;
I actually had a hard time getting started as it was really just too simple. Thankfully, Ondrej was kind enough to nudge me in the right direction! He has sample projects to get you started, including how to work with node.js modules. It’s an amazingly powerful tool.
And speed is much greater with this tool than the old TWebBrowser .ExecJS style approach. For small scripts with little data, you may not notice much difference. But, once your scripts get larger and your data gets more complex, you will see a massive improvement in speed by replacing TWebBrowser with ChakraCore. Clone the repo and you can be up and running in a few minutes - once you download the required binaries from Microsoft of course. Drop the ChakraCore.dll file into your project’s bin folder and you’re good to go, and it’s just a little under 5MB in size. I’ve included the Win32 version of the .dll in a simple example project on GitHub.
A big Thank-You out to Ondrej Kelle for the work on the chakracore-delphi project, for the quick online help, and for the connection request on LinkedIn. The Delphi community has been hit hard over the years, and there’s been a seemingly continuous talk of its imminent death for the last two decades, but it seems to still be vibrant and strong today thanks to people like Ondrej!
Of course, as I was typing this blog post, I came across an article from the Grijjy folks about their solution: Duktape for Delphi. This minimizes the dependency down to a single half-megabyte DLL which apparently supports the complete ECMAScript 5.1 spec as well as parts of 2015/2016 versions.) There is simply an amazing amount of Delphi code out there once you start looking! I’ll have to spend some time on this library soon…so many Delphi toys, so little time!