How can I execute Javascript in my Delphi program without TWebBrowser? - javascript

I am working with a Web API that uses a Javascript interface to make requests, and the response is via a callback Javascript function. Is there a way to call Javascript code from Delphi without using a TWebBrowsercomponent?

You can always run cscript.exe on windows machines.
Advantages:
It's available on all default windows installs since windows 98.
It's dead easy.
No third-party Delphi components needed.
No dll's + wrappers needed, so deployment is simple.
Disadvantages:
You'll be spawning new processes. Starting cscript.exe on a web server feels wrong. I'm not sure what the security implications are.
You don't have direct access to the internals of the scripting engine.
Example program (it's just a proof-of-concept.. there are probably better ways to do this):
program JsExample;
{$APPTYPE CONSOLE}
uses Windows, IoUtils;
// start a new process
function RunProgram(const aProg, aParams: string; aHow2Show: Word; const aWaitTime: dword): boolean;
var LProcInfo: TProcessInformation; LStartUpInfo: TStartupInfo;
begin
FillChar(LStartUpInfo, SizeOf(TStartupInfo), #0); FillChar(LProcInfo, SizeOf(TProcessInformation), #0);
with LStartUpInfo do
begin
cb := SizeOf(LStartUpInfo);
lpReserved := nil; lpDesktop := nil; lpTitle := nil; lpReserved2 := nil; cbReserved2 := 0;
dwFlags := STARTF_USESHOWWINDOW;
wShowWindow := aHow2Show;
end;
Result := CreateProcess(nil, PChar(aProg + ' ' + aParams), nil, nil, false, CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil, nil, LStartUpInfo, LProcInfo);
if Result then
Result := WaitForSingleObject(LProcInfo.hProcess, aWaitTime) <> WAIT_FAILED;
end;
// run javascript code
procedure RunJs(const aJavaScript: String);
var LTmpFileName: String;
begin
LTmpFileName := TPath.ChangeExtension(TPath.GetTempFileName, '.js');
try
TFile.WriteAllText(LTmpFileName, aJavaScript);
RunProgram('cscript', '/NOLOGO "' + LTmpFileName + '"', SW_SHOWNORMAL, INFINITE);
finally
TFile.Delete(LTmpFileName);
end;
end;
// main
begin
// execute some stupid javascript sample code
RunJs
(
'var Text="Hello from JavaScript!";' + // creating a js variable
'for(var i=0;i<Text.length;i++)' + // creating a js looop
' WScript.Echo(Text.charAt(i));' // calling string.charAt() and print some stuff
);
ReadLn;
end.
This method is really simple.. write the JavaScript to a file, then call cscript.exe with the filename as a parameter.

SpiderMonkey
V8
No clue if any of this actually (still) works though.

Are you looking for a JavaScript engine? There are some on the market, such as FastScript, and also I saw a Delphi wrapper for Windows Scripting Host (which has JavaScript support). Note, though, that if your scripts use web- and browser-related classes and functions, no engine except browser-based one will be able to offer them.

Is there a way to call Javascript code from Delphi without using a
TWebBrowsercomponent?
Yes, other way to use JavaScript wrapper for SpiderMonkey (FireFox) javascript engine.
http://code.google.com/p/delphi-javascript/
Required only 1 DLL. Compatible with XE2/XE4/XE5. Ready for x86 and x64 systems.
Usame sample:
Can I execute a Javascript function inside Spidermonkey and get the return value?

Related

Close Excel Workbook from VBA/JScript without crashing Excel

in VBA, I have a global script control variable in JScript language (Javascript ES3). I have the var "ThisWorkbook" set as
var ThisWorkbook = GetObject('', 'Excel.Application').Workbooks('" + ThisWorkbook.Name + "')
Then I can close the workbook by saying
ThisWorkbook.Close(false)
Full VBA code for completion:
Sub Test
Dim ScriptC as Object
Set ScriptC = CreateObject("ScriptControl"): ScriptC.Language = "JScript"
ScriptC.Eval "var ThisWorkbook = GetObject('', 'Excel.Application').Workbooks('" + ThisWorkbook.Name + "')"
ScriptC.Eval "ThisWorkbook.Close(false)"
End Sub
However, this crashes my Excel and all open workbooks (Excel 2016) - what would be a good way to avoid this? I have to do this from JScript/Javascript, but could for example do it through a WScript variable (as long as it's called from within JScript). The reason for this is that it's triggered by an event that's evaluated in JScript and not in VBA (VBA is just the wrapper in this case).
I've tried "ThisWorkbook.Application.Quit' (as per https://learn.microsoft.com/en-us/office/vba/api/excel.application.quit ), but that doesn't work either.
Thanks!
This bug only occurs when running the command from the immediate window - if run from within a subroutine it does NOT crash.
I had tested in immediate a bunch of times before realizing this.
Non-issue, apologies.

Swift JavaScriptCore not working with large files?

https://github.com/gg2001/monero/blob/master/monero/NewWallet.js
I have a js file that is quite large 6000 lines and JavaScript core does not seem to be able to retrieve variable values whereas running the same file in any web browser works fine for me. When I try to retrieve the value of a variable it shows up as undefined, but when I use a js console in a browswer it shows up fine. I am speculating that this is due to the size of the file because when I put
var helloWorld = "Hello World";
in the front of the js file this swift code can retrieve it
func helloWorld() {
if let variableHelloWorld = self.jsContext.objectForKeyedSubscript("helloWorld") {
print(variableHelloWorld.toString())
}
}
but when I put it at the end it cannot.
Normally this indicates a parsing error. Try adding an error handler to self.jsContext before calling objectForKeyedSubscript() and see if it outputs anything insightful.
self.jsContext.exceptionHandler = { context, exception in
print("JS Error: \(exception?.description ?? "unknown error")")
}
Although your JS code may be valid in a browser console, iOS Safari doesn't support as many Javascript features as newer browsers.
I did see a line in your JS source code beginning with just a semicolon (followed immediately by (function). I wonder if the parser might complain about an empty line without a statement..? Maybe nothing, though.

Getting "picked up Java tool options" error while running a test script in HPALM integrated with CA LISA

I am trying to integrate HP-ALM with CA-LISA (a service virtualization tool). On trying to run the below test script
function Test_Main(Debug, CurrentTestSet, CurrentTest, CurrentRun)
{
try
{
TDOutput.Clear();
lisa = new ActiveXObject("MercuryLisaBridge.MercuryTestRunner");
lisa.Init(TDConnection, TDOutput);
lisa.Reload(ThisTest);
if (Debug) lisa.Debug(ThisTest);
if (!Debug) lisa.Run(CurrentTest, CurrentRun);
}
catch(e)
{
TDOutput.Print("Run-time error [" + (e.number & 0xFFFF) + "] : " + e.description);
}
}
I am getting this error
Run-time error [5376] : Picked up JAVA_TOOL_OPTIONS: -agentlib:jvmhook
Picked up _JAVA_OPTIONS: -Xbootclasspath/a:"C:\Program Files (x86)\HP\Unified Functional Testing\bin\java_shared\classes\jasmine.jar"
Picked up JAVA_TOOL_OPTIONS: -agentlib:jvmhook
_JAVA_OPTIONS and JAVA_TOOL_OPTIONS are environment variables which allows you to provide default values for Java options which will be picked up by every JVM (see details on http://progexc.blogspot.com.cy/2013/12/what-i-discovered-while-trying-to-pass.html and Difference between _JAVA_OPTIONS JAVA_TOOL_OPTIONS and JAVA_OPTS for details).
This variables are set by UFT installer (and probably by some other HP ALM related stuff).
I'm not sure why it causes your script to fail (maybe because they are written in standard error stream - I don't remember), but if you want to elimimate them you need to clear those two environment variables on the machine where script is running. I would clear them for a particular process, but leave them untouched globally, because it may affect UFT stuff.

IPython notebook ~ Using javascript to run python code?

I am trying to execute python code through javascript directly:
I fire up IPython Notebook on Chrome
Using chrome developer tools I open up the javascript console.
In the javascript consolde, I type: IPython.notebook.kernel.execute("2+2")
But I get a strange output: "6CEA73CC644648DDA978FDD6A913E519"
Is there any way to take advantage of all the IPython javascript functions available, to run python code from the javascript console as depicted in the image? I'm sure there's a way but I've been beating at it for way too long and thought I would post here.
(I need this to build an app on top of IPython)
Thanks in advance!
You can call Python code execution from JavaScript with Jupyter.notebook.kernel.execute() function.
Depend on this gist from Craig Dennis you can insert this code in Jupyter cell and run it
%%javascript
window.executePython = function(python) {
return new Promise((resolve, reject) => {
var callbacks = {
iopub: {
output: (data) => resolve(data.content.text.trim())
}
};
Jupyter.notebook.kernel.execute(`${python}`, callbacks);
});
}
function Log_out(r)
{ console.log(r); };
var code =
'for i in range(1,6):'+
' print( "#" + str(i))';
window.executePython( code )
.then(result => Log_out(result)); // Log out
Result would be output to browser javascript console.
Are you aware of this blogpost? http://jakevdp.github.io/blog/2013/06/01/ipython-notebook-javascript-python-communication/
I think the exact way he uses doesn't work anymore, but maybe it can get you a step forward
After spending two days on it, here is the solution that worked for me.
To run Python code I am simpy using 'Jupyter.notebook.kernel.execute'. To get the answer from it I found usefull information at this link: https://jupyter-notebook.readthedocs.io/en/stable/comms.html
from ipykernel.comm import Comm
js_input = [] #case willing to track
def func_edit(cobj,text):
my_comm = Comm(target_name=cobj) #this is the callback
my_comm.send('' if text == '' else 'Return: ' + text)
global js_input
js_input.append(f'origin={cobj} text={text}')
from IPython.display import display, HTML
html = """
<script>
var comm_name = "this_control";
function fcalc(x)
{
// here I am passing to the Python function the value to edit and the address for getting the return value
IPython.notebook.kernel.execute("func_edit('" + comm_name + "','" + x.value + "')")
}
Jupyter.notebook.kernel.comm_manager.register_target(comm_name, function(comm, msg)
{
// comm is the frontend comm instance, msg is the comm_open message, which can carry data
// Register handlers for later messages:
comm.on_msg(function(msg) {
document.getElementById("out").value = msg.content.data;
});
//comm.on_close(function(msg) {...});
//comm.send({'foo': 40}); what is it??
});
</script>
<label for="in">Input:</label>
<input type="text" id="in" name="in" oninput="fcalc(this)">
<label for="out">Out:</label>
<input type="text" id="out">
"""
display(HTML(html))
In an effort to isolate a minimum viable implementation, I was able to get responses back from the IPython kernel in just a couple of steps using essentially the same approach as ChrCury78.
Since I want to use the data returned from Python within Javascript, in these examples I just stored the message contents in a member on console. (Unlike what ChrCury78 did, where he pushed the result to the output of the notebook cell.) In my real extension, I'll probably just attach it to a name on Jupyter, or maybe an object of my own creation.
>> Jupyter.notebook.kernel.comm_manager.register_target("mycomm", (comm, msg) => {comm.on_msg( m => {console.retval = m.content.data})})
<- undefined
>> Jupyter.notebook.kernel.execute("from ipykernel.comm import Comm; Comm(target_name='mycomm').send('FOO')")
<- "{hex UID}"
>> console.retval
<- "FOO"
Multi-line Python code worked just fine, too; and, since I'd already imported Comm, I didn't need to import it again:
>> Jupyter.notebook.kernel.execute("l = []\nfor x in range(5):\n l.append(x)\nComm(target_name='mycomm').send(l)")
<- "{hex UID}"
>> console.retval
<- Array(5) [ 0, 1, 2, 3, 4 ]
If you want to keep the kernel namespace unpolluted afterward, you could add a del Comm to the end of the Python command.
I'll definitely be writing wrapper functions of some kind for both of these operations.
This is with Python 3.9.11 and the following packages installed:
ipykernel 6.9.2
ipython 8.1.1
ipython-genutils 0.2.0
ipywidgets 7.7.0
jupyter 1.0.0
jupyter-client 7.1.2
jupyter-console 6.4.3
jupyter-contrib-core 0.3.3
jupyter-contrib-nbextensions 0.5.1
jupyter-core 4.9.2
jupyter-highlight-selected-word 0.2.0
jupyter-latex-envs 1.4.6
jupyter-nbextensions-configurator 0.4.1
jupyterlab-pygments 0.1.2
jupyterlab-widgets 1.1.0

Issuing MySQL queries from standalone Javascript (no, I'm not crazy, my vendor is)

Our lab recently got an Agilent Bravo pipetting robot (it precisely dispenses tiny quantities of liquid for doing rapidly doing many biology or chemistry experiments). Apparently the glue language for extending the software that controls the robot is Javascript! I know, right?
Anyway, for the robot to be useful, we have to be able to retrieve information about the samples it's handling but every example I can find for sending queries in Javascript depends on PHP and usually the assumption that the script is running in a web-browser.
Is there some way to wrap a command-line mysql or is there already some library or utility that does this? The OS we're running is Windows 7.
Wow, thanks for the quick and useful answers.
In addition, I found a platform-specific answer: http://www.velocity11.com/techdocs/helpsystem/vworks_ug/usingjavascriptinvworks.html
Long story short, VWorks (control software for Agilent's equipment) has a run() global function that does exactly that. But, the above answers are probably more useful to this site than my own is, because they are relevant to a broader range of problems, so thanks again.
"sending queries in Javascript depends on PHP"
no it doesn't.
Just send retreive data(json) using ajax, I'd use http://api.jquery.com/jQuery.ajax/.
Yes, you can use ADO with Javascript on Windows to access various data sources. Search for "jscript ado" and you will get lots of information on this, e.g.:
// path to database
var DBpath="\\\\Server\\Path\\myDB.mdb"
// set up a few object constants
var adLockReadOnly=1
var adOpenForwardOnly=0
var adCmdText=1
// create and open a new connection (MSAccess)
var cnn=new ActiveXObject("ADODB.connection")
cnn.Provider = "Microsoft.Jet.OLEDB.4.0;Data Source=" + DBpath
try
{
cnn.open
}
catch(err)
{
// could not open connection
// view details in err.Description and err.Number
return 0
}
//open a read only recordset
var rs = new ActiveXObject("ADODB.Recordset")
try
{
rs.Open("Select * from myTable", cnn, adOpenForwardOnly, adLockReadOnly)
}
catch(err)
{
// could not open recordset
return 0
}
while(!rs.EOF)
{
// do something
rs.movenext
}
rs.close
Update:
According to info here, you can develop plugins using Visual Studio/C#. Maybe that is of some use? You could write a plugin to send the data somewhere...

Categories

Resources