新手第一次用winform。遇到的js脚本错误跟证书弹框两者不可兼得的问题。以下是网上搜索遇到的坑跟最终的解决方案
坑一:将ScriptErrorsSuppressed设置为true。就是这个导致证书无法弹出来。进不了一些需要证书的网站。
private void browser_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
((WebBrowser)sender).Document.Window.Error
+= new HtmlElementErrorEventHandler(Window_Error);
}
private void Window_Error(object sender, HtmlElementErrorEventArgs
e)
{
// Ignore the error and suppress the error dialog box.
e.Handled = true;
}
网上给出的上面这段代码。不设置true然后加上这段代码。我觉得是能屏蔽掉一些脚本错误的。但是大部分的js报错还是无法屏蔽。
坑二:引入SHDocVw。可以屏蔽脚本错误。但是证书弹不出来
实际解决方案:
1、添加类NativeMethods
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace AuthClient
{
public static class NativeMethods
{
public enum OLECMDF
{
// Fields
OLECMDF_DEFHIDEONCTXTMENU = 0x20,
OLECMDF_ENABLED = 2,
OLECMDF_INVISIBLE = 0x10,
OLECMDF_LATCHED = 4,
OLECMDF_NINCHED = 8,
OLECMDF_SUPPORTED = 1
}
public enum OLECMDID
{
// Fields
OLECMDID_PAGESETUP = 8,
OLECMDID_PRINT = 6,
OLECMDID_PRINTPREVIEW = 7,
OLECMDID_PROPERTIES = 10,
OLECMDID_SAVEAS = 4,
OLECMDID_SHOWSCRIPTERROR = 40
}
public enum OLECMDEXECOPT
{
// Fields
OLECMDEXECOPT_DODEFAULT = 0,
OLECMDEXECOPT_DONTPROMPTUSER = 2,
OLECMDEXECOPT_PROMPTUSER = 1,
OLECMDEXECOPT_SHOWHELP = 3
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770"), ComVisible(true)]
public interface IOleCommandTarget
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryStatus(ref Guid pguidCmdGroup, int cCmds, [In, Out] NativeMethods.OLECMD prgCmds, [In, Out] IntPtr pCmdText);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Exec(ref Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, [In, MarshalAs(UnmanagedType.LPArray)] object[] pvaIn, ref int pvaOut);
}
[StructLayout(LayoutKind.Sequential)]
public class OLECMD
{
[MarshalAs(UnmanagedType.U4)]
public int cmdID;
[MarshalAs(UnmanagedType.U4)]
public int cmdf;
public OLECMD()
{
}
}
public const int S_FALSE = 1;
public const int S_OK = 0;
public static readonly Guid CGID_DocHostCommandHandler = new Guid("f38bc242-b950-11d1-8918-00c04fc2c836");
public const int VARIANT_TRUE = -1;
public const int VARIANT_FALSE = 0;
public const int OLECMDERR_E_NOTSUPPORTED = -2147221244;
}
}
2、写一个自己的mywebbrowser类继承webbrowser
public class WygIeWebBrowser : WebBrowser
{
System.Windows.Forms.AxHost.ConnectionPointCookie cookie;
NewWebBrowserEvent events;
public event EventHandler BeforeNavigate;
public delegate void OnNewWindow2(WebBrowserUrlForWygIe webPra, WebBrowserEvent cancel);
public event OnNewWindow2 BeforeNewWindowForWygIe;
protected override void CreateSink()
{
base.CreateSink();//还是需要源
events = new NewWebBrowserEvent(this);
cookie = new System.Windows.Forms.AxHost.ConnectionPointCookie(this.ActiveXInstance, events, typeof(INewDWWebBrowserEvent));
}
protected override void DetachSink()
{
if (null != cookie)
{
cookie.Disconnect();
cookie = null;
}
base.DetachSink();
}
public void OnBeforeNavigate(string url, string frame, out bool cancel)
{
var Arg = BeforeNavigate;
WebBrowserUrl webBrowserUrl = new WebBrowserUrl(url, frame);
Arg?.Invoke(this, webBrowserUrl);
cancel = webBrowserUrl.Cancel;
}
public void OnBeforeNewWindow(string url, out bool cancel)
{
//var Arg = BeforeNewWindow;
//WebBrowserUrl webBrowserUrl = new WebBrowserUrl(url, null);
//Arg?.Invoke(this, webBrowserUrl);
//cancel = webBrowserUrl.Cancel;
var Arg = BeforeNewWindowForWygIe;
WebBrowserUrlForWygIe webBrowserUrl = new WebBrowserUrlForWygIe(url, null);
WebBrowserEvent webBrowserEvent = new WebBrowserEvent();
Arg?.Invoke(webBrowserUrl, webBrowserEvent);
cancel = webBrowserEvent.cancel;
}
class ExtendedWebBrowserSite : WebBrowser.WebBrowserSite, NativeMethods.IOleCommandTarget
{
/// <summary>
/// Creates a new instance of the <see cref="ExtendedWebBrowserSite"/> class
/// </summary>
/// <param name="host">The <see cref="ExtendedWebBrowser"/> hosting the browser</param>
public ExtendedWebBrowserSite(WebBrowser host)
: base(host)
{
_host = host;
}
private WebBrowser _host;
private WebBrowser Host
{
get
{
return _host;
}
}
#region IOleCommandTarget Members
int NativeMethods.IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, int cCmds, NativeMethods.OLECMD prgCmds, IntPtr pCmdText)
{
return NativeMethods.S_FALSE;
}
int NativeMethods.IOleCommandTarget.Exec(ref Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, object[] pvaIn, ref int pvaOut)
{
int hResult = NativeMethods.S_OK;
if (pguidCmdGroup == null)
return hResult;
// Check for invalid pointers (or get a NullReferenceException on a value type???)
//if (NativeMethods.CGID_DocHostCommandHandler.Equals(pguidCmdGroup))
{
switch (nCmdID)
{
case (int)NativeMethods.OLECMDID.OLECMDID_SHOWSCRIPTERROR:
// Hide the dialog
pvaOut = NativeMethods.VARIANT_TRUE;
break;
default:
hResult = NativeMethods.OLECMDERR_E_NOTSUPPORTED;
break;
}
}
return hResult;
}
#endregion
}
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
{
return new ExtendedWebBrowserSite(this);
}
}
这种解决方案是参考了文档:https://www.cnblogs.com/qq1223558/p/3431736.html
跟https://www.xuebuyuan.com/180680.html。引入代码后解决了一些报错。实际上可行。
另外上面这一段加入后有一点不完美的地方忘记是什么了。我把最开始尝试屏蔽js脚本错误但没作用的一段代码打开了就可以了。尝试的方法是下面这段代码。
访问链接后获取SHDocVw.WebBrowser对象
SHDocVw.WebBrowser wb;
wygIeWebBrowser.Navigate(url);
wb = (SHDocVw.WebBrowser)wygIeWebBrowser.ActiveXInstance;
wb.NavigateComplete2 += new DWebBrowserEvents2_NavigateComplete2EventHandler(wb_NavigateComplete2);//wb是一个Webbrowser控件
重写NavigateComplete2 方法。
void wb_NavigateComplete2(object pDisp, ref object URL)
{
mshtml.IHTMLDocument2 doc = wb.Document as mshtml.IHTMLDocument2;
doc.parentWindow.execScript("window.alert=null", "javascript");
doc.parentWindow.execScript("window.confirm=null", "javascript");
doc.parentWindow.execScript("window.open=null", "javascript");
doc.parentWindow.execScript("window.showModalDialog=null", "javascript");
doc.parentWindow.execScript("window.close=null", "javascript");
doc.parentWindow.execScript("function alert(str){return ''}", "javascript");
}
需要引入两个dll文件shdocvw.dll跟Microsoft.mshtml.dll
第一个文件在你系统目录C:\Windows\System32下面可以找到
第二个文件在vs里面能找到