3

I have a webpage that when visited, declares a variable called date using the following:

var date=new Date("03 Oct 2013 16:04:19");

That date is then displayed at the top of the page. Is there a way for me to modify that date variable? (and not just the visible HTML source)

I have been experimenting with InvokeScript but am finding it hard to grasp, if anybody knows and could post some examples relating directly to this I'd be hugely grateful. Thankyou.

noseratio
  • 59,932
  • 34
  • 208
  • 486
John Cliven
  • 973
  • 1
  • 8
  • 21

2 Answers2

3

You can inject any JavaScript code using JavaScript's eval, it works with any IE version. You'd need to make sure the page has at least one <script> tag, but this is easy:

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Call WebBrowser1.Navigate("http://example.com")
    End Sub

    Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
        '
        ' use WebBrowser1.Document.InvokeScript to inject script
        '
        ' make sure the page has at least one script element, so eval works
        WebBrowser1.Document.Body.AppendChild(WebBrowser1.Document.CreateElement("script"))
        WebBrowser1.Document.InvokeScript("eval", New [Object]() {"(function() { window.newDate=new Date('03 Oct 2013 16:04:19'); })()"})
        Dim result As String = WebBrowser1.Document.InvokeScript("eval", New [Object]() {"(function() { return window.newDate.toString(); })()"})
        MessageBox.Show(result)

    End Sub

End Class

Alternatively, you can use VB.NET late binding to call eval directly, instead of Document.InvokeScript, which might be easier to code and read:

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Call WebBrowser1.Navigate("http://example.com")
    End Sub

    Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted

        '
        ' use VB late binding to call eval directly (seamlessly provided by.NET DLR)
        '
        Dim htmlDocument = WebBrowser1.Document.DomDocument
        Dim htmlWindow = htmlDocument.parentWindow
        ' make sure the page has at least one script element, so eval works
        htmlDocument.body.appendChild(htmlDocument.createElement("script"))
        htmlWindow.eval("var anotherDate = new Date('04 Oct 2013 16:04:19').toString()")
        MessageBox.Show(htmlWindow.anotherDate)
        ' the above shows we don't have to use JavaScript anonymous function,
        ' but it's always a good coding style to do so, to scope the context:
        htmlWindow.eval("window.createNewDate = function(){ return new Date().toString(); }")
        MessageBox.Show(htmlWindow.eval("window.createNewDate()"))

        ' we can also mix late binding and InvokeScript
        MessageBox.Show(WebBrowser1.Document.InvokeScript("createNewDate"))

    End Sub

End Class
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 1
    +1 Good call on the `eval` function. I was going to suggest that too if the OP didn't have access to the source of the webpage. – Cameron Tinker Oct 08 '13 at 13:06
2

According to the documentation, you need to invoke an existing script defined in the client:
JavaScript:

var extDate = new Date("03 Oct 2013 16:04:19");

function test(date) {
  alert(date);
  extDate = date;
}

You could also call eval and run an anonymous function. This would be the preferred method if you have no control over the page source. Essentially, you would be invoking and running code in the JavaScript interpreter.

C#:

private void InvokeTestMethod(DateTime date)
{
    if (webBrowser1.Document != null)
    {
        webBrowser1.Document.Body.AppendChild(webBrowser1.Document.CreateElement("script"));
        webBrowser1.Document.InvokeScript("eval", (Object)"(function() { window.date=new Date('03 Oct 2013 16:04:19'); })()");
        webBrowser1.Document.InvokeScript("eval", (Object)"(function() { alert(window.newDate.toString()); })()");
        webBrowser1.Document.InvokeScript("eval", (Object)"(function() { window.date=new Date('" + date.ToString("dd MMM yyyy HH:mm:ss") + "'); })()");
        webBrowser1.Document.InvokeScript("eval", (Object)"(function() { alert(window.newDate.toString()); })()");
    }
}

private void Test()
{
    InvokeTestMethod(DateTime.Now);
}

VB.NET

Private Sub InvokeTestMethod([date] As DateTime)
    If webBrowser1.Document IsNot Nothing Then
        webBrowser1.Document.Body.AppendChild(webBrowser1.Document.CreateElement("script"))
        webBrowser1.Document.InvokeScript("eval", new [Object]() {"(function() { window.date=new Date('03 Oct 2013 16:04:19'); })()"}))
        webBrowser1.Document.InvokeScript("eval", new [Object]() {"(function() { alert(window.newDate.toString()); })()"}))
        webBrowser1.Document.InvokeScript("eval", new [Object]() {"(function() { window.date=new Date('" + [date].ToString("dd MMM yyyy HH:mm:ss") + "'); })()"})
        webBrowser1.Document.InvokeScript("eval", new [Object]() {"(function() { alert(window.newDate.toString()); })()"}))
    End If
End Sub

Private Sub Test()
    InvokeTestMethod(DateTime.Now)
End Sub

http://msdn.microsoft.com/en-us/library/system.windows.forms.htmldocument.invokescript.aspx

By using eval, you can invoke anonymous JavaScript functions and run your own code within the context of the web page. In the last two calls to eval, I set the date using DateTime.Now and format the date in a way that JavaScript can understand.

Cameron Tinker
  • 9,634
  • 10
  • 46
  • 85
  • Thanks Cameron, if Date is defined outside of a function does it mean I cannot modify it? – John Cliven Oct 07 '13 at 14:29
  • Just declare your date variable externally from the function and set the date from the argument passed to the function. I've updated my answer to show how this is done. – Cameron Tinker Oct 07 '13 at 18:23
  • Appreciate the help, perhaps I'm not explaining it well enough..I have no access to the server I'm requesting, and therefore cannot add a function that sets the date. I want to know if it's possible to set the date (or any other variable) that are declared outside of a function. I therefore cannot use the InvokeTestMethod() / InvokeScript you provided because there is no variable declarations within a function to call – John Cliven Oct 07 '13 at 23:57
  • 1
    @johndyas, if you do not own the page, you can still add any script to it using `WebBrowser.Document.CreateElement("script")` or just use JavaScript `eval` as I explained in [my answer](http://stackoverflow.com/a/19242163/1768303). – noseratio Oct 08 '13 at 08:18
  • 2
    @CameronTinker, there's one thing missing in the new edition of your answer (at the time of this comment). If the target web page doesn't contain any scripts (e.g., http://example.com), you won't be able to inject JavaScript with `eval`. An empty ` – noseratio Oct 08 '13 at 14:05
  • 1
    @Noseratio I've updated my answer to append a ` – Cameron Tinker Oct 08 '13 at 15:08