2012-01-16 18 views
8

मेरे पास एक WinForms एप्लिकेशन है जिसमें मैंने WebBrowser नियंत्रण के अंदर एक वेब पेज होस्ट किया है।वेबब्राउज़र नियंत्रण में ऑनबर्ननलोड ईवेंट को कैसे रोकें?

वेब पृष्ठ की सामग्री निम्नलिखित है:

<!DOCTYPE html> 
<html lang="en" dir="ltr"> 
<head> 
    <title>onbeforeunload test</title> 
    <meta charset="utf-8"> 
</head> 
<body> 

<a href="#" onclick="window.location.reload();">Test</a> 

<script type="text/javascript"> 
    window.onbeforeunload = function() { 
     return 'Are you sure you want to leave this page?'; 
    }; 
</script> 
</body> 
</html> 

आप देख सकते हैं मैं onbeforeunload घटना है जो इस पेज से नेविगेट करने से पहले एक पुष्टिकरण संवाद दिखा सकता है, की सदस्यता ली है। यह ठीक काम करता है जब मैं एंकर पर क्लिक करता हूं जो पृष्ठ को पुनः लोड करता है। पुष्टिकरण बॉक्स दिखाया गया है और उपयोगकर्ता पृष्ठ के पुनः लोड को रद्द कर सकता है। यह WinForms होस्टेड नियंत्रण के अंदर ठीक काम करता है।

अब, मुझे इस समस्या को रोकना और निष्पादित करना है जब उपयोगकर्ता WinForms एप्लिकेशन को बंद करता है (उदाहरण के लिए एक्स बटन पर क्लिक करके)।

मैं WinForms एप्लिकेशन में इस फ़ंक्शन की सामग्री लाने में सक्षम हूं लेकिन इससे कोई फर्क नहीं पड़ता कि मैंने कोशिश की कि मैं इस स्ट्रिंग की स्ट्रिंग की सामग्री प्राप्त नहीं कर पा रहा हूं ताकि मैं इसे बाद में नकली में उपयोग कर सकूं।

webBrowser1.Navigated += (sender, e) => 
{ 
    webBrowser1.Document.Window.Load += (s, ee) => 
    { 
     // In order to get the IHTMLWindow2 interface I have referenced 
     // the Microsoft HTML Object Library (MSHTML) COM control 
     var window = (IHTMLWindow2)webBrowser1.Document.Window.DomWindow; 

     // the bu variable contains the script of the onbeforeunload event 
     var bu = window.onbeforeunload(); 

     // How to get the string that is returned by this function 
     // so that I can subscribe to the Close event of the WinForms application 
     // and show a fake MessageBox with the same text? 
    }; 
}; 
webBrowser1.Navigate("file:///c:/index.htm"); 

मुझे कोई उपलब्ध करने के लिए window.execScript विधि की कोशिश की है: MessageBox जब उपयोगकर्ता अनुप्रयोग को बंद करने का प्रयास करता

// returns null 
var script = string.Format("({0})();", bu); 
var result = window.execScript(script, "javascript"); 

मैं भी कोशिश की है निम्नलिखित लेकिन यह भी अशक्त लौट आए:

01,235,
var result = window.execScript("(function() { return 'foo'; })();", "javascript"); 

अंतिम उपाय के रूप में मैं एक तृतीय पक्ष जावास्क्रिप्ट पार्सर का उपयोग कर सकता हूं जिसके लिए मैं इस समारोह के शरीर को खिला सकता हूं और यह इसे निष्पादित करेगा और मुझे वापसी मूल्य देगा लेकिन यह वास्तव में अंतिम उपाय होगा। माइक्रोसॉफ्ट की एमएसएचटीएमएल लाइब्रेरी का उपयोग करके ऐसा करने का एक और मूल तरीका होने पर मुझे खुशी होगी।


अद्यतन:

यह अब excellent answer कि @Hans प्रदान की करने के लिए धन्यवाद हल किया जाता है। किसी कारण से मैं अपनी टेस्ट मशीन (विन 7 एक्स 64, .NET 4.0 क्लाइंट प्रोफाइल, आईई 9, एन-यूएस लोकेल) पर अपना समाधान काम नहीं कर सका और IDispatch.Invoke कॉल के बाद मुझे हमेशा hr = -2147024809 मिल रहा था। तो मैं निम्नलिखित करने के लिए IDispatch पी/आह्वान हस्ताक्षर को संशोधित किया है (इस हस्ताक्षर c:\windows\system32\stdole2.tlb के लिए एक संदर्भ की आवश्यकता नहीं है परियोजना के लिए जोड़ा जा करने के लिए):

using System; 
using System.Runtime.InteropServices; 
using System.Runtime.InteropServices.ComTypes; 

[ComImport] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
[Guid("00020400-0000-0000-C000-000000000046")] 
public interface IDispatch 
{ 
    [PreserveSig] 
    int GetTypeInfoCount(out int Count); 
    [PreserveSig] 
    int GetTypeInfo(
     [MarshalAs(UnmanagedType.U4)] int iTInfo, 
     [MarshalAs(UnmanagedType.U4)] int lcid, 
     out ITypeInfo typeInfo 
    ); 

    [PreserveSig] 
    int GetIDsOfNames(
     ref Guid riid, 
     [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgsNames, 
     int cNames, 
     int lcid, 
     [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId 
    ); 

    [PreserveSig] 
    int Invoke(
     int dispIdMember, 
     ref Guid riid, 
     uint lcid, 
     ushort wFlags, 
     ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, 
     out object pVarResult, 
     ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, 
     IntPtr[] pArgErr 
    ); 
} 

और फिर मैं के समापन घटना की सदस्यता ली है फार्म और संदेश onbeforeunload घटना द्वारा वापस लाने के लिए कर रहा था और के लिए संकेत करें:

protected override void OnFormClosing(FormClosingEventArgs e) 
{ 
    var window = (IHTMLWindow2)webBrowser1.Document.Window.DomWindow; 
    var args = new System.Runtime.InteropServices.ComTypes.DISPPARAMS(); 
    var result = new object(); 
    var except = new System.Runtime.InteropServices.ComTypes.EXCEPINFO(); 
    var idisp = window.onbeforeunload as IDispatch; 
    if (idisp != null) 
    { 
     var iid = Guid.Empty; 
     var lcid = (uint)CultureInfo.CurrentCulture.LCID; 
     int hr = idisp.Invoke(0, ref iid, lcid, 1, ref args, out result, ref except, null); 
     if (hr == 0) 
     { 
      var msgBox = MessageBox.Show(
       this, 
       (string)result, 
       "Confirm", 
       MessageBoxButtons.OKCancel 
      ); 
      e.Cancel = msgBox == DialogResult.Cancel; 
     } 
    } 
    base.OnFormClosing(e); 
} 
+0

कभी 'window.onbeforeunload पर भरोसा करते हैं()', वे कभी ओपेरा ब्राउज़र के तहत काम कभी नहीं होगा। बस एक टिप। –

+0

@ sh4nx0r, मुझे ओपेरा के बारे में परवाह नहीं है। मैं WinForms एप्लिकेशन में होस्ट किए गए वेबब्रोसर नियंत्रण का उपयोग कर रहा हूं। यह इंटरनेट एक्सप्लोरर का तात्पर्य है। –

+0

जाहिर है 'execScript' हमेशा शून्य वापस आ जाएगा: एस मददगार मुझे पता है। मैं सोच सकता हूं कि आप अपना खुद का बहुत ही बुनियादी पार्सर रोल करते हैं जो सिंगल कोट्स द्वारा 'bu' के परिणाम को विभाजित करता है और पहले आइटम को पुनर्प्राप्त स्ट्रिंग सरणी में ले जाता है; जैसे मैंने बहुत ही बुनियादी कहा;) –

उत्तर

10

IHtmlWindow2.onbeforeunload स्वयं संवाद प्रदर्शित नहीं करता है। यह केवल एक स्ट्रिंग देता है जिसे होस्ट को संदेश बॉक्स में उपयोग करना चाहिए। चूंकि आपका Winforms ऐप होस्ट है, इसलिए इसे MessageBox.Show() का उपयोग करना होगा। ऑनबर्नलोड लोड करना मुश्किल है, यह एक आईडीस्पैच पॉइंटर है जिसका डिफ़ॉल्ट सदस्य (डिस्पिड 0) स्ट्रिंग देता है।c:\windows\system32\stdole2.tlb के लिए एक संदर्भ जोड़ें और इस कोड पेस्ट करें:

using System.Runtime.InteropServices; 
... 
     [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-C000-000000000046")] 
     public interface IDispatch { 
      int dummy1(); 
      int dummy2(); 
      int dummy3(); 
      [PreserveSig] 
      int Invoke(int dispIdMember, ref Guid riid, int lcid, int dwFlags, 
       [In, Out] stdole.DISPPARAMS pDispParams, 
       [Out, MarshalAs(UnmanagedType.LPArray)] object[] pVarResult, 
       [In, Out] stdole.EXCEPINFO pExcepInfo, 
       [Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] pArgErr); 
     } 

आप इसे इस तरह का उपयोग करेंगे:

protected override void OnFormClosing(FormClosingEventArgs e) { 
     var window = (IHTMLWindow2)webBrowser1.Document.Window.DomWindow; 
     var args = new stdole.DISPPARAMS(); 
     var result = new object[1]; 
     var except = new stdole.EXCEPINFO(); 
     var idisp = (IDispatch)window.onbeforeunload; 
     var iid = Guid.Empty; 
     int hr = idisp.Invoke(0, ref iid, 1033, 1, args, result, except, null); 
     if (hr == 0) { 
      if (MessageBox.Show(this, (string)result[0], "Confirm", 
       MessageBoxButtons.OKCancel) == DialogResult.Cancel) e.Cancel = true; 
     } 
     base.OnFormClosing(e);              
    } 
+0

वाह, यह बेहद आशाजनक दिखता है। उत्कृष्ट जवाब। बहुत बहुत धन्यवाद। यह सिर्फ मुझे 'आमंत्रण' कॉल के बाद 'hr = -2147024809' मिलता है। मैं विंडोज 7 x64 बिट पर चल रहा हूं। क्या इसका कुछ प्रभाव हो सकता है? अभी x86 पर परीक्षण नहीं कर सकता जो मेरे आवेदन के लिए अंतिम लक्ष्य होगा। IE9 स्थापित के साथ .NET 4.0 क्लाइंट प्रोफ़ाइल का उपयोग करना। क्या कुछ और विस्तृत त्रुटि जानकारी प्राप्त करना संभव है? –

+0

मैंने Win7 x64 पर इसका परीक्षण किया। त्रुटि कोड का अर्थ है "अवैध तर्क", यह एक Windows त्रुटि है, COM त्रुटि नहीं। यकीन है कि इसका क्या कारण है। केवल 1033 है, यूएस अंग्रेज़ी के लिए भाषा आईडी। आप अंग्रेजी नहीं हैं। इसके बजाय CultureInfo.LCID आज़माएं। –

+0

मैं एक अमेरिकी-यूएस लोकेल पर हूं। 'CultureInfo.CurrentCulture.LCID = 1033'। अगर मैं 'संदेशबॉक्स' दिखाता हूं (नया Win32Exc eption (मार्शल.GetLastWin32Error()) संदेश); ​​'आमंत्रण कॉल के ठीक बाद यह दिखाता है: ऑपरेशन सफलतापूर्वक पूरा हुआ, इसलिए मुझे लगता है कि यह Win32 त्रुटि नहीं है। –

1

यदि आपका समय से पहले ही घटना कोड (कुछ भी हो सकता है) निम्नलिखित अपने Window.Load में मेरे लिए स्ट्रिंग कब्जा निष्पादित करने के लिए खुश ;

Object[] args = { @"(" + bu + ")();" }; 
string result = webBrowser1.Document.InvokeScript("eval", args).ToString(); 
3

मैं सिर्फ एक समान समस्या के साथ निपटा। यह एक देर का जवाब है, लेकिन उम्मीद है कि यह किसी की मदद कर सकता है। समाधान this MSKB article पर आधारित है। यह उन मामलों के लिए भी काम करता है जब वेब पेज onbeforeunload ईवेंट attachEvent या addEventListener के माध्यम से संभालता है।

void Form1_FormClosing(object sender, FormClosingEventArgs e) 
{ 
    // this code depends on SHDocVw.dll COM interop assembly, 
    // generate SHDocVw.dll: "tlbimp.exe ieframe.dll", 
    // and add as a reference to the project 

    var activeX = this.webBrowser.ActiveXInstance; 
    object arg1 = Type.Missing; 
    object arg2 = true; 
    ((SHDocVw.WebBrowser)activeX).ExecWB(SHDocVw.OLECMDID.OLECMDID_ONUNLOAD, SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT, ref arg1, ref arg2); 
    if (!(bool)arg2) 
    { 
     e.Cancel = true; 
    } 
} 

ऊपर कोड WebBrowser नियंत्रण से WinForms संस्करण के लिए है। WPF संस्करण के लिए, ActiveXInstance पहले प्रतिबिंब के माध्यम से प्राप्त किया जाना चाहिए:

var activeX = this.WB.GetType().InvokeMember("ActiveXInstance", 
        BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, 
        null, this.WB, new object[] { }) as SHDocVw.WebBrowser; 
संबंधित मुद्दे