How to get a JS script console output in TWebbrowser? - delphi

I want to run a javascript code in TWebbrowser and get the console output of it. For instance, if i run this code in the console :
var a = 2; var b = 3; var c = a +b ; console.log('The result is '+ c);
I get this output on console :
The result is 5
The code i use to run a JS script with TWebbrowser is this :
twebbrowser1.navigate('javascript:var a = 2; var b = 3; var c = a +b ; console.log('The result is '+ c);');
It works, but i don't know how to get the console output. Is there a way to do it ?
Thanks in advance !

According to MSDN, it looks like your (Delphi) app would need to implement the IDeveloperConsoleMessageReceiver interface.
Then you can connect an object instance of your IDeveloperConsoleMessageReceiver to the browser's current Document. Query the TWebBrowser.Document property for its IOleCommandTarget interface and then call its Exec() method to issue a IDM_ADDCONSOLEMESSAGERECEIVER command.
Try that, and if you get stuck, try asking again.

Related

Run an automation script via a URL

Maximo 7.6.1.1:
I want to run a Maximo automation script by invoking a URL in a separate system.
Is it possible to do this?
This is a great use-case and something that we've been working through in the last few days.
Create automation script. - mine is called automation_api_test
Manually invoke it through the API using a browser to make sure that you can actually get it to run. (%servername%/maximo/oslc/script/automation_api_test?var1=1212321232&var2=1555&site=OPS&_lid=wilson&_lpwd=wilson)
Script it like you would your regular automation script. Here's one that can read in a few parameters from the URL and use those to perform operations in the core system.
importPackage(Packages.psdi.server);
importPackage(Packages.psdi.util.logging);
var resp = {};
// Get the Site ID from the Query Parameters
//var site = request.getQueryParam("site");
var var1 = request.getQueryParam("var1");
var var2 = request.getQueryParam("var2");
var site = request.getQueryParam("site");
//var zxqponum = request.getQueryParam("ponum");
//logger.debug(zxqprinter);
service.log("TESTING script Params" + request.getQueryParams());
service.log("var1 " + request.getQueryParam("var1"));
service.log("var2 " + request.getQueryParam("var2"));
//count the number of WO's in the site
var woset = MXServer.getMXServer().getMboSet("WORKORDER", request.getUserInfo());
woset.setQbe("SITEID","="+site);
var woCount = woset.count();
resp.wo_count = woCount;
woset.close();
// Get Total Count
resp.total = woCount;
//create the response - still not sure why I had to append the vars to a string.
resp.var1= "" + var1;
resp.var2= "" + var2;
resp.site= "" + site;
var responseBody = JSON.stringify(resp);
Here's an expanded version of Kasey's answer.
Create a sample automation script in Maximo:
Automation Scripts >> More Actions >> Create >> Script
Script [name]: HELLOWORLD
Script Language: js
Paste in this code:
//THIS IS JAVASCRIPT! NOT JYTHON!
//load("nashorn:mozilla_compat.js"); //More info about this here: https://stackoverflow.com/questions/57537142/maximo-js-automation-script-importpackage-is-not-defined
//importPackage(Packages.psdi.server);
//importPackage(Packages.psdi.util.logging);
var resp = {};
var var1 = request.getQueryParam("var1");
resp.var1= " " + var1 + " World!";
var responseBody = JSON.stringify(resp);
Click Create
Try out a URL:
This URL will send the word "Hello" to the automation script. The automation script will append the word " World!" onto "Hello".
The phrase, "Hello World!" is returned.
In a browser, run this URL: http://yourhostname:1234/maximo/oslc/script/helloworld?var1=Hello&_lid=wilson&_lpwd=wilson
Replace yourhostname with your host name
Replace 1234 with your port number
Replace maximo with the appropriate value.
The URL request should return this JSON object to the browser:
{"var1":" Hello World!"}
From there, create a hyperlink in a separate system (using the above URL). And click it to run the automation script.
If the last line in the script were to be deleted, nothing would be returned to the browser.
Note:
The URL only seems to work for me under the WILSON user. It doesn't work with my own user:
{"oslc:Error":{"oslc:statusCode":"401","spi:reasonCode":"BMXAA7901E","oslc:message":
"You cannot log in at this time. Contact the system administrator.","oslc:extendedError"
:{"oslc:moreInfo":{"rdf:resource":"http:\/\/something\/maximo\/oslc\
/error\/messages\/BMXAA7901E"}}}}
Best guess is: my user is not set up correctly.
Here's a really simple JavaScript example:
responseBody = "asdf";
Then just run the URL in a browser (or somewhere else like an automation script in Maximo or a Python script in GIS).
https://<<my host>>/maximo/oslc/script/testscript
It's pretty much the same for Python (no semi-colon):
responseBody = "asdf"

What is causing this mvc razor syntax error?

var openWos = #Model.MyMaintenanceDashboard.OpenWorkOrders;
Why is Visual Studio saying this is a syntax error? It runs fine, but what would the proper syntax be?
Update: OpenWos is a javascript variable
If this is a javascript code, then you need to quote it so that you do not get the 'syntax' error.
var openWos = '#Model.MyMaintenanceDashboard.OpenWorkOrders';
If you're setting a C# var, the correct syntax would be without the # in front of Model as you're already in a C# code block:
#{
var openWos = Model.MyMaintenanceDashboard.OpenWorkOrders;
}
Edit:
You've clarified that this is a JavaScript variable. There shouldn't be a syntax error at all, as this is valid Razor. There is a distinct difference between quoting the value as suggested by Stephen, and the code that you posted originally. The type of the JavaScript variable is a string when quoted instead of a number.
For example, including this in a page:
<script>
#{ int z = 10; }
var x = #z;
console.log(x);
console.log(typeof x);
var y = '#z';
console.log(y);
console.log(typeof y);
</script>
Results in the following being logged to the console:
10
number
10
string
And there is no syntax error reported using the variable #z in either instance.
I've found that you can get around this by adding zero:
var openWos = #Model.MyMaintenanceDashboard.OpenWorkOrders + 0;

Firefox bootstrapped extension: Get native HWND handle of the browser window

I have an external application and I want it to display some information on top of the browser window. My bootstrapped extension needs to pass the browser window handle (native HWND) to my application, along with some other useful information about the window. I'm able to do the communication between them, the only thing that is missing is a way to get the native HWND of the Firefox window.
I read a lot about it and although I belive it's possible, I couldn't find a working solution. Here's what I've tried so far:
This one should give me nsIBaseWindow, so I could get nsIBaseWindow.nativeHandle or nsIBaseWindow.ParentNativeWindow, but no success:
var window = SomeDOMWindow; // Informative
var baseWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIXULWindow)
.docShell
.QueryInterface(Components.interfaces.nsIBaseWindow);
The above code is widely spread on forums, but I couldn't get it to work for me.
The other one does not seem to be much accurate since it gets the HWND based on the window's class and title, which can lead to wrong results:
Components.utils.import("resource://gre/modules/ctypes.jsm");
var lib = ctypes.open("user32.dll");
var fww = lib.declare("FindWindowW", ctypes.winapi_abi,
ctypes.voidptr_t, ctypes.jschar.ptr, ctypes.jschar.ptr);
var sfw = lib.declare("SetForegroundWindow", ctypes.winapi_abi,
ctypes.int32_t, ctypes.voidptr_t);
var hwnd = fww("MozillaWindowClass", document.title);
setTimeout(function() {
sfw(hwnd);
lib.close();
}, 3000);
Any help would be appreciated.
window must be a root one (i.e. an instance of ChromeWindow)
The following code should work
var win = Cc["#mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator).getMostRecentWindow("navigator:browser");
var basewindow = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.nsIBaseWindow;
var nativehandle = basewindow.nativeHandle;
The problem was that I was querying the wrong interface from the subject param in the xul-window-registered observer. I need to get an nsIDOMWindow instead of an nsIXULWindow so the first code mentioned in my question works. So now I'm doing the following, with some piece of code #Noit suggested:
observe: function(subject, topic, data) {
var newWindow = subject.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
var basewindow = newWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.nsIBaseWindow;
var nativehandle = basewindow.nativeHandle;
}
And it works!
Thank you very much for your help.
I also just came across this, it might be nice:
Cu.import("resource://gre/modules/ctypes.jsm");
/*start getcursorpos*/
var lib = ctypes.open("user32.dll");
/*foreground window stuff*/
var FindWindowA = lib.declare('FindWindowA', ctypes.winapi_abi, ctypes.uint32_t, ctypes.jschar.ptr, ctypes.jschar.ptr)
var GetForegroundWindow = lib.declare('GetForegroundWindow', ctypes.winapi_abi, ctypes.uint32_t)
function doFindWindow() {
var wm = Cc['#mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator);
var title = wm.getMostRecentWindow('navigator:browser').gBrowser.contentDocument.title;
Cu.reportError('title=' + title)
var ret = FindWindowA('', title + ' - Mozilla Firefox');
//var ret = GetForegroundWindow();
Cu.reportError(ret);
}
/*end foreground window stuff*/
The code in the answer of user 'paa' worked until Firefox version 69.
If you execute it in Firefox 70 you will get an exception:
TypeError: win.QueryInterface is not a function
This is strange because the variable win has the same content in Firefox 69 and 70.
When I execute alert(win) I get: "[object ChromeWindow]" in both browsers.
And alert(win.document.title) displays correctly the title of the document in both browsers.
I downloaded the sourcecode of both Firefox versions to compare them and possibly find the cause. But the source code of Firefox is huge (2 Gigabyte) and nearly completely free of comments. I found that I'm wasting my time with that approach.
It is extremely difficult to understand sourcecode of Firefox which runs spread over multiple processes which communicate with each other. It seems that the content of the variable win corresponds to the C++ class mozIDOMWindowProxy or nsChromeOuterWindowProxy. But these seem to be only wrapper classes for other classes. Finally I gave up trying to understand Firefox sourcecode.
But playing around for some hours I finally found a solution by try and error.
It is even simpler:
var baseWindow = win.docShell
.treeOwner
.nsIBaseWindow;
It works on Firefox 70 up to 79 (which is currently the latest version). However this new code does not run on Firefox versions <= 62. On Firefox 62 or older you get the error
TypeError: win.docShell is undefined
So the Firefoxes from 63 to 69 allow both versions of code. Maybe in version 70 the QueryInterface() has been removed because it is not needed anymore and has become legacy?
NOTE: In Firefox 68 they made another change. Now there are 2 native windows: The toplevel 'MozillaWindowClass' now has a child window 'MozillaCompositorWindowClass' which runs in another process and draws the web content.

Translating PowerPoint VBA code to Delphi, "keep source formatting" issue

I am working with Delphi(2010), but I'm new with PowerPoint(2010)
I've found two codes for copying slides with "keep source formatting":
Sub test1()
Dim orig_slide, new_slide As Slide
Dim slide_range As SlideRange
Set orig_slide = ActivePresentation.Slides(2)
orig_slide.Copy
Set slide_range = ActivePresentation.Slides.Paste(6)
Set new_slide = slide_range.Item(1)
new_slide.Design = orig_slide.Design
new_slide.ColorScheme = orig_slide.ColorScheme
End Sub
Sub test2()
ActivePresentation.Slides(2).Select
ActiveWindow.Selection.Copy
ActiveWindow.View.PasteSpecial (DataType = ppPasteOLEObject)
End Sub
They both are giving desired results in PowerPoint but in Delphi i get exceptions :
test1, line
new_slide.Design = orig_slide.Design
exception class EOleSysError with message 'Member not found'
test2, line
ActiveWindow.View.PasteSpecial (DataType = ppPasteOLEObject)
exception class EOleException with message 'View.PasteSpecial : Invalid request. The specified data type is unavailable'
I am using Slide Sorter View, copying and pasting are working ok, I'm only trying to add "keep source formatting" command.
Thanks in advance
I think I've found a solution :
This code in Delphi (doesn't work)
var OrigSlide, NewSlide : Variant;
NewSlide.Design := OrigSlide.Design;
on the right side, Delphi seems to accept only variant_variable, it doesn't accept variant_variable.property
Left side seems to work in opposite way ?!?
When I replaced it with this code, it works
OrigSlide := OrigSlide.Design;
NewSlide.Design := OrigSlide;
But I can only guess why.

How to make an input from command line in JScript?

How can I read input from the command line in JScript, similar to Pascal's readln?
It sounds like you're asking about Windows Script Host. If you're using cscript.exe to run your scripts, you can work with WScript.StdIn:
WScript.Echo("Enter something");
WScript.Echo("You entered " +WScript.StdIn.ReadLine());
http://msdn.microsoft.com/en-us/library/skwz6sz4(v=VS.85).aspx
Assuming cscript the.js a1 a2 ... you can;
var args = WScript.Arguments;
for (var i= 0; i < args.length; i++) {
WScript.Echo(args(i))
}
It has been like forever that I have looked into Pascal, so I'm not quite sure what ReadLn() exactly does. If you just want to get a line from the user in the command line you may use the WScript.StdIn.ReadLine() method as described here.
But if you want to read from a file, then you may try:
var myFileSysObj = new ActiveXObject("Scripting.FileSystemObject");
var myInputTextStream = myFileSysObj.OpenTextFile("c:\\temp\\test.txt", 1, true);
var myString = myInputTextStream.ReadLine();
myInputTextStream.Close();
from here.

Resources