2008-09-30 28 views
70

He intentado esto:Cómo inyectar Javascript en el control WebBrowser?

string newScript = textBox1.Text; 
HtmlElement head = browserCtrl.Document.GetElementsByTagName("head")[0]; 
HtmlElement scriptEl = browserCtrl.Document.CreateElement("script"); 
lblStatus.Text = scriptEl.GetType().ToString(); 
scriptEl.SetAttribute("type", "text/javascript"); 
head.AppendChild(scriptEl); 
scriptEl.InnerHtml = "function sayHello() { alert('hello') }"; 

scriptEl.InnerHtml y scriptEl.InnerText ambos dan errores:

System.NotSupportedException: Property is not supported on this type of HtmlElement. 
    at System.Windows.Forms.HtmlElement.set_InnerHtml(String value) 
    at SForceApp.Form1.button1_Click(Object sender, EventArgs e) in d:\jsight\installs\SForceApp\SForceApp\Form1.cs:line 31 
    at System.Windows.Forms.Control.OnClick(EventArgs e) 
    at System.Windows.Forms.Button.OnClick(EventArgs e) 
    at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) 
    at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) 
    at System.Windows.Forms.Control.WndProc(Message& m) 
    at System.Windows.Forms.ButtonBase.WndProc(Message& m) 
    at System.Windows.Forms.Button.WndProc(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 

¿Hay una manera fácil de inyectar un script en el Reino?

Respuesta

89

Por alguna razón la solución de Richard no funciona en mi final (insertAdjacentText fallado con una excepción). Sin embargo, esto parece funcionar:

HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0]; 
HtmlElement scriptEl = webBrowser1.Document.CreateElement("script"); 
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement; 
element.text = "function sayHello() { alert('hello') }"; 
head.AppendChild(scriptEl); 
webBrowser1.Document.InvokeScript("sayHello"); 

This answer explica cómo obtener la interfaz IHTMLScriptElement en su proyecto.

+1

Genial, creo que el uso de IHTMLScriptElement hace que el código sea más obvio en cualquier caso. Me pregunto por qué obtuviste una excepción, pero a veces compites con la interoperabilidad COM. – ZeroBugBounce

+0

¿Qué tal si agregas una referencia a un archivo js local? Por favor, consulte http://stackoverflow.com/questions/4029602/how-do-i-add-a-local-script-file-to-the-html-of-a-webbrowser-control – IAmAN00B

+0

Por favor, ayúdenme con esto. Como hiciste esto. Quiero inyectar JS en mi página en tiempo real a través de mi aplicación C++. ¿Cómo debo hacerlo? – Johnydep

0

Lo que se quiere hacer es usar Page.RegisterStartupScript (clave, guión) :

Vea aquí para más detalles: http://msdn.microsoft.com/en-us/library/aa478975.aspx

Lo que lo hace básicamente es construir su cadena de javascript, pasarlo a que método y darle un ID único (en caso de que intente registrarlo dos veces en una página)

EDITAR: Esto es lo que usted llama gatillo feliz. Siéntete libre de derribarlo. :)

+4

ASP.Net doesn No tiene mucho que ver con la creación de scripts del control WebBrowser en una aplicación de winforms. – jsight

+0

Voy a dejar esto aquí para el castigo que merezco;) – mattlant

+0

Probablemente habría leído menos de la misma manera y dada la misma respuesta incorrecta – Grank

1

Siempre puede usar una propiedad "DocumentStream" o "DocumentText". Para trabajar con documentos HTML, recomiendo un HTML Agility Pack.

+0

Buen consejo ... Estoy seguro de que la lib será útil en algún momento. – jsight

9

El contenedor administrado para el documento HTML no implementa por completo la funcionalidad que necesita, por lo que necesita para sumergirse en la API de MSHTML para lograr lo que quiere:

1) Añadir una referencia a MSHTML, que se probalby se llamará "Microsoft HTML Object Library" bajo COM referencias.

2) Agregue 'using mshtml;' a tus espacios de nombres

3) Obtener una referencia a IHTMLElement de su elemento de script:

IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement; 

4) llama al método insertAdjacentText, con el primer valor del parámetro de "afterBegin". Todos los valores posibles se enumeran here:

iScriptEl.insertAdjacentText("afterBegin", "function sayHello() { alert('hello') }"); 

5) Ahora usted será capaz de ver el código de la propiedad scriptEl.InnerText.

HTH, Richard

+1

Agradable ... esto junto con los consejos proporcionados por korchev funciona perfectamente. Ojalá pudiera establecer dos soluciones aceptadas en este caso. :) – jsight

17

Si todo lo que realmente desea es ejecutar Javascript, esto sería más fácil (VB .Net):

MyWebBrowser.Navigate("javascript:function foo(){alert('hello');}foo();") 

supongo que esto no sería "inyectar", pero que va a ejecutar su función, si eso es lo que buscas. (En caso de que haya complicado demasiado el problema). Y si puede averiguar cómo inyectar en javascript, ponga eso en el cuerpo de la función "foo" y deje que javascript haga la inyección por usted.

21

Además, en .NET 4 esto es aún más fácil si utiliza la palabra clave dinámica:

dynamic document = this.browser.Document; 
dynamic head = document.GetElementsByTagName("head")[0]; 
dynamic scriptEl = document.CreateElement("script"); 
scriptEl.text = ...; 
head.AppendChild(scriptEl); 
+2

¿Por qué alguien necesitaría una dinámica para eso?Si intentas guardar algo de tipeo, tenemos una inferencia de tipo desde C# 3.0, por lo que var sería aceptable. No hay necesidad de comenzar a invocar el DLR. – alimbada

+21

Este es básicamente el punto de la palabra clave dinámica: interoperabilidad COM. En realidad, no tiene Type Inference aquí, tiene documentación. Debido a que un IHTMLElement2 no es asignable desde IHtmlElement por ejemplo, y en tiempo de ejecución solo tiene un objeto proxy COM. Solo tienes que saber qué interfaces lanzar en qué. La palabra clave dinámica le ayuda a reducir mucho de ese cruft. ¿Sabes que existe el método de por qué echarlo en alguna interfaz? No 'invoca exactamente el DLR', solo genera código que sabe cómo invocar el método en objetos COM (en este caso). –

+1

@ justin.m.chase me salvaste la vida. –

7

esta es una solución utilizando mshtml

IHTMLDocument2 doc = new HTMLDocumentClass(); 
doc.write(new object[] { File.ReadAllText(filePath) }); 
doc.close(); 

IHTMLElement head = (IHTMLElement)((IHTMLElementCollection)doc.all.tags("head")).item(null, 0); 
IHTMLScriptElement scriptObject = (IHTMLScriptElement)doc.createElement("script"); 
scriptObject.type = @"text/javascript"; 
scriptObject.text = @"function btn1_OnClick(str){ 
    alert('you clicked' + str); 
}"; 
((HTMLHeadElementClass)head).appendChild((IHTMLDOMNode)scriptObject); 
+2

dos años tarde Me temo –

+2

Como este es un recurso de la comunidad, su respuesta sigue siendo útil para otros (como yo). +1 para el equivalente mshtml, me salvó una pregunta. – Tyrsius

+0

Para cualquier persona que encuentre esto, elimine 'clase' de la última línea, debe leer el encabezado '((HTMLHeadElement)) .appendChild ((IHTMLDOMNode) scriptObject);' de lo contrario obtendrá errores. – Tyrsius

40
HtmlDocument doc = browser.Document; 
HtmlElement head = doc.GetElementsByTagName("head")[0]; 
HtmlElement s = doc.CreateElement("script"); 
s.SetAttribute("text","function sayHello() { alert('hello'); }"); 
head.AppendChild(s); 
browser.Document.InvokeScript("sayHello"); 

(probado en .NET 4/Aplicación Windows Forms)

Editar: Problema solucionado en el conjunto de funciones.

+10

Aprecio esta solución porque no se basa en el ensamblado (aunque útil) IHTMLSCriptElement. –

+4

@jsight Esta debería ser la respuesta aceptada. Es lo mismo que la respuesta actual, pero más simple y sin la dependencia 'IHTMLSCriptElement'. –

7

Creo que el método más simple para inyectar Javascript en un documento HTML Control WebBrowser desde C# es invocar el método "execStrip" con el código que se inyectará como argumento.

En este ejemplo, el código JavaScript se inyecta y se ejecuta en el ámbito global:

var jsCode="alert('hello world from injected code');"; 
WebBrowser.Document.InvokeScript("execScript", new Object[] { jsCode, "JavaScript" }); 

Si desea retrasar la ejecución, inyectar funciones y llamarlos después:

var jsCode="function greet(msg){alert(msg);};"; 
WebBrowser.Document.InvokeScript("execScript", new Object[] { jsCode, "JavaScript" }); 
............... 
WebBrowser.Document.InvokeScript("greet",new object[] {"hello world"}); 

Esto es válido para Controles de Windows Forms y WPF WebBrowser.

Esta solución no es un navegador cruzado porque "execScript" se define solo en IE y Chrome. Pero la pregunta es acerca de los controles de Microsoft WebBrowser y IE es el único compatible.

Para un método de navegador cruzado válido para inyectar código JavaScript, cree un objeto Function con la nueva Palabra clave. Este ejemplo crea una función anónima con código inyectado y lo ejecuta (javascript implementa cierres y la función tiene acceso al espacio global sin contaminación variable local).

var jsCode="alert('hello world');"; 
(new Function(code))(); 

Por supuesto, se puede retrasar la ejecución:

var jsCode="alert('hello world');"; 
var inserted=new Function(code); 
................. 
inserted(); 

creo que sirve

1

Aquí es un ejemplo VB.Net si usted está tratando de recuperar el valor de una variable dentro de una página cargada en un control WebBrowser.

Paso 1) Añadir una referencia COM en su proyecto para objetos HTML de Microsoft

Paso 2) A continuación, agregue este código VB.Net a su Form1 para importar la biblioteca mshtml:
importaciones mshtml

Paso 3) Incluir este código VB.Net encima de la línea "Public Class Form1":
< System.Runtime.InteropServices.ComVisibleAttribute (Verdadero) >

Paso 4) Añadir un control WebBrowser a su proyecto

Paso 5) Incluir este código de VB.Net a su función Form1_Load:
WebBrowser1.ObjectForScripting = Me

Paso 6) Incluir este VB.sub neta que inyectará una función "CallbackGetVar" en la página web de Javascript:

Public Sub InjectCallbackGetVar(ByRef wb As WebBrowser) 
     Dim head As HtmlElement 
     Dim script As HtmlElement 
     Dim domElement As IHTMLScriptElement 

     head = wb.Document.GetElementsByTagName("head")(0) 
     script = wb.Document.CreateElement("script") 
     domElement = script.DomElement 
     domElement.type = "text/javascript" 
     domElement.text = "function CallbackGetVar(myVar) { window.external.Callback_GetVar(eval(myVar)); }" 
     head.AppendChild(script) 
    End Sub 

Paso 7) Añadir las siguientes sub VB.Net cual el Javascript buscará entonces cuando se invoca:

Public Sub Callback_GetVar(ByVal vVar As String) 
     Debug.Print(vVar) 
    End Sub 

paso 8) Por último, para invocar la devolución de llamada Javascript, añadir el código VB.Net cuando se pulsa un botón, o donde quiera que guste:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     WebBrowser1.Document.InvokeScript("CallbackGetVar", New Object() {"NameOfVarToRetrieve"}) 
    End Sub 

paso 9) Si te sorprende que esto funciona, Må y desea leer la función "eval" de Javascript, utilizada en el Paso 6, que es lo que hace esto posible. Tomará una cadena y determinará si existe una variable con ese nombre y, de ser así, devolverá el valor de esa variable.

23

Aquí es la manera más fácil que he encontrado después de trabajar en esto:

string jCode = "alert("Hello");" 
// or any combination of your JavaScript commands 
// (including function calls, variables... etc) 

// WebBrowser webBrowser1 is what you are using for your web browser 
webBrowser1.Document.InvokeScript("eval", new object[] { jCode }); 

Qué función global JavaScript eval(str) qué es, análisis y ejecuta lo que está escrito en str. Consultar w3schools ref here.

7

Como seguimiento a la accepted answer, esta es una definición mínima de la IHTMLScriptElement interface que no requiere incluir las bibliotecas de tipos adicionales:

[ComImport, ComVisible(true), Guid(@"3050f28b-98b5-11cf-bb82-00aa00bdce0b")] 
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] 
[TypeLibType(TypeLibTypeFlags.FDispatchable)] 
public interface IHTMLScriptElement 
{ 
    [DispId(1006)] 
    string text { set; [return: MarshalAs(UnmanagedType.BStr)] get; } 
} 

lo tanto, un código completo dentro de un control WebBrowser clase derivada se vería como:

protected override void OnDocumentCompleted(
    WebBrowserDocumentCompletedEventArgs e) 
{ 
    base.OnDocumentCompleted(e); 

    // Disable text selection. 
    var doc = Document; 
    if (doc != null) 
    { 
     var heads = doc.GetElementsByTagName(@"head"); 
     if (heads.Count > 0) 
     { 
      var scriptEl = doc.CreateElement(@"script"); 
      if (scriptEl != null) 
      { 
       var element = (IHTMLScriptElement)scriptEl.DomElement; 
       element.text = 
        @"function disableSelection() 
        { 
         document.body.onselectstart=function(){ return false; }; 
         document.body.ondragstart=function() { return false; }; 
        }"; 
       heads[0].AppendChild(scriptEl); 
       doc.InvokeScript(@"disableSelection"); 
      } 
     } 
    } 
} 
0

Si necesita inyectar un archivo completo, puede utilizar esto:

With Browser.Document'  
    'Dim Head As HtmlElement = .GetElementsByTagName("head")(0)' 
    'Dim Script As HtmlElement = .CreateElement("script")' 
    'Dim Streamer As New StreamReader(<Here goes path to file as String>)' 
    'Using Streamer' 
     'Script.SetAttribute("text", Streamer.ReadToEnd())' 
    'End Using' 
    'Head.AppendChild(Script)' 
    '.InvokeScript(<Here goes a method name as String and without parentheses>)' 
'End With' 

Recuerde importar System.IO para usar StreamReader. Espero que sea ayudarle

+0

Sé que esto fue respondido 3 días antes de hace un año, pero ¿podrías usarlo para poner un archivo en una sección '' input type = "file ''? –

2

utilicé esta: D

HtmlElement script = this.WebNavegador.Document.CreateElement("SCRIPT"); 
script.SetAttribute("TEXT", "function GetNameFromBrowser() {" + 
"return 'My name is David';" + 
"}"); 

this.WebNavegador.Document.Body.AppendChild(script); 

A continuación, puede ejecutar y conseguir el resultado con:

string myNameIs = (string)this.WebNavegador.Document.InvokeScript("GetNameFromBrowser"); 

espero ser útil

Cuestiones relacionadas