Can't call method of a JavaScript object created in code injected to WebBrowser's Document after navigating
I've found some other questions like this, but not exactly, and with solutions that doesn't solve this particular problem. I'm working on a project that is something like iMacros for Internet Explorer. This is my simplified code:
public partial class Form1 : Form
{
public JSObject jsObject = new JSObject();
int uniqueNameEnsurer = 0;
public Form1()
{
InitializeComponent();
webBrowser1.Navigate("www.google.com");
}
private void InvokeCode(string functionCode)
{
HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0];
HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
element.text = "function MyInjectedFunction" + uniqueNameEnsurer + "(Param){" + functionCode + "}";
head.AppendChild(scriptEl);
webBrowser1.Document.InvokeScript("MyI开发者_如何转开发njectedFunction" + uniqueNameEnsurer, new object[] { jsObject });
uniqueNameEnsurer++;
}
private void button1_Click(object sender, EventArgs e)
{
InvokeCode(@"
function MyObject()
{
this.Something = 'hello';
this.SomeFunc = function(){
alert('in SomeFunc!!!');
}
}
Param.UserData = new MyObject();
");
}
private void button2_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("www.bing.com");
}
private void button3_Click(object sender, EventArgs e)
{
InvokeCode(@"
alert(Param.UserData.Something);
Param.UserData.SomeFunc();
");
}
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class JSObject
{
public object UserData;
}
So, what I do is, click button1 (which calls button1_Click
), then button2 (which calls button2_Click
), wait a sec to load, and then click button3 (which calls button3_Click
).
When I click button3, I get an alert saying "hello" (which means the object somehow persists after navigating), but right after that, I get an error saying “Can't execute code from a freed script”. This is probably some kind of security thing. I've found some posts talking about but none of them solve my problem. I can do a work around by creating my SomeFunc
as a string and then using eval
, but this is a nasty solution. If there is anything I can do to my C# code that would let me keep the JavaScript code just the way it is (and work, of course), it would be super cool. If not, what would be the best work around so that I can call SomeFunc
after navigating?
There are a few things going on here that I don't quite understand. First off I wouldn't count on scripts being there after a call to Navigate. Once you navigate I think you should re-inject all your scripts that you want.
Second I'm not seeing where "MyObject" is defined? I see "new MyObject();" in your script there but I don't see the MyObject function defined anywhere so it doesn't surprise me that your SomeFunc() is not defined. Assuming that the sample is just incomplete.
And finally you should look into implementing IReflect and IExpando on your JSObject. It might solve all your problems.
OK, apparently it is just NOT possible to do what I'm trying to do with just C#. I will need to implement some kind of object serialization and deserialization system in JavaScript and serialize the the UserData
before navigating and deserialize it after navigating.
精彩评论