Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Invoking JavaScript in a SHDocVw.WebBrowser from QM?
#1
Hi -

I have a web page (a SHDocVw.WebBrowser control in a dialog) that is loading nicely in QM. When it loads I get a DocumentComplete callback; In that callback I get a SHDocVw.IWebBrowser2 object that I can walk with Document.getElementById() to get a particular DOM element and I can attach a OnPropertyChange callback to that.

So - any time the specified element changes in the web page I get a callback. This is all working smoothly.

I was wondering what the cleanest way would be to go in the other direction - is it possible to call InvokeScript or some other function where I could invoke a JavaScript function from inside of QM? I don't see anything in the API for this.
When I try this:
Code:
Copy      Help
SHDocVw.IWebBrowser2 wb
wb.Document.execCommand("blah" "true" 0)
I get a Javascript error from inside the browser - so I think I'm close. (I have a JavaScript function named "blah").
Another alternative might be just to write out DOM elements and use jQuery change() callbacks to generate JavaScript calls. But I'd rather call JavaScript directly if I can.

Any help appreciated :-).
#2
Function dialog_web_browser_invoke_javascript
Code:
Copy      Help
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages

str controls = "3"
str ax3SHD
ax3SHD=
;<html><head>
;<script type="text/javascript">
;function blah(x)
;{
;alert(x);
;return 5;
;}
;</script>
;</head>
;<body>test<body/>
;</html>

if(!ShowDialog("dialog_web_browser_invoke_javascript" &dialog_web_browser_invoke_javascript &controls)) ret

;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 223 135 "Dialog"
;3 ActiveX 0x54030000 0x0 0 0 224 114 "SHDocVw.WebBrowser"
;4 Button 0x54032000 0x0 6 116 48 14 "blah"
;1 Button 0x54030001 0x4 120 116 48 14 "OK"
;2 Button 0x54030000 0x4 170 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040000 "*" "" "" ""

ret
;messages
sel message
,case WM_INITDIALOG
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case 4
,SHDocVw.WebBrowser we3
,we3._getcontrol(id(3 hDlg))
,
,MSHTML.IHTMLDocument2 d=we3.Document
,d.parentWindow.execScript("blah(''BLAH'');" "JavaScript")
,
,;or in single line
,;we3.Document.parentWindow.execScript("blah(20);" "JavaScript")
,
,;if need the return value
,;MSHTML.IHTMLDocument2 d=we3.Document
,;d.parentWindow.execScript("R=blah(''BLAH'');" "JavaScript")
,;out d.Script.R
ret 1
#3
If the dialog box is already open - can I make the call to JavaScript?
Code:
Copy      Help
int w1=win("RadFusionRDialog" "#32770")

int c=child("" "Internet Explorer_Server" w1 0x0 "accName=http://emiswd0vm1/RadFusionR/RadFusionRClient.aspx") ;; 'http://localhost:63351/RadF...'

SHDocVw.WebBrowser wb._getcontrol(id(3 w1))
str location = wb.LocationURL
out F"Browser location {location}"

MSHTML.IHTMLDocument2 d=wb.Document
MSHTML.IHTMLWindow2 parentWindow = d.parentWindow

parentWindow.execScript("blah(''BLAH'');" "JavaScript")
,

When I run this I get the following in the console:
Quote:Browser location http://emiswd0vm1/RadFusionR/RadFusionRClient.aspx
Error (RT) in RadFusionSendMsg: Exception 0xC0000005. Access violation. Cannot read memory at 0x144. In MSHTML.dll at 0x62E4C6F1 (0x62E00000+0x4C6F1). ?
From this all I know is that it's finding the window and that it can access the wb.Location (and return the correct value) - but it throws an exception when evaluating "d.parentWindow".

I know that if run this inside context of the dialog that I can make these calls (and that the JavaScript works as expected).

What I want (eventually) is for this window to run hidden and use the calls to JavaScript to use the SignalR protocol for communicating with other peers on the network. I can't do this in C# because SignalR requires .NET 4.0 - but if I use HTML/JavaScript as an intermediary it will work. I want the window to persist and be able to handle callbacks from SignalR (works very well) and I want to be able to send messages in the JavaScript (which would replace the 'blah()' function above).

Thanks!
#4
Probably cannot call these functions from other thread. Use SendMessage to send a message to the dialog. When the dialog receives the message, let it call the functions.
#5
This sounds exactly right - but I'm not getting it to work. I'm hoping that I'm missing something simple here. I'm using the WM_COPYDATA example from the forums to send the message (I wasn't sure if I should be sending them to the window or the html control).

Code:
Copy      Help
Function [b]RadFusionSendMsg3[/b] [help1][/help1]
[code]int w1=win("RadFusionRDialog" "#32770")

int c=child("" "Internet Explorer_Server" w1 0x0 "accName=http://emiswd0vm1/RadFusionR/RadFusionRClient.aspx") ;; 'http://localhost:63351/RadF...'


SHDocVw.WebBrowser wb._getcontrol(id(3 w1))
str location = wb.LocationURL
out F"Browser location {location}"

str groupName = "RFGroupName"
str clientType = "Impax Client"
str commandName = "This is a test, only a test from RadFusion"

str javascriptString = F"testSendCommand(''{groupName}'', ''{clientType}'', ''{commandName}'','''');"

COPYDATASTRUCT cds
cds.dwData=4194305
cds.lpData=javascriptString
cds.cbData=javascriptString.len+1


SendMessage(w1 WM_COPYDATA 0 &cds)
SendMessage(c WM_COPYDATA 0 &cds)
[/code]

Then - in JavaScript I've set up some listeners:
Code:
Copy      Help
window.addEventListener('message', function (e) {
                    alert("window Message arrived " + e.data);
                }, false);
document.addEventListener('message', function (e) {
                    alert("document Message arrived " + e.data);
                }, false);
I've also created an iFrame in the window and set up listeners on that as well (I'm using IE10 - as I've been looking around it sounds like there is a problem sending messages to windows but it works sending to iFrames). But I never get the alerts from the web pages.

My questions:
  • Is WM_COPYDATA a reasonable message type to send?
  • What is the right entity to send the message to (I'm assuming it's the 'c' above)
  • Is there a similar mechanism for achieving the same end (sending JavaScript functions with arguments to an existing web dialog). Note that the dialog might be hidden and I don't know if this means that certain UI interactions won't work.

Thanks!
#6
WM_COPYDATA is good message for this. Also there are other ways to send data to other thread.
Move all the code except sending message to the dialog procedure.
Send message to the dialog (w1).
When the dialog receives your message, let it execute the code with the sent string.
#7
Function dialog_web_browser_invoke_javascript2
Code:
Copy      Help
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages

str controls = "3"
str ax3SHD
ax3SHD=
;<html><head>
;<script type="text/javascript">
;function blah(x)
;{
;alert(x);
;return 5;
;}
;</script>
;</head>
;<body>test<body/>
;</html>

if(!ShowDialog("" &dialog_web_browser_invoke_javascript2 &controls)) ret

;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 223 135 "RadFusionRDialog"
;3 ActiveX 0x54030000 0x0 0 0 224 114 "SHDocVw.WebBrowser"
;4 Button 0x54032000 0x0 6 116 48 14 "blah"
;1 Button 0x54030001 0x4 120 116 48 14 "OK"
;2 Button 0x54030000 0x4 170 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040000 "*" "" "" ""

ret
;messages
sel message
,case WM_INITDIALOG
,case WM_DESTROY
,case WM_COMMAND goto messages2
,case WM_COPYDATA
,COPYDATASTRUCT& cds=+lParam
,sel cds.dwData
,,case 4194305
,,SHDocVw.WebBrowser we3
,,we3._getcontrol(id(3 hDlg))
,,MSHTML.IHTMLDocument2 d=we3.Document
,,lpstr code=cds.lpData
,,d.parentWindow.execScript(code "JavaScript")
ret
;messages2
sel wParam
,case IDOK
,case 4
ret 1
Macro Macro2233
Code:
Copy      Help
str javascriptString="blah(''BLAH'');"

int w1=win("RadFusionRDialog" "#32770")
COPYDATASTRUCT cds
cds.dwData=4194305
cds.lpData=javascriptString
cds.cbData=javascriptString.len+1
SendMessage(w1 WM_COPYDATA 0 &cds)
#8
Wow. Perfect. Thanks!
#9
This is great, thanks!

I'd like to ask, how can I execute javascript as above but without a dialog? (perhaps without SHDocVw also). I'm trying to send WM_COPYDATA (js code) for an HTA file (opened by mstha.exe, internet explorer) but I just can't get it to work. Ideally, I'd like to to know of a neat, generic solution I can adapt to pass string values to js (for also firefox, chrome, etc)... even more ideally, including string arrays but that's optional, not sure what it requires. Going through the forums, I also saw the alternative option of shared memory and the sample codes seemed short, but I'm really out of my depth.

I'd appreciate any help!


Forum Jump:


Users browsing this thread: 1 Guest(s)