web-dev-qa-db-fra.com

Comment injecter du Javascript dans le contrôle WebBrowser?

J'ai essayé ceci:

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 et scriptEl.InnerText donnent tous deux des erreurs:

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)

Existe-t-il un moyen facile d’injecter un script dans le dom?

79
jsight

Pour une raison quelconque, la solution de Richard n'a pas fonctionné de mon côté (insertAdjacentText a échoué avec une exception). Cela semble cependant fonctionner:

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");

Cette réponse explique comment insérer l'interface IHTMLScriptElement dans votre projet.

98
Atanas Korchev
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");

(testé dans .NET 4/Windows Forms App)

Modifier: problème de casse résolu dans le jeu de fonctions.

46
typpo

Voici le moyen le plus simple que j'ai trouvé après avoir travaillé sur ceci:

string javascript = "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[] { javascript });

Ce que la fonction JavaScript globale eval(str) fait, c'est d'analyser et d'exécuter tout ce qui est écrit dans str. Vérifiez réf. W3schools ici .

29
Ilya Rosikhin

En outre, dans .NET 4, cela est encore plus facile si vous utilisez le mot-clé dynamic:

dynamic document = this.browser.Document;
dynamic head = document.GetElementsByTagName("head")[0];
dynamic scriptEl = document.CreateElement("script");
scriptEl.text = ...;
head.AppendChild(scriptEl);
21
justin.m.chase

Si tout ce que vous voulez, c'est exécuter du javascript, ce serait plus simple (VB .Net):

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

J'imagine que cela ne "l'injecterait" pas, mais que votre fonction serait exécutée, si c'est ce que vous recherchez. (Juste au cas où vous auriez trop compliqué le problème.) Et si vous pouvez comprendre comment injecter du javascript, mettez cela dans le corps de la fonction "foo" et laissez le javascript faire l'injection à votre place.

17
Eyal

Le wrapper géré pour le document HTML n'implémente pas complètement la fonctionnalité dont vous avez besoin, vous devez donc plonger dans l'API MSHTML pour accomplir ce que vous voulez:

1) Ajoutez une référence à MSHTML, qui sera probablement appelée "Bibliothèque d'objets Microsoft HTML" sous [~ # ~] com [~ # ~] références .

2) Ajouter 'using mshtml;' à vos espaces de noms.

3) Obtenez une référence au IHTMLElement de votre élément de script:

IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement;

4) Appelez la méthode insertAdjacentText, avec la première valeur de paramètre "afterBegin". Toutes les valeurs possibles sont listées ici :

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

5) Vous pourrez maintenant voir le code dans la propriété scriptEl.InnerText.

Hth, Richard

10
ZeroBugBounce

Pour faire suite à réponse acceptée , il s'agit d'une définition minimale de l'interface IHTMLScriptElement qui ne nécessite pas l'inclusion de bibliothèques de types supplémentaires:

[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; }
}

Ainsi, un code complet dans une classe dérivée de contrôle WebBrowser ressemblerait à ceci:

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");
            }
        }
    }
}
8
Uwe Keim

c'est une solution utilisant 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);
7
Camilo Sanchez

Je pense que la méthode la plus simple pour injecter du code Javascript dans un document HTML de WebBrowser Control à partir de c # consiste à appeler la méthode "execStrip" avec le code à injecter en tant qu'argument.

Dans cet exemple, le code javascript est injecté et exécuté au niveau global:

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

Si vous souhaitez retarder l'exécution, injectez des fonctions et appelez-les après:

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

Ceci est valable pour les contrôles Windows Forms et WPF WebBrowser.

Cette solution n’est pas compatible avec plusieurs navigateurs, car "execScript" est défini uniquement dans IE et Chrome. La question concerne toutefois les contrôles Microsoft WebBrowser et IE est le seul prise en charge.

Pour une méthode inter-navigateurs valide permettant d'injecter du code JavaScript, créez un objet Function avec le nouveau mot-clé. Cet exemple crée une fonction anonyme avec du code injecté et l'exécute (javascript implémente des fermetures et la fonction a accès à un espace global sans pollution par des variables locales).

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

Bien sûr, vous pouvez retarder l'exécution:

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

J'espère que ça aide

7
Santiago

J'ai utilisé ceci: D

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

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

Ensuite, vous pouvez exécuter et obtenir le résultat avec:

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

J'espère être utile

Voici un exemple VB.Net si vous essayez d'extraire la valeur d'une variable à partir d'une page chargée dans un contrôle WebBrowser.

Étape 1) Ajouter une référence COM dans votre projet à la bibliothèque d'objets Microsoft HTML

Étape 2) Ensuite, ajoutez ce code VB.Net à votre Form1 pour importer la bibliothèque mshtml:
Importations mshtml

Étape 3) Ajoutez ce code VB.Net au-dessus de votre ligne "Public Class Form1":
<System.Runtime.InteropServices.ComVisibleAttribute (True)>

Étape 4) Ajouter un contrôle WebBrowser à votre projet

Étape 5) Ajoutez ce code VB.Net à votre fonction Form1 Load:
WebBrowser1.ObjectForScripting = Me

Étape 6) Ajoutez ce sous-répertoire VB.Net qui injectera une fonction "CallbackGetVar" dans le code Javascript de la page Web:

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

Étape 7) Ajoutez le sous-fichier VB.Net suivant que le Javascript recherchera ensuite lorsqu’il est appelé:

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

Étape 8) Enfin, pour invoquer le rappel Javascript, ajoutez ce code VB.Net lorsque vous appuyez sur un bouton ou à l'endroit souhaité:

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

Étape 9) Si cela vous surprend, vous voudrez peut-être lire la fonction javascript "eval", utilisée à l'étape 6, qui rend tout cela possible. Il faudra une chaîne pour déterminer si une variable existe avec ce nom et, si tel est le cas, renvoie la valeur de cette variable.

2
sh0ber

Vous pouvez toujours utiliser une propriété "DocumentStream" ou "DocumentText". Pour travailler avec des documents HTML, je recommande un HTML Agility Pack .

1
TcKs

j'utilise ceci:

webBrowser.Document.InvokeScript("execScript", new object[] { "alert(123)", "JavaScript" })
0
Z.R.T.

Si vous devez injecter un fichier entier, vous pouvez utiliser ceci:

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

N'oubliez pas d'importer System.IO pour utiliser le StreamReader. J'espère que ça aide.

0
pablo

Ce que vous voulez faire est d'utiliser Page.RegisterStartupScript (clé, script):

Voir ici pour plus de détails: http://msdn.Microsoft.com/en-us/library/aa478975.aspx

En gros, vous construisez votre chaîne javascript, transmettez-la à cette méthode et attribuez-lui un identifiant unique (si vous essayez de l'enregistrer deux fois sur une page).

EDIT: C'est ce que vous appelez le déclencheur heureux. N'hésitez pas à le descendre. :)

0
mattlant