Posts: 65
Threads: 32
Joined: Jan 2013
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:
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 :-).
Posts: 12,072
Threads: 140
Joined: Dec 2002
Function dialog_web_browser_invoke_javascript
\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
Posts: 65
Threads: 32
Joined: Jan 2013
If the dialog box is already open - can I make the call to JavaScript?
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!
Posts: 12,072
Threads: 140
Joined: Dec 2002
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.
Posts: 65
Threads: 32
Joined: Jan 2013
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).
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:
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!
Posts: 12,072
Threads: 140
Joined: Dec 2002
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.
Posts: 12,072
Threads: 140
Joined: Dec 2002
Function dialog_web_browser_invoke_javascript2
\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
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)
Posts: 65
Threads: 32
Joined: Jan 2013
Posts: 13
Threads: 3
Joined: Sep 2008
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!
|