WebBrowser kontrolünde Javascript nasıl enjekte edilir?


81

Bunu denedim:

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 ve scriptEl.InnerText'in her ikisi de hata veriyor:

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)

Doma bir komut dosyası enjekte etmenin kolay bir yolu var mı?

Yanıtlar:


101

Nedense Richard'ın çözümü benim tarafımda işe yaramadı (insertAdjacentText bir istisna ile başarısız oldu). Ancak bu işe yarıyor gibi görünüyor:

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

Bu cevap , IHTMLScriptElementarayüzü projenize nasıl dahil edeceğinizi açıklar .


1
Harika, sanırım IHTMLScriptElement kullanımı her durumda kod amacını daha açık hale getiriyor. Neden bir istisnanız olduğunu merak ediyorum, ancak bazen COM interop ile yaşayın.
ZeroBugBounce

Yerel bir js dosyasına referans eklemeye ne dersiniz? Lütfen stackoverflow.com/questions/4029602/…
IAmAN00B

Lütfen bana yardım et. Bunu nasıl yaptın. C ++ uygulamam aracılığıyla sayfama gerçek zamanlı olarak JS enjekte etmek istiyorum. Nasıl devam etmeliyim?
Johnydep

bu jquery dosyasını enjekte etmek için de geçerli mi?
gumuruh

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

(.NET 4 / Windows Forms Uygulamasında test edilmiştir)

Düzenleme: İşlev setindeki durum sorunu düzeltildi.


12
Bu çözümü takdir ettim çünkü (faydalı olsa da!) IHTMLSCriptElement derlemesine dayanmıyor.
Micah Smith

6
@jsight Bu kabul edilen cevap olmalıdır. Mevcut cevapla aynı, ancak daha basit ve IHTMLSCriptElementbağımlılık yok.
BlueRaja - Danny Pflughoeft

32

İşte bunun üzerinde çalıştıktan sonra bulduğum en kolay yol:

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

Genel JavaScript işlevinin eval(str)yaptığı şey, str'de yazılanları ayrıştırıp yürütmektir. W3schools referansını buradan kontrol edin .


22

Ayrıca, .NET 4'te dinamik anahtar sözcüğü kullanırsanız bu daha da kolaydır:

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

2
Bunun için neden dinamiğe ihtiyaç duyulsun? Bazı yazımları kaydetmeye çalışıyorsanız, C # 3.0'dan beri tür çıkarımımız var, bu nedenle var kabul edilebilir. DLR'yi başlatmaya gerek yoktur.
alimbada

23
Bu temelde tam olarak dinamik anahtar kelimenin amacıdır: COM birlikte çalışma. Aslında burada Tür Çıkarımına sahip değilsiniz, belgeleriniz var. Örneğin bir IHTMLElement2, IHtmlElement'ten atanabilir olmadığından ve çalışma zamanında yalnızca bir COM proxy nesnesine sahip olursunuz. Sadece hangi arayüzlerin neye dönüştürüleceğini bilmeniz gerekir. Dinamik anahtar kelime, bu kusurların çoğunu azaltmanıza yardımcı olur. Yöntemin var olduğunu biliyorsunuz, neden onu bir arayüze çeviriyorsunuz? Tam olarak 'DLR'yi çağırmaz', sadece COM nesnelerinde yöntemin nasıl çağrılacağını bilen bir kod üretir (bu durumda).
justin.m.chase

1
@ justin.m.chase hayatımı kurtardın.
Khizar Iqbal

17

Gerçekten istediğiniz tek şey javascript çalıştırmaksa, bu en kolayı olacaktır (VB .Net):

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

Sanırım bu onu "enjekte" etmeyecek, ancak peşinde olduğunuz şey buysa, işlevinizi çalıştıracaktır. (Sorunu aşırı karmaşık hale getirmeniz durumunda.) Ve javascript'i nasıl enjekte edeceğinizi bulabilirseniz, bunu "foo" işlevinin gövdesine koyun ve javascript'in enjeksiyonu sizin için yapmasına izin verin.


10

HTML belgesi için yönetilen sarmalayıcı ihtiyacınız olan işlevselliği tam olarak uygulamaz, bu nedenle istediğinizi başarmak için MSHTML API'sine girmeniz gerekir:

1) MSHTML'ye, muhtemelen COM referansları altında "Microsoft HTML Nesne Kitaplığı" olarak adlandırılacak bir referans ekleyin .

2) 'using mshtml' ekleyin; ad alanlarınıza.

3) Komut dosyası öğenizin IHTMLElement'ine bir referans alın:

IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement;

4) "afterBegin" ilk parametre değeriyle insertAdjacentText yöntemini çağırın. Tüm olası değerler burada listelenmiştir :

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

5) Artık kodu scriptEl.InnerText özelliğinde görebileceksiniz.

Hth, Richard


1
Güzel ... bu korchev tarafından sağlanan ipuçlarıyla birlikte mükemmel çalışıyor. Keşke bu konuda iki kabul edilmiş çözüm belirleyebilseydim. :)
jsight

8

Bir takibinde gelince kabul cevap , bu minimal tanımıdır IHTMLScriptElementarayüzüne ek tip kütüphaneleri dahil etmek gerektirmez:

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

Dolayısıyla, bir WebBrowser denetiminden türetilmiş sınıf içindeki tam kod şu şekilde görünür:

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

C # 'dan bir WebBrowser Control HTML Dokümanına Javascript enjekte etmenin en basit yönteminin, argüman olarak enjekte edilecek kodla "execScript" yöntemini çağırmak olduğuna inanıyorum.

Bu örnekte, javascript kodu genel kapsamda enjekte edilir ve yürütülür:

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

Yürütmeyi ertelemek istiyorsanız, işlevleri enjekte edin ve sonra çağırın:

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

Bu, Windows Forms ve WPF WebBrowser denetimleri için geçerlidir.

Bu çözüm çapraz tarayıcı değildir çünkü "execScript" yalnızca IE ve Chrome'da tanımlanmıştır. Ancak soru Microsoft WebBrowser kontrolleriyle ilgili ve desteklenen tek soru IE'dir.

JavaScript kodunu enjekte etmek üzere geçerli bir tarayıcılar arası yöntem için, yeni Anahtar Sözcük ile bir Function nesnesi oluşturun. Bu örnek, enjekte edilen kodla anonim bir işlev yaratır ve onu çalıştırır (javascript kapanışları uygular ve işlevin yerel değişken kirliliği olmadan küresel alana erişimi vardır).

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

Elbette yürütmeyi erteleyebilirsiniz:

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

Umarım yardımcı olur


7

bu mshtml kullanan bir çözümdür

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
Bu bir topluluk kaynağı olduğu için yanıtı başkaları için hala yararlıdır (benim gibi). Mshtml eşdeğeri için +1, bana bir soru kaydetti.
Kyeotic

1
Bunu bulan herkes için son satırdan 'sınıfı' kaldırın, ((HTMLHeadElement)head).appendChild((IHTMLDOMNode)scriptObject);aksi takdirde hata alacağınızı okumalısınız .
Kyeotic

1
Bu cevabın yöneticiler tarafından terfi ettirilebileceği bir yol var mı? Bunun üzerindekiler gerçekte yanlıştır. Bu geç gelen biriydi ama gerçekten en doğru cevap.
justin.m.chase

2

Bunu kullandım: D

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

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

Sonra şu şekilde çalıştırabilir ve sonucu alabilirsiniz:

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

Yardımcı olmayı umuyorum


2

WebBrowser denetimine yüklenen bir sayfadan bir değişkenin değerini almaya çalışıyorsanız, burada bir VB.Net örneği verilmiştir.

Adım 1) Projenize Microsoft HTML Nesne Kitaplığı'na bir COM referansı ekleyin

Adım 2) Ardından, mshtml kitaplığını içe aktarmak için bu VB.Net kodunu Form1'e ekleyin: mshtml'yi içe
aktarır

Adım 3) Bu VB.Net kodunu "Public Class Form1" satırınızın üstüne ekleyin:
<System.Runtime.InteropServices.ComVisibleAttribute (True)>

Adım 4) Projenize bir WebBrowser denetimi ekleyin

Adım 5) Bu VB.Net kodunu Form1_Load işlevinize ekleyin:
WebBrowser1.ObjectForScripting = Me

Adım 6) Web sayfasının Javascript'ine bir "CallbackGetVar" işlevi enjekte edecek bu VB.Net alt bölümünü ekleyin:

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

Adım 7) Javascript'in daha sonra çağrıldığında arayacağı aşağıdaki VB.Net altını ekleyin:

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

Adım 8) Son olarak, Javascript geri aramasını çağırmak için, bu VB.Net kodunu bir düğmeye basıldığında veya istediğiniz yere ekleyin:

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

Adım 9) Bunun işe yaraması sizi şaşırttıysa, Adım 6'da kullanılan Javascript "eval" işlevini okumak isteyebilirsiniz, bu da bunu mümkün kılar. Bir dizge alır ve bu isimde bir değişkenin var olup olmadığını belirler ve eğer öyleyse, o değişkenin değerini döndürür.


1

Her zaman bir "DocumentStream" veya "DocumentText" özelliğini kullanabilirsiniz. HTML belgeleriyle çalışmak için bir HTML Çeviklik Paketi öneririm .


Güzel ipucu ... Eminim ki lib bir noktada işe yarayacaktır.
jsight

1

Bunu kullanıyorum:

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

0

Yapmak istediğiniz, Page.RegisterStartupScript (anahtar, komut dosyası) kullanmaktır:

Daha fazla ayrıntı için buraya bakın: http://msdn.microsoft.com/en-us/library/aa478975.aspx

Temelde yaptığınız şey, javascript dizenizi oluşturmak, onu bu yönteme iletmek ve benzersiz bir kimlik vermektir (bir sayfada iki kez kaydetmeye çalışmanız durumunda).

DÜZENLEME: Bu, tetikleyici mutlu dediğiniz şeydir. İndirmekten çekinmeyin. :)


4
ASP.Net'in bir winforms uygulamasında WebBrowser kontrolünün komut dosyasıyla yazılmasıyla pek ilgisi yoktur.
jsight

Muhtemelen aynı şekilde az okuyup aynı yanlış cevabı
verirdim

0

Bütün bir dosyayı enjekte etmeniz gerekiyorsa, bunu kullanabilirsiniz:

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

İthalat unutmayın System.IOkullanmak için StreamReader. Umarım bu yardımcı olur.


Bunun bir yıldan 3 gün önce yanıtlandığını biliyorum, ancak bunu bir dosyayı bir input type="file"bölüme koymak için kullanabilir misin?
Chris Hobbs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.