QWebFrame::evaluateJavaScript crash
-
Alrightie then. Since my case is rather specific (I need to evaluate a function call in a 3rd party JS chunk, and don't really care about the DOM as such - I just need the code to run), I ended up using QScriptEngine instead with a very sparse dummy DOM injected in the script engine instance, and then running the desired method.
Not sure what the issue with QWebKit is here (threading?), but QScriptEngine works for me in this case.
Others having the same issue (but needing a full DOM) might be interested in http://www.envjs.com, implementing a full DOM. The project https://qt.gitorious.org/qt-labs/qtscript-browser-env puts this in a Qt context as a QScriptEngine plugin, although the project is not compiling for Qt5.x. Should be easy to fix though.
-
occurs only in debug mode?
-
In release as well.
-
I think the
QWebFrame::setContent
does not work well, it is equivalent tosetHTML
but is a little more advanced, so has no way to set the content of a page has loaded.The right thing would be this:
QWebPage *page = ui->webview->page(); QString scriptContent = "<scr" + "ipt>function HelloWorld() { alert('Hello World!!!'); }</sc" + "ript>"; QByteArray injectScript = QString(scriptContent).toUtf8(); page->mainFrame()->setContent(injectScript, "text/html");@
But for your purpose this will not work, the right would you use another type of injection, such as the very "evaluateScript", like this:
QString injectionJS = "(function() { var new = document.createElement('scr" + "ipt');"; injectionJS += "new.inner" + "HTML = String((" + scriptContent + "));"; injectionJS += "document.body.appendChild(new)"; injectionJS += "});"; page->mainFrame()->evaluateJavaScript(injectionJS);
It's true
Sounds like a bug. Please go to http://bugreports.qt-project.org/
After create an issue, post your link here.Thanks!
-
Did it really crash on evaluating this?
-
Not the evaluateScript that causes the "crash", but using the incorrect way QwebFrame::setContent. He apparently simulates the loading of a file, but if the page is already loaded it fails to load again.
Same is not true-if the "crash" the QwebFrame::setContent would not work for what you want to do, because it would wipe the entire page and its original content would be lost.
View this would be the proper way to work with QwebFrame::setContent does:
@QwebFrame::setContent (QString("<scr"+"ipt>content</scr"+"ipt>").toUtf8()," text/html");@
What I mean is that it seems that server to create a home page (as in Chrome have the "SpeedDial")
For you to achieve your goal, I recommend doing something like this:
https://gist.github.com/brcontainer/98016ee3655cfa535e8e (I fixed my example here)
I tested, no crash using evaluateScript.
-
Hm, the thing is, my approach works in most cases. The JS gets loaded and run. But when it meets certain injections (they are LARGE all of them - several MB of minified JS code), it crashes (as in the application dies, with a crash report and all, as in the one I've shown).
As you can see in the crash report, the culprit has to do with a string destructor after my call to QWebFrame::evaluateJavaScript(). For some reason I don't think it's related to the way the JS is loaded.
In any case, I'll try your approach at the earliest convenience; but for now QScript works for me.Thanks!
-
Got it, then it is a limitation of reading time with the QtWebKit runtime.
Perhaps the process for files only work if the injection was asynchronous, but the QtWebKit does not support multiprocess (as is Chrome).
Why do not you do this:
-
Create um custom protocol in "QNetWorkAccessManager::createRequest", like "qrc:", eg. @janfaore://@
-
Save your Javascript in an file located in "User folder" (in Window c:\Users\USER_NAME\Local Datac\AppData\Local\project_user_data)
-
After save, inject saved file by your custom protocol, like this: @janfaore://myfile.js@
-
Set an interval/timeout before perform: @QWebFrame::evaluateScript("custom_function();");@
QNetWorkAccessManager example:
@QNetworkReply * netWork::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) {
const QString scheme = request.url().scheme().toLower().trimmed();
if ("janfaore" == scheme) {
return [YOUR CUSTOM QNetworkReply];
}QNetWorkAccessManager::createRequest(op, request, outgoingData);
}@
Note: Maybe need reimplement QNetWorkReply (create an custom QNetWorkReply).
-
-
I appreciate your efforts in trying to help, but the problem is not loading the scripts (which are online resources that change regularly). I have no problem with this being asynchronous. The function I need to call via evaluateScript() is very, very simple and short (a few string manipulations), and a timeout in that context is very inlikely.
-
Is that you said that major routes injected with "the evaluate" that caused the "crash", by this thought that if you create yourself a custom protocol like in "Firefox", you could throw huge scripts and the "Main Thread" (windows) would not crash.
Using "evaluateScript", you inject only this:
@< script src="janfaore://myfile.js"></ script >@
After use QTimer::singleShot() for evaluate your function.